From 1b2b6a1b15fc3a3beedd7f344aedd40e1d426dde Mon Sep 17 00:00:00 2001 From: Sasha <64744993+r1tsuu@users.noreply.github.com> Date: Mon, 24 Mar 2025 15:49:30 +0200 Subject: [PATCH 01/77] fix: respect `draft: true` when querying docs for the join field (#11763) Previously, if you were querying a collection that has a join field with `draft: true`, and the join field's collection also has `versions.drafts: true` our db adapter would still query the original SQL table / mongodb collection instead of the versions one which isn't quite right since we respect `draft: true` when populating relationships --- packages/db-mongodb/src/find.ts | 2 + packages/db-mongodb/src/findOne.ts | 3 +- .../src/utilities/buildJoinAggregation.ts | 69 +++++++++++++++---- packages/drizzle/src/find.ts | 15 +++- .../drizzle/src/find/buildFindManyArgs.ts | 3 + packages/drizzle/src/find/findMany.ts | 2 + packages/drizzle/src/find/traverseFields.ts | 54 +++++++++++++-- packages/drizzle/src/findOne.ts | 3 +- .../src/transform/read/traverseFields.ts | 1 - packages/next/src/layouts/Root/index.tsx | 4 +- .../src/collections/operations/find.ts | 1 + .../src/collections/operations/findByID.ts | 1 + packages/payload/src/database/types.ts | 2 + packages/payload/src/index.ts | 10 ++- .../drafts/replaceWithDraftIfAvailable.ts | 1 - packages/ui/src/fields/Upload/Input.tsx | 2 +- test/joins/int.spec.ts | 21 ++++++ 17 files changed, 165 insertions(+), 29 deletions(-) diff --git a/packages/db-mongodb/src/find.ts b/packages/db-mongodb/src/find.ts index f33df57990..938940c513 100644 --- a/packages/db-mongodb/src/find.ts +++ b/packages/db-mongodb/src/find.ts @@ -18,6 +18,7 @@ export const find: Find = async function find( this: MongooseAdapter, { collection: collectionSlug, + draftsEnabled, joins = {}, limit = 0, locale, @@ -128,6 +129,7 @@ export const find: Find = async function find( adapter: this, collection: collectionSlug, collectionConfig, + draftsEnabled, joins, locale, query, diff --git a/packages/db-mongodb/src/findOne.ts b/packages/db-mongodb/src/findOne.ts index 16f7c8f992..0ffe97b108 100644 --- a/packages/db-mongodb/src/findOne.ts +++ b/packages/db-mongodb/src/findOne.ts @@ -14,7 +14,7 @@ import { transform } from './utilities/transform.js' export const findOne: FindOne = async function findOne( this: MongooseAdapter, - { collection: collectionSlug, joins, locale, req, select, where = {} }, + { collection: collectionSlug, draftsEnabled, joins, locale, req, select, where = {} }, ) { const { collectionConfig, Model } = getCollection({ adapter: this, collectionSlug }) @@ -42,6 +42,7 @@ export const findOne: FindOne = async function findOne( adapter: this, collection: collectionSlug, collectionConfig, + draftsEnabled, joins, locale, projection, diff --git a/packages/db-mongodb/src/utilities/buildJoinAggregation.ts b/packages/db-mongodb/src/utilities/buildJoinAggregation.ts index ca01765236..0d8afb3688 100644 --- a/packages/db-mongodb/src/utilities/buildJoinAggregation.ts +++ b/packages/db-mongodb/src/utilities/buildJoinAggregation.ts @@ -2,14 +2,19 @@ import type { PipelineStage } from 'mongoose' import { APIError, + appendVersionToQueryKey, + buildVersionCollectionFields, type CollectionSlug, + combineQueries, type FlattenedField, + getQueryDraftsSort, type JoinQuery, type SanitizedCollectionConfig, } from 'payload' import { fieldShouldBeLocalized } from 'payload/shared' import type { MongooseAdapter } from '../index.js' +import type { CollectionModel } from '../types.js' import { buildQuery } from '../queries/buildQuery.js' import { buildSortParam } from '../queries/buildSortParam.js' @@ -19,6 +24,7 @@ type BuildJoinAggregationArgs = { adapter: MongooseAdapter collection: CollectionSlug collectionConfig: SanitizedCollectionConfig + draftsEnabled?: boolean joins?: JoinQuery locale?: string projection?: Record @@ -32,6 +38,7 @@ export const buildJoinAggregation = async ({ adapter, collection, collectionConfig, + draftsEnabled, joins, locale, projection, @@ -262,10 +269,27 @@ export const buildJoinAggregation = async ({ continue } - const { collectionConfig, Model: JoinModel } = getCollection({ - adapter, - collectionSlug: join.field.collection as string, - }) + const collectionConfig = adapter.payload.collections[join.field.collection as string]?.config + + if (!collectionConfig) { + throw new APIError( + `Collection config for ${join.field.collection.toString()} was not found`, + ) + } + + let JoinModel: CollectionModel | undefined + + const useDrafts = (draftsEnabled || versions) && Boolean(collectionConfig.versions.drafts) + + if (useDrafts) { + JoinModel = adapter.versions[collectionConfig.slug] + } else { + JoinModel = adapter.collections[collectionConfig.slug] + } + + if (!JoinModel) { + throw new APIError(`Join Model was not found for ${collectionConfig.slug}`) + } const { count, @@ -279,12 +303,16 @@ export const buildJoinAggregation = async ({ throw new Error('Unreachable') } + const fields = useDrafts + ? buildVersionCollectionFields(adapter.payload.config, collectionConfig, true) + : collectionConfig.flattenedFields + const sort = buildSortParam({ adapter, config: adapter.payload.config, - fields: collectionConfig.flattenedFields, + fields, locale, - sort: sortJoin, + sort: useDrafts ? getQueryDraftsSort({ collectionConfig, sort: sortJoin }) : sortJoin, timestamps: true, }) const sortProperty = Object.keys(sort)[0]! @@ -293,7 +321,13 @@ export const buildJoinAggregation = async ({ const $match = await JoinModel.buildQuery({ locale, payload: adapter.payload, - where: whereJoin, + where: useDrafts + ? combineQueries(appendVersionToQueryKey(whereJoin), { + latest: { + equals: true, + }, + }) + : whereJoin, }) const pipeline: Exclude[] = [ @@ -345,6 +379,12 @@ export const buildJoinAggregation = async ({ }, ) + let foreignFieldPrefix = '' + + if (useDrafts) { + foreignFieldPrefix = 'version.' + } + if (adapter.payload.config.localization && locale === 'all') { adapter.payload.config.localization.localeCodes.forEach((code) => { const as = `${versions ? `version.${join.joinPath}` : join.joinPath}${code}` @@ -353,7 +393,7 @@ export const buildJoinAggregation = async ({ { $lookup: { as: `${as}.docs`, - foreignField: `${join.field.on}${code}${polymorphicSuffix}`, + foreignField: `${foreignFieldPrefix}${join.field.on}${code}${polymorphicSuffix}`, from: JoinModel.collection.name, localField: versions ? 'parent' : '_id', pipeline, @@ -364,7 +404,7 @@ export const buildJoinAggregation = async ({ [`${as}.docs`]: { $map: { as: 'doc', - in: '$$doc._id', + in: useDrafts ? `$$doc.parent` : '$$doc._id', input: `$${as}.docs`, }, }, // Slicing the docs to match the limit @@ -387,7 +427,10 @@ export const buildJoinAggregation = async ({ } if (count) { - addTotalDocsAggregation(as, `${join.field.on}${code}${polymorphicSuffix}`) + addTotalDocsAggregation( + as, + `${foreignFieldPrefix}${join.field.on}${code}${polymorphicSuffix}`, + ) } }) } else { @@ -414,7 +457,7 @@ export const buildJoinAggregation = async ({ { $lookup: { as: `${as}.docs`, - foreignField, + foreignField: `${foreignFieldPrefix}${foreignField}`, from: JoinModel.collection.name, localField: versions ? 'parent' : '_id', pipeline, @@ -425,7 +468,7 @@ export const buildJoinAggregation = async ({ [`${as}.docs`]: { $map: { as: 'doc', - in: '$$doc._id', + in: useDrafts ? `$$doc.parent` : '$$doc._id', input: `$${as}.docs`, }, }, // Slicing the docs to match the limit @@ -437,7 +480,7 @@ export const buildJoinAggregation = async ({ ) if (count) { - addTotalDocsAggregation(as, foreignField) + addTotalDocsAggregation(as, `${foreignFieldPrefix}${foreignField}`) } if (limitJoin > 0) { diff --git a/packages/drizzle/src/find.ts b/packages/drizzle/src/find.ts index 98d78e4d1b..ef3e58d0ff 100644 --- a/packages/drizzle/src/find.ts +++ b/packages/drizzle/src/find.ts @@ -8,7 +8,19 @@ import { findMany } from './find/findMany.js' export const find: Find = async function find( this: DrizzleAdapter, - { collection, joins, limit, locale, page = 1, pagination, req, select, sort: sortArg, where }, + { + collection, + draftsEnabled, + joins, + limit, + locale, + page = 1, + pagination, + req, + select, + sort: sortArg, + where, + }, ) { const collectionConfig: SanitizedCollectionConfig = this.payload.collections[collection].config const sort = sortArg !== undefined && sortArg !== null ? sortArg : collectionConfig.defaultSort @@ -18,6 +30,7 @@ export const find: Find = async function find( return findMany({ adapter: this, collectionSlug: collectionConfig.slug, + draftsEnabled, fields: collectionConfig.flattenedFields, joins, limit, diff --git a/packages/drizzle/src/find/buildFindManyArgs.ts b/packages/drizzle/src/find/buildFindManyArgs.ts index a8b0ca2435..4febf335d1 100644 --- a/packages/drizzle/src/find/buildFindManyArgs.ts +++ b/packages/drizzle/src/find/buildFindManyArgs.ts @@ -11,6 +11,7 @@ type BuildFindQueryArgs = { adapter: DrizzleAdapter collectionSlug?: string depth: number + draftsEnabled?: boolean fields: FlattenedField[] joinQuery?: JoinQuery /** @@ -35,6 +36,7 @@ export const buildFindManyArgs = ({ adapter, collectionSlug, depth, + draftsEnabled, fields, joinQuery, joins = [], @@ -80,6 +82,7 @@ export const buildFindManyArgs = ({ currentArgs: result, currentTableName: tableName, depth, + draftsEnabled, fields, joinQuery, joins, diff --git a/packages/drizzle/src/find/findMany.ts b/packages/drizzle/src/find/findMany.ts index 01e886f8ca..6874e74403 100644 --- a/packages/drizzle/src/find/findMany.ts +++ b/packages/drizzle/src/find/findMany.ts @@ -22,6 +22,7 @@ type Args = { export const findMany = async function find({ adapter, collectionSlug, + draftsEnabled, fields, joins: joinQuery, limit: limitArg, @@ -74,6 +75,7 @@ export const findMany = async function find({ adapter, collectionSlug, depth: 0, + draftsEnabled, fields, joinQuery, joins, diff --git a/packages/drizzle/src/find/traverseFields.ts b/packages/drizzle/src/find/traverseFields.ts index 629f5b124e..771033cc29 100644 --- a/packages/drizzle/src/find/traverseFields.ts +++ b/packages/drizzle/src/find/traverseFields.ts @@ -1,8 +1,18 @@ import type { LibSQLDatabase } from 'drizzle-orm/libsql' import type { SQLiteSelectBase } from 'drizzle-orm/sqlite-core' -import type { FlattenedField, JoinQuery, SelectMode, SelectType, Where } from 'payload' import { and, asc, count, desc, eq, or, sql } from 'drizzle-orm' +import { + appendVersionToQueryKey, + buildVersionCollectionFields, + combineQueries, + type FlattenedField, + getQueryDraftsSort, + type JoinQuery, + type SelectMode, + type SelectType, + type Where, +} from 'payload' import { fieldIsVirtual, fieldShouldBeLocalized } from 'payload/shared' import toSnakeCase from 'to-snake-case' @@ -61,6 +71,7 @@ type TraverseFieldArgs = { currentArgs: Result currentTableName: string depth?: number + draftsEnabled?: boolean fields: FlattenedField[] joinQuery: JoinQuery joins?: BuildQueryJoinAliases @@ -88,6 +99,7 @@ export const traverseFields = ({ currentArgs, currentTableName, depth, + draftsEnabled, fields, joinQuery = {}, joins, @@ -193,6 +205,7 @@ export const traverseFields = ({ currentArgs: withArray, currentTableName: arrayTableName, depth, + draftsEnabled, fields: field.flattenedFields, joinQuery, locale, @@ -304,6 +317,7 @@ export const traverseFields = ({ currentArgs: withBlock, currentTableName: tableName, depth, + draftsEnabled, fields: block.flattenedFields, joinQuery, locale, @@ -345,6 +359,7 @@ export const traverseFields = ({ currentArgs, currentTableName, depth, + draftsEnabled, fields: field.flattenedFields, joinQuery, joins, @@ -511,9 +526,23 @@ export const traverseFields = ({ .from(sql`${currentQuery.as(subQueryAlias)}`) .where(sqlWhere)}`.as(columnName) } else { - const fields = adapter.payload.collections[field.collection].config.flattenedFields + const useDrafts = + (versions || draftsEnabled) && + Boolean(adapter.payload.collections[field.collection].config.versions.drafts) - const joinCollectionTableName = adapter.tableNameMap.get(toSnakeCase(field.collection)) + const fields = useDrafts + ? buildVersionCollectionFields( + adapter.payload.config, + adapter.payload.collections[field.collection].config, + true, + ) + : adapter.payload.collections[field.collection].config.flattenedFields + + const joinCollectionTableName = adapter.tableNameMap.get( + useDrafts + ? `_${toSnakeCase(field.collection)}${adapter.versionsSuffix}` + : toSnakeCase(field.collection), + ) const joins: BuildQueryJoinAliases = [] @@ -546,6 +575,12 @@ export const traverseFields = ({ } } + if (useDrafts) { + joinQueryWhere = combineQueries(appendVersionToQueryKey(joinQueryWhere), { + latest: { equals: true }, + }) + } + const columnName = `${path.replaceAll('.', '_')}${field.name}` const subQueryAlias = `${columnName}_alias` @@ -567,7 +602,12 @@ export const traverseFields = ({ locale, parentIsLocalized, selectLocale: true, - sort, + sort: useDrafts + ? getQueryDraftsSort({ + collectionConfig: adapter.payload.collections[field.collection].config, + sort, + }) + : sort, tableName: joinCollectionTableName, where: joinQueryWhere, }) @@ -610,6 +650,10 @@ export const traverseFields = ({ } } + if (useDrafts) { + selectFields.parent = newAliasTable.parent + } + const subQuery = chainMethods({ methods: chainedMethods, query: db @@ -636,7 +680,7 @@ export const traverseFields = ({ currentArgs.extras[columnName] = sql`${db .select({ result: jsonAggBuildObject(adapter, { - id: sql.raw(`"${subQueryAlias}".id`), + id: sql.raw(`"${subQueryAlias}".${useDrafts ? 'parent_id' : 'id'}`), ...(selectFields._locale && { locale: sql.raw(`"${subQueryAlias}".${selectFields._locale.name}`), }), diff --git a/packages/drizzle/src/findOne.ts b/packages/drizzle/src/findOne.ts index 4dbcf14ab9..76737bdce3 100644 --- a/packages/drizzle/src/findOne.ts +++ b/packages/drizzle/src/findOne.ts @@ -8,7 +8,7 @@ import { findMany } from './find/findMany.js' export async function findOne( this: DrizzleAdapter, - { collection, joins, locale, req, select, where }: FindOneArgs, + { collection, draftsEnabled, joins, locale, req, select, where }: FindOneArgs, ): Promise { const collectionConfig: SanitizedCollectionConfig = this.payload.collections[collection].config @@ -17,6 +17,7 @@ export async function findOne( const { docs } = await findMany({ adapter: this, collectionSlug: collection, + draftsEnabled, fields: collectionConfig.flattenedFields, joins, limit: 1, diff --git a/packages/drizzle/src/transform/read/traverseFields.ts b/packages/drizzle/src/transform/read/traverseFields.ts index 9a051d1f67..68a5c64d2b 100644 --- a/packages/drizzle/src/transform/read/traverseFields.ts +++ b/packages/drizzle/src/transform/read/traverseFields.ts @@ -1,7 +1,6 @@ import type { FlattenedBlock, FlattenedField, JoinQuery, SanitizedConfig } from 'payload' import { fieldIsVirtual, fieldShouldBeLocalized } from 'payload/shared' -import toSnakeCase from 'to-snake-case' import type { DrizzleAdapter } from '../../types.js' import type { BlocksMap } from '../../utilities/createBlocksMap.js' diff --git a/packages/next/src/layouts/Root/index.tsx b/packages/next/src/layouts/Root/index.tsx index 24cb25e444..f0c8c31526 100644 --- a/packages/next/src/layouts/Root/index.tsx +++ b/packages/next/src/layouts/Root/index.tsx @@ -23,15 +23,15 @@ export const metadata = { export const RootLayout = async ({ children, config: configPromise, + htmlProps = {}, importMap, serverFunction, - htmlProps = {}, }: { readonly children: React.ReactNode readonly config: Promise + readonly htmlProps?: React.HtmlHTMLAttributes readonly importMap: ImportMap readonly serverFunction: ServerFunctionClient - readonly htmlProps?: React.HtmlHTMLAttributes }) => { checkDependencies() diff --git a/packages/payload/src/collections/operations/find.ts b/packages/payload/src/collections/operations/find.ts index a04044d81c..48810c7285 100644 --- a/packages/payload/src/collections/operations/find.ts +++ b/packages/payload/src/collections/operations/find.ts @@ -183,6 +183,7 @@ export const findOperation = async < result = await payload.db.find>({ collection: collectionConfig.slug, + draftsEnabled, joins: req.payloadAPI === 'GraphQL' ? false : sanitizedJoins, limit: sanitizedLimit, locale, diff --git a/packages/payload/src/collections/operations/findByID.ts b/packages/payload/src/collections/operations/findByID.ts index 3684559998..594a9ae0dc 100644 --- a/packages/payload/src/collections/operations/findByID.ts +++ b/packages/payload/src/collections/operations/findByID.ts @@ -117,6 +117,7 @@ export const findByIDOperation = async < const findOneArgs: FindOneArgs = { collection: collectionConfig.slug, + draftsEnabled: draftEnabled, joins: req.payloadAPI === 'GraphQL' ? false : sanitizedJoins, locale, req: { diff --git a/packages/payload/src/database/types.ts b/packages/payload/src/database/types.ts index b208b5ed01..d978e9d1f2 100644 --- a/packages/payload/src/database/types.ts +++ b/packages/payload/src/database/types.ts @@ -206,6 +206,7 @@ export type QueryDrafts = (args: QueryDraftsArgs) => Promise @@ -217,6 +218,7 @@ export type FindOne = (args: FindOneArgs) => Promise( async (ids, relatedCollectionSlug) => { if (!ids.length) { - return; + return } const query: { diff --git a/test/joins/int.spec.ts b/test/joins/int.spec.ts index 1fa4a7fe21..a725a7939d 100644 --- a/test/joins/int.spec.ts +++ b/test/joins/int.spec.ts @@ -606,6 +606,27 @@ describe('Joins Field', () => { expect(res.docs[0].relatedVersions.docs[0].id).toBe(version.id) }) + it('should populate joins with hasMany when on both sides documents are in draft', async () => { + const category = await payload.create({ + collection: 'categories-versions', + data: { _status: 'draft' }, + draft: true, + }) + + const version = await payload.create({ + collection: 'versions', + data: { _status: 'draft', categoryVersion: category.id }, + draft: true, + }) + + const res = await payload.find({ + collection: 'categories-versions', + draft: true, + }) + + expect(res.docs[0].relatedVersions.docs[0].id).toBe(version.id) + }) + it('should populate joins when versions on both sides draft true payload.db.queryDrafts', async () => { const category = await payload.create({ collection: 'categories-versions', data: {} }) From b1469eae096afe815e661de54f607c489b1f1e0f Mon Sep 17 00:00:00 2001 From: Elliot DeNolf Date: Mon, 24 Mar 2025 09:56:50 -0400 Subject: [PATCH 02/77] ci: sanitize breaking section in release notes --- tools/releaser/src/utils/generateReleaseNotes.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/releaser/src/utils/generateReleaseNotes.ts b/tools/releaser/src/utils/generateReleaseNotes.ts index 4138042faf..81ea2c4b3f 100755 --- a/tools/releaser/src/utils/generateReleaseNotes.ts +++ b/tools/releaser/src/utils/generateReleaseNotes.ts @@ -107,6 +107,9 @@ export const generateReleaseNotes = async (args: Args = {}): Promise { if (c.isBreaking) { + if (!sections.breaking) { + sections.breaking = [] + } sections.breaking.push(c) } From bb14cc9b413f9bb79f97b8aade114414864f08be Mon Sep 17 00:00:00 2001 From: Elliot DeNolf Date: Mon, 24 Mar 2025 09:59:42 -0400 Subject: [PATCH 03/77] chore(release): v3.30.0 [skip ci] --- package.json | 2 +- packages/admin-bar/package.json | 2 +- packages/create-payload-app/package.json | 2 +- packages/db-mongodb/package.json | 2 +- packages/db-postgres/package.json | 2 +- packages/db-sqlite/package.json | 2 +- packages/db-vercel-postgres/package.json | 2 +- packages/drizzle/package.json | 2 +- packages/email-nodemailer/package.json | 2 +- packages/email-resend/package.json | 2 +- packages/graphql/package.json | 2 +- packages/live-preview-react/package.json | 2 +- packages/live-preview-vue/package.json | 2 +- packages/live-preview/package.json | 2 +- packages/next/package.json | 2 +- packages/payload-cloud/package.json | 2 +- packages/payload/package.json | 2 +- packages/plugin-cloud-storage/package.json | 2 +- packages/plugin-form-builder/package.json | 2 +- packages/plugin-import-export/package.json | 2 +- packages/plugin-multi-tenant/package.json | 2 +- packages/plugin-nested-docs/package.json | 2 +- packages/plugin-redirects/package.json | 2 +- packages/plugin-search/package.json | 2 +- packages/plugin-sentry/package.json | 2 +- packages/plugin-seo/package.json | 2 +- packages/plugin-stripe/package.json | 2 +- packages/richtext-lexical/package.json | 2 +- packages/richtext-slate/package.json | 2 +- packages/storage-azure/package.json | 2 +- packages/storage-gcs/package.json | 2 +- packages/storage-s3/package.json | 2 +- packages/storage-uploadthing/package.json | 2 +- packages/storage-vercel-blob/package.json | 2 +- packages/translations/package.json | 2 +- packages/ui/package.json | 2 +- 36 files changed, 36 insertions(+), 36 deletions(-) diff --git a/package.json b/package.json index 68c5751aec..3ee9f79572 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "payload-monorepo", - "version": "3.29.0", + "version": "3.30.0", "private": true, "type": "module", "scripts": { diff --git a/packages/admin-bar/package.json b/packages/admin-bar/package.json index ea7a8897c0..269216696f 100644 --- a/packages/admin-bar/package.json +++ b/packages/admin-bar/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/admin-bar", - "version": "3.29.0", + "version": "3.30.0", "description": "An admin bar for React apps using Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/create-payload-app/package.json b/packages/create-payload-app/package.json index 732e595e4a..bdf535b0f1 100644 --- a/packages/create-payload-app/package.json +++ b/packages/create-payload-app/package.json @@ -1,6 +1,6 @@ { "name": "create-payload-app", - "version": "3.29.0", + "version": "3.30.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/db-mongodb/package.json b/packages/db-mongodb/package.json index 2ced07df5b..7e14dbc80d 100644 --- a/packages/db-mongodb/package.json +++ b/packages/db-mongodb/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-mongodb", - "version": "3.29.0", + "version": "3.30.0", "description": "The officially supported MongoDB database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-postgres/package.json b/packages/db-postgres/package.json index 0a04cd1ad5..f5c3c9f3fa 100644 --- a/packages/db-postgres/package.json +++ b/packages/db-postgres/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-postgres", - "version": "3.29.0", + "version": "3.30.0", "description": "The officially supported Postgres database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-sqlite/package.json b/packages/db-sqlite/package.json index b4436cb98b..c0f75077dd 100644 --- a/packages/db-sqlite/package.json +++ b/packages/db-sqlite/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-sqlite", - "version": "3.29.0", + "version": "3.30.0", "description": "The officially supported SQLite database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-vercel-postgres/package.json b/packages/db-vercel-postgres/package.json index ebf0bdaabb..5d0274ecc0 100644 --- a/packages/db-vercel-postgres/package.json +++ b/packages/db-vercel-postgres/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-vercel-postgres", - "version": "3.29.0", + "version": "3.30.0", "description": "Vercel Postgres adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/drizzle/package.json b/packages/drizzle/package.json index a26e277b58..4ef539d60d 100644 --- a/packages/drizzle/package.json +++ b/packages/drizzle/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/drizzle", - "version": "3.29.0", + "version": "3.30.0", "description": "A library of shared functions used by different payload database adapters", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/email-nodemailer/package.json b/packages/email-nodemailer/package.json index 27fb2116b3..89070b2c7b 100644 --- a/packages/email-nodemailer/package.json +++ b/packages/email-nodemailer/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/email-nodemailer", - "version": "3.29.0", + "version": "3.30.0", "description": "Payload Nodemailer Email Adapter", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/email-resend/package.json b/packages/email-resend/package.json index b4067709c3..8dc9de3fdb 100644 --- a/packages/email-resend/package.json +++ b/packages/email-resend/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/email-resend", - "version": "3.29.0", + "version": "3.30.0", "description": "Payload Resend Email Adapter", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/graphql/package.json b/packages/graphql/package.json index 06a2b97dd2..551132c0e8 100644 --- a/packages/graphql/package.json +++ b/packages/graphql/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/graphql", - "version": "3.29.0", + "version": "3.30.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/live-preview-react/package.json b/packages/live-preview-react/package.json index f8cadb9361..a93e9916c8 100644 --- a/packages/live-preview-react/package.json +++ b/packages/live-preview-react/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview-react", - "version": "3.29.0", + "version": "3.30.0", "description": "The official React SDK for Payload Live Preview", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/live-preview-vue/package.json b/packages/live-preview-vue/package.json index 0f2a9d5777..fcc5e9113c 100644 --- a/packages/live-preview-vue/package.json +++ b/packages/live-preview-vue/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview-vue", - "version": "3.29.0", + "version": "3.30.0", "description": "The official Vue SDK for Payload Live Preview", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/live-preview/package.json b/packages/live-preview/package.json index d144265381..4623397374 100644 --- a/packages/live-preview/package.json +++ b/packages/live-preview/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview", - "version": "3.29.0", + "version": "3.30.0", "description": "The official live preview JavaScript SDK for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/next/package.json b/packages/next/package.json index 105559872c..3ca142c1db 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/next", - "version": "3.29.0", + "version": "3.30.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/payload-cloud/package.json b/packages/payload-cloud/package.json index 7b9c439248..fd6f5682bb 100644 --- a/packages/payload-cloud/package.json +++ b/packages/payload-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/payload-cloud", - "version": "3.29.0", + "version": "3.30.0", "description": "The official Payload Cloud plugin", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/payload/package.json b/packages/payload/package.json index 9b1f68df70..11afab175e 100644 --- a/packages/payload/package.json +++ b/packages/payload/package.json @@ -1,6 +1,6 @@ { "name": "payload", - "version": "3.29.0", + "version": "3.30.0", "description": "Node, React, Headless CMS and Application Framework built on Next.js", "keywords": [ "admin panel", diff --git a/packages/plugin-cloud-storage/package.json b/packages/plugin-cloud-storage/package.json index f414f6e808..0436572d5d 100644 --- a/packages/plugin-cloud-storage/package.json +++ b/packages/plugin-cloud-storage/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-cloud-storage", - "version": "3.29.0", + "version": "3.30.0", "description": "The official cloud storage plugin for Payload CMS", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/plugin-form-builder/package.json b/packages/plugin-form-builder/package.json index 098b8d2e12..35be02fe17 100644 --- a/packages/plugin-form-builder/package.json +++ b/packages/plugin-form-builder/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-form-builder", - "version": "3.29.0", + "version": "3.30.0", "description": "Form builder plugin for Payload CMS", "keywords": [ "payload", diff --git a/packages/plugin-import-export/package.json b/packages/plugin-import-export/package.json index f017eff75d..d6de0219f0 100644 --- a/packages/plugin-import-export/package.json +++ b/packages/plugin-import-export/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-import-export", - "version": "3.29.0", + "version": "3.30.0", "description": "Import-Export plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-multi-tenant/package.json b/packages/plugin-multi-tenant/package.json index 7d923e9e69..c839810da4 100644 --- a/packages/plugin-multi-tenant/package.json +++ b/packages/plugin-multi-tenant/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-multi-tenant", - "version": "3.29.0", + "version": "3.30.0", "description": "Multi Tenant plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-nested-docs/package.json b/packages/plugin-nested-docs/package.json index 57d4e1c798..80e2ed2d78 100644 --- a/packages/plugin-nested-docs/package.json +++ b/packages/plugin-nested-docs/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-nested-docs", - "version": "3.29.0", + "version": "3.30.0", "description": "The official Nested Docs plugin for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/plugin-redirects/package.json b/packages/plugin-redirects/package.json index 62598eabeb..1f75f99691 100644 --- a/packages/plugin-redirects/package.json +++ b/packages/plugin-redirects/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-redirects", - "version": "3.29.0", + "version": "3.30.0", "description": "Redirects plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-search/package.json b/packages/plugin-search/package.json index 58c413b1f9..8b5cea8bd5 100644 --- a/packages/plugin-search/package.json +++ b/packages/plugin-search/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-search", - "version": "3.29.0", + "version": "3.30.0", "description": "Search plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-sentry/package.json b/packages/plugin-sentry/package.json index 2117031b95..cf12065234 100644 --- a/packages/plugin-sentry/package.json +++ b/packages/plugin-sentry/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-sentry", - "version": "3.29.0", + "version": "3.30.0", "description": "Sentry plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-seo/package.json b/packages/plugin-seo/package.json index 02fbe82fa1..574ab5ed8a 100644 --- a/packages/plugin-seo/package.json +++ b/packages/plugin-seo/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-seo", - "version": "3.29.0", + "version": "3.30.0", "description": "SEO plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-stripe/package.json b/packages/plugin-stripe/package.json index 677abcb801..7b311a8bf9 100644 --- a/packages/plugin-stripe/package.json +++ b/packages/plugin-stripe/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-stripe", - "version": "3.29.0", + "version": "3.30.0", "description": "Stripe plugin for Payload", "keywords": [ "payload", diff --git a/packages/richtext-lexical/package.json b/packages/richtext-lexical/package.json index 12d0e0094b..f420feb9ea 100644 --- a/packages/richtext-lexical/package.json +++ b/packages/richtext-lexical/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/richtext-lexical", - "version": "3.29.0", + "version": "3.30.0", "description": "The officially supported Lexical richtext adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/richtext-slate/package.json b/packages/richtext-slate/package.json index 85cc9b484f..12a804a064 100644 --- a/packages/richtext-slate/package.json +++ b/packages/richtext-slate/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/richtext-slate", - "version": "3.29.0", + "version": "3.30.0", "description": "The officially supported Slate richtext adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-azure/package.json b/packages/storage-azure/package.json index a07715ee43..28604d70c9 100644 --- a/packages/storage-azure/package.json +++ b/packages/storage-azure/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-azure", - "version": "3.29.0", + "version": "3.30.0", "description": "Payload storage adapter for Azure Blob Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-gcs/package.json b/packages/storage-gcs/package.json index b21a0c4cf9..af5069e2ff 100644 --- a/packages/storage-gcs/package.json +++ b/packages/storage-gcs/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-gcs", - "version": "3.29.0", + "version": "3.30.0", "description": "Payload storage adapter for Google Cloud Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-s3/package.json b/packages/storage-s3/package.json index 1861b4d927..fa5897455a 100644 --- a/packages/storage-s3/package.json +++ b/packages/storage-s3/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-s3", - "version": "3.29.0", + "version": "3.30.0", "description": "Payload storage adapter for Amazon S3", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-uploadthing/package.json b/packages/storage-uploadthing/package.json index 4807f4f546..74e8265dd8 100644 --- a/packages/storage-uploadthing/package.json +++ b/packages/storage-uploadthing/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-uploadthing", - "version": "3.29.0", + "version": "3.30.0", "description": "Payload storage adapter for uploadthing", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-vercel-blob/package.json b/packages/storage-vercel-blob/package.json index 3258327dd6..cbc5a44ff0 100644 --- a/packages/storage-vercel-blob/package.json +++ b/packages/storage-vercel-blob/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-vercel-blob", - "version": "3.29.0", + "version": "3.30.0", "description": "Payload storage adapter for Vercel Blob Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/translations/package.json b/packages/translations/package.json index 7931936c84..f363d2a7e3 100644 --- a/packages/translations/package.json +++ b/packages/translations/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/translations", - "version": "3.29.0", + "version": "3.30.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/ui/package.json b/packages/ui/package.json index a44642ab04..e09842c2f4 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/ui", - "version": "3.29.0", + "version": "3.30.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", From 998181b986f72dac15850345f090d90c8ac384e7 Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Mon, 24 Mar 2025 13:16:39 -0400 Subject: [PATCH 04/77] feat: query presets (#11330) Query Presets allow you to save and share filters, columns, and sort orders for your collections. This is useful for reusing common or complex filtering patterns and column configurations across your team. Query Presets are defined on the fly by the users of your app, rather than being hard coded into the Payload Config. Here's a screen recording demonstrating the general workflow as it relates to the list view. Query Presets are not exclusive to the admin panel, however, as they could be useful in a number of other contexts and environments. https://github.com/user-attachments/assets/1fe1155e-ae78-4f59-9138-af352762a1d5 Each Query Preset is saved as a new record in the database under the `payload-query-presets` collection. This will effectively make them CRUDable and allows for an endless number of preset configurations. As you make changes to filters, columns, limit, etc. you can choose to save them as a new record and optionally share them with others. Normal document-level access control will determine who can read, update, and delete these records. Payload provides a set of sensible defaults here, such as "only me", "everyone", and "specific users", but you can also extend your own set of access rules on top of this, such as "by role", etc. Access control is customizable at the operation-level, for example you can set this to "everyone" can read, but "only me" can update. To enable the Query Presets within a particular collection, set `enableQueryPresets` on that collection's config. Here's an example: ```ts { // ... enableQueryPresets: true } ``` Once enabled, a new set of controls will appear within the list view of the admin panel. This is where you can select and manage query presets. General settings for Query Presets are configured under the root `queryPresets` property. This is where you can customize the labels, apply custom access control rules, etc. Here's an example of how you might augment the access control properties with your own custom rule to achieve RBAC: ```ts { // ... queryPresets: { constraints: { read: [ { label: 'Specific Roles', value: 'specificRoles', fields: [roles], access: ({ req: { user } }) => ({ 'access.update.roles': { in: [user?.roles], }, }), }, ], } } } ``` Related: #4193 and #3092 --------- Co-authored-by: Dan Ribbens --- .github/workflows/main.yml | 1 + docs/admin/react-hooks.mdx | 33 +- docs/configuration/collections.mdx | 47 +- docs/configuration/overview.mdx | 1 + docs/query-presets/overview.mdx | 171 ++ .../views/Document/handleServerFunction.tsx | 3 + packages/next/src/views/Document/index.tsx | 7 +- .../src/views/List/handleServerFunction.tsx | 3 + packages/next/src/views/List/index.tsx | 64 +- .../src/views/List/renderListViewSlots.tsx | 1 + packages/payload/src/admin/forms/Label.ts | 2 +- packages/payload/src/admin/functions/index.ts | 3 +- packages/payload/src/admin/views/index.ts | 2 - packages/payload/src/admin/views/list.ts | 5 + .../utilities/getFromImportMap.ts | 1 + .../payload/src/collections/config/types.ts | 5 + packages/payload/src/config/client.ts | 3 + packages/payload/src/config/sanitize.ts | 67 +- packages/payload/src/config/types.ts | 24 +- .../src/exports/components/utilities.ts | 0 packages/payload/src/exports/shared.ts | 15 +- packages/payload/src/index.ts | 1 + packages/payload/src/preferences/types.ts | 2 + packages/payload/src/query-presets/access.ts | 94 + packages/payload/src/query-presets/config.ts | 164 + .../payload/src/query-presets/constraints.ts | 104 + packages/payload/src/query-presets/types.ts | 33 + .../src/utilities/mergeListSearchAndWhere.ts | 6 +- .../src/utilities}/transformWhereQuery.ts | 15 +- .../src/utilities}/validateWhereQuery.ts | 18 +- packages/translations/src/clientKeys.ts | 3 + packages/translations/src/languages/ar.ts | 3 + packages/translations/src/languages/az.ts | 3 + packages/translations/src/languages/bg.ts | 3 + packages/translations/src/languages/ca.ts | 3 + packages/translations/src/languages/cs.ts | 3 + packages/translations/src/languages/da.ts | 3 + packages/translations/src/languages/de.ts | 3 + packages/translations/src/languages/en.ts | 3 + packages/translations/src/languages/es.ts | 3 + packages/translations/src/languages/et.ts | 3 + packages/translations/src/languages/fa.ts | 3 + packages/translations/src/languages/fr.ts | 3 + packages/translations/src/languages/he.ts | 3 + packages/translations/src/languages/hr.ts | 3 + packages/translations/src/languages/hu.ts | 3 + packages/translations/src/languages/it.ts | 3 + packages/translations/src/languages/ja.ts | 3 + packages/translations/src/languages/ko.ts | 3 + packages/translations/src/languages/lt.ts | 3 + packages/translations/src/languages/my.ts | 3 + packages/translations/src/languages/nb.ts | 3 + packages/translations/src/languages/nl.ts | 3 + packages/translations/src/languages/pl.ts | 3 + packages/translations/src/languages/pt.ts | 3 + packages/translations/src/languages/ro.ts | 3 + packages/translations/src/languages/rs.ts | 3 + .../translations/src/languages/rsLatin.ts | 3 + packages/translations/src/languages/ru.ts | 3 + packages/translations/src/languages/sk.ts | 3 + packages/translations/src/languages/sl.ts | 3 + packages/translations/src/languages/sv.ts | 3 + packages/translations/src/languages/th.ts | 3 + packages/translations/src/languages/tr.ts | 3 + packages/translations/src/languages/uk.ts | 3 + packages/translations/src/languages/vi.ts | 3 + packages/translations/src/languages/zh.ts | 3 + packages/translations/src/languages/zhTw.ts | 3 + .../ui/src/elements/ColumnSelector/index.scss | 5 +- .../ui/src/elements/ColumnSelector/index.tsx | 2 +- .../ui/src/elements/DeleteDocument/index.tsx | 4 +- packages/ui/src/elements/DeleteMany/index.tsx | 2 +- .../elements/DocumentDrawer/DrawerContent.tsx | 3 +- .../ui/src/elements/DocumentDrawer/types.ts | 4 + .../src/elements/EditMany/DrawerContent.tsx | 3 +- .../ListControls/ActiveQueryPreset/index.scss | 21 + .../ListControls/ActiveQueryPreset/index.tsx | 65 + .../ui/src/elements/ListControls/index.scss | 14 +- .../ui/src/elements/ListControls/index.tsx | 270 +- .../ui/src/elements/ListControls/types.ts | 34 + .../elements/ListControls/useQueryPresets.tsx | 326 ++ .../src/elements/ListDrawer/DrawerContent.tsx | 5 +- packages/ui/src/elements/ListDrawer/types.ts | 7 +- packages/ui/src/elements/Pill/index.scss | 39 +- packages/ui/src/elements/Pill/index.tsx | 13 +- .../elements/Popup/PopupButtonList/index.tsx | 3 + .../elements/Popup/PopupDivider/index.scss | 10 + .../src/elements/Popup/PopupDivider/index.tsx | 9 + .../elements/Popup/PopupGroupLabel/index.scss | 8 + .../elements/Popup/PopupGroupLabel/index.tsx | 11 + packages/ui/src/elements/Popup/index.tsx | 5 +- .../QueryPresets/cells/AccessCell/index.tsx | 30 + .../QueryPresets/cells/ColumnsCell/index.scss | 9 + .../QueryPresets/cells/ColumnsCell/index.tsx | 32 + .../QueryPresets/cells/WhereCell/index.tsx | 33 + .../fields/ColumnsField/index.scss | 17 + .../fields/ColumnsField/index.tsx | 36 + .../QueryPresets/fields/WhereField/index.scss | 23 + .../QueryPresets/fields/WhereField/index.tsx | 114 + .../cells/DrawerLink/index.tsx | 2 +- .../src/elements/RelationshipTable/index.tsx | 7 +- .../elements/WhereBuilder/Condition/index.tsx | 2 +- .../ui/src/elements/WhereBuilder/index.tsx | 30 +- packages/ui/src/exports/client/index.ts | 11 +- packages/ui/src/exports/shared/index.ts | 13 +- packages/ui/src/icons/Chevron/index.tsx | 4 +- packages/ui/src/icons/Dots/index.scss | 14 + packages/ui/src/icons/Dots/index.tsx | 21 +- packages/ui/src/icons/People/index.scss | 11 + packages/ui/src/icons/People/index.tsx | 21 + .../ui/src/providers/DocumentInfo/types.ts | 1 + .../src/providers/EntityVisibility/index.tsx | 3 +- .../ui/src/providers/ListQuery/context.ts | 4 + packages/ui/src/providers/ListQuery/index.tsx | 47 +- packages/ui/src/providers/ListQuery/types.ts | 9 +- .../ui/src/providers/Preferences/index.tsx | 8 + .../src/providers/ServerFunctions/index.tsx | 1 + .../TableColumns/RenderDefaultCell/index.scss | 0 .../TableColumns/RenderDefaultCell/index.tsx | 7 +- .../TableColumns/buildColumnState.tsx | 4 +- .../buildPolymorphicColumnState.tsx | 4 +- .../TableColumns/context.ts | 0 .../TableColumns/filterFields.tsx | 0 .../TableColumns/getInitialColumns.ts | 0 .../TableColumns/index.tsx | 7 +- .../TableColumns/types.ts | 2 +- packages/ui/src/utilities/renderTable.tsx | 8 +- .../ui/src/utilities/upsertPreferences.ts | 35 +- packages/ui/src/views/Edit/index.tsx | 3 +- packages/ui/src/views/List/index.tsx | 10 +- test/admin/e2e/list-view/e2e.spec.ts | 19 +- test/fields-relationship/e2e.spec.ts | 4 +- test/fields/collections/Array/e2e.spec.ts | 1 - test/fields/collections/Text/e2e.spec.ts | 6 +- test/fields/payload-types.ts | 1 + test/helpers.ts | 2 +- test/helpers/e2e/addListFilter.ts | 6 +- test/helpers/e2e/openListColumns.ts | 8 +- test/helpers/e2e/openListFilters.ts | 12 +- test/helpers/e2e/toggleColumn.ts | 13 +- test/helpers/e2e/toggleListMenu.ts | 26 + test/helpers/sdk/types.ts | 2 +- .../collections/Pages/index.ts | 2 +- .../collections/Posts/index.ts | 2 +- .../collections/Users/index.ts | 4 +- test/locked-documents/config.ts | 40 +- test/locked-documents/int.spec.ts | 18 +- test/locked-documents/seed.ts | 57 + test/locked-documents/slugs.ts | 7 + test/query-presets/.gitignore | 2 + test/query-presets/collections/Pages/index.ts | 21 + test/query-presets/collections/Users/index.ts | 19 + test/query-presets/config.ts | 66 + test/query-presets/e2e.spec.ts | 392 +++ test/query-presets/eslint.config.js | 23 + test/query-presets/fields/roles.ts | 21 + test/query-presets/helpers/assertURLParams.ts | 39 + .../helpers/openQueryPresetDrawer.ts | 5 + test/query-presets/helpers/togglePreset.ts | 53 + test/query-presets/int.spec.ts | 568 ++++ test/query-presets/payload-types.ts | 359 +++ test/query-presets/schema.graphql | 2693 +++++++++++++++++ test/query-presets/seed.ts | 182 ++ test/query-presets/slugs.ts | 5 + test/query-presets/tsconfig.eslint.json | 13 + test/query-presets/tsconfig.json | 3 + test/sort/int.spec.ts | 4 +- tsconfig.base.json | 2 +- 168 files changed, 6737 insertions(+), 418 deletions(-) create mode 100644 docs/query-presets/overview.mdx delete mode 100644 packages/payload/src/exports/components/utilities.ts create mode 100644 packages/payload/src/query-presets/access.ts create mode 100644 packages/payload/src/query-presets/config.ts create mode 100644 packages/payload/src/query-presets/constraints.ts create mode 100644 packages/payload/src/query-presets/types.ts rename packages/{ui => payload}/src/utilities/mergeListSearchAndWhere.ts (83%) rename packages/{ui/src/elements/WhereBuilder => payload/src/utilities}/transformWhereQuery.ts (64%) rename packages/{ui/src/elements/WhereBuilder => payload/src/utilities}/validateWhereQuery.ts (63%) create mode 100644 packages/ui/src/elements/ListControls/ActiveQueryPreset/index.scss create mode 100644 packages/ui/src/elements/ListControls/ActiveQueryPreset/index.tsx create mode 100644 packages/ui/src/elements/ListControls/types.ts create mode 100644 packages/ui/src/elements/ListControls/useQueryPresets.tsx create mode 100644 packages/ui/src/elements/Popup/PopupDivider/index.scss create mode 100644 packages/ui/src/elements/Popup/PopupDivider/index.tsx create mode 100644 packages/ui/src/elements/Popup/PopupGroupLabel/index.scss create mode 100644 packages/ui/src/elements/Popup/PopupGroupLabel/index.tsx create mode 100644 packages/ui/src/elements/QueryPresets/cells/AccessCell/index.tsx create mode 100644 packages/ui/src/elements/QueryPresets/cells/ColumnsCell/index.scss create mode 100644 packages/ui/src/elements/QueryPresets/cells/ColumnsCell/index.tsx create mode 100644 packages/ui/src/elements/QueryPresets/cells/WhereCell/index.tsx create mode 100644 packages/ui/src/elements/QueryPresets/fields/ColumnsField/index.scss create mode 100644 packages/ui/src/elements/QueryPresets/fields/ColumnsField/index.tsx create mode 100644 packages/ui/src/elements/QueryPresets/fields/WhereField/index.scss create mode 100644 packages/ui/src/elements/QueryPresets/fields/WhereField/index.tsx create mode 100644 packages/ui/src/icons/People/index.scss create mode 100644 packages/ui/src/icons/People/index.tsx rename packages/ui/src/{elements => providers}/TableColumns/RenderDefaultCell/index.scss (100%) rename packages/ui/src/{elements => providers}/TableColumns/RenderDefaultCell/index.tsx (93%) rename packages/ui/src/{elements => providers}/TableColumns/buildColumnState.tsx (98%) rename packages/ui/src/{elements => providers}/TableColumns/buildPolymorphicColumnState.tsx (98%) rename packages/ui/src/{elements => providers}/TableColumns/context.ts (100%) rename packages/ui/src/{elements => providers}/TableColumns/filterFields.tsx (100%) rename packages/ui/src/{elements => providers}/TableColumns/getInitialColumns.ts (100%) rename packages/ui/src/{elements => providers}/TableColumns/index.tsx (92%) rename packages/ui/src/{elements => providers}/TableColumns/types.ts (93%) create mode 100644 test/helpers/e2e/toggleListMenu.ts create mode 100644 test/locked-documents/seed.ts create mode 100644 test/locked-documents/slugs.ts create mode 100644 test/query-presets/.gitignore create mode 100644 test/query-presets/collections/Pages/index.ts create mode 100644 test/query-presets/collections/Users/index.ts create mode 100644 test/query-presets/config.ts create mode 100644 test/query-presets/e2e.spec.ts create mode 100644 test/query-presets/eslint.config.js create mode 100644 test/query-presets/fields/roles.ts create mode 100644 test/query-presets/helpers/assertURLParams.ts create mode 100644 test/query-presets/helpers/openQueryPresetDrawer.ts create mode 100644 test/query-presets/helpers/togglePreset.ts create mode 100644 test/query-presets/int.spec.ts create mode 100644 test/query-presets/payload-types.ts create mode 100644 test/query-presets/schema.graphql create mode 100644 test/query-presets/seed.ts create mode 100644 test/query-presets/slugs.ts create mode 100644 test/query-presets/tsconfig.eslint.json create mode 100644 test/query-presets/tsconfig.json diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 755f7acde0..e8d852eed5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -309,6 +309,7 @@ jobs: - fields__collections__Text - fields__collections__UI - fields__collections__Upload + - query-presets - form-state - live-preview - localization diff --git a/docs/admin/react-hooks.mdx b/docs/admin/react-hooks.mdx index f5c87207d0..7dcd2a2f80 100644 --- a/docs/admin/react-hooks.mdx +++ b/docs/admin/react-hooks.mdx @@ -474,7 +474,7 @@ Field: '/path/to/CustomArrayManagerField', rows={[ [ { - value: '**\\\`path\\\`**', + value: '**\\`path\\`**', }, { value: 'The path to the array or block field', @@ -482,7 +482,7 @@ Field: '/path/to/CustomArrayManagerField', ], [ { - value: '**\\\`rowIndex\\\`**', + value: '**\\`rowIndex\\`**', }, { value: 'The index of the row to remove', @@ -561,7 +561,7 @@ Field: '/path/to/CustomArrayManagerField', rows={[ [ { - value: '**\\\`path\\\`**', + value: '**\\`path\\`**', }, { value: 'The path to the array or block field', @@ -569,7 +569,7 @@ Field: '/path/to/CustomArrayManagerField', ], [ { - value: '**\\\`rowIndex\\\`**', + value: '**\\`rowIndex\\`**', }, { value: 'The index of the row to replace', @@ -577,7 +577,7 @@ Field: '/path/to/CustomArrayManagerField', ], [ { - value: '**\\\`data\\\`**', + value: '**\\`data\\`**', }, { value: 'The data to replace within the row', @@ -791,17 +791,18 @@ const MyComponent: React.FC = () => { The `useListQuery` hook returns an object with the following properties: -| Property | Description | -| ------------------------- | ------------------------------------------------------------------------ | -| **`data`** | The data that is being displayed in the List View. | -| **`defaultLimit`** | The default limit of items to display in the List View. | -| **`defaultSort`** | The default sort order of items in the List View. | -| **`handlePageChange`** | A method to handle page changes in the List View. | -| **`handlePerPageChange`** | A method to handle per page changes in the List View. | -| **`handleSearchChange`** | A method to handle search changes in the List View. | -| **`handleSortChange`** | A method to handle sort changes in the List View. | -| **`handleWhereChange`** | A method to handle where changes in the List View. | -| **`query`** | The current query that is being used to fetch the data in the List View. | +| Property | Description | +| ------------------------- | -------------------------------------------------------------------------------------- | +| **`data`** | The data that is being displayed in the List View. | +| **`defaultLimit`** | The default limit of items to display in the List View. | +| **`defaultSort`** | The default sort order of items in the List View. | +| **`handlePageChange`** | A method to handle page changes in the List View. | +| **`handlePerPageChange`** | A method to handle per page changes in the List View. | +| **`handleSearchChange`** | A method to handle search changes in the List View. | +| **`handleSortChange`** | A method to handle sort changes in the List View. | +| **`handleWhereChange`** | A method to handle where changes in the List View. | +| **`modified`** | Whether the query has been changed from its [Query Preset](../query-presets/overview). | +| **`query`** | The current query that is being used to fetch the data in the List View. | ## useSelection diff --git a/docs/configuration/collections.mdx b/docs/configuration/collections.mdx index c239a26890..67402182ba 100644 --- a/docs/configuration/collections.mdx +++ b/docs/configuration/collections.mdx @@ -60,29 +60,30 @@ export const Posts: CollectionConfig = { The following options are available: -| Option | Description | -| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `admin` | The configuration options for the Admin Panel. [More details](#admin-options). | -| `access` | Provide Access Control functions to define exactly who should be able to do what with Documents in this Collection. [More details](../access-control/collections). | -| `auth` | Specify options if you would like this Collection to feature authentication. [More details](../authentication/overview). | -| `custom` | Extension point for adding custom data (e.g. for plugins) | -| `disableDuplicate` | When true, do not show the "Duplicate" button while editing documents within this Collection and prevent `duplicate` from all APIs. | -| `defaultSort` | Pass a top-level field to sort by default in the Collection List View. Prefix the name of the field with a minus symbol ("-") to sort in descending order. Multiple fields can be specified by using a string array. | -| `dbName` | Custom table or Collection name depending on the Database Adapter. Auto-generated from slug if not defined. | -| `endpoints` | Add custom routes to the REST API. Set to `false` to disable routes. [More details](../rest-api/overview#custom-endpoints). | -| `fields` \* | Array of field types that will determine the structure and functionality of the data stored within this Collection. [More details](../fields/overview). | -| `graphQL` | Manage GraphQL-related properties for this collection. [More](#graphql) | -| `hooks` | Entry point for Hooks. [More details](../hooks/overview#collection-hooks). | -| `labels` | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. | -| `lockDocuments` | Enables or disables document locking. By default, document locking is enabled. Set to an object to configure, or set to `false` to disable locking. [More details](../admin/locked-documents). | -| `slug` \* | Unique, URL-friendly string that will act as an identifier for this Collection. | -| `timestamps` | Set to false to disable documents' automatically generated `createdAt` and `updatedAt` timestamps. | -| `typescript` | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. | -| `upload` | Specify options if you would like this Collection to support file uploads. For more, consult the [Uploads](../upload/overview) documentation. | -| `versions` | Set to true to enable default options, or configure with object properties. [More details](../versions/overview#collection-config). | -| `defaultPopulate` | Specify which fields to select when this Collection is populated from another document. [More Details](../queries/select#defaultpopulate-collection-config-property). | -| `indexes` | Define compound indexes for this collection. This can be used to either speed up querying/sorting by 2 or more fields at the same time or to ensure uniqueness between several fields. | -| `forceSelect` | Specify which fields should be selected always, regardless of the `select` query which can be useful that the field exists for access control / hooks | +| Option | Description | +| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `admin` | The configuration options for the Admin Panel. [More details](#admin-options). | +| `access` | Provide Access Control functions to define exactly who should be able to do what with Documents in this Collection. [More details](../access-control/collections). | +| `auth` | Specify options if you would like this Collection to feature authentication. [More details](../authentication/overview). | +| `custom` | Extension point for adding custom data (e.g. for plugins) | +| `disableDuplicate` | When true, do not show the "Duplicate" button while editing documents within this Collection and prevent `duplicate` from all APIs. | +| `defaultSort` | Pass a top-level field to sort by default in the Collection List View. Prefix the name of the field with a minus symbol ("-") to sort in descending order. Multiple fields can be specified by using a string array. | +| `dbName` | Custom table or Collection name depending on the Database Adapter. Auto-generated from slug if not defined. | +| `endpoints` | Add custom routes to the REST API. Set to `false` to disable routes. [More details](../rest-api/overview#custom-endpoints). | +| `fields` \* | Array of field types that will determine the structure and functionality of the data stored within this Collection. [More details](../fields/overview). | +| `graphQL` | Manage GraphQL-related properties for this collection. [More](#graphql) | +| `hooks` | Entry point for Hooks. [More details](../hooks/overview#collection-hooks). | +| `labels` | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. | +| `enableQueryPresets` | Enable query presets for this Collection. [More details](../query-presets/overview). | +| `lockDocuments` | Enables or disables document locking. By default, document locking is enabled. Set to an object to configure, or set to `false` to disable locking. [More details](../admin/locked-documents). | +| `slug` \* | Unique, URL-friendly string that will act as an identifier for this Collection. | +| `timestamps` | Set to false to disable documents' automatically generated `createdAt` and `updatedAt` timestamps. | +| `typescript` | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. | +| `upload` | Specify options if you would like this Collection to support file uploads. For more, consult the [Uploads](../upload/overview) documentation. | +| `versions` | Set to true to enable default options, or configure with object properties. [More details](../versions/overview#collection-config). | +| `defaultPopulate` | Specify which fields to select when this Collection is populated from another document. [More Details](../queries/select#defaultpopulate-collection-config-property). | +| `indexes` | Define compound indexes for this collection. This can be used to either speed up querying/sorting by 2 or more fields at the same time or to ensure uniqueness between several fields. | +| `forceSelect` | Specify which fields should be selected always, regardless of the `select` query which can be useful that the field exists for access control / hooks | _\* An asterisk denotes that a property is required._ diff --git a/docs/configuration/overview.mdx b/docs/configuration/overview.mdx index f2720bb7fd..cf14f14a51 100644 --- a/docs/configuration/overview.mdx +++ b/docs/configuration/overview.mdx @@ -84,6 +84,7 @@ The following options are available: | **`csrf`** | A whitelist array of URLs to allow Payload to accept cookies from. [More details](../authentication/cookies#csrf-attacks). | | **`defaultDepth`** | If a user does not specify `depth` while requesting a resource, this depth will be used. [More details](../queries/depth). | | **`defaultMaxTextLength`** | The maximum allowed string length to be permitted application-wide. Helps to prevent malicious public document creation. | +| `queryPresets` | An object that to configure Collection Query Presets. [More details](../query-presets/overview). | | **`maxDepth`** | The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries. Defaults to `10`. [More details](../queries/depth). | | **`indexSortableFields`** | Automatically index all sortable top-level fields in the database to improve sort performance and add database compatibility for Azure Cosmos and similar. | | **`upload`** | Base Payload upload configuration. [More details](../upload/overview#payload-wide-upload-options). | diff --git a/docs/query-presets/overview.mdx b/docs/query-presets/overview.mdx new file mode 100644 index 0000000000..be94e19293 --- /dev/null +++ b/docs/query-presets/overview.mdx @@ -0,0 +1,171 @@ +--- +title: Query Presets +label: Overview +order: 10 +desc: Query Presets allow you to save and share filters, columns, and sort orders for your collections. +keywords: +--- + +Query Presets allow you to save and share filters, columns, and sort orders for your [Collections](../configuration/collections). This is useful for reusing common or complex filtering patterns and/or sharing them across your team. + +Each Query Preset is saved as a new record in the database under the `payload-query-presets` collection. This allows for an endless number of preset configurations, where the users of your app define the presets that are most useful to them, rather than being hard coded into the Payload Config. + +Within the [Admin Panel](../admin/overview), Query Presets are applied to the List View. When enabled, new controls are displayed for users to manage presets. Once saved, these presets can be loaded up at any time and optionally shared with others. + +To enable Query Presets on a Collection, use the `enableQueryPresets` property in your [Collection Config](../configuration/collections): + +```ts +import type { CollectionConfig } from 'payload' + +export const MyCollection: CollectionConfig = { + // ... + // highlight-start + enableQueryPresets: true, + // highlight-end +} +``` + +## Config Options + +While not required, you may want to customize the behavior of Query Presets to suit your needs, such as add custom labels or access control rules. + +Settings for Query Presets are managed on the `queryPresets` property at the root of your [Payload Config](../configuration/overview): + +```ts +import { buildConfig } from 'payload' + +const config = buildConfig({ + // ... + // highlight-start + queryPresets: { + // ... + }, + // highlight-end +}) +``` + +The following options are available for Query Presets: + +| Option | Description | +| ------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| `access` | Used to define custom collection-level access control that applies to all presets. [More details](#access-control). | +| `constraints` | Used to define custom document-level access control that apply to individual presets. [More details](#document-access-control). | +| `labels` | Custom labels to use for the Query Presets collection. | + +## Access Control + +Query Presets are subject to the same [Access Control](../access-control/overview) as the rest of Payload. This means you can use the same patterns you are already familiar with to control who can read, update, and delete presets. + +Access Control for Query Presets can be customized in two ways: + +1. [Collection Access Control](#static-access-control): Applies to all presets. These rules are not controllable by the user and are statically defined in the config. +2. [Document Access Control](#dynamic-access-control): Applies to each individual preset. These rules are controllable by the user and are saved to the document. + +### Collection Access Control + +Collection-level access control applies to _all_ presets within the Query Presets collection. Users cannot control these rules, they are written statically in your config. + +To add Collection Access Control, use the `queryPresets.access` property in your [Payload Config](../configuration/overview): + +```ts +import { buildConfig } from 'payload' + +const config = buildConfig({ + // ... + queryPresets: { + // ... + // highlight-start + access: { + read: ({ req: { user } }) => + user ? user?.roles?.some((role) => role === 'admin') : false, + update: ({ req: { user } }) => + user ? user?.roles?.some((role) => role === 'admin') : false, + }, + // highlight-end + }, +}) +``` + +This example restricts all Query Presets to users with the role of `admin`. + + + **Note:** Custom access control will override the defaults on this collection, + including the requirement for a user to be authenticated. Be sure to include + any necessary checks in your custom rules unless you intend on making these + publicly accessible. + + +### Document Access Control + +You can also define access control rules that apply to each specific preset. Users have the ability to define and modify these rules on the fly as they manage presets. These are saved dynamically in the database on each document. + +When a user manages a preset, document-level access control options will be available to them in the Admin Panel for each operation. + +By default, Payload provides a set of sensible defaults for all Query Presets, but you can customize these rules to suit your needs: + +- **Only Me**: Only the user who created the preset can read, update, and delete it. +- **Everyone**: All users can read, update, and delete the preset. +- **Specific Users**: Only select users can read, update, and delete the preset. + +#### Custom Access Control + +You can augment the default access control rules with your own custom rules. This can be useful for creating more complex access control patterns that the defaults don't provide, such as for RBAC. + +Adding custom access control rules requires: + +1. A label to display in the dropdown +2. A set of fields to conditionally render when that option is selected +3. A function that returns the access control rules for that option + +To do this, use the `queryPresets.constraints` property in your [Payload Config](../configuration/payload-config). + +```ts +import { buildConfig } from 'payload' + +const config = buildConfig({ + // ... + queryPresets: { + // ... + // highlight-start + constraints: { + read: { + label: 'Specific Roles', + value: 'specificRoles', + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: [ + { label: 'Admin', value: 'admin' }, + { label: 'User', value: 'user' }, + ], + }, + ], + access: ({ req: { user } }) => ({ + 'access.read.roles': { + in: [user?.roles], + }, + }), + }, + // highlight-end + }, + }, +}) +``` + +In this example, we've added a new option called `Specific Roles` that allows users to select from a list of roles. When this option is selected, the user will be prompted to select one or more roles from a list of options. The access control rule for this option is that the user operating on the preset must have one of the selected roles. + + + **Note:** Payload places your custom fields into the `access[operation]` field + group, so your rules will need to reflect this. + + +The following options are available for each constraint: + +| Option | Description | +| -------- | ------------------------------------------------------------------------ | +| `label` | The label to display in the dropdown for this constraint. | +| `value` | The value to store in the database when this constraint is selected. | +| `fields` | An array of fields to render when this constraint is selected. | +| `access` | A function that determines the access control rules for this constraint. | diff --git a/packages/next/src/views/Document/handleServerFunction.tsx b/packages/next/src/views/Document/handleServerFunction.tsx index 90632aac28..8838888a64 100644 --- a/packages/next/src/views/Document/handleServerFunction.tsx +++ b/packages/next/src/views/Document/handleServerFunction.tsx @@ -28,6 +28,7 @@ export const renderDocumentHandler = async (args: { initialState?: FormState locale?: Locale overrideEntityVisibility?: boolean + redirectAfterCreate?: boolean redirectAfterDelete: boolean redirectAfterDuplicate: boolean req: PayloadRequest @@ -40,6 +41,7 @@ export const renderDocumentHandler = async (args: { initialData, locale, overrideEntityVisibility, + redirectAfterCreate, redirectAfterDelete, redirectAfterDuplicate, req, @@ -165,6 +167,7 @@ export const renderDocumentHandler = async (args: { segments: ['collections', collectionSlug, docID], }, payload, + redirectAfterCreate, redirectAfterDelete, redirectAfterDuplicate, searchParams: {}, diff --git a/packages/next/src/views/Document/index.tsx b/packages/next/src/views/Document/index.tsx index 74d96af927..bca8ee8bb7 100644 --- a/packages/next/src/views/Document/index.tsx +++ b/packages/next/src/views/Document/index.tsx @@ -44,6 +44,7 @@ export const renderDocument = async ({ initPageResult, overrideEntityVisibility, params, + redirectAfterCreate, redirectAfterDelete, redirectAfterDuplicate, searchParams, @@ -51,6 +52,9 @@ export const renderDocument = async ({ }: { drawerSlug?: string overrideEntityVisibility?: boolean + readonly redirectAfterCreate?: boolean + readonly redirectAfterDelete?: boolean + readonly redirectAfterDuplicate?: boolean } & AdminViewServerProps): Promise<{ data: Data Document: React.ReactNode @@ -308,7 +312,7 @@ export const renderDocument = async ({ id = doc.id isEditing = getIsEditing({ id: doc.id, collectionSlug, globalSlug }) - if (!drawerSlug) { + if (!drawerSlug && redirectAfterCreate !== false) { const redirectURL = formatAdminURL({ adminRoute, path: `/collections/${collectionSlug}/${doc.id}`, @@ -358,6 +362,7 @@ export const renderDocument = async ({ key={locale?.code} lastUpdateTime={lastUpdateTime} mostRecentVersionIsAutosaved={mostRecentVersionIsAutosaved} + redirectAfterCreate={redirectAfterCreate} redirectAfterDelete={redirectAfterDelete} redirectAfterDuplicate={redirectAfterDuplicate} unpublishedVersionCount={unpublishedVersionCount} diff --git a/packages/next/src/views/List/handleServerFunction.tsx b/packages/next/src/views/List/handleServerFunction.tsx index ea792b25ee..f4a3014972 100644 --- a/packages/next/src/views/List/handleServerFunction.tsx +++ b/packages/next/src/views/List/handleServerFunction.tsx @@ -16,6 +16,7 @@ export const renderListHandler = async (args: { disableActions?: boolean disableBulkDelete?: boolean disableBulkEdit?: boolean + disableQueryPresets?: boolean documentDrawerSlug: string drawerSlug?: string enableRowSelections: boolean @@ -30,6 +31,7 @@ export const renderListHandler = async (args: { disableActions, disableBulkDelete, disableBulkEdit, + disableQueryPresets, drawerSlug, enableRowSelections, overrideEntityVisibility, @@ -135,6 +137,7 @@ export const renderListHandler = async (args: { disableActions, disableBulkDelete, disableBulkEdit, + disableQueryPresets, drawerSlug, enableRowSelections, i18n, diff --git a/packages/next/src/views/List/index.tsx b/packages/next/src/views/List/index.tsx index 07a246932b..62e08b1262 100644 --- a/packages/next/src/views/List/index.tsx +++ b/packages/next/src/views/List/index.tsx @@ -1,20 +1,29 @@ +import type { + AdminViewServerProps, + ColumnPreference, + DefaultDocumentIDType, + ListPreferences, + ListQuery, + ListViewClientProps, + ListViewServerPropsOnly, + QueryPreset, + SanitizedCollectionPermission, + Where, +} from 'payload' + import { DefaultListView, HydrateAuthProvider, ListQueryProvider } from '@payloadcms/ui' import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent' import { renderFilters, renderTable, upsertPreferences } from '@payloadcms/ui/rsc' -import { mergeListSearchAndWhere } from '@payloadcms/ui/shared' import { notFound } from 'next/navigation.js' import { - type AdminViewServerProps, - type ColumnPreference, - type ListPreferences, - type ListQuery, - type ListViewClientProps, - type ListViewServerPropsOnly, - type Where, -} from 'payload' -import { formatAdminURL, isNumber, transformColumnsToPreferences } from 'payload/shared' + formatAdminURL, + isNumber, + mergeListSearchAndWhere, + transformColumnsToPreferences, +} from 'payload/shared' import React, { Fragment } from 'react' +import { getDocumentPermissions } from '../Document/getDocumentPermissions.js' import { renderListViewSlots } from './renderListViewSlots.js' import { resolveAllFilterOptions } from './resolveAllFilterOptions.js' @@ -22,10 +31,13 @@ type RenderListViewArgs = { customCellProps?: Record disableBulkDelete?: boolean disableBulkEdit?: boolean + disableQueryPresets?: boolean drawerSlug?: string enableRowSelections: boolean overrideEntityVisibility?: boolean query: ListQuery + redirectAfterDelete?: boolean + redirectAfterDuplicate?: boolean } & AdminViewServerProps export const renderListView = async ( @@ -38,6 +50,7 @@ export const renderListView = async ( customCellProps, disableBulkDelete, disableBulkEdit, + disableQueryPresets, drawerSlug, enableRowSelections, initPageResult, @@ -85,6 +98,7 @@ export const renderListView = async ( value: { columns, limit: isNumber(query?.limit) ? Number(query.limit) : undefined, + preset: (query?.preset as DefaultDocumentIDType) || null, sort: query?.sort as string, }, }) @@ -127,6 +141,32 @@ export const renderListView = async ( } } + let queryPreset: QueryPreset | undefined + let queryPresetPermissions: SanitizedCollectionPermission | undefined + + if (listPreferences?.preset) { + try { + queryPreset = (await payload.findByID({ + id: listPreferences?.preset, + collection: 'payload-query-presets', + depth: 0, + overrideAccess: false, + user, + })) as QueryPreset + + if (queryPreset) { + queryPresetPermissions = await getDocumentPermissions({ + id: queryPreset.id, + collectionConfig: config.collections.find((c) => c.slug === 'payload-query-presets'), + data: queryPreset, + req, + })?.then(({ docPermissions }) => docPermissions) + } + } catch (err) { + req.payload.logger.error(`Error fetching query preset or preset permissions: ${err}`) + } + } + const data = await payload.find({ collection: collectionSlug, depth: 0, @@ -212,6 +252,7 @@ export const renderListView = async ( resolvedFilterOptions?: Map } & ListViewSlots diff --git a/packages/payload/src/bin/generateImportMap/utilities/getFromImportMap.ts b/packages/payload/src/bin/generateImportMap/utilities/getFromImportMap.ts index f8832104d5..1f7fde074b 100644 --- a/packages/payload/src/bin/generateImportMap/utilities/getFromImportMap.ts +++ b/packages/payload/src/bin/generateImportMap/utilities/getFromImportMap.ts @@ -1,5 +1,6 @@ import type { PayloadComponent } from '../../../config/types.js' import type { ImportMap } from '../index.js' + import { parsePayloadComponent } from './parsePayloadComponent.js' export const getFromImportMap = (args: { diff --git a/packages/payload/src/collections/config/types.ts b/packages/payload/src/collections/config/types.ts index 98b15a040f..c080c2e2b6 100644 --- a/packages/payload/src/collections/config/types.ts +++ b/packages/payload/src/collections/config/types.ts @@ -420,6 +420,11 @@ export type CollectionConfig = { * When true, do not show the "Duplicate" button while editing documents within this collection and prevent `duplicate` from all APIs */ disableDuplicate?: boolean + /** + * Opt-in to enable query presets for this collection. + * @see https://payloadcms.com/docs/query-presets/overview + */ + enableQueryPresets?: boolean /** * Custom rest api endpoints, set false to disable all rest endpoints for this collection. */ diff --git a/packages/payload/src/config/client.ts b/packages/payload/src/config/client.ts index 16f615abbf..9a6ad9a86e 100644 --- a/packages/payload/src/config/client.ts +++ b/packages/payload/src/config/client.ts @@ -17,6 +17,7 @@ import { } from '../collections/config/client.js' import { createClientBlocks } from '../fields/config/client.js' import { type ClientGlobalConfig, createClientGlobalConfigs } from '../globals/config/client.js' + export type ServerOnlyRootProperties = keyof Pick< SanitizedConfig, | 'bin' @@ -34,6 +35,7 @@ export type ServerOnlyRootProperties = keyof Pick< | 'logger' | 'onInit' | 'plugins' + | 'queryPresets' | 'secret' | 'sharp' | 'typescript' @@ -83,6 +85,7 @@ export const serverOnlyConfigProperties: readonly Partial Promise> = [] const schedulePublishCollections: CollectionSlug[] = [] + + const queryPresetsCollections: CollectionSlug[] = [] + const schedulePublishGlobals: GlobalSlug[] = [] const collectionSlugs = new Set() @@ -192,6 +196,7 @@ export const sanitizeConfig = async (incomingConfig: Config): Promise 0) { configWithDefaults.collections.push( await sanitizeCollection( config as unknown as Config, - migrationsCollection, + getQueryPresetsConfig(config as unknown as Config), richTextSanitizationPromises, validRelationships, ), @@ -380,9 +397,11 @@ export const sanitizeConfig = async (incomingConfig: Config): Promise[] = [] + for (const sanitizeFunction of richTextSanitizationPromises) { promises.push(sanitizeFunction(config as SanitizedConfig)) } + await Promise.all(promises) return config as SanitizedConfig diff --git a/packages/payload/src/config/types.ts b/packages/payload/src/config/types.ts index fd39a85f98..96f3773537 100644 --- a/packages/payload/src/config/types.ts +++ b/packages/payload/src/config/types.ts @@ -49,6 +49,7 @@ import type { RequestContext, TypedUser, } from '../index.js' +import type { QueryPreset, QueryPresetConstraints } from '../query-presets/types.js' import type { PayloadRequest, Where } from '../types/index.js' import type { PayloadLogger } from '../utilities/logger.js' @@ -944,12 +945,12 @@ export type Config = { cookiePrefix?: string /** Either a whitelist array of URLS to allow CORS requests from, or a wildcard string ('*') to accept incoming requests from any domain. */ cors?: '*' | CORSConfig | string[] - /** A whitelist array of URLs to allow Payload cookies to be accepted from as a form of CSRF protection. */ csrf?: string[] /** Extension point to add your custom data. Server only. */ custom?: Record + /** Pass in a database adapter for use on this project. */ db: DatabaseAdapterResult /** Enable to expose more detailed error information. */ @@ -1039,7 +1040,6 @@ export type Config = { * @default false // disable localization */ localization?: false | LocalizationConfig - /** * Logger options, logger options with a destination stream, or an instantiated logger instance. * @@ -1096,6 +1096,7 @@ export type Config = { * @default 10 */ maxDepth?: number + /** A function that is called immediately following startup that receives the Payload instance as its only argument. */ onInit?: (payload: Payload) => Promise | void /** @@ -1104,6 +1105,25 @@ export type Config = { * @see https://payloadcms.com/docs/plugins/overview */ plugins?: Plugin[] + /** + * Allow you to save and share filters, columns, and sort orders for your collections. + * @see https://payloadcms.com/docs/query-presets/overview + */ + queryPresets?: { + access: { + create?: Access + delete?: Access + read?: Access + update?: Access + } + constraints: { + create?: QueryPresetConstraints + delete?: QueryPresetConstraints + read?: QueryPresetConstraints + update?: QueryPresetConstraints + } + labels?: CollectionConfig['labels'] + } /** Control the routing structure that Payload binds itself to. */ routes?: { /** The route for the admin panel. diff --git a/packages/payload/src/exports/components/utilities.ts b/packages/payload/src/exports/components/utilities.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/payload/src/exports/shared.ts b/packages/payload/src/exports/shared.ts index c404336dc6..0f6b2431bc 100644 --- a/packages/payload/src/exports/shared.ts +++ b/packages/payload/src/exports/shared.ts @@ -45,7 +45,6 @@ export { validOperators, validOperatorSet } from '../types/constants.js' export { formatFilesize } from '../uploads/formatFilesize.js' export { isImage } from '../uploads/isImage.js' - export { deepCopyObject, deepCopyObjectComplex, @@ -61,13 +60,15 @@ export { } from '../utilities/deepMerge.js' export { fieldSchemaToJSON } from '../utilities/fieldSchemaToJSON.js' - export { flattenAllFields } from '../utilities/flattenAllFields.js' + export { default as flattenTopLevelFields } from '../utilities/flattenTopLevelFields.js' export { formatAdminURL } from '../utilities/formatAdminURL.js' - +export { formatLabels, toWords } from '../utilities/formatLabels.js' export { getDataByPath } from '../utilities/getDataByPath.js' + export { getFieldPermissions } from '../utilities/getFieldPermissions.js' + export { getSelectMode } from '../utilities/getSelectMode.js' export { getSiblingData } from '../utilities/getSiblingData.js' @@ -86,6 +87,11 @@ export { isReactServerComponentOrFunction, } from '../utilities/isReactComponent.js' +export { + hoistQueryParamsToAnd, + mergeListSearchAndWhere, +} from '../utilities/mergeListSearchAndWhere.js' + export { reduceFieldsToValues } from '../utilities/reduceFieldsToValues.js' export { setsAreEqual } from '../utilities/setsAreEqual.js' @@ -97,8 +103,11 @@ export { transformColumnsToSearchParams, } from '../utilities/transformColumnPreferences.js' +export { transformWhereQuery } from '../utilities/transformWhereQuery.js' + export { unflatten } from '../utilities/unflatten.js' export { validateMimeType } from '../utilities/validateMimeType.js' +export { validateWhereQuery } from '../utilities/validateWhereQuery.js' export { wait } from '../utilities/wait.js' export { default as wordBoundariesRegex } from '../utilities/wordBoundariesRegex.js' export { versionDefaults } from '../versions/defaults.js' diff --git a/packages/payload/src/index.ts b/packages/payload/src/index.ts index ea94b55c18..61c24caa9e 100644 --- a/packages/payload/src/index.ts +++ b/packages/payload/src/index.ts @@ -1391,6 +1391,7 @@ export type { PreferenceUpdateRequest, TabsPreferences, } from './preferences/types.js' +export type { QueryPreset } from './query-presets/types.js' export { jobAfterRead } from './queues/config/index.js' export type { JobsConfig, RunJobAccess, RunJobAccessArgs } from './queues/config/types/index.js' diff --git a/packages/payload/src/preferences/types.ts b/packages/payload/src/preferences/types.ts index fff45efe63..49f110eb02 100644 --- a/packages/payload/src/preferences/types.ts +++ b/packages/payload/src/preferences/types.ts @@ -1,3 +1,4 @@ +import type { DefaultDocumentIDType } from '../index.js' import type { PayloadRequest } from '../types/index.js' export type PreferenceRequest = { @@ -36,5 +37,6 @@ export type ColumnPreference = { export type ListPreferences = { columns?: ColumnPreference[] limit?: number + preset?: DefaultDocumentIDType sort?: string } diff --git a/packages/payload/src/query-presets/access.ts b/packages/payload/src/query-presets/access.ts new file mode 100644 index 0000000000..4d62a088ca --- /dev/null +++ b/packages/payload/src/query-presets/access.ts @@ -0,0 +1,94 @@ +import type { Access, Config } from '../config/types.js' +import type { Operation } from '../types/index.js' + +import defaultAccess from '../auth/defaultAccess.js' + +const operations: Operation[] = ['delete', 'read', 'update', 'create'] as const + +const defaultCollectionAccess = { + create: defaultAccess, + delete: defaultAccess, + read: defaultAccess, + unlock: defaultAccess, + update: defaultAccess, +} + +export const getAccess = (config: Config): Record => + operations.reduce( + (acc, operation) => { + acc[operation] = async (args) => { + const { req } = args + + const collectionAccess = config?.queryPresets?.access?.[operation] + ? await config.queryPresets.access[operation](args) + : defaultCollectionAccess?.[operation] + ? defaultCollectionAccess[operation](args) + : true + + // If collection-level access control is `false`, no need to continue to document-level access + if (collectionAccess === false) { + return false + } + + // The `create` operation does not affect the document-level access control + if (operation === 'create') { + return collectionAccess + } + + return { + and: [ + { + or: [ + // Default access control ensures a user exists, but custom access control may not + ...(req?.user + ? [ + { + and: [ + { + [`access.${operation}.users`]: { + in: [req.user.id], + }, + }, + { + [`access.${operation}.constraint`]: { + in: ['onlyMe', 'specificUsers'], + }, + }, + ], + }, + ] + : []), + { + [`access.${operation}.constraint`]: { + equals: 'everyone', + }, + }, + ...(await Promise.all( + (config?.queryPresets?.constraints?.[operation] || []).map(async (constraint) => { + const constraintAccess = constraint.access + ? await constraint.access(args) + : undefined + + return { + and: [ + ...(typeof constraintAccess === 'object' ? [constraintAccess] : []), + { + [`access.${operation}.constraint`]: { + equals: constraint.value, + }, + }, + ], + } + }), + )), + ], + }, + ...(typeof collectionAccess === 'object' ? [collectionAccess] : []), + ], + } + } + + return acc + }, + {} as Record, + ) diff --git a/packages/payload/src/query-presets/config.ts b/packages/payload/src/query-presets/config.ts new file mode 100644 index 0000000000..ba2d3ee6ff --- /dev/null +++ b/packages/payload/src/query-presets/config.ts @@ -0,0 +1,164 @@ +import type { CollectionConfig } from '../collections/config/types.js' +import type { Config } from '../config/types.js' +import type { Option } from '../fields/config/types.js' + +import { transformWhereQuery } from '../utilities/transformWhereQuery.js' +import { validateWhereQuery } from '../utilities/validateWhereQuery.js' +import { getAccess } from './access.js' +import { getConstraints } from './constraints.js' +import { operations, type QueryPreset } from './types.js' + +export const queryPresetsCollectionSlug = 'payload-query-presets' + +export const getQueryPresetsConfig = (config: Config): CollectionConfig => ({ + slug: queryPresetsCollectionSlug, + access: getAccess(config), + admin: { + defaultColumns: ['title', 'isShared', 'access', 'where', 'columns'], + hidden: true, + useAsTitle: 'title', + }, + fields: [ + { + name: 'title', + type: 'text', + required: true, + }, + { + name: 'isShared', + type: 'checkbox', + defaultValue: false, + validate: (isShared, { data }) => { + const typedData = data as QueryPreset + + // ensure the `isShared` is only true if all constraints are 'onlyMe' + if (typedData?.access) { + const someOperationsAreShared = Object.values(typedData.access).some( + (operation) => operation.constraint !== 'onlyMe', + ) + + if (!isShared && someOperationsAreShared) { + return 'If any constraint is not "onlyMe", the preset must be shared' + } + } + + return true + }, + }, + getConstraints(config), + { + name: 'where', + type: 'json', + admin: { + components: { + Cell: '@payloadcms/ui#QueryPresetsWhereCell', + Field: '@payloadcms/ui#QueryPresetsWhereField', + }, + }, + hooks: { + beforeValidate: [ + ({ data }) => { + // transform the "where" query here so that the client-side doesn't have to + if (data?.where) { + if (validateWhereQuery(data.where)) { + return data.where + } else { + return transformWhereQuery(data.where) + } + } + + return data?.where + }, + ], + }, + label: 'Filters', + }, + { + name: 'columns', + type: 'json', + admin: { + components: { + Cell: '@payloadcms/ui#QueryPresetsColumnsCell', + Field: '@payloadcms/ui#QueryPresetsColumnField', + }, + }, + validate: (value) => { + if (value) { + try { + JSON.parse(JSON.stringify(value)) + } catch { + return 'Invalid JSON' + } + } + + return true + }, + }, + { + name: 'relatedCollection', + type: 'select', + admin: { + hidden: true, + }, + options: config.collections + ? config.collections.reduce((acc, collection) => { + if (collection.enableQueryPresets) { + acc.push({ + label: collection.labels?.plural || collection.slug, + value: collection.slug, + }) + } + return acc + }, [] as Option[]) + : [], + required: true, + }, + ], + hooks: { + beforeValidate: [ + ({ data, operation, req }) => { + // TODO: type this + const typedData = data as any + + if (operation === 'create' || operation === 'update') { + // Ensure all operations have a constraint + operations.forEach((operation) => { + if (!typedData.access) { + typedData.access = {} + } + + if (!typedData.access?.[operation]) { + typedData[operation] = {} + } + + // Ensure all operations have a constraint + if (!typedData.access[operation]?.constraint) { + typedData.access[operation] = { + ...typedData.access[operation], + constraint: 'onlyMe', + } + } + }) + + // If at least one constraint is not `onlyMe` then `isShared` must be true + if (typedData?.access) { + const someOperationsAreShared = Object.values(typedData.access).some( + // TODO: remove the `any` here + (operation: any) => operation.constraint !== 'onlyMe', + ) + + typedData.isShared = someOperationsAreShared + } + } + + return typedData + }, + ], + }, + labels: { + plural: 'Presets', + singular: 'Preset', + ...(config.queryPresets?.labels || {}), + }, + lockDocuments: false, +}) diff --git a/packages/payload/src/query-presets/constraints.ts b/packages/payload/src/query-presets/constraints.ts new file mode 100644 index 0000000000..2453276b54 --- /dev/null +++ b/packages/payload/src/query-presets/constraints.ts @@ -0,0 +1,104 @@ +import { getTranslation } from '@payloadcms/translations' + +import type { Config } from '../config/types.js' +import type { Field } from '../fields/config/types.js' + +import { fieldAffectsData } from '../fields/config/types.js' +import { toWords } from '../utilities/formatLabels.js' +import { operations, type QueryPresetConstraint } from './types.js' + +export const getConstraints = (config: Config): Field => ({ + name: 'access', + type: 'group', + admin: { + components: { + Cell: '@payloadcms/ui#QueryPresetsAccessCell', + }, + condition: (data) => Boolean(data?.isShared), + }, + fields: operations.map((operation) => ({ + type: 'collapsible', + fields: [ + { + name: operation, + type: 'group', + admin: { + hideGutter: true, + }, + fields: [ + { + name: 'constraint', + type: 'select', + defaultValue: 'onlyMe', + label: ({ i18n }) => + `Specify who can ${operation} this ${getTranslation(config.queryPresets?.labels?.singular || 'Preset', i18n)}`, + options: [ + { + label: 'Everyone', + value: 'everyone', + }, + { + label: 'Only Me', + value: 'onlyMe', + }, + { + label: 'Specific Users', + value: 'specificUsers', + }, + ...(config?.queryPresets?.constraints?.[operation]?.map( + (option: QueryPresetConstraint) => ({ + label: option.label, + value: option.value, + }), + ) || []), + ], + }, + { + name: 'users', + type: 'relationship', + admin: { + condition: (data) => + Boolean(data?.access?.[operation]?.constraint === 'specificUsers'), + }, + hasMany: true, + hooks: { + beforeChange: [ + ({ data, req }) => { + if (data?.access?.[operation]?.constraint === 'onlyMe') { + if (req.user) { + return [req.user.id] + } + } + + return data?.access?.[operation]?.users + }, + ], + }, + relationTo: 'users', + }, + ...(config?.queryPresets?.constraints?.[operation]?.reduce( + (acc: Field[], option: QueryPresetConstraint) => { + option.fields.forEach((field, index) => { + acc.push({ ...field }) + + if (fieldAffectsData(field)) { + acc[index].admin = { + ...(acc[index]?.admin || {}), + condition: (data) => + Boolean(data?.access?.[operation]?.constraint === option.value), + } + } + }) + + return acc + }, + [] as Field[], + ) || []), + ], + label: false, + }, + ], + label: () => toWords(operation), + })), + label: 'Sharing settings', +}) diff --git a/packages/payload/src/query-presets/types.ts b/packages/payload/src/query-presets/types.ts new file mode 100644 index 0000000000..a2f35de730 --- /dev/null +++ b/packages/payload/src/query-presets/types.ts @@ -0,0 +1,33 @@ +import type { Field } from '../fields/config/types.js' +import type { Access, CollectionSlug } from '../index.js' +import type { ListPreferences } from '../preferences/types.js' +import type { Where } from '../types/index.js' + +// Note: order matters here as it will change the rendered order in the UI +export const operations = ['read', 'update', 'delete'] as const + +type Operation = (typeof operations)[number] + +export type QueryPreset = { + access: { + [operation in Operation]: { + constraint: 'everyone' | 'onlyMe' | 'specificUsers' + users?: string[] + } + } + columns: ListPreferences['columns'] + id: number | string + isShared: boolean + relatedCollection: CollectionSlug + title: string + where: Where +} + +export type QueryPresetConstraint = { + access: Access + fields: Field[] + label: string + value: string +} + +export type QueryPresetConstraints = QueryPresetConstraint[] diff --git a/packages/ui/src/utilities/mergeListSearchAndWhere.ts b/packages/payload/src/utilities/mergeListSearchAndWhere.ts similarity index 83% rename from packages/ui/src/utilities/mergeListSearchAndWhere.ts rename to packages/payload/src/utilities/mergeListSearchAndWhere.ts index 7e9ad5ba0e..0824be02e9 100644 --- a/packages/ui/src/utilities/mergeListSearchAndWhere.ts +++ b/packages/payload/src/utilities/mergeListSearchAndWhere.ts @@ -1,4 +1,6 @@ -import type { ClientCollectionConfig, SanitizedCollectionConfig, Where } from 'payload' +import type { ClientCollectionConfig } from '../collections/config/client.js' +import type { SanitizedCollectionConfig } from '../collections/config/types.js' +import type { Where } from '../types/index.js' const isEmptyObject = (obj: object) => Object.keys(obj).length === 0 @@ -11,7 +13,7 @@ export const hoistQueryParamsToAnd = (currentWhere: Where, incomingWhere: Where) return incomingWhere } - if ('and' in currentWhere) { + if ('and' in currentWhere && currentWhere.and) { currentWhere.and.push(incomingWhere) } else if ('or' in currentWhere) { currentWhere = { diff --git a/packages/ui/src/elements/WhereBuilder/transformWhereQuery.ts b/packages/payload/src/utilities/transformWhereQuery.ts similarity index 64% rename from packages/ui/src/elements/WhereBuilder/transformWhereQuery.ts rename to packages/payload/src/utilities/transformWhereQuery.ts index f61ca5f27c..8bfa199bb0 100644 --- a/packages/ui/src/elements/WhereBuilder/transformWhereQuery.ts +++ b/packages/payload/src/utilities/transformWhereQuery.ts @@ -1,15 +1,18 @@ -'use client' -import type { Where } from 'payload' +import type { Where } from '../types/index.js' /** - * Something like [or][0][and][0][text][equals]=example%20post will work and pass through the validateWhereQuery check. - * However, something like [text][equals]=example%20post will not work and will fail the validateWhereQuery check, - * even though it is a valid Where query. This needs to be transformed here. + * Transforms a basic "where" query into a format in which the "where builder" can understand. + * Even though basic queries are valid, we need to hoist them into the "and" / "or" format. + * Use this function alongside `validateWhereQuery` to check that for valid queries before transforming. + * @example + * Inaccurate: [text][equals]=example%20post + * Accurate: [or][0][and][0][text][equals]=example%20post */ -export const transformWhereQuery = (whereQuery): Where => { +export const transformWhereQuery = (whereQuery: Where): Where => { if (!whereQuery) { return {} } + // Check if 'whereQuery' has 'or' field but no 'and'. This is the case for "correct" queries if (whereQuery.or && !whereQuery.and) { return { diff --git a/packages/ui/src/elements/WhereBuilder/validateWhereQuery.ts b/packages/payload/src/utilities/validateWhereQuery.ts similarity index 63% rename from packages/ui/src/elements/WhereBuilder/validateWhereQuery.ts rename to packages/payload/src/utilities/validateWhereQuery.ts index 725a6849a0..bf9b4d802c 100644 --- a/packages/ui/src/elements/WhereBuilder/validateWhereQuery.ts +++ b/packages/payload/src/utilities/validateWhereQuery.ts @@ -1,10 +1,18 @@ -'use client' -import type { Operator, Where } from 'payload' +import type { Operator, Where } from '../types/index.js' -import { validOperatorSet } from 'payload/shared' +import { validOperatorSet } from '../types/constants.js' -const validateWhereQuery = (whereQuery): whereQuery is Where => { +/** + * Validates that a "where" query is in a format in which the "where builder" can understand. + * Even though basic queries are valid, we need to hoist them into the "and" / "or" format. + * Use this function alongside `transformWhereQuery` to perform a transformation if the query is not valid. + * @example + * Inaccurate: [text][equals]=example%20post + * Accurate: [or][0][and][0][text][equals]=example%20post + */ +export const validateWhereQuery = (whereQuery: Where): whereQuery is Where => { if ( + whereQuery?.or && whereQuery?.or?.length > 0 && whereQuery?.or?.[0]?.and && whereQuery?.or?.[0]?.and?.length > 0 @@ -44,5 +52,3 @@ const validateWhereQuery = (whereQuery): whereQuery is Where => { return false } - -export default validateWhereQuery diff --git a/packages/translations/src/clientKeys.ts b/packages/translations/src/clientKeys.ts index 60c87ee14f..d92cb05690 100644 --- a/packages/translations/src/clientKeys.ts +++ b/packages/translations/src/clientKeys.ts @@ -252,6 +252,7 @@ export const clientTranslationKeys = createClientTranslationKeys([ 'general:selectAll', 'general:selectAllRows', 'general:selectedCount', + 'general:selectLabel', 'general:selectValue', 'general:showAllLabel', 'general:sorryNotFound', @@ -280,7 +281,9 @@ export const clientTranslationKeys = createClientTranslationKeys([ 'general:unsavedChangesDuplicate', 'general:untitled', 'general:updatedAt', + 'general:updatedLabelSuccessfully', 'general:updatedCountSuccessfully', + 'general:updateForEveryone', 'general:updatedSuccessfully', 'general:updating', 'general:value', diff --git a/packages/translations/src/languages/ar.ts b/packages/translations/src/languages/ar.ts index 643f6dd8d5..af7c4f25f8 100644 --- a/packages/translations/src/languages/ar.ts +++ b/packages/translations/src/languages/ar.ts @@ -311,6 +311,7 @@ export const arTranslations: DefaultTranslationsObject = { selectAll: 'تحديد كل {{count}} {{label}}', selectAllRows: 'حدد جميع الصفوف', selectedCount: 'تم تحديد {{count}} {{label}}', + selectLabel: 'حدد {{label}}', selectValue: 'اختيار قيمة', showAllLabel: 'عرض كل {{label}}', sorryNotFound: 'عذرًا - لا يوجد شيء يتوافق مع طلبك.', @@ -338,7 +339,9 @@ export const arTranslations: DefaultTranslationsObject = { upcomingEvents: 'الأحداث القادمة', updatedAt: 'تم التحديث في', updatedCountSuccessfully: 'تم تحديث {{count}} {{label}} بنجاح.', + updatedLabelSuccessfully: 'تم تحديث {{label}} بنجاح.', updatedSuccessfully: 'تم التحديث بنجاح.', + updateForEveryone: 'تحديث للجميع', updating: 'جار التحديث', uploading: 'جار الرفع', uploadingBulk: 'جاري التحميل {{current}} من {{total}}', diff --git a/packages/translations/src/languages/az.ts b/packages/translations/src/languages/az.ts index ace7b7b191..717acbe639 100644 --- a/packages/translations/src/languages/az.ts +++ b/packages/translations/src/languages/az.ts @@ -314,6 +314,7 @@ export const azTranslations: DefaultTranslationsObject = { selectAll: 'Bütün {{count}} {{label}} seç', selectAllRows: 'Bütün sıraları seçin', selectedCount: '{{count}} {{label}} seçildi', + selectLabel: '{{label}} seçin', selectValue: 'Dəyər seçin', showAllLabel: 'Bütün {{label}}-ı göstər', sorryNotFound: 'Üzr istəyirik - sizin tələbinizə uyğun heç nə yoxdur.', @@ -343,7 +344,9 @@ export const azTranslations: DefaultTranslationsObject = { upcomingEvents: 'Gələcək Tədbirlər', updatedAt: 'Yeniləndiyi tarix', updatedCountSuccessfully: '{{count}} {{label}} uğurla yeniləndi.', + updatedLabelSuccessfully: '{{label}} uğurla yeniləndi.', updatedSuccessfully: 'Uğurla yeniləndi.', + updateForEveryone: 'Hər kəs üçün yeniləmə', updating: 'Yenilənir', uploading: 'Yüklənir', uploadingBulk: '{{total}}-dan {{current}}-un yüklənməsi', diff --git a/packages/translations/src/languages/bg.ts b/packages/translations/src/languages/bg.ts index e4ef1cf723..5b3cc213c0 100644 --- a/packages/translations/src/languages/bg.ts +++ b/packages/translations/src/languages/bg.ts @@ -314,6 +314,7 @@ export const bgTranslations: DefaultTranslationsObject = { selectAll: 'Избери всички {{count}} {{label}}', selectAllRows: 'Избери всички редове', selectedCount: '{{count}} {{label}} избрани', + selectLabel: 'Изберете {{label}}', selectValue: 'Избери стойност', showAllLabel: 'Покажи всички {{label}}', sorryNotFound: 'Съжаляваме-няма нищо, което да отговаря на търсенето ти.', @@ -341,7 +342,9 @@ export const bgTranslations: DefaultTranslationsObject = { upcomingEvents: 'Предстоящи събития', updatedAt: 'Обновен на', updatedCountSuccessfully: 'Обновени {{count}} {{label}} успешно.', + updatedLabelSuccessfully: 'Успешно обновихме {{label}}.', updatedSuccessfully: 'Обновен успешно.', + updateForEveryone: 'Актуализация за всички', updating: 'Обновява се', uploading: 'Качва се', uploadingBulk: 'Качване на {{current}} от {{total}}', diff --git a/packages/translations/src/languages/ca.ts b/packages/translations/src/languages/ca.ts index 140d85406b..c6235daf44 100644 --- a/packages/translations/src/languages/ca.ts +++ b/packages/translations/src/languages/ca.ts @@ -315,6 +315,7 @@ export const caTranslations: DefaultTranslationsObject = { selectAll: 'Selecciona totes les {{count}} {{label}}', selectAllRows: 'Selecciona totes les files', selectedCount: '{{count}} {{label}} seleccionats', + selectLabel: 'Selecciona {{label}}', selectValue: 'Selecciona un valor', showAllLabel: 'Mostra totes {{label}}', sorryNotFound: "Ho sento, no s'ha trobat la pàgina que busques.", @@ -342,7 +343,9 @@ export const caTranslations: DefaultTranslationsObject = { upcomingEvents: 'Esdeveniments programats', updatedAt: 'Actualitzat el', updatedCountSuccessfully: 'Actualitzat {{count}} {{label}} correctament.', + updatedLabelSuccessfully: 'Actualitzat {{label}} amb èxit.', updatedSuccessfully: 'Actualitzat amb exit.', + updateForEveryone: 'Actualització per a tothom', updating: 'Actualitzant', uploading: 'Pujant', uploadingBulk: 'Pujant {{current}} de {{total}}', diff --git a/packages/translations/src/languages/cs.ts b/packages/translations/src/languages/cs.ts index 7b6a62e01f..56b59453fa 100644 --- a/packages/translations/src/languages/cs.ts +++ b/packages/translations/src/languages/cs.ts @@ -312,6 +312,7 @@ export const csTranslations: DefaultTranslationsObject = { selectAll: 'Vybrat vše {{count}} {{label}}', selectAllRows: 'Vyberte všechny řádky', selectedCount: 'Vybráno {{count}} {{label}}', + selectLabel: 'Vyberte {{label}}', selectValue: 'Vyberte hodnotu', showAllLabel: 'Zobrazit všechny {{label}}', sorryNotFound: 'Je nám líto, ale neexistuje nic, co by odpovídalo vašemu požadavku.', @@ -339,7 +340,9 @@ export const csTranslations: DefaultTranslationsObject = { upcomingEvents: 'Nadcházející události', updatedAt: 'Aktualizováno v', updatedCountSuccessfully: 'Úspěšně aktualizováno {{count}} {{label}}.', + updatedLabelSuccessfully: 'Úspěšně aktualizovaný {{label}}.', updatedSuccessfully: 'Úspěšně aktualizováno.', + updateForEveryone: 'Aktualizace pro všechny', updating: 'Aktualizace', uploading: 'Nahrávání', uploadingBulk: 'Nahrávání {{current}} z {{total}}', diff --git a/packages/translations/src/languages/da.ts b/packages/translations/src/languages/da.ts index d66a3bf5d7..9aa2081509 100644 --- a/packages/translations/src/languages/da.ts +++ b/packages/translations/src/languages/da.ts @@ -313,6 +313,7 @@ export const daTranslations: DefaultTranslationsObject = { selectAll: 'Vælg alle {{count}} {{label}}', selectAllRows: 'Vælg alle rækker', selectedCount: '{{count}} {{label}} valgt', + selectLabel: 'Vælg {{label}}', selectValue: 'Vælg en værdi', showAllLabel: 'Vis alle {{label}}', sorryNotFound: 'Beklager—der er intet, der svarer til din handling.', @@ -340,7 +341,9 @@ export const daTranslations: DefaultTranslationsObject = { upcomingEvents: 'Kommende Begivenheder', updatedAt: 'Opdateret ved', updatedCountSuccessfully: 'Opdateret {{count}} {{label}} successfully.', + updatedLabelSuccessfully: 'Opdaterede {{label}} med succes.', updatedSuccessfully: 'Opdateret.', + updateForEveryone: 'Opdatering for alle', updating: 'Opdaterer', uploading: 'Uploader', uploadingBulk: 'Uploader {{current}} af {{total}}', diff --git a/packages/translations/src/languages/de.ts b/packages/translations/src/languages/de.ts index c8476df60e..f926cf8fed 100644 --- a/packages/translations/src/languages/de.ts +++ b/packages/translations/src/languages/de.ts @@ -318,6 +318,7 @@ export const deTranslations: DefaultTranslationsObject = { selectAll: 'Alle auswählen {{count}} {{label}}', selectAllRows: 'Wählen Sie alle Zeilen aus', selectedCount: '{{count}} {{label}} ausgewählt', + selectLabel: 'Wählen Sie {{label}}', selectValue: 'Wert auswählen', showAllLabel: 'Zeige alle {{label}}', sorryNotFound: 'Entschuldige, es entspricht nichts deiner Anfrage', @@ -347,7 +348,9 @@ export const deTranslations: DefaultTranslationsObject = { upcomingEvents: 'Bevorstehende Veranstaltungen', updatedAt: 'Aktualisiert am', updatedCountSuccessfully: '{{count}} {{label}} erfolgreich aktualisiert.', + updatedLabelSuccessfully: '{{label}} erfolgreich aktualisiert.', updatedSuccessfully: 'Erfolgreich aktualisiert.', + updateForEveryone: 'Aktualisierung für alle', updating: 'Aktualisierung', uploading: 'Hochladen', uploadingBulk: 'Hochladen von {{current}} von {{total}}', diff --git a/packages/translations/src/languages/en.ts b/packages/translations/src/languages/en.ts index e55801fad0..5aba5fa6ad 100644 --- a/packages/translations/src/languages/en.ts +++ b/packages/translations/src/languages/en.ts @@ -315,6 +315,7 @@ export const enTranslations = { selectAll: 'Select all {{count}} {{label}}', selectAllRows: 'Select all rows', selectedCount: '{{count}} {{label}} selected', + selectLabel: 'Select {{label}}', selectValue: 'Select a value', showAllLabel: 'Show all {{label}}', sorryNotFound: 'Sorry—there is nothing to correspond with your request.', @@ -342,7 +343,9 @@ export const enTranslations = { upcomingEvents: 'Upcoming Events', updatedAt: 'Updated At', updatedCountSuccessfully: 'Updated {{count}} {{label}} successfully.', + updatedLabelSuccessfully: 'Updated {{label}} successfully.', updatedSuccessfully: 'Updated successfully.', + updateForEveryone: 'Update for everyone', updating: 'Updating', uploading: 'Uploading', uploadingBulk: 'Uploading {{current}} of {{total}}', diff --git a/packages/translations/src/languages/es.ts b/packages/translations/src/languages/es.ts index bede932313..49248629bc 100644 --- a/packages/translations/src/languages/es.ts +++ b/packages/translations/src/languages/es.ts @@ -319,6 +319,7 @@ export const esTranslations: DefaultTranslationsObject = { selectAll: 'Seleccionar todo {{count}} {{label}}', selectAllRows: 'Selecciona todas las filas', selectedCount: '{{count}} {{label}} seleccionado', + selectLabel: 'Seleccione {{label}}', selectValue: 'Selecciona un valor', showAllLabel: 'Muestra todas {{label}}', sorryNotFound: 'Lo sentimos. No hay nada que corresponda con tu solicitud.', @@ -346,7 +347,9 @@ export const esTranslations: DefaultTranslationsObject = { upcomingEvents: 'Próximos Eventos', updatedAt: 'Fecha de modificado', updatedCountSuccessfully: '{{count}} {{label}} actualizado con éxito.', + updatedLabelSuccessfully: 'Actualizado {{label}} con éxito.', updatedSuccessfully: 'Actualizado con éxito.', + updateForEveryone: 'Actualización para todos', updating: 'Actualizando', uploading: 'Subiendo', uploadingBulk: 'Subiendo {{current}} de {{total}}', diff --git a/packages/translations/src/languages/et.ts b/packages/translations/src/languages/et.ts index fd02081934..06ba68fcf9 100644 --- a/packages/translations/src/languages/et.ts +++ b/packages/translations/src/languages/et.ts @@ -311,6 +311,7 @@ export const etTranslations: DefaultTranslationsObject = { selectAll: 'Vali kõik {{count}} {{label}}', selectAllRows: 'Vali kõik read', selectedCount: '{{count}} {{label}} valitud', + selectLabel: 'Valige {{label}}', selectValue: 'Vali väärtus', showAllLabel: 'Näita kõiki {{label}}', sorryNotFound: 'Vabandust - teie päringule vastavat sisu ei leitud.', @@ -338,7 +339,9 @@ export const etTranslations: DefaultTranslationsObject = { upcomingEvents: 'Eelseisvad sündmused', updatedAt: 'Uuendatud', updatedCountSuccessfully: 'Uuendatud {{count}} {{label}} edukalt.', + updatedLabelSuccessfully: 'Uuendas {{label}} edukalt.', updatedSuccessfully: 'Edukalt uuendatud.', + updateForEveryone: 'Uuendus kõigile', updating: 'Uuendamine', uploading: 'Üleslaadimine', uploadingBulk: 'Üleslaadimine {{current}} / {{total}}', diff --git a/packages/translations/src/languages/fa.ts b/packages/translations/src/languages/fa.ts index e6a89079e3..8a17f5be61 100644 --- a/packages/translations/src/languages/fa.ts +++ b/packages/translations/src/languages/fa.ts @@ -312,6 +312,7 @@ export const faTranslations: DefaultTranslationsObject = { selectAll: 'انتخاب همه {{count}} {{label}}', selectAllRows: 'انتخاب تمام سطرها', selectedCount: '{{count}} {{label}} انتخاب شد', + selectLabel: '{{label}} را انتخاب کنید', selectValue: 'یک مقدار را انتخاب کنید', showAllLabel: 'نمایش همه {{label}}', sorryNotFound: 'متأسفانه چیزی برای مطابقت با درخواست شما وجود ندارد.', @@ -339,7 +340,9 @@ export const faTranslations: DefaultTranslationsObject = { upcomingEvents: 'رویدادهای آینده', updatedAt: 'بروز شده در', updatedCountSuccessfully: 'تعداد {{count}} با عنوان {{label}} با موفقیت بروزرسانی شدند.', + updatedLabelSuccessfully: 'به روزرسانی {{label}} با موفقیت انجام شد.', updatedSuccessfully: 'با موفقیت به‌روز شد.', + updateForEveryone: 'بروزرسانی برای همه', updating: 'در حال به‌روزرسانی', uploading: 'در حال بارگذاری', uploadingBulk: 'بارگذاری {{current}} از {{total}}', diff --git a/packages/translations/src/languages/fr.ts b/packages/translations/src/languages/fr.ts index 58eb27c248..6b49660418 100644 --- a/packages/translations/src/languages/fr.ts +++ b/packages/translations/src/languages/fr.ts @@ -322,6 +322,7 @@ export const frTranslations: DefaultTranslationsObject = { selectAll: 'Tout sélectionner {{count}} {{label}}', selectAllRows: 'Sélectionnez toutes les lignes', selectedCount: '{{count}} {{label}} sélectionné', + selectLabel: 'Sélectionnez {{label}}', selectValue: 'Sélectionnez une valeur', showAllLabel: 'Afficher tous les {{label}}', sorryNotFound: 'Désolé, rien ne correspond à votre demande.', @@ -351,7 +352,9 @@ export const frTranslations: DefaultTranslationsObject = { upcomingEvents: 'Événements à venir', updatedAt: 'Modifié le', updatedCountSuccessfully: '{{count}} {{label}} mis à jour avec succès.', + updatedLabelSuccessfully: '{{label}} mis à jour avec succès.', updatedSuccessfully: 'Mis à jour avec succès.', + updateForEveryone: 'Mise à jour pour tout le monde', updating: 'Mise à jour', uploading: 'Téléchargement', uploadingBulk: 'Téléchargement de {{current}} sur {{total}}', diff --git a/packages/translations/src/languages/he.ts b/packages/translations/src/languages/he.ts index 0f20ccdc47..c2bc56a717 100644 --- a/packages/translations/src/languages/he.ts +++ b/packages/translations/src/languages/he.ts @@ -307,6 +307,7 @@ export const heTranslations: DefaultTranslationsObject = { selectAll: 'בחר את כל {{count}} ה{{label}}', selectAllRows: 'בחר את כל השורות', selectedCount: '{{count}} {{label}} נבחרו', + selectLabel: '{{label}} בחר', selectValue: 'בחר ערך', showAllLabel: 'הצג את כל ה{{label}}', sorryNotFound: 'מצטערים - אין תוצאות התואמות את הבקשה.', @@ -334,7 +335,9 @@ export const heTranslations: DefaultTranslationsObject = { upcomingEvents: 'אירועים קרובים', updatedAt: 'עודכן בתאריך', updatedCountSuccessfully: 'עודכן {{count}} {{label}} בהצלחה.', + updatedLabelSuccessfully: 'עודכן {{label}} בהצלחה.', updatedSuccessfully: 'עודכן בהצלחה.', + updateForEveryone: 'עדכון לכולם', updating: 'מעדכן', uploading: 'מעלה', uploadingBulk: 'מעלה {{current}} מתוך {{total}}', diff --git a/packages/translations/src/languages/hr.ts b/packages/translations/src/languages/hr.ts index 271fef8446..0ee1aaf478 100644 --- a/packages/translations/src/languages/hr.ts +++ b/packages/translations/src/languages/hr.ts @@ -314,6 +314,7 @@ export const hrTranslations: DefaultTranslationsObject = { selectAll: 'Odaberite sve {{count}} {{label}}', selectAllRows: 'Odaberite sve redove', selectedCount: '{{count}} {{label}} odabrano', + selectLabel: 'Odaberite {{label}}', selectValue: 'Odaberi vrijednost', showAllLabel: 'Prikaži sve {{label}}', sorryNotFound: 'Nažalost, ne postoji ništa što odgovara vašem zahtjevu.', @@ -341,7 +342,9 @@ export const hrTranslations: DefaultTranslationsObject = { upcomingEvents: 'Nadolazeći događaji', updatedAt: 'Ažurirano u', updatedCountSuccessfully: 'Uspješno ažurirano {{count}} {{label}}.', + updatedLabelSuccessfully: 'Uspješno ažurirano {{label}}.', updatedSuccessfully: 'Uspješno ažurirano.', + updateForEveryone: 'Ažuriranje za sve', updating: 'Ažuriranje', uploading: 'Prijenos', uploadingBulk: 'Prenosim {{current}} od {{total}}', diff --git a/packages/translations/src/languages/hu.ts b/packages/translations/src/languages/hu.ts index 8d0d3a29a7..4ae82303f8 100644 --- a/packages/translations/src/languages/hu.ts +++ b/packages/translations/src/languages/hu.ts @@ -317,6 +317,7 @@ export const huTranslations: DefaultTranslationsObject = { selectAll: 'Az összes kijelölése: {{count}} {{label}}', selectAllRows: 'Válassza ki az összes sort', selectedCount: '{{count}} {{label}} kiválasztva', + selectLabel: 'Válassza ki a(z) {{label}} opciót', selectValue: 'Válasszon ki egy értéket', showAllLabel: 'Mutasd az összes {{címke}}', sorryNotFound: 'Sajnáljuk – nincs semmi, ami megfelelne a kérésének.', @@ -344,7 +345,9 @@ export const huTranslations: DefaultTranslationsObject = { upcomingEvents: 'Közelgő események', updatedAt: 'Frissítve:', updatedCountSuccessfully: '{{count}} {{label}} sikeresen frissítve.', + updatedLabelSuccessfully: 'A(z) {{label}} sikeresen frissült.', updatedSuccessfully: 'Sikeresen frissítve.', + updateForEveryone: 'Frissítés mindenkinek', updating: 'Frissítés', uploading: 'Feltöltés', uploadingBulk: 'Feltöltés: {{current}} / {{total}}', diff --git a/packages/translations/src/languages/it.ts b/packages/translations/src/languages/it.ts index 258fbddb03..4191ce53ff 100644 --- a/packages/translations/src/languages/it.ts +++ b/packages/translations/src/languages/it.ts @@ -318,6 +318,7 @@ export const itTranslations: DefaultTranslationsObject = { selectAll: 'Seleziona tutto {{count}} {{label}}', selectAllRows: 'Seleziona tutte le righe', selectedCount: '{{count}} {{label}} selezionato', + selectLabel: 'Seleziona {{label}}', selectValue: 'Seleziona un valore', showAllLabel: 'Mostra tutti {{label}}', sorryNotFound: "Siamo spiacenti, non c'è nulla che corrisponda alla tua richiesta.", @@ -345,7 +346,9 @@ export const itTranslations: DefaultTranslationsObject = { upcomingEvents: 'Eventi Imminenti', updatedAt: 'Aggiornato il', updatedCountSuccessfully: '{{count}} {{label}} aggiornato con successo.', + updatedLabelSuccessfully: '{{label}} aggiornata con successo.', updatedSuccessfully: 'Aggiornato con successo.', + updateForEveryone: 'Aggiornamento per tutti', updating: 'Aggiornamento', uploading: 'Caricamento', uploadingBulk: 'Caricamento {{current}} di {{total}}', diff --git a/packages/translations/src/languages/ja.ts b/packages/translations/src/languages/ja.ts index 1f1b4bb63a..aa2dcb8866 100644 --- a/packages/translations/src/languages/ja.ts +++ b/packages/translations/src/languages/ja.ts @@ -314,6 +314,7 @@ export const jaTranslations: DefaultTranslationsObject = { selectAll: 'すべての{{count}}つの{{label}}を選択', selectAllRows: 'すべての行を選択します', selectedCount: '{{count}}つの{{label}}を選択中', + selectLabel: '{{label}}を選択してください', selectValue: '値を選択', showAllLabel: 'すべての{{label}}を表示する', sorryNotFound: '申し訳ありません。リクエストに対応する内容が見つかりませんでした。', @@ -341,7 +342,9 @@ export const jaTranslations: DefaultTranslationsObject = { upcomingEvents: '今後のイベント', updatedAt: '更新日', updatedCountSuccessfully: '{{count}}つの{{label}}を正常に更新しました。', + updatedLabelSuccessfully: '{{label}}の更新に成功しました。', updatedSuccessfully: '更新成功。', + updateForEveryone: '皆様への更新情報', updating: '更新中', uploading: 'アップロード中', uploadingBulk: '{{current}} / {{total}} をアップロード中', diff --git a/packages/translations/src/languages/ko.ts b/packages/translations/src/languages/ko.ts index fbfd8521ed..6d13bbcc3a 100644 --- a/packages/translations/src/languages/ko.ts +++ b/packages/translations/src/languages/ko.ts @@ -312,6 +312,7 @@ export const koTranslations: DefaultTranslationsObject = { selectAll: '{{count}}개 {{label}} 모두 선택', selectAllRows: '모든 행 선택', selectedCount: '{{count}}개의 {{label}} 선택됨', + selectLabel: '{{label}}을 선택하십시오.', selectValue: '값 선택', showAllLabel: '{{label}} 모두 표시', sorryNotFound: '죄송합니다. 요청과 일치하는 항목이 없습니다.', @@ -339,7 +340,9 @@ export const koTranslations: DefaultTranslationsObject = { upcomingEvents: '다가오는 이벤트', updatedAt: '업데이트 일시', updatedCountSuccessfully: '{{count}}개의 {{label}}을(를) 업데이트했습니다.', + updatedLabelSuccessfully: '{{label}}이(가) 성공적으로 업데이트되었습니다.', updatedSuccessfully: '성공적으로 업데이트되었습니다.', + updateForEveryone: '모두를 위한 업데이트', updating: '업데이트 중', uploading: '업로드 중', uploadingBulk: '{{current}} / {{total}} 업로드 중', diff --git a/packages/translations/src/languages/lt.ts b/packages/translations/src/languages/lt.ts index 911ab9dbbc..2afcd0dd5e 100644 --- a/packages/translations/src/languages/lt.ts +++ b/packages/translations/src/languages/lt.ts @@ -316,6 +316,7 @@ export const ltTranslations: DefaultTranslationsObject = { selectAll: 'Pasirinkite visus {{count}} {{label}}', selectAllRows: 'Pasirinkite visas eilutes', selectedCount: '{{count}} {{label}} pasirinkta', + selectLabel: 'Pasirinkite {{label}}', selectValue: 'Pasirinkite reikšmę', showAllLabel: 'Rodyti visus {{label}}', sorryNotFound: 'Atsiprašau - nėra nieko, atitinkančio jūsų užklausą.', @@ -343,7 +344,9 @@ export const ltTranslations: DefaultTranslationsObject = { upcomingEvents: 'Artimieji renginiai', updatedAt: 'Atnaujinta', updatedCountSuccessfully: '{{count}} {{label}} sėkmingai atnaujinta.', + updatedLabelSuccessfully: 'Sėkmingai atnaujinta {{label}}.', updatedSuccessfully: 'Sėkmingai atnaujinta.', + updateForEveryone: 'Atnaujinimas visiems', updating: 'Atnaujinimas', uploading: 'Įkeliama', uploadingBulk: 'Įkeliamas {{current}} iš {{total}}', diff --git a/packages/translations/src/languages/my.ts b/packages/translations/src/languages/my.ts index 1fab28b045..2150356137 100644 --- a/packages/translations/src/languages/my.ts +++ b/packages/translations/src/languages/my.ts @@ -317,6 +317,7 @@ export const myTranslations: DefaultTranslationsObject = { selectAll: '{{count}} {{label}} အားလုံးကို ရွေးပါ', selectAllRows: 'အားလုံးကိုရွေးချယ်ပါ', selectedCount: '{{count}} {{label}} ကို ရွေးထားသည်။', + selectLabel: 'Pilih {{label}}', selectValue: 'တစ်ခုခုကို ရွေးချယ်ပါ။', showAllLabel: 'Tunjukkan semua {{label}}', sorryNotFound: 'ဝမ်းနည်းပါသည်။ သင်ရှာနေတဲ့ဟာ ဒီမှာမရှိပါ။', @@ -346,7 +347,9 @@ export const myTranslations: DefaultTranslationsObject = { upcomingEvents: 'လာမည့် အစီအစဉ်များ', updatedAt: 'ပြင်ဆင်ခဲ့သည့်အချိန်', updatedCountSuccessfully: '{{count}} {{label}} ကို အောင်မြင်စွာ အပ်ဒိတ်လုပ်ခဲ့သည်။', + updatedLabelSuccessfully: 'Berjaya mengemas kini {{label}}.', updatedSuccessfully: 'အပ်ဒိတ်လုပ်ပြီးပါပြီ။', + updateForEveryone: 'အားလုံးအတွက် အပြောင်းအလဲ', updating: 'ပြင်ဆင်ရန်', uploading: 'တင်ပေးနေသည်', uploadingBulk: 'တင်နေသည် {{current}} ခု အမှတ်ဖြစ်သည် {{total}} ခုစုစုပေါင်းဖြင့်', diff --git a/packages/translations/src/languages/nb.ts b/packages/translations/src/languages/nb.ts index b37990f5e3..6a2e923c10 100644 --- a/packages/translations/src/languages/nb.ts +++ b/packages/translations/src/languages/nb.ts @@ -315,6 +315,7 @@ export const nbTranslations: DefaultTranslationsObject = { selectAll: 'Velg alle {{count}} {{label}}', selectAllRows: 'Velg alle rader', selectedCount: '{{count}} {{label}} valgt', + selectLabel: 'Velg {{label}}', selectValue: 'Velg en verdi', showAllLabel: 'Vis alle {{label}}', sorryNotFound: 'Beklager, det er ingenting som samsvarer med forespørselen din.', @@ -342,7 +343,9 @@ export const nbTranslations: DefaultTranslationsObject = { upcomingEvents: 'Kommende hendelser', updatedAt: 'Oppdatert', updatedCountSuccessfully: 'Oppdaterte {{count}} {{label}} vellykket.', + updatedLabelSuccessfully: 'Oppdatert {{label}} vellykket.', updatedSuccessfully: 'Oppdatert.', + updateForEveryone: 'Oppdatering for alle', updating: 'Oppdatering', uploading: 'Opplasting', uploadingBulk: 'Laster opp {{current}} av {{total}}', diff --git a/packages/translations/src/languages/nl.ts b/packages/translations/src/languages/nl.ts index e388533959..025c3ad040 100644 --- a/packages/translations/src/languages/nl.ts +++ b/packages/translations/src/languages/nl.ts @@ -318,6 +318,7 @@ export const nlTranslations: DefaultTranslationsObject = { selectAll: 'Alles selecteren {{count}} {{label}}', selectAllRows: 'Selecteer alle rijen', selectedCount: '{{count}} {{label}} geselecteerd', + selectLabel: 'Selecteer {{label}}', selectValue: 'Selecteer een waarde', showAllLabel: 'Toon alle {{label}}', sorryNotFound: 'Sorry, er is niets dat overeen komt met uw verzoek.', @@ -345,7 +346,9 @@ export const nlTranslations: DefaultTranslationsObject = { upcomingEvents: 'Aankomende Evenementen', updatedAt: 'Aangepast op', updatedCountSuccessfully: '{{count}} {{label}} succesvol bijgewerkt.', + updatedLabelSuccessfully: 'Met succes {{label}} bijgewerkt.', updatedSuccessfully: 'Succesvol aangepast.', + updateForEveryone: 'Update voor iedereen', updating: 'Bijwerken', uploading: 'Uploaden', uploadingBulk: 'Bezig met uploaden {{current}} van {{total}}', diff --git a/packages/translations/src/languages/pl.ts b/packages/translations/src/languages/pl.ts index 73dbb670e8..a67690df69 100644 --- a/packages/translations/src/languages/pl.ts +++ b/packages/translations/src/languages/pl.ts @@ -314,6 +314,7 @@ export const plTranslations: DefaultTranslationsObject = { selectAll: 'Wybierz wszystkie {{count}} {{label}}', selectAllRows: 'Wybierz wszystkie wiersze', selectedCount: 'Wybrano {{count}} {{label}}', + selectLabel: 'Wybierz {{label}}', selectValue: 'Wybierz wartość', showAllLabel: 'Pokaż wszystkie {{label}}', sorryNotFound: 'Przepraszamy — nie ma nic, co odpowiadałoby twojemu zapytaniu.', @@ -341,7 +342,9 @@ export const plTranslations: DefaultTranslationsObject = { upcomingEvents: 'Nadchodzące Wydarzenia', updatedAt: 'Data edycji', updatedCountSuccessfully: 'Pomyślnie zaktualizowano {{count}} {{label}}.', + updatedLabelSuccessfully: 'Pomyślnie zaktualizowano {{label}}.', updatedSuccessfully: 'Aktualizacja zakończona sukcesem.', + updateForEveryone: 'Aktualizacja dla wszystkich', updating: 'Aktualizacja', uploading: 'Przesyłanie', uploadingBulk: 'Przesyłanie {{current}} z {{total}}', diff --git a/packages/translations/src/languages/pt.ts b/packages/translations/src/languages/pt.ts index e7cbd2845d..48b383a954 100644 --- a/packages/translations/src/languages/pt.ts +++ b/packages/translations/src/languages/pt.ts @@ -315,6 +315,7 @@ export const ptTranslations: DefaultTranslationsObject = { selectAll: 'Selecione tudo {{count}} {{label}}', selectAllRows: 'Selecione todas as linhas', selectedCount: '{{count}} {{label}} selecionado', + selectLabel: 'Selecione {{label}}', selectValue: 'Selecione um valor', showAllLabel: 'Mostre todos {{label}}', sorryNotFound: 'Desculpe—não há nada que corresponda à sua requisição.', @@ -342,7 +343,9 @@ export const ptTranslations: DefaultTranslationsObject = { upcomingEvents: 'Próximos Eventos', updatedAt: 'Atualizado Em', updatedCountSuccessfully: 'Atualizado {{count}} {{label}} com sucesso.', + updatedLabelSuccessfully: '{{label}} atualizado com sucesso.', updatedSuccessfully: 'Atualizado com sucesso.', + updateForEveryone: 'Atualização para todos', updating: 'Atualizando', uploading: 'Fazendo upload', uploadingBulk: 'Carregando {{current}} de {{total}}', diff --git a/packages/translations/src/languages/ro.ts b/packages/translations/src/languages/ro.ts index ef8514a486..865f227a8e 100644 --- a/packages/translations/src/languages/ro.ts +++ b/packages/translations/src/languages/ro.ts @@ -318,6 +318,7 @@ export const roTranslations: DefaultTranslationsObject = { selectAll: 'Selectați toate {{count}} {{label}}', selectAllRows: 'Selectează toate rândurile', selectedCount: '{{count}} {{label}} selectate', + selectLabel: 'Selectați {{label}}', selectValue: 'Selectați o valoare', showAllLabel: 'Afișează toate {{eticheta}}', sorryNotFound: 'Ne pare rău - nu există nimic care să corespundă cu cererea dvs.', @@ -345,7 +346,9 @@ export const roTranslations: DefaultTranslationsObject = { upcomingEvents: 'Evenimente viitoare', updatedAt: 'Actualizat la', updatedCountSuccessfully: 'Actualizate {{count}} {{label}} cu succes.', + updatedLabelSuccessfully: '{{label}} actualizată cu succes.', updatedSuccessfully: 'Actualizat cu succes.', + updateForEveryone: 'Actualizare pentru toată lumea', updating: 'Actualizare', uploading: 'Încărcare', uploadingBulk: 'Încărcare {{current}} din {{total}}', diff --git a/packages/translations/src/languages/rs.ts b/packages/translations/src/languages/rs.ts index ca880f71e2..d36fec3f46 100644 --- a/packages/translations/src/languages/rs.ts +++ b/packages/translations/src/languages/rs.ts @@ -314,6 +314,7 @@ export const rsTranslations: DefaultTranslationsObject = { selectAll: 'Одаберите све {{count}} {{label}}', selectAllRows: 'Одаберите све редове', selectedCount: '{{count}} {{label}} одабрано', + selectLabel: 'Izaberite {{label}}', selectValue: 'Одабери вредност', showAllLabel: 'Прикажи све {{label}}', sorryNotFound: 'Нажалост, не постоји ништа што одговара вашем захтеву.', @@ -341,7 +342,9 @@ export const rsTranslations: DefaultTranslationsObject = { upcomingEvents: 'Predstojeći događaji', updatedAt: 'Ажурирано у', updatedCountSuccessfully: 'Успешно ажурирано {{count}} {{label}}.', + updatedLabelSuccessfully: 'Uspešno ažurirano {{label}}.', updatedSuccessfully: 'Успешно ажурирано.', + updateForEveryone: 'Ažuriranje za sve', updating: 'Ажурирање', uploading: 'Пренос', uploadingBulk: 'Отпремање {{current}} од {{total}}', diff --git a/packages/translations/src/languages/rsLatin.ts b/packages/translations/src/languages/rsLatin.ts index be7f527bbc..64c87c304a 100644 --- a/packages/translations/src/languages/rsLatin.ts +++ b/packages/translations/src/languages/rsLatin.ts @@ -315,6 +315,7 @@ export const rsLatinTranslations: DefaultTranslationsObject = { selectAll: 'Odaberite sve {{count}} {{label}}', selectAllRows: 'Odaberite sve redove', selectedCount: '{{count}} {{label}} odabrano', + selectLabel: 'Izaberite {{label}}', selectValue: 'Odaberi vrednost', showAllLabel: 'Prikaži sve {{label}}', sorryNotFound: 'Nažalost, ne postoji ništa što odgovara vašem zahtevu.', @@ -342,7 +343,9 @@ export const rsLatinTranslations: DefaultTranslationsObject = { upcomingEvents: 'Predstojeći događaji', updatedAt: 'Ažurirano u', updatedCountSuccessfully: 'Uspešno ažurirano {{count}} {{label}}.', + updatedLabelSuccessfully: 'Uspešno ažurirano {{label}}.', updatedSuccessfully: 'Uspešno ažurirano.', + updateForEveryone: 'Ažuriranje za sve', updating: 'Ažuriranje', uploading: 'Prenos', uploadingBulk: 'Otpremanje {{current}} od {{total}}', diff --git a/packages/translations/src/languages/ru.ts b/packages/translations/src/languages/ru.ts index 1cae34446b..d031100085 100644 --- a/packages/translations/src/languages/ru.ts +++ b/packages/translations/src/languages/ru.ts @@ -316,6 +316,7 @@ export const ruTranslations: DefaultTranslationsObject = { selectAll: 'Выбрать все {{count}} {{label}}', selectAllRows: 'Выбрать все строки', selectedCount: '{{count}} {{label}} выбрано', + selectLabel: 'Выберите {{label}}', selectValue: 'Выбрать значение', showAllLabel: 'Показать все {{label}}', sorryNotFound: 'К сожалению, ничего подходящего под ваш запрос нет.', @@ -345,7 +346,9 @@ export const ruTranslations: DefaultTranslationsObject = { upcomingEvents: 'Предстоящие события', updatedAt: 'Дата правки', updatedCountSuccessfully: 'Обновлено {{count}} {{label}} успешно.', + updatedLabelSuccessfully: 'Успешно обновлено {{label}}.', updatedSuccessfully: 'Успешно Обновлено.', + updateForEveryone: 'Обновление для всех', updating: 'Обновление', uploading: 'Загрузка', uploadingBulk: 'Загрузка {{current}} из {{total}}', diff --git a/packages/translations/src/languages/sk.ts b/packages/translations/src/languages/sk.ts index 067c08607e..ed6cee95fb 100644 --- a/packages/translations/src/languages/sk.ts +++ b/packages/translations/src/languages/sk.ts @@ -315,6 +315,7 @@ export const skTranslations: DefaultTranslationsObject = { selectAll: 'Vybrať všetko {{count}} {{label}}', selectAllRows: 'Vybrať všetky riadky', selectedCount: 'Vybrané {{count}} {{label}}', + selectLabel: 'Vyberte {{label}}', selectValue: 'Vybrať hodnotu', showAllLabel: 'Zobraziť všetky {{label}}', sorryNotFound: 'Je nám ľúto, ale neexistuje nič, čo by zodpovedalo vášmu požiadavku.', @@ -342,7 +343,9 @@ export const skTranslations: DefaultTranslationsObject = { upcomingEvents: 'Nadchádzajúce udalosti', updatedAt: 'Aktualizované v', updatedCountSuccessfully: 'Úspešne aktualizované {{count}} {{label}}.', + updatedLabelSuccessfully: 'Úspešne aktualizované {{label}}.', updatedSuccessfully: 'Úspešne aktualizované.', + updateForEveryone: 'Aktualizácia pre všetkých', updating: 'Aktualizácia', uploading: 'Nahrávanie', uploadingBulk: 'Nahrávanie {{current}} z {{total}}', diff --git a/packages/translations/src/languages/sl.ts b/packages/translations/src/languages/sl.ts index 81551dcd1e..cc716047b4 100644 --- a/packages/translations/src/languages/sl.ts +++ b/packages/translations/src/languages/sl.ts @@ -313,6 +313,7 @@ export const slTranslations: DefaultTranslationsObject = { selectAll: 'Izberi vse {{count}} {{label}}', selectAllRows: 'Izberi vse vrstice', selectedCount: '{{count}} {{label}} izbranih', + selectLabel: 'Izberite {{label}}', selectValue: 'Izberi vrednost', showAllLabel: 'Pokaži vse {{label}}', sorryNotFound: 'Oprostite - ničesar ni mogoče najti, kar bi ustrezalo vaši zahtevi.', @@ -340,7 +341,9 @@ export const slTranslations: DefaultTranslationsObject = { upcomingEvents: 'Prihajajoči dogodki', updatedAt: 'Posodobljeno', updatedCountSuccessfully: 'Uspešno posodobljeno {{count}} {{label}}.', + updatedLabelSuccessfully: '{{label}} uspešno posodobljen.', updatedSuccessfully: 'Uspešno posodobljeno.', + updateForEveryone: 'Posodobitev za vse', updating: 'Posodabljanje', uploading: 'Nalaganje', uploadingBulk: 'Nalaganje {{current}} od {{total}}', diff --git a/packages/translations/src/languages/sv.ts b/packages/translations/src/languages/sv.ts index 701e9e5803..009892e999 100644 --- a/packages/translations/src/languages/sv.ts +++ b/packages/translations/src/languages/sv.ts @@ -315,6 +315,7 @@ export const svTranslations: DefaultTranslationsObject = { selectAll: 'Välj alla {{count}} {{label}}', selectAllRows: 'Välj alla rader', selectedCount: '{{count}} {{label}} har valts', + selectLabel: 'Välj {{label}}', selectValue: 'Välj ett värde', showAllLabel: 'Visa alla {{label}}', sorryNotFound: 'Tyvärr–det finns inget som motsvarar din begäran.', @@ -342,7 +343,9 @@ export const svTranslations: DefaultTranslationsObject = { upcomingEvents: 'Kommande händelser', updatedAt: 'Uppdaterat', updatedCountSuccessfully: 'Uppdaterade {{count}} {{label}}', + updatedLabelSuccessfully: 'Uppdaterade {{label}} framgångsrikt.', updatedSuccessfully: 'Uppdaterades', + updateForEveryone: 'Uppdatering för alla', updating: 'Uppdaterar...', uploading: 'Laddar upp...', uploadingBulk: 'Laddar upp {{current}} av {{total}}', diff --git a/packages/translations/src/languages/th.ts b/packages/translations/src/languages/th.ts index 05586481b4..70173f55bb 100644 --- a/packages/translations/src/languages/th.ts +++ b/packages/translations/src/languages/th.ts @@ -310,6 +310,7 @@ export const thTranslations: DefaultTranslationsObject = { selectAll: 'เลือกทั้งหมด {{count}} {{label}}', selectAllRows: 'เลือกทุกแถว', selectedCount: 'เลือก {{count}} {{label}} แล้ว', + selectLabel: 'เลือก {{label}}', selectValue: 'เลือกค่า', showAllLabel: 'แสดง {{label}} ทั้งหมด', sorryNotFound: 'ขออภัย ไม่สามารถทำตามคำขอของคุณได้', @@ -337,7 +338,9 @@ export const thTranslations: DefaultTranslationsObject = { upcomingEvents: 'กิจกรรมที่จะถึง', updatedAt: 'แก้ไขเมื่อ', updatedCountSuccessfully: 'อัปเดต {{count}} {{label}} เรียบร้อยแล้ว', + updatedLabelSuccessfully: 'อัปเดต {{label}} สำเร็จแล้ว', updatedSuccessfully: 'แก้ไขสำเร็จ', + updateForEveryone: 'อัปเดตสำหรับทุกคน', updating: 'กำลังอัปเดต', uploading: 'กำลังอัปโหลด', uploadingBulk: 'อัปโหลด {{current}} จาก {{total}}', diff --git a/packages/translations/src/languages/tr.ts b/packages/translations/src/languages/tr.ts index 1e2f95fbed..56a9189799 100644 --- a/packages/translations/src/languages/tr.ts +++ b/packages/translations/src/languages/tr.ts @@ -318,6 +318,7 @@ export const trTranslations: DefaultTranslationsObject = { selectAll: "Tüm {{count}} {{label}}'ı seçin", selectAllRows: 'Tüm satırları seçin', selectedCount: '{{count}} {{label}} seçildi', + selectLabel: '{{label}} seçin', selectValue: 'Bir değer seçin', showAllLabel: 'Tüm {{label}} göster', sorryNotFound: 'Üzgünüz, isteğinizle eşleşen bir sonuç bulunamadı.', @@ -346,7 +347,9 @@ export const trTranslations: DefaultTranslationsObject = { upcomingEvents: 'Yaklaşan Etkinlikler', updatedAt: 'Güncellenme tarihi', updatedCountSuccessfully: '{{count}} {{label}} başarıyla güncellendi.', + updatedLabelSuccessfully: '{{label}} başarıyla güncellendi.', updatedSuccessfully: 'Başarıyla güncellendi.', + updateForEveryone: 'Herkes için güncelleme', updating: 'Güncelleniyor', uploading: 'Yükleniyor', uploadingBulk: "{{total}}'den {{current}} yükleniyor", diff --git a/packages/translations/src/languages/uk.ts b/packages/translations/src/languages/uk.ts index cedd1b40d4..57690d2f05 100644 --- a/packages/translations/src/languages/uk.ts +++ b/packages/translations/src/languages/uk.ts @@ -313,6 +313,7 @@ export const ukTranslations: DefaultTranslationsObject = { selectAll: 'Вибрати всі {{count}} {{label}}', selectAllRows: 'Обрати всі рядки', selectedCount: 'Обрано {{count}} {{label}}', + selectLabel: 'Виберіть {{label}}', selectValue: 'Обрати значення', showAllLabel: 'Показати всі {{label}}', sorryNotFound: 'Вибачте, немає нічого, що відповідало б Вашому запиту.', @@ -340,7 +341,9 @@ export const ukTranslations: DefaultTranslationsObject = { upcomingEvents: 'Майбутні події', updatedAt: 'Змінено', updatedCountSuccessfully: 'Успішно оновлено {{count}} {{label}}.', + updatedLabelSuccessfully: 'Успішно оновлено {{label}}.', updatedSuccessfully: 'Успішно відредаговано.', + updateForEveryone: 'Оновлення для всіх', updating: 'оновлення', uploading: 'завантаження', uploadingBulk: 'Завантаження {{current}} з {{total}}', diff --git a/packages/translations/src/languages/vi.ts b/packages/translations/src/languages/vi.ts index 71d63e61d0..10def88682 100644 --- a/packages/translations/src/languages/vi.ts +++ b/packages/translations/src/languages/vi.ts @@ -313,6 +313,7 @@ export const viTranslations: DefaultTranslationsObject = { selectAll: 'Chọn tất cả {{count}} {{label}}', selectAllRows: 'Chọn tất cả các hàng', selectedCount: 'Đã chọn {{count}} {{label}}', + selectLabel: 'Chọn {{label}}', selectValue: 'Chọn một giá trị', showAllLabel: 'Hiển thị tất cả {{label}}', sorryNotFound: 'Xin lỗi, không có kết quả nào tương ứng với request của bạn.', @@ -340,7 +341,9 @@ export const viTranslations: DefaultTranslationsObject = { upcomingEvents: 'Sự kiện sắp tới', updatedAt: 'Ngày cập nhật', updatedCountSuccessfully: 'Đã cập nhật thành công {{count}} {{label}}.', + updatedLabelSuccessfully: 'Đã cập nhật {{label}} thành công.', updatedSuccessfully: 'Cập nhật thành công.', + updateForEveryone: 'Cập nhật cho mọi người', updating: 'Đang cập nhật', uploading: 'Đang tải lên', uploadingBulk: 'Đang tải lên {{current}} trong tổng số {{total}}', diff --git a/packages/translations/src/languages/zh.ts b/packages/translations/src/languages/zh.ts index 4d0bccec28..5a460b2230 100644 --- a/packages/translations/src/languages/zh.ts +++ b/packages/translations/src/languages/zh.ts @@ -303,6 +303,7 @@ export const zhTranslations: DefaultTranslationsObject = { selectAll: '选择所有 {{count}} {{label}}', selectAllRows: '选择所有行', selectedCount: '已选择 {{count}} {{label}}', + selectLabel: '选择{{label}}', selectValue: '选择一个值', showAllLabel: '显示所有{{label}}', sorryNotFound: '对不起,没有与您的请求相对应的东西。', @@ -330,7 +331,9 @@ export const zhTranslations: DefaultTranslationsObject = { upcomingEvents: '即将到来的活动', updatedAt: '更新于', updatedCountSuccessfully: '已成功更新 {{count}} {{label}}。', + updatedLabelSuccessfully: '成功更新了 {{label}}。', updatedSuccessfully: '更新成功。', + updateForEveryone: '给大家的更新', updating: '更新中', uploading: '上传中', uploadingBulk: '正在上传{{current}},共{{total}}', diff --git a/packages/translations/src/languages/zhTw.ts b/packages/translations/src/languages/zhTw.ts index be386f234d..2dfb06f2ad 100644 --- a/packages/translations/src/languages/zhTw.ts +++ b/packages/translations/src/languages/zhTw.ts @@ -303,6 +303,7 @@ export const zhTwTranslations: DefaultTranslationsObject = { selectAll: '選擇所有 {{count}} 個 {{label}}', selectAllRows: '選擇所有行', selectedCount: '已選擇 {{count}} 個 {{label}}', + selectLabel: '選擇 {{label}}', selectValue: '選擇一個值', showAllLabel: '顯示所有{{label}}', sorryNotFound: '對不起,沒有找到您請求的東西。', @@ -330,7 +331,9 @@ export const zhTwTranslations: DefaultTranslationsObject = { upcomingEvents: '即將來臨的活動', updatedAt: '更新於', updatedCountSuccessfully: '已成功更新 {{count}} 個 {{label}}。', + updatedLabelSuccessfully: '成功更新了{{label}}。', updatedSuccessfully: '更新成功。', + updateForEveryone: '給所有人的更新', updating: '更新中', uploading: '上傳中', uploadingBulk: '正在上傳 {{current}} / {{total}}', diff --git a/packages/ui/src/elements/ColumnSelector/index.scss b/packages/ui/src/elements/ColumnSelector/index.scss index a194d629e5..d310aa1b8d 100644 --- a/packages/ui/src/elements/ColumnSelector/index.scss +++ b/packages/ui/src/elements/ColumnSelector/index.scss @@ -5,11 +5,10 @@ display: flex; flex-wrap: wrap; background: var(--theme-elevation-50); - padding: base(1) base(1) base(0.5); + padding: var(--base); + gap: calc(var(--base) / 2); &__column { - margin-right: base(0.5); - margin-bottom: base(0.5); background-color: transparent; box-shadow: 0 0 0 1px var(--theme-elevation-150); diff --git a/packages/ui/src/elements/ColumnSelector/index.tsx b/packages/ui/src/elements/ColumnSelector/index.tsx index 643e12eebd..e03cf154cd 100644 --- a/packages/ui/src/elements/ColumnSelector/index.tsx +++ b/packages/ui/src/elements/ColumnSelector/index.tsx @@ -8,9 +8,9 @@ import { FieldLabel } from '../../fields/FieldLabel/index.js' import { PlusIcon } from '../../icons/Plus/index.js' import { XIcon } from '../../icons/X/index.js' import { useEditDepth } from '../../providers/EditDepth/index.js' +import { useTableColumns } from '../../providers/TableColumns/index.js' import { DraggableSortable } from '../DraggableSortable/index.js' import { Pill } from '../Pill/index.js' -import { useTableColumns } from '../TableColumns/index.js' import './index.scss' const baseClass = 'column-selector' diff --git a/packages/ui/src/elements/DeleteDocument/index.tsx b/packages/ui/src/elements/DeleteDocument/index.tsx index 59e5d24fdf..a53f4e9664 100644 --- a/packages/ui/src/elements/DeleteDocument/index.tsx +++ b/packages/ui/src/elements/DeleteDocument/index.tsx @@ -60,8 +60,6 @@ export const DeleteDocument: React.FC = (props) => { const { startRouteTransition } = useRouteTransition() const { openModal } = useModal() - const titleToRender = titleFromProps || title || id - const modalSlug = `delete-${id}` const addDefaultError = useCallback(() => { @@ -163,7 +161,7 @@ export const DeleteDocument: React.FC = (props) => { t={t} variables={{ label: getTranslation(singularLabel, i18n), - title: titleToRender, + title: titleFromProps || title || id, }} /> } diff --git a/packages/ui/src/elements/DeleteMany/index.tsx b/packages/ui/src/elements/DeleteMany/index.tsx index a7fc4451dc..fc68d64877 100644 --- a/packages/ui/src/elements/DeleteMany/index.tsx +++ b/packages/ui/src/elements/DeleteMany/index.tsx @@ -4,6 +4,7 @@ import type { ClientCollectionConfig } from 'payload' import { useModal } from '@faceless-ui/modal' import { getTranslation } from '@payloadcms/translations' import { useRouter, useSearchParams } from 'next/navigation.js' +import { mergeListSearchAndWhere } from 'payload/shared' import * as qs from 'qs-esm' import React, { useCallback } from 'react' import { toast } from 'sonner' @@ -14,7 +15,6 @@ import { useRouteCache } from '../../providers/RouteCache/index.js' import { SelectAllStatus, useSelection } from '../../providers/Selection/index.js' import { useTranslation } from '../../providers/Translation/index.js' import { requests } from '../../utilities/api.js' -import { mergeListSearchAndWhere } from '../../utilities/mergeListSearchAndWhere.js' import { ConfirmationModal } from '../ConfirmationModal/index.js' import './index.scss' diff --git a/packages/ui/src/elements/DocumentDrawer/DrawerContent.tsx b/packages/ui/src/elements/DocumentDrawer/DrawerContent.tsx index 0795660eef..e2cf8f33a7 100644 --- a/packages/ui/src/elements/DocumentDrawer/DrawerContent.tsx +++ b/packages/ui/src/elements/DocumentDrawer/DrawerContent.tsx @@ -22,11 +22,11 @@ export const DocumentDrawerContent: React.FC = ({ drawerSlug, Header, initialData, - initialState, onDelete: onDeleteFromProps, onDuplicate: onDuplicateFromProps, onSave: onSaveFromProps, overrideEntityVisibility = true, + redirectAfterCreate, redirectAfterDelete, redirectAfterDuplicate, }) => { @@ -62,6 +62,7 @@ export const DocumentDrawerContent: React.FC = ({ initialData, locale, overrideEntityVisibility, + redirectAfterCreate, redirectAfterDelete: redirectAfterDelete !== undefined ? redirectAfterDelete : false, redirectAfterDuplicate: redirectAfterDuplicate !== undefined ? redirectAfterDuplicate : false, diff --git a/packages/ui/src/elements/DocumentDrawer/types.ts b/packages/ui/src/elements/DocumentDrawer/types.ts index 2e94640cf8..dee572ab66 100644 --- a/packages/ui/src/elements/DocumentDrawer/types.ts +++ b/packages/ui/src/elements/DocumentDrawer/types.ts @@ -12,8 +12,12 @@ export type DocumentDrawerProps = { readonly drawerSlug?: string readonly id?: null | number | string readonly initialData?: Data + /** + * @deprecated + */ readonly initialState?: FormState readonly overrideEntityVisibility?: boolean + readonly redirectAfterCreate?: boolean readonly redirectAfterDelete?: boolean readonly redirectAfterDuplicate?: boolean } & Pick & diff --git a/packages/ui/src/elements/EditMany/DrawerContent.tsx b/packages/ui/src/elements/EditMany/DrawerContent.tsx index 688ddd7ae8..7f7e3dc00f 100644 --- a/packages/ui/src/elements/EditMany/DrawerContent.tsx +++ b/packages/ui/src/elements/EditMany/DrawerContent.tsx @@ -5,7 +5,7 @@ import type { SelectType } from 'payload' import { useModal } from '@faceless-ui/modal' import { getTranslation } from '@payloadcms/translations' import { useRouter, useSearchParams } from 'next/navigation.js' -import { unflatten } from 'payload/shared' +import { mergeListSearchAndWhere, unflatten } from 'payload/shared' import * as qs from 'qs-esm' import React, { useCallback, useEffect, useMemo, useState } from 'react' @@ -27,7 +27,6 @@ import { SelectAllStatus, useSelection } from '../../providers/Selection/index.j import { useServerFunctions } from '../../providers/ServerFunctions/index.js' import { useTranslation } from '../../providers/Translation/index.js' import { abortAndIgnore, handleAbortRef } from '../../utilities/abortAndIgnore.js' -import { mergeListSearchAndWhere } from '../../utilities/mergeListSearchAndWhere.js' import { parseSearchParams } from '../../utilities/parseSearchParams.js' import { FieldSelect } from '../FieldSelect/index.js' import { baseClass, type EditManyProps } from './index.js' diff --git a/packages/ui/src/elements/ListControls/ActiveQueryPreset/index.scss b/packages/ui/src/elements/ListControls/ActiveQueryPreset/index.scss new file mode 100644 index 0000000000..e73be0f353 --- /dev/null +++ b/packages/ui/src/elements/ListControls/ActiveQueryPreset/index.scss @@ -0,0 +1,21 @@ +@import '../../../scss/styles'; + +@layer payload-default { + .active-query-preset { + &.pill { + max-width: 150px; + overflow: hidden; + } + + .pill__label { + display: flex; + align-items: center; + } + + &__label-text { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + } + } +} diff --git a/packages/ui/src/elements/ListControls/ActiveQueryPreset/index.tsx b/packages/ui/src/elements/ListControls/ActiveQueryPreset/index.tsx new file mode 100644 index 0000000000..4e1be0e462 --- /dev/null +++ b/packages/ui/src/elements/ListControls/ActiveQueryPreset/index.tsx @@ -0,0 +1,65 @@ +'use client' +import type { QueryPreset } from 'payload' + +import { getTranslation } from '@payloadcms/translations' + +import { PeopleIcon } from '../../../icons/People/index.js' +import { XIcon } from '../../../icons/X/index.js' +import { useConfig } from '../../../providers/Config/index.js' +import { useTranslation } from '../../../providers/Translation/index.js' +import { Pill } from '../../Pill/index.js' +import './index.scss' + +const baseClass = 'active-query-preset' + +export function ActiveQueryPreset({ + activePreset, + openPresetListDrawer, + resetPreset, +}: { + activePreset: QueryPreset + openPresetListDrawer: () => void + resetPreset: () => Promise +}) { + const { i18n, t } = useTranslation() + const { getEntityConfig } = useConfig() + + const presetsConfig = getEntityConfig({ + collectionSlug: 'payload-query-presets', + }) + + return ( + { + openPresetListDrawer() + }} + pillStyle={activePreset ? 'always-white' : 'light'} + > + {activePreset?.isShared && } +
+ {activePreset?.title || + t('general:selectLabel', { label: getTranslation(presetsConfig.labels.singular, i18n) })} +
+ {activePreset ? ( +
{ + e.stopPropagation() + await resetPreset() + }} + onKeyDown={async (e) => { + e.stopPropagation() + await resetPreset() + }} + role="button" + tabIndex={0} + > + +
+ ) : null} +
+ ) +} diff --git a/packages/ui/src/elements/ListControls/index.scss b/packages/ui/src/elements/ListControls/index.scss index a369793ff8..0f3740a962 100644 --- a/packages/ui/src/elements/ListControls/index.scss +++ b/packages/ui/src/elements/ListControls/index.scss @@ -24,18 +24,14 @@ border-radius: 0; } + &__modified { + color: var(--theme-elevation-500); + } + &__buttons-wrap { display: flex; align-items: center; - gap: base(0.2); - - .pill { - background-color: var(--theme-elevation-150); - - &:hover { - background-color: var(--theme-elevation-100); - } - } + gap: 4px; } .column-selector, diff --git a/packages/ui/src/elements/ListControls/index.tsx b/packages/ui/src/elements/ListControls/index.tsx index 2deb787076..40dbed24e2 100644 --- a/packages/ui/src/elements/ListControls/index.tsx +++ b/packages/ui/src/elements/ListControls/index.tsx @@ -1,9 +1,11 @@ 'use client' -import type { ClientCollectionConfig, ResolvedFilterOptions, Where } from 'payload' import { useWindowInfo } from '@faceless-ui/window-info' import { getTranslation } from '@payloadcms/translations' -import React, { useEffect, useRef, useState } from 'react' +import { validateWhereQuery } from 'payload/shared' +import React, { Fragment, useEffect, useRef, useState } from 'react' + +import type { ListControlsProps } from './types.js' import { Popup, PopupList } from '../../elements/Popup/index.js' import { useUseTitleField } from '../../hooks/useUseAsTitle.js' @@ -17,36 +19,13 @@ import { ColumnSelector } from '../ColumnSelector/index.js' import { Pill } from '../Pill/index.js' import { SearchFilter } from '../SearchFilter/index.js' import { WhereBuilder } from '../WhereBuilder/index.js' -import validateWhereQuery from '../WhereBuilder/validateWhereQuery.js' +import { ActiveQueryPreset } from './ActiveQueryPreset/index.js' import { getTextFieldsToBeSearched } from './getTextFieldsToBeSearched.js' +import { useQueryPresets } from './useQueryPresets.js' import './index.scss' const baseClass = 'list-controls' -export type ListControlsProps = { - readonly beforeActions?: React.ReactNode[] - readonly collectionConfig: ClientCollectionConfig - readonly collectionSlug: string - /** - * @deprecated - * These are now handled by the `ListSelection` component - */ - readonly disableBulkDelete?: boolean - /** - * @deprecated - * These are now handled by the `ListSelection` component - */ - readonly disableBulkEdit?: boolean - readonly enableColumns?: boolean - readonly enableSort?: boolean - readonly handleSearchChange?: (search: string) => void - readonly handleSortChange?: (sort: string) => void - readonly handleWhereChange?: (where: Where) => void - readonly listMenuItems?: React.ReactNode[] - readonly renderedFilters?: Map - readonly resolvedFilterOptions?: Map -} - /** * The ListControls component is used to render the controls (search, filter, where) * for a collection's list view. You can find those directly above the table which lists @@ -57,15 +36,36 @@ export const ListControls: React.FC = (props) => { beforeActions, collectionConfig, collectionSlug, + disableQueryPresets, enableColumns = true, enableSort = false, - listMenuItems, + listMenuItems: listMenuItemsFromProps, + queryPreset: activePreset, + queryPresetPermissions, renderedFilters, resolvedFilterOptions, } = props + const { handleSearchChange, query } = useListQuery() + + const { + CreateNewPresetDrawer, + DeletePresetModal, + EditPresetDrawer, + hasModifiedPreset, + openPresetListDrawer, + PresetListDrawer, + queryPresetMenuItems, + resetPreset, + } = useQueryPresets({ + activePreset, + collectionSlug, + queryPresetPermissions, + }) + const titleField = useUseTitleField(collectionConfig) const { i18n, t } = useTranslation() + const { breakpoints: { s: smallBreak }, } = useWindowInfo() @@ -135,109 +135,131 @@ export const ListControls: React.FC = (props) => { } }, [t, listSearchableFields, i18n, searchLabel]) + let listMenuItems: React.ReactNode[] = listMenuItemsFromProps + + if ( + collectionConfig?.enableQueryPresets && + !disableQueryPresets && + queryPresetMenuItems?.length > 0 + ) { + // Cannot push or unshift into `listMenuItemsFromProps` as it will mutate the original array + listMenuItems = [ + ...queryPresetMenuItems, + listMenuItemsFromProps?.length > 0 ? : null, + ...(listMenuItemsFromProps || []), + ] + } + return ( -
-
- - { - return void handleSearchChange(search) - }} - // @ts-expect-error @todo: fix types - initialParams={query} - key={collectionSlug} - label={searchLabelTranslated.current} - /> -
-
- {!smallBreak && {beforeActions && beforeActions}} - {enableColumns && ( + +
+
+ + { + return void handleSearchChange(search) + }} + // @ts-expect-error @todo: fix types + initialParams={query} + key={collectionSlug} + label={searchLabelTranslated.current} + /> + {activePreset && hasModifiedPreset ? ( +
Modified
+ ) : null} +
+
+ {!smallBreak && {beforeActions && beforeActions}} + {enableColumns && ( + } + onClick={() => + setVisibleDrawer(visibleDrawer !== 'columns' ? 'columns' : undefined) + } + pillStyle="light" + > + {t('general:columns')} + + )} } - onClick={() => - setVisibleDrawer(visibleDrawer !== 'columns' ? 'columns' : undefined) - } + aria-controls={`${baseClass}-where`} + aria-expanded={visibleDrawer === 'where'} + className={`${baseClass}__toggle-where`} + icon={} + onClick={() => setVisibleDrawer(visibleDrawer !== 'where' ? 'where' : undefined)} pillStyle="light" > - {t('general:columns')} + {t('general:filters')} - )} - } - onClick={() => setVisibleDrawer(visibleDrawer !== 'where' ? 'where' : undefined)} - pillStyle="light" - > - {t('general:filters')} - - {enableSort && ( - } - onClick={() => setVisibleDrawer(visibleDrawer !== 'sort' ? 'sort' : undefined)} - pillStyle="light" - > - {t('general:sort')} - - )} - {listMenuItems && ( - } - className={`${baseClass}__popup`} - horizontalAlign="right" - size="large" - verticalAlign="bottom" - > - {listMenuItems.map((item) => item)} - - )} + {enableSort && ( + } + onClick={() => setVisibleDrawer(visibleDrawer !== 'sort' ? 'sort' : undefined)} + pillStyle="light" + > + {t('general:sort')} + + )} + {!disableQueryPresets && ( + + )} + {listMenuItems && Array.isArray(listMenuItems) && listMenuItems.length > 0 && ( + } + className={`${baseClass}__popup`} + horizontalAlign="right" + id="list-menu" + size="large" + verticalAlign="bottom" + > + + {listMenuItems.map((item, i) => ( + {item} + ))} + + + )} +
+ {enableColumns && ( + + + + )} + + +
- {enableColumns && ( - - - - )} - - - - {enableSort && ( - -

Sort Complex

- {/* */} -
- )} -
+ {PresetListDrawer} + {EditPresetDrawer} + {CreateNewPresetDrawer} + {DeletePresetModal} + ) } diff --git a/packages/ui/src/elements/ListControls/types.ts b/packages/ui/src/elements/ListControls/types.ts new file mode 100644 index 0000000000..a3ae40fca9 --- /dev/null +++ b/packages/ui/src/elements/ListControls/types.ts @@ -0,0 +1,34 @@ +import type { + ClientCollectionConfig, + QueryPreset, + ResolvedFilterOptions, + SanitizedCollectionPermission, + Where, +} from 'payload' + +export type ListControlsProps = { + readonly beforeActions?: React.ReactNode[] + readonly collectionConfig: ClientCollectionConfig + readonly collectionSlug: string + /** + * @deprecated + * These are now handled by the `ListSelection` component + */ + readonly disableBulkDelete?: boolean + /** + * @deprecated + * These are now handled by the `ListSelection` component + */ + readonly disableBulkEdit?: boolean + readonly disableQueryPresets?: boolean + readonly enableColumns?: boolean + readonly enableSort?: boolean + readonly handleSearchChange?: (search: string) => void + readonly handleSortChange?: (sort: string) => void + readonly handleWhereChange?: (where: Where) => void + readonly listMenuItems?: React.ReactNode[] + readonly queryPreset?: QueryPreset + readonly queryPresetPermissions?: SanitizedCollectionPermission + readonly renderedFilters?: Map + readonly resolvedFilterOptions?: Map +} diff --git a/packages/ui/src/elements/ListControls/useQueryPresets.tsx b/packages/ui/src/elements/ListControls/useQueryPresets.tsx new file mode 100644 index 0000000000..cafc1d041d --- /dev/null +++ b/packages/ui/src/elements/ListControls/useQueryPresets.tsx @@ -0,0 +1,326 @@ +import type { CollectionSlug, QueryPreset, SanitizedCollectionPermission } from 'payload' + +import { useModal } from '@faceless-ui/modal' +import { getTranslation } from '@payloadcms/translations' +import { transformColumnsToPreferences, transformColumnsToSearchParams } from 'payload/shared' +import React, { Fragment, useCallback, useMemo } from 'react' +import { toast } from 'sonner' + +import { useConfig } from '../../providers/Config/index.js' +import { useListQuery } from '../../providers/ListQuery/context.js' +import { useTranslation } from '../../providers/Translation/index.js' +import { ConfirmationModal } from '../ConfirmationModal/index.js' +import { useDocumentDrawer } from '../DocumentDrawer/index.js' +import { useListDrawer } from '../ListDrawer/index.js' +import { PopupList } from '../Popup/index.js' +import { PopupListGroupLabel } from '../Popup/PopupGroupLabel/index.js' +import { Translation } from '../Translation/index.js' + +const confirmDeletePresetModalSlug = 'confirm-delete-preset' + +const queryPresetsSlug = 'payload-query-presets' + +export const useQueryPresets = ({ + activePreset, + collectionSlug, + queryPresetPermissions, +}: { + activePreset: QueryPreset + collectionSlug: CollectionSlug + queryPresetPermissions: SanitizedCollectionPermission +}): { + CreateNewPresetDrawer: React.ReactNode + DeletePresetModal: React.ReactNode + EditPresetDrawer: React.ReactNode + hasModifiedPreset: boolean + openPresetListDrawer: () => void + PresetListDrawer: React.ReactNode + queryPresetMenuItems: React.ReactNode[] + resetPreset: () => Promise +} => { + const { modified, query, refineListData, setModified: setQueryModified } = useListQuery() + + const { i18n, t } = useTranslation() + const { openModal } = useModal() + + const { + config: { + routes: { api: apiRoute }, + }, + getEntityConfig, + } = useConfig() + + const presetConfig = getEntityConfig({ collectionSlug: queryPresetsSlug }) + + const [PresetDocumentDrawer, , { openDrawer: openDocumentDrawer }] = useDocumentDrawer({ + id: activePreset?.id, + collectionSlug: queryPresetsSlug, + }) + + const [ + CreateNewPresetDrawer, + , + { closeDrawer: closeCreateNewDrawer, openDrawer: openCreateNewDrawer }, + ] = useDocumentDrawer({ + collectionSlug: queryPresetsSlug, + }) + + const [ListDrawer, , { closeDrawer: closeListDrawer, openDrawer: openListDrawer }] = + useListDrawer({ + collectionSlugs: [queryPresetsSlug], + }) + + const handlePresetChange = useCallback( + async (preset: QueryPreset) => { + await refineListData( + { + columns: preset.columns ? transformColumnsToSearchParams(preset.columns) : undefined, + preset: preset.id, + where: preset.where, + }, + false, + ) + }, + [refineListData], + ) + + const resetQueryPreset = useCallback(async () => { + await refineListData( + { + columns: undefined, + preset: undefined, + where: undefined, + }, + false, + ) + }, [refineListData]) + + const handleDeletePreset = useCallback(async () => { + try { + await fetch(`${apiRoute}/${queryPresetsSlug}/${activePreset.id}`, { + method: 'DELETE', + }).then(async (res) => { + try { + const json = await res.json() + + if (res.status < 400) { + toast.success( + t('general:titleDeleted', { + label: getTranslation(presetConfig?.labels?.singular, i18n), + title: activePreset.title, + }), + ) + + await resetQueryPreset() + } else { + if (json.errors) { + json.errors.forEach((error) => toast.error(error.message)) + } else { + toast.error(t('error:deletingTitle', { title: activePreset.title })) + } + } + } catch (_err) { + toast.error(t('error:deletingTitle', { title: activePreset.title })) + } + }) + } catch (_err) { + toast.error(t('error:deletingTitle', { title: activePreset.title })) + } + }, [apiRoute, activePreset?.id, activePreset?.title, t, presetConfig, i18n, resetQueryPreset]) + + const saveCurrentChanges = useCallback(async () => { + try { + await fetch(`${apiRoute}/payload-query-presets/${activePreset.id}`, { + body: JSON.stringify({ + columns: transformColumnsToPreferences(query.columns), + where: query.where, + }), + credentials: 'include', + headers: { + 'Content-Type': 'application/json', + }, + method: 'PATCH', + }).then(async (res) => { + try { + const json = await res.json() + + if (res.status < 400) { + toast.success( + t('general:updatedLabelSuccessfully', { + label: getTranslation(presetConfig?.labels?.singular, i18n), + }), + ) + + setQueryModified(false) + } else { + if (json.errors) { + json.errors.forEach((error) => toast.error(error.message)) + } else { + toast.error(t('error:unknown')) + } + } + } catch (_err) { + toast.error(t('error:unknown')) + } + }) + } catch (_err) { + toast.error(t('error:unknown')) + } + }, [ + apiRoute, + activePreset?.id, + query.columns, + query.where, + t, + presetConfig?.labels?.singular, + i18n, + setQueryModified, + ]) + + // Memoize so that components aren't re-rendered on query and column changes + const queryPresetMenuItems = useMemo(() => { + const menuItems: React.ReactNode[] = [ + , + ] + + if (activePreset && modified) { + menuItems.push( + { + await refineListData( + { + columns: transformColumnsToSearchParams(activePreset.columns), + where: activePreset.where, + }, + false, + ) + }} + > + {t('general:reset')} + , + ) + + if (queryPresetPermissions.update) { + menuItems.push( + { + await saveCurrentChanges() + }} + > + {activePreset.isShared ? t('general:updateForEveryone') : t('general:save')} + , + ) + } + } + + menuItems.push( + { + openCreateNewDrawer() + }} + > + {t('general:createNew')} + , + ) + + if (activePreset && queryPresetPermissions?.delete) { + menuItems.push( + + openModal(confirmDeletePresetModalSlug)}> + {t('general:delete')} + + { + openDocumentDrawer() + }} + > + {t('general:edit')} + + , + ) + } + + return menuItems + }, [ + activePreset, + queryPresetPermissions?.delete, + queryPresetPermissions?.update, + openCreateNewDrawer, + openDocumentDrawer, + openModal, + saveCurrentChanges, + t, + refineListData, + modified, + presetConfig?.labels?.plural, + i18n, + ]) + + return { + CreateNewPresetDrawer: ( + { + closeCreateNewDrawer() + await handlePresetChange(doc as QueryPreset) + }} + redirectAfterCreate={false} + /> + ), + DeletePresetModal: ( + {children}, + }} + i18nKey="general:aboutToDelete" + t={t} + variables={{ + label: presetConfig?.labels?.singular, + title: activePreset?.title, + }} + /> + } + confirmingLabel={t('general:deleting')} + heading={t('general:confirmDeletion')} + modalSlug={confirmDeletePresetModalSlug} + onConfirm={handleDeletePreset} + /> + ), + EditPresetDrawer: ( + { + // setSelectedPreset(undefined) + }} + onDuplicate={async ({ doc }) => { + await handlePresetChange(doc as QueryPreset) + }} + onSave={async ({ doc }) => { + await handlePresetChange(doc as QueryPreset) + }} + /> + ), + hasModifiedPreset: modified, + openPresetListDrawer: openListDrawer, + PresetListDrawer: ( + { + closeListDrawer() + await handlePresetChange(doc as QueryPreset) + }} + /> + ), + queryPresetMenuItems, + resetPreset: resetQueryPreset, + } +} diff --git a/packages/ui/src/elements/ListDrawer/DrawerContent.tsx b/packages/ui/src/elements/ListDrawer/DrawerContent.tsx index 3e74151707..27e6124a2e 100644 --- a/packages/ui/src/elements/ListDrawer/DrawerContent.tsx +++ b/packages/ui/src/elements/ListDrawer/DrawerContent.tsx @@ -2,6 +2,7 @@ import type { ListQuery } from 'payload' import { useModal } from '@faceless-ui/modal' +import { hoistQueryParamsToAnd } from 'payload/shared' import React, { useCallback, useEffect, useState } from 'react' import type { ListDrawerProps } from './types.js' @@ -10,7 +11,6 @@ import { useDocumentDrawer } from '../../elements/DocumentDrawer/index.js' import { useEffectEvent } from '../../hooks/useEffectEvent.js' import { useConfig } from '../../providers/Config/index.js' import { useServerFunctions } from '../../providers/ServerFunctions/index.js' -import { hoistQueryParamsToAnd } from '../../utilities/mergeListSearchAndWhere.js' import { ListDrawerContextProvider } from '../ListDrawer/Provider.js' import { LoadingOverlay } from '../Loading/index.js' import { type Option } from '../ReactSelect/index.js' @@ -18,6 +18,7 @@ import { type Option } from '../ReactSelect/index.js' export const ListDrawerContent: React.FC = ({ allowCreate = true, collectionSlugs, + disableQueryPresets, drawerSlug, enableRowSelections, filterOptions, @@ -91,6 +92,7 @@ export const ListDrawerContent: React.FC = ({ collectionSlug: slug, disableBulkDelete: true, disableBulkEdit: true, + disableQueryPresets, drawerSlug, enableRowSelections, overrideEntityVisibility, @@ -117,6 +119,7 @@ export const ListDrawerContent: React.FC = ({ enableRowSelections, filterOptions, overrideEntityVisibility, + disableQueryPresets, ], ) diff --git a/packages/ui/src/elements/ListDrawer/types.ts b/packages/ui/src/elements/ListDrawer/types.ts index 73f86928de..7d37ca1155 100644 --- a/packages/ui/src/elements/ListDrawer/types.ts +++ b/packages/ui/src/elements/ListDrawer/types.ts @@ -7,6 +7,7 @@ import type { ListDrawerContextProps } from './Provider.js' export type ListDrawerProps = { readonly allowCreate?: boolean readonly collectionSlugs: SanitizedCollectionConfig['slug'][] + readonly disableQueryPresets?: boolean readonly drawerSlug?: string readonly enableRowSelections?: boolean readonly filterOptions?: FilterOptionsResult @@ -28,10 +29,8 @@ export type UseListDrawer = (args: { selectedCollection?: SanitizedCollectionConfig['slug'] uploads?: boolean // finds all collections with upload: true }) => [ - React.FC< - Pick - >, // drawer - React.FC>, // toggler + React.FC>, + React.FC>, { closeDrawer: () => void collectionSlugs: SanitizedCollectionConfig['slug'][] diff --git a/packages/ui/src/elements/Pill/index.scss b/packages/ui/src/elements/Pill/index.scss index 3b946f806b..f370546f3b 100644 --- a/packages/ui/src/elements/Pill/index.scss +++ b/packages/ui/src/elements/Pill/index.scss @@ -73,22 +73,28 @@ background: var(--theme-elevation-0); &.pill--has-action { - &:hover { - background: var(--theme-elevation-100); - } - + &:hover, &:active { background: var(--theme-elevation-100); } } } + &--style-always-white { + background: var(--theme-elevation-850); + color: var(--theme-elevation-0); + + &.pill--has-action { + &:hover, + &:active { + background: var(--theme-elevation-750); + } + } + } + &--style-light { &.pill--has-action { - &:hover { - background: var(--theme-elevation-100); - } - + &:hover, &:active { background: var(--theme-elevation-100); } @@ -139,4 +145,21 @@ line-height: 18px; } } + + html[data-theme='light'] { + .pill { + &--style-always-white { + background: var(--theme-elevation-0); + color: var(--theme-elevation-800); + border: 1px solid var(--theme-elevation-100); + + &.pill--has-action { + &:hover, + &:active { + background: var(--theme-elevation-100); + } + } + } + } + } } diff --git a/packages/ui/src/elements/Pill/index.tsx b/packages/ui/src/elements/Pill/index.tsx index 80e9085ca0..e7e5d310a3 100644 --- a/packages/ui/src/elements/Pill/index.tsx +++ b/packages/ui/src/elements/Pill/index.tsx @@ -20,7 +20,15 @@ export type PillProps = { icon?: React.ReactNode id?: string onClick?: () => void - pillStyle?: 'dark' | 'error' | 'light' | 'light-gray' | 'success' | 'warning' | 'white' + pillStyle?: + | 'always-white' + | 'dark' + | 'error' + | 'light' + | 'light-gray' + | 'success' + | 'warning' + | 'white' rounded?: boolean size?: 'medium' | 'small' to?: string @@ -64,6 +72,7 @@ const DraggablePill: React.FC = (props) => { const StaticPill: React.FC = (props) => { const { + id, alignIcon = 'right', 'aria-checked': ariaChecked, 'aria-controls': ariaControls, @@ -101,6 +110,7 @@ const StaticPill: React.FC = (props) => { if (onClick && !to) { Element = 'button' } + if (to) { Element = Link } @@ -114,6 +124,7 @@ const StaticPill: React.FC = (props) => { aria-label={ariaLabel} className={classes} href={to || null} + id={id} onClick={onClick} type={Element === 'button' ? 'button' : undefined} > diff --git a/packages/ui/src/elements/Popup/PopupButtonList/index.tsx b/packages/ui/src/elements/Popup/PopupButtonList/index.tsx index b29f07754c..f9f4d4f4e6 100644 --- a/packages/ui/src/elements/Popup/PopupButtonList/index.tsx +++ b/packages/ui/src/elements/Popup/PopupButtonList/index.tsx @@ -8,6 +8,9 @@ import './index.scss' const baseClass = 'popup-button-list' +export { PopupListDivider as Divider } from '../PopupDivider/index.js' +export { PopupListGroupLabel as GroupLabel } from '../PopupGroupLabel/index.js' + export const ButtonGroup: React.FC<{ buttonSize?: 'default' | 'small' children: React.ReactNode diff --git a/packages/ui/src/elements/Popup/PopupDivider/index.scss b/packages/ui/src/elements/Popup/PopupDivider/index.scss new file mode 100644 index 0000000000..943ee639cf --- /dev/null +++ b/packages/ui/src/elements/Popup/PopupDivider/index.scss @@ -0,0 +1,10 @@ +@import '../../../scss/styles.scss'; + +@layer payload-default { + .popup-divider { + width: 100%; + height: 1px; + background-color: var(--theme-elevation-150); + border: none; + } +} diff --git a/packages/ui/src/elements/Popup/PopupDivider/index.tsx b/packages/ui/src/elements/Popup/PopupDivider/index.tsx new file mode 100644 index 0000000000..bd3e890522 --- /dev/null +++ b/packages/ui/src/elements/Popup/PopupDivider/index.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +import './index.scss' + +const baseClass = 'popup-divider' + +export const PopupListDivider: React.FC = () => { + return
+} diff --git a/packages/ui/src/elements/Popup/PopupGroupLabel/index.scss b/packages/ui/src/elements/Popup/PopupGroupLabel/index.scss new file mode 100644 index 0000000000..ff3e14c95f --- /dev/null +++ b/packages/ui/src/elements/Popup/PopupGroupLabel/index.scss @@ -0,0 +1,8 @@ +@import '../../../scss/styles.scss'; + +@layer payload-default { + .popup-list-group-label { + color: var(--theme-elevation-500); + padding: 0 var(--list-button-padding); + } +} diff --git a/packages/ui/src/elements/Popup/PopupGroupLabel/index.tsx b/packages/ui/src/elements/Popup/PopupGroupLabel/index.tsx new file mode 100644 index 0000000000..00361be73c --- /dev/null +++ b/packages/ui/src/elements/Popup/PopupGroupLabel/index.tsx @@ -0,0 +1,11 @@ +import React from 'react' + +import './index.scss' + +const baseClass = 'popup-list-group-label' + +export const PopupListGroupLabel: React.FC<{ + label: string +}> = ({ label }) => { + return

{label}

+} diff --git a/packages/ui/src/elements/Popup/index.tsx b/packages/ui/src/elements/Popup/index.tsx index 6ffb7e5257..afa2e41ec9 100644 --- a/packages/ui/src/elements/Popup/index.tsx +++ b/packages/ui/src/elements/Popup/index.tsx @@ -7,8 +7,8 @@ import { useWindowInfo } from '@faceless-ui/window-info' import React, { useCallback, useEffect, useRef, useState } from 'react' import { useIntersect } from '../../hooks/useIntersect.js' -import './index.scss' import { PopupTrigger } from './PopupTrigger/index.js' +import './index.scss' const baseClass = 'popup' @@ -60,6 +60,7 @@ export const Popup: React.FC = (props) => { verticalAlign: verticalAlignFromProps = 'top', } = props const { height: windowHeight, width: windowWidth } = useWindowInfo() + const [intersectionRef, intersectionEntry] = useIntersect({ root: boundingRef?.current || null, rootMargin: '-100px 0px 0px 0px', @@ -212,7 +213,7 @@ export const Popup: React.FC = (props) => {
{render && render({ close: () => setActive(false) })} - {children && children} + {children}
diff --git a/packages/ui/src/elements/QueryPresets/cells/AccessCell/index.tsx b/packages/ui/src/elements/QueryPresets/cells/AccessCell/index.tsx new file mode 100644 index 0000000000..d5d0cae8f0 --- /dev/null +++ b/packages/ui/src/elements/QueryPresets/cells/AccessCell/index.tsx @@ -0,0 +1,30 @@ +import type { DefaultCellComponentProps } from 'payload' +import type { JSX } from 'react' + +import { toWords } from 'payload/shared' +import React, { Fragment } from 'react' + +export const QueryPresetsAccessCell: React.FC = ({ cellData }) => { + // first sort the operations in the order they should be displayed + const operations = ['read', 'update', 'delete'] + + return ( +

+ {operations.reduce((acc, operation, index) => { + const operationData = (cellData as JSON)?.[operation] + + if (operationData && operationData.constraint) { + acc.push( + + + {toWords(operation)}: {toWords(operationData.constraint)} + + {index !== operations.length - 1 && ', '} + , + ) + } + return acc + }, [] as JSX.Element[])} +

+ ) +} diff --git a/packages/ui/src/elements/QueryPresets/cells/ColumnsCell/index.scss b/packages/ui/src/elements/QueryPresets/cells/ColumnsCell/index.scss new file mode 100644 index 0000000000..02ff5f8084 --- /dev/null +++ b/packages/ui/src/elements/QueryPresets/cells/ColumnsCell/index.scss @@ -0,0 +1,9 @@ +@import '../../../../scss/styles'; + +@layer payload-default { + .query-preset-columns-cell { + display: flex; + flex-wrap: wrap; + gap: 4px; + } +} diff --git a/packages/ui/src/elements/QueryPresets/cells/ColumnsCell/index.tsx b/packages/ui/src/elements/QueryPresets/cells/ColumnsCell/index.tsx new file mode 100644 index 0000000000..efd14ca6a5 --- /dev/null +++ b/packages/ui/src/elements/QueryPresets/cells/ColumnsCell/index.tsx @@ -0,0 +1,32 @@ +import type { ColumnPreference, DefaultCellComponentProps } from 'payload' + +import { toWords, transformColumnsToSearchParams } from 'payload/shared' +import React from 'react' + +import { Pill } from '../../../Pill/index.js' +import './index.scss' + +const baseClass = 'query-preset-columns-cell' + +export const QueryPresetsColumnsCell: React.FC = ({ cellData }) => { + return ( +
+ {cellData + ? transformColumnsToSearchParams(cellData as ColumnPreference[]).map((column, i) => { + const isColumnActive = !column.startsWith('-') + + // to void very lengthy cells, only display the active columns + if (!isColumnActive) { + return null + } + + return ( + + {toWords(column)} + + ) + }) + : 'No columns selected'} +
+ ) +} diff --git a/packages/ui/src/elements/QueryPresets/cells/WhereCell/index.tsx b/packages/ui/src/elements/QueryPresets/cells/WhereCell/index.tsx new file mode 100644 index 0000000000..d7c875aee1 --- /dev/null +++ b/packages/ui/src/elements/QueryPresets/cells/WhereCell/index.tsx @@ -0,0 +1,33 @@ +import type { DefaultCellComponentProps, Where } from 'payload' + +import { toWords } from 'payload/shared' +import React from 'react' + +/** @todo: improve this */ +const transformWhereToNaturalLanguage = (where: Where): string => { + if (where.or && where.or.length > 0 && where.or[0].and && where.or[0].and.length > 0) { + const orQuery = where.or[0] + const andQuery = orQuery?.and?.[0] + + if (!andQuery) { + return 'No where query' + } + + const key = Object.keys(andQuery)[0] + + if (!andQuery[key]) { + return 'No where query' + } + + const operator = Object.keys(andQuery[key])[0] + const value = andQuery[key][operator] + + return `${toWords(key)} ${operator} ${toWords(value)}` + } + + return '' +} + +export const QueryPresetsWhereCell: React.FC = ({ cellData }) => { + return
{cellData ? transformWhereToNaturalLanguage(cellData) : 'No where query'}
+} diff --git a/packages/ui/src/elements/QueryPresets/fields/ColumnsField/index.scss b/packages/ui/src/elements/QueryPresets/fields/ColumnsField/index.scss new file mode 100644 index 0000000000..37f31f036c --- /dev/null +++ b/packages/ui/src/elements/QueryPresets/fields/ColumnsField/index.scss @@ -0,0 +1,17 @@ +@import '../../../../scss/styles'; + +@layer payload-default { + .query-preset-columns-field { + .field-label { + margin-bottom: calc(var(--base) / 2); + } + + .value-wrapper { + background-color: var(--theme-elevation-50); + padding: var(--base); + display: flex; + flex-wrap: wrap; + gap: calc(var(--base) / 2); + } + } +} diff --git a/packages/ui/src/elements/QueryPresets/fields/ColumnsField/index.tsx b/packages/ui/src/elements/QueryPresets/fields/ColumnsField/index.tsx new file mode 100644 index 0000000000..78570d6671 --- /dev/null +++ b/packages/ui/src/elements/QueryPresets/fields/ColumnsField/index.tsx @@ -0,0 +1,36 @@ +'use client' +import type { ColumnPreference, JSONFieldClientComponent } from 'payload' + +import { toWords, transformColumnsToSearchParams } from 'payload/shared' +import React from 'react' + +import { FieldLabel } from '../../../../fields/FieldLabel/index.js' +import { useField } from '../../../../forms/useField/index.js' +import { Pill } from '../../../Pill/index.js' +import './index.scss' + +export const QueryPresetsColumnField: JSONFieldClientComponent = ({ + field: { label, required }, + path, +}) => { + const { value } = useField({ path }) + + return ( +
+ +
+ {value + ? transformColumnsToSearchParams(value as ColumnPreference[]).map((column, i) => { + const isColumnActive = !column.startsWith('-') + + return ( + + {toWords(column)} + + ) + }) + : 'No columns selected'} +
+
+ ) +} diff --git a/packages/ui/src/elements/QueryPresets/fields/WhereField/index.scss b/packages/ui/src/elements/QueryPresets/fields/WhereField/index.scss new file mode 100644 index 0000000000..2376aad439 --- /dev/null +++ b/packages/ui/src/elements/QueryPresets/fields/WhereField/index.scss @@ -0,0 +1,23 @@ +@import '../../../../scss/styles'; + +@layer payload-default { + .query-preset-where-field { + .field-label { + margin-bottom: calc(var(--base) / 2); + } + + .value-wrapper { + background-color: var(--theme-elevation-50); + padding: var(--base); + } + } + + .query-preset-where-field { + .pill { + &--style-always-white { + background: var(--theme-elevation-250); + color: var(--theme-elevation-1000); + } + } + } +} diff --git a/packages/ui/src/elements/QueryPresets/fields/WhereField/index.tsx b/packages/ui/src/elements/QueryPresets/fields/WhereField/index.tsx new file mode 100644 index 0000000000..564cbe82b1 --- /dev/null +++ b/packages/ui/src/elements/QueryPresets/fields/WhereField/index.tsx @@ -0,0 +1,114 @@ +'use client' +import type { JSONFieldClientComponent, Where } from 'payload' + +import { getTranslation } from '@payloadcms/translations' +import { toWords } from 'payload/shared' +import React from 'react' + +import { FieldLabel } from '../../../../fields/FieldLabel/index.js' +import { useField } from '../../../../forms/useField/index.js' +import { useConfig } from '../../../../providers/Config/index.js' +import { useListQuery } from '../../../../providers/ListQuery/index.js' +import { useTranslation } from '../../../../providers/Translation/index.js' +import { Pill } from '../../../Pill/index.js' +import './index.scss' + +/** @todo: improve this */ +const transformWhereToNaturalLanguage = ( + where: Where, + collectionLabel: string, +): React.ReactNode => { + if (!where) { + return null + } + + const renderCondition = (condition: any): React.ReactNode => { + const key = Object.keys(condition)[0] + + if (!condition[key]) { + return 'No where query' + } + + const operator = Object.keys(condition[key])[0] + let value = condition[key][operator] + + // TODO: this is not right, but works for now at least. + // Ideally we look up iterate _fields_ so we know the type of the field + // Currently, we're only iterating over the `where` field's value, so we don't know the type + if (typeof value === 'object') { + try { + value = new Date(value).toLocaleDateString() + } catch (_err) { + value = 'Unknown error has occurred' + } + } + + return ( + + {toWords(key)} {operator} {toWords(value)} + + ) + } + + const renderWhere = (where: Where, collectionLabel: string): React.ReactNode => { + if (where.or && where.or.length > 0) { + return ( +
+ {where.or.map((orCondition, orIndex) => ( + + {orCondition.and && orCondition.and.length > 0 ? ( +
+ {orIndex === 0 && ( + {`Filter ${collectionLabel} where `} + )} + {orIndex > 0 && or } + {orCondition.and.map((andCondition, andIndex) => ( + + {renderCondition(andCondition)} + {andIndex < orCondition.and.length - 1 && ( + and + )} + + ))} +
+ ) : ( + renderCondition(orCondition) + )} +
+ ))} +
+ ) + } + + return renderCondition(where) + } + + return renderWhere(where, collectionLabel) +} + +export const QueryPresetsWhereField: JSONFieldClientComponent = ({ + field: { label, required }, + path, +}) => { + const { value } = useField({ path }) + const { collectionSlug } = useListQuery() + const { getEntityConfig } = useConfig() + + const collectionConfig = getEntityConfig({ collectionSlug }) + + const { i18n } = useTranslation() + + return ( +
+ +
+ {value + ? transformWhereToNaturalLanguage( + value as Where, + getTranslation(collectionConfig.labels.plural, i18n), + ) + : 'No where query'} +
+
+ ) +} diff --git a/packages/ui/src/elements/RelationshipTable/cells/DrawerLink/index.tsx b/packages/ui/src/elements/RelationshipTable/cells/DrawerLink/index.tsx index 8219f994c2..1c07f3a649 100644 --- a/packages/ui/src/elements/RelationshipTable/cells/DrawerLink/index.tsx +++ b/packages/ui/src/elements/RelationshipTable/cells/DrawerLink/index.tsx @@ -5,9 +5,9 @@ import React, { useCallback } from 'react' import type { DocumentDrawerProps } from '../../../DocumentDrawer/types.js' import { EditIcon } from '../../../../icons/Edit/index.js' +import { useCellProps } from '../../../../providers/TableColumns/RenderDefaultCell/index.js' import { useDocumentDrawer } from '../../../DocumentDrawer/index.js' import { DefaultCell } from '../../../Table/DefaultCell/index.js' -import { useCellProps } from '../../../TableColumns/RenderDefaultCell/index.js' import './index.scss' export const DrawerLink: React.FC<{ diff --git a/packages/ui/src/elements/RelationshipTable/index.tsx b/packages/ui/src/elements/RelationshipTable/index.tsx index 76795c6c1e..a6588961cf 100644 --- a/packages/ui/src/elements/RelationshipTable/index.tsx +++ b/packages/ui/src/elements/RelationshipTable/index.tsx @@ -8,7 +8,7 @@ import { type PaginatedDocs, type Where, } from 'payload' -import { transformColumnsToPreferences } from 'payload/shared' +import { hoistQueryParamsToAnd, transformColumnsToPreferences } from 'payload/shared' import React, { Fragment, useCallback, useEffect, useState } from 'react' import type { DocumentDrawerProps } from '../DocumentDrawer/types.js' @@ -22,17 +22,16 @@ import { useAuth } from '../../providers/Auth/index.js' import { useConfig } from '../../providers/Config/index.js' import { ListQueryProvider } from '../../providers/ListQuery/index.js' import { useServerFunctions } from '../../providers/ServerFunctions/index.js' +import { TableColumnsProvider } from '../../providers/TableColumns/index.js' import { useTranslation } from '../../providers/Translation/index.js' -import { hoistQueryParamsToAnd } from '../../utilities/mergeListSearchAndWhere.js' import { AnimateHeight } from '../AnimateHeight/index.js' -import './index.scss' import { ColumnSelector } from '../ColumnSelector/index.js' import { useDocumentDrawer } from '../DocumentDrawer/index.js' import { Popup, PopupList } from '../Popup/index.js' import { RelationshipProvider } from '../Table/RelationshipProvider/index.js' -import { TableColumnsProvider } from '../TableColumns/index.js' import { DrawerLink } from './cells/DrawerLink/index.js' import { RelationshipTablePagination } from './Pagination.js' +import './index.scss' const baseClass = 'relationship-table' diff --git a/packages/ui/src/elements/WhereBuilder/Condition/index.tsx b/packages/ui/src/elements/WhereBuilder/Condition/index.tsx index 644ee39215..20ca8ed2e1 100644 --- a/packages/ui/src/elements/WhereBuilder/Condition/index.tsx +++ b/packages/ui/src/elements/WhereBuilder/Condition/index.tsx @@ -26,8 +26,8 @@ import { useEffectEvent } from '../../../hooks/useEffectEvent.js' import { useTranslation } from '../../../providers/Translation/index.js' import { Button } from '../../Button/index.js' import { ReactSelect } from '../../ReactSelect/index.js' -import { DefaultFilter } from './DefaultFilter/index.js' import './index.scss' +import { DefaultFilter } from './DefaultFilter/index.js' const baseClass = 'condition' diff --git a/packages/ui/src/elements/WhereBuilder/index.tsx b/packages/ui/src/elements/WhereBuilder/index.tsx index d9b4b21bda..7bf6ed3564 100644 --- a/packages/ui/src/elements/WhereBuilder/index.tsx +++ b/packages/ui/src/elements/WhereBuilder/index.tsx @@ -2,6 +2,7 @@ import type { Operator } from 'payload' import { getTranslation } from '@payloadcms/translations' +import { transformWhereQuery, validateWhereQuery } from 'payload/shared' import React, { useMemo } from 'react' import type { AddCondition, RemoveCondition, UpdateCondition, WhereBuilderProps } from './types.js' @@ -12,8 +13,6 @@ import { Button } from '../Button/index.js' import { Condition } from './Condition/index.js' import fieldTypes from './field-types.js' import { reduceFields } from './reduceFields.js' -import { transformWhereQuery } from './transformWhereQuery.js' -import validateWhereQuery from './validateWhereQuery.js' import './index.scss' const baseClass = 'where-builder' @@ -84,22 +83,29 @@ export const WhereBuilder: React.FC = (props) => { const updateCondition: UpdateCondition = React.useCallback( async ({ andIndex, field, operator: incomingOperator, orIndex, value: valueArg }) => { - const existingRowCondition = conditions[orIndex].and[andIndex] + const existingCondition = conditions[orIndex].and[andIndex] const defaults = fieldTypes[field.field.type] const operator = incomingOperator || defaults.operators[0].value - if (typeof existingRowCondition === 'object' && field.value) { - const value = valueArg ?? existingRowCondition?.[operator] + if (typeof existingCondition === 'object' && field.value) { + const value = valueArg ?? existingCondition?.[operator] - const newRowCondition = { - [field.value]: { [operator]: value }, + const valueChanged = value !== existingCondition?.[field.value]?.[operator] + + const operatorChanged = + operator !== Object.keys(existingCondition?.[field.value] || {})?.[0] + + if (valueChanged || operatorChanged) { + const newRowCondition = { + [field.value]: { [operator]: value }, + } + + const newConditions = [...conditions] + newConditions[orIndex].and[andIndex] = newRowCondition + + await handleWhereChange({ or: newConditions }) } - - const newConditions = [...conditions] - newConditions[orIndex].and[andIndex] = newRowCondition - - await handleWhereChange({ or: newConditions }) } }, [conditions, handleWhereChange], diff --git a/packages/ui/src/exports/client/index.ts b/packages/ui/src/exports/client/index.ts index 1d1a53d725..c36770f883 100644 --- a/packages/ui/src/exports/client/index.ts +++ b/packages/ui/src/exports/client/index.ts @@ -22,6 +22,13 @@ export { useEffectEvent } from '../../hooks/useEffectEvent.js' export { useUseTitleField } from '../../hooks/useUseAsTitle.js' +// query preset elements +export { QueryPresetsColumnsCell } from '../../elements/QueryPresets/cells/ColumnsCell/index.js' +export { QueryPresetsWhereCell } from '../../elements/QueryPresets/cells/WhereCell/index.js' +export { QueryPresetsAccessCell } from '../../elements/QueryPresets/cells/AccessCell/index.js' +export { QueryPresetsColumnField } from '../../elements/QueryPresets/fields/ColumnsField/index.js' +export { QueryPresetsWhereField } from '../../elements/QueryPresets/fields/WhereField/index.js' + // elements export { ConfirmationModal } from '../../elements/ConfirmationModal/index.js' export type { OnCancel } from '../../elements/ConfirmationModal/index.js' @@ -29,11 +36,11 @@ export { Link } from '../../elements/Link/index.js' export { LeaveWithoutSaving } from '../../elements/LeaveWithoutSaving/index.js' export { DocumentTakeOver } from '../../elements/DocumentTakeOver/index.js' export { DocumentLocked } from '../../elements/DocumentLocked/index.js' -export { TableColumnsProvider, useTableColumns } from '../../elements/TableColumns/index.js' +export { TableColumnsProvider, useTableColumns } from '../../providers/TableColumns/index.js' export { RenderDefaultCell, useCellProps, -} from '../../elements/TableColumns/RenderDefaultCell/index.js' +} from '../../providers/TableColumns/RenderDefaultCell/index.js' export { Translation } from '../../elements/Translation/index.js' export { default as DatePicker } from '../../elements/DatePicker/DatePicker.js' diff --git a/packages/ui/src/exports/shared/index.ts b/packages/ui/src/exports/shared/index.ts index a5268a3fdf..cfde4aac69 100644 --- a/packages/ui/src/exports/shared/index.ts +++ b/packages/ui/src/exports/shared/index.ts @@ -1,6 +1,3 @@ -// IMPORTANT: the shared.ts file CANNOT contain any Server Components _that import client components_. -export { filterFields } from '../../elements/TableColumns/filterFields.js' -export { getInitialColumns } from '../../elements/TableColumns/getInitialColumns.js' export { Translation } from '../../elements/Translation/index.js' export { withMergedProps } from '../../elements/withMergedProps/index.js' // cannot be within a 'use client', thus we export this from shared export { WithServerSideProps } from '../../elements/WithServerSideProps/index.js' @@ -8,6 +5,9 @@ export { mergeFieldStyles } from '../../fields/mergeFieldStyles.js' export { reduceToSerializableFields } from '../../forms/Form/reduceToSerializableFields.js' export { PayloadIcon } from '../../graphics/Icon/index.js' export { PayloadLogo } from '../../graphics/Logo/index.js' +// IMPORTANT: the shared.ts file CANNOT contain any Server Components _that import client components_. +export { filterFields } from '../../providers/TableColumns/filterFields.js' +export { getInitialColumns } from '../../providers/TableColumns/getInitialColumns.js' export { abortAndIgnore, handleAbortRef } from '../../utilities/abortAndIgnore.js' export { requests } from '../../utilities/api.js' export { findLocaleFromCode } from '../../utilities/findLocaleFromCode.js' @@ -26,5 +26,10 @@ export { handleTakeOver } from '../../utilities/handleTakeOver.js' export { hasSavePermission } from '../../utilities/hasSavePermission.js' export { isClientUserObject } from '../../utilities/isClientUserObject.js' export { isEditing } from '../../utilities/isEditing.js' -export { mergeListSearchAndWhere } from '../../utilities/mergeListSearchAndWhere.js' export { sanitizeID } from '../../utilities/sanitizeID.js' +/** + * @deprecated + * The `mergeListSearchAndWhere` function is deprecated. + * Import this from `payload/shared` instead. + */ +export { mergeListSearchAndWhere } from 'payload/shared' diff --git a/packages/ui/src/icons/Chevron/index.tsx b/packages/ui/src/icons/Chevron/index.tsx index eb102cabf9..93c7b23c6c 100644 --- a/packages/ui/src/icons/Chevron/index.tsx +++ b/packages/ui/src/icons/Chevron/index.tsx @@ -3,11 +3,13 @@ import React from 'react' import './index.scss' export const ChevronIcon: React.FC<{ + readonly ariaLabel?: string readonly className?: string readonly direction?: 'down' | 'left' | 'right' | 'up' readonly size?: 'large' | 'small' -}> = ({ className, direction, size }) => ( +}> = ({ ariaLabel, className, direction, size }) => ( div { width: 2.5px; height: 2.5px; diff --git a/packages/ui/src/icons/Dots/index.tsx b/packages/ui/src/icons/Dots/index.tsx index 9bea6bf69e..620bccb9b7 100644 --- a/packages/ui/src/icons/Dots/index.tsx +++ b/packages/ui/src/icons/Dots/index.tsx @@ -2,13 +2,24 @@ import React from 'react' import './index.scss' -export const Dots: React.FC<{ ariaLabel?: string; className?: string }> = ({ - ariaLabel, - className, -}) => ( +const baseClass = 'dots' + +export const Dots: React.FC<{ + ariaLabel?: string + className?: string + noBackground?: boolean + orientation?: 'horizontal' | 'vertical' +}> = ({ ariaLabel, className, noBackground, orientation = 'vertical' }) => (
diff --git a/packages/ui/src/icons/People/index.scss b/packages/ui/src/icons/People/index.scss new file mode 100644 index 0000000000..f0156ed8c6 --- /dev/null +++ b/packages/ui/src/icons/People/index.scss @@ -0,0 +1,11 @@ +@import '../../scss/styles'; + +@layer payload-default { + .icon--people { + .stroke { + stroke: currentColor; + stroke-width: $style-stroke-width; + fill: none; + } + } +} diff --git a/packages/ui/src/icons/People/index.tsx b/packages/ui/src/icons/People/index.tsx new file mode 100644 index 0000000000..23f5c168c0 --- /dev/null +++ b/packages/ui/src/icons/People/index.tsx @@ -0,0 +1,21 @@ +import React from 'react' + +import './index.scss' + +export const PeopleIcon: React.FC<{ + className: string +}> = ({ className }) => ( + + + +) diff --git a/packages/ui/src/providers/DocumentInfo/types.ts b/packages/ui/src/providers/DocumentInfo/types.ts index d282fdfad4..6babc9b439 100644 --- a/packages/ui/src/providers/DocumentInfo/types.ts +++ b/packages/ui/src/providers/DocumentInfo/types.ts @@ -36,6 +36,7 @@ export type DocumentInfoProps = { readonly isLocked: boolean readonly lastUpdateTime: number readonly mostRecentVersionIsAutosaved: boolean + readonly redirectAfterCreate?: boolean readonly redirectAfterDelete?: boolean readonly redirectAfterDuplicate?: boolean readonly unpublishedVersionCount: number diff --git a/packages/ui/src/providers/EntityVisibility/index.tsx b/packages/ui/src/providers/EntityVisibility/index.tsx index accaac5c43..2da537ebe3 100644 --- a/packages/ui/src/providers/EntityVisibility/index.tsx +++ b/packages/ui/src/providers/EntityVisibility/index.tsx @@ -48,5 +48,4 @@ export const EntityVisibilityProvider: React.FC<{ ) } -export const useEntityVisibility = (): VisibleEntitiesContextType => - use(EntityVisibilityContext) +export const useEntityVisibility = (): VisibleEntitiesContextType => use(EntityVisibilityContext) diff --git a/packages/ui/src/providers/ListQuery/context.ts b/packages/ui/src/providers/ListQuery/context.ts index 99c732889d..9cd564575a 100644 --- a/packages/ui/src/providers/ListQuery/context.ts +++ b/packages/ui/src/providers/ListQuery/context.ts @@ -5,3 +5,7 @@ import type { IListQueryContext } from './types.js' export const ListQueryContext = createContext({} as IListQueryContext) export const useListQuery = (): IListQueryContext => use(ListQueryContext) + +export const ListQueryModifiedContext = createContext(false) + +export const useListQueryModified = (): boolean => use(ListQueryModifiedContext) diff --git a/packages/ui/src/providers/ListQuery/index.tsx b/packages/ui/src/providers/ListQuery/index.tsx index 93d9ddf0eb..ad9dd0669c 100644 --- a/packages/ui/src/providers/ListQuery/index.tsx +++ b/packages/ui/src/providers/ListQuery/index.tsx @@ -3,20 +3,21 @@ import { useRouter, useSearchParams } from 'next/navigation.js' import { type ListQuery, type Where } from 'payload' import { isNumber, transformColumnsToSearchParams } from 'payload/shared' import * as qs from 'qs-esm' -import React, { useCallback, useEffect, useMemo, useState } from 'react' +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import type { ListQueryProps } from './types.js' +import type { IListQueryContext, ListQueryProps } from './types.js' import { useListDrawerContext } from '../../elements/ListDrawer/Provider.js' import { useEffectEvent } from '../../hooks/useEffectEvent.js' import { useRouteTransition } from '../../providers/RouteTransition/index.js' import { parseSearchParams } from '../../utilities/parseSearchParams.js' -import { ListQueryContext } from './context.js' +import { ListQueryContext, ListQueryModifiedContext } from './context.js' export { useListQuery } from './context.js' export const ListQueryProvider: React.FC = ({ children, + collectionSlug, columns, data, defaultLimit, @@ -29,12 +30,17 @@ export const ListQueryProvider: React.FC = ({ const router = useRouter() const rawSearchParams = useSearchParams() const { startRouteTransition } = useRouteTransition() + const [modified, setModified] = useState(false) const searchParams = useMemo( () => parseSearchParams(rawSearchParams), [rawSearchParams], ) + const contextRef = useRef({} as IListQueryContext) + + contextRef.current.modified = modified + const { onQueryChange } = useListDrawerContext() const [currentQuery, setCurrentQuery] = useState(() => { @@ -47,20 +53,33 @@ export const ListQueryProvider: React.FC = ({ const refineListData = useCallback( // eslint-disable-next-line @typescript-eslint/require-await - async (query: ListQuery) => { - let page = 'page' in query ? query.page : currentQuery?.page + async (incomingQuery: ListQuery, modified?: boolean) => { + if (modified !== undefined) { + setModified(modified) + } else { + setModified(true) + } - if ('where' in query || 'search' in query) { + let page = 'page' in incomingQuery ? incomingQuery.page : currentQuery?.page + + if ('where' in incomingQuery || 'search' in incomingQuery) { page = '1' } const newQuery: ListQuery = { - columns: 'columns' in query ? query.columns : currentQuery.columns, - limit: 'limit' in query ? query.limit : (currentQuery?.limit ?? String(defaultLimit)), + columns: 'columns' in incomingQuery ? incomingQuery.columns : currentQuery.columns, + limit: + 'limit' in incomingQuery + ? incomingQuery.limit + : (currentQuery?.limit ?? String(defaultLimit)), page, - search: 'search' in query ? query.search : currentQuery?.search, - sort: 'sort' in query ? query.sort : ((currentQuery?.sort as string) ?? defaultSort), - where: 'where' in query ? query.where : currentQuery?.where, + preset: 'preset' in incomingQuery ? incomingQuery.preset : currentQuery?.preset, + search: 'search' in incomingQuery ? incomingQuery.search : currentQuery?.search, + sort: + 'sort' in incomingQuery + ? incomingQuery.sort + : ((currentQuery?.sort as string) ?? defaultSort), + where: 'where' in incomingQuery ? incomingQuery.where : currentQuery?.where, } if (modifySearchParams) { @@ -89,6 +108,7 @@ export const ListQueryProvider: React.FC = ({ currentQuery?.search, currentQuery?.sort, currentQuery?.where, + currentQuery?.preset, startRouteTransition, defaultLimit, defaultSort, @@ -180,6 +200,7 @@ export const ListQueryProvider: React.FC = ({ return ( = ({ handleWhereChange, query: currentQuery, refineListData, + setModified, + ...contextRef.current, }} > - {children} + {children} ) } diff --git a/packages/ui/src/providers/ListQuery/types.ts b/packages/ui/src/providers/ListQuery/types.ts index accd66a906..979b960a1f 100644 --- a/packages/ui/src/providers/ListQuery/types.ts +++ b/packages/ui/src/providers/ListQuery/types.ts @@ -1,8 +1,10 @@ import type { + ClientCollectionConfig, ColumnPreference, ListPreferences, ListQuery, PaginatedDocs, + QueryPreset, Sort, Where, } from 'payload' @@ -19,7 +21,7 @@ export type OnListQueryChange = (query: ListQuery) => void export type ListQueryProps = { readonly children: React.ReactNode - readonly collectionSlug?: string + readonly collectionSlug?: ClientCollectionConfig['slug'] readonly columns?: ColumnPreference[] readonly data: PaginatedDocs readonly defaultLimit?: number @@ -34,9 +36,12 @@ export type ListQueryProps = { } export type IListQueryContext = { + collectionSlug: ClientCollectionConfig['slug'] data: PaginatedDocs defaultLimit?: number defaultSort?: Sort + modified: boolean query: ListQuery - refineListData: (args: ListQuery) => Promise + refineListData: (args: ListQuery, setModified?: boolean) => Promise + setModified: (modified: boolean) => void } & ContextHandlers diff --git a/packages/ui/src/providers/Preferences/index.tsx b/packages/ui/src/providers/Preferences/index.tsx index f0fe18960c..f405bfea76 100644 --- a/packages/ui/src/providers/Preferences/index.tsx +++ b/packages/ui/src/providers/Preferences/index.tsx @@ -51,9 +51,11 @@ export const PreferencesProvider: React.FC<{ children?: React.ReactNode }> = ({ const getPreference = useCallback( async (key: string): Promise => { const prefs = preferencesRef.current + if (typeof prefs[key] !== 'undefined') { return prefs[key] } + const promise = new Promise((resolve: (value: T) => void) => { void (async () => { const request = await requests.get(`${serverURL}${api}/payload-preferences/${key}`, { @@ -61,16 +63,22 @@ export const PreferencesProvider: React.FC<{ children?: React.ReactNode }> = ({ 'Accept-Language': i18n.language, }, }) + let value = null + if (request.status === 200) { const preference = await request.json() value = preference.value } + preferencesRef.current[key] = value + resolve(value) })() }) + prefs[key] = promise + return promise }, [i18n.language, api, preferencesRef, serverURL], diff --git a/packages/ui/src/providers/ServerFunctions/index.tsx b/packages/ui/src/providers/ServerFunctions/index.tsx index e0061a7e2d..995b08087b 100644 --- a/packages/ui/src/providers/ServerFunctions/index.tsx +++ b/packages/ui/src/providers/ServerFunctions/index.tsx @@ -44,6 +44,7 @@ type RenderDocument = (args: { initialData?: Data locale?: Locale overrideEntityVisibility?: boolean + redirectAfterCreate?: boolean redirectAfterDelete?: boolean redirectAfterDuplicate?: boolean signal?: AbortSignal diff --git a/packages/ui/src/elements/TableColumns/RenderDefaultCell/index.scss b/packages/ui/src/providers/TableColumns/RenderDefaultCell/index.scss similarity index 100% rename from packages/ui/src/elements/TableColumns/RenderDefaultCell/index.scss rename to packages/ui/src/providers/TableColumns/RenderDefaultCell/index.scss diff --git a/packages/ui/src/elements/TableColumns/RenderDefaultCell/index.tsx b/packages/ui/src/providers/TableColumns/RenderDefaultCell/index.tsx similarity index 93% rename from packages/ui/src/elements/TableColumns/RenderDefaultCell/index.tsx rename to packages/ui/src/providers/TableColumns/RenderDefaultCell/index.tsx index 4fefe9bb96..e962df1c72 100644 --- a/packages/ui/src/elements/TableColumns/RenderDefaultCell/index.tsx +++ b/packages/ui/src/providers/TableColumns/RenderDefaultCell/index.tsx @@ -4,16 +4,15 @@ import type { DefaultCellComponentProps } from 'payload' import React from 'react' import { useListDrawerContext } from '../../../elements/ListDrawer/Provider.js' -import { DefaultCell } from '../../Table/DefaultCell/index.js' -import './index.scss' +import { DefaultCell } from '../../../elements/Table/DefaultCell/index.js' import { useTableColumns } from '../index.js' +import './index.scss' const baseClass = 'default-cell' const CellPropsContext = React.createContext(null) -export const useCellProps = (): DefaultCellComponentProps | null => - React.use(CellPropsContext) +export const useCellProps = (): DefaultCellComponentProps | null => React.use(CellPropsContext) export const RenderDefaultCell: React.FC<{ clientProps: DefaultCellComponentProps diff --git a/packages/ui/src/elements/TableColumns/buildColumnState.tsx b/packages/ui/src/providers/TableColumns/buildColumnState.tsx similarity index 98% rename from packages/ui/src/elements/TableColumns/buildColumnState.tsx rename to packages/ui/src/providers/TableColumns/buildColumnState.tsx index bdd89ab7b5..de12112783 100644 --- a/packages/ui/src/elements/TableColumns/buildColumnState.tsx +++ b/packages/ui/src/providers/TableColumns/buildColumnState.tsx @@ -24,8 +24,9 @@ import { } from 'payload/shared' import React from 'react' -import type { SortColumnProps } from '../SortColumn/index.js' +import type { SortColumnProps } from '../../elements/SortColumn/index.js' +import { RenderServerComponent } from '../../elements/RenderServerComponent/index.js' import { DefaultCell, RenderCustomComponent, @@ -34,7 +35,6 @@ import { // eslint-disable-next-line payload/no-imports-from-exports-dir } from '../../exports/client/index.js' import { hasOptionLabelJSXElement } from '../../utilities/hasOptionLabelJSXElement.js' -import { RenderServerComponent } from '../RenderServerComponent/index.js' import { filterFields } from './filterFields.js' type Args = { diff --git a/packages/ui/src/elements/TableColumns/buildPolymorphicColumnState.tsx b/packages/ui/src/providers/TableColumns/buildPolymorphicColumnState.tsx similarity index 98% rename from packages/ui/src/elements/TableColumns/buildPolymorphicColumnState.tsx rename to packages/ui/src/providers/TableColumns/buildPolymorphicColumnState.tsx index 916ce7836f..b4273394cb 100644 --- a/packages/ui/src/elements/TableColumns/buildPolymorphicColumnState.tsx +++ b/packages/ui/src/providers/TableColumns/buildPolymorphicColumnState.tsx @@ -23,7 +23,7 @@ import { } from 'payload/shared' import React from 'react' -import type { SortColumnProps } from '../SortColumn/index.js' +import type { SortColumnProps } from '../../elements/SortColumn/index.js' import { RenderCustomComponent, @@ -31,7 +31,7 @@ import { SortColumn, // eslint-disable-next-line payload/no-imports-from-exports-dir } from '../../exports/client/index.js' -import { RenderServerComponent } from '../RenderServerComponent/index.js' +import { RenderServerComponent } from '../../elements/RenderServerComponent/index.js' import { filterFields } from './filterFields.js' type Args = { diff --git a/packages/ui/src/elements/TableColumns/context.ts b/packages/ui/src/providers/TableColumns/context.ts similarity index 100% rename from packages/ui/src/elements/TableColumns/context.ts rename to packages/ui/src/providers/TableColumns/context.ts diff --git a/packages/ui/src/elements/TableColumns/filterFields.tsx b/packages/ui/src/providers/TableColumns/filterFields.tsx similarity index 100% rename from packages/ui/src/elements/TableColumns/filterFields.tsx rename to packages/ui/src/providers/TableColumns/filterFields.tsx diff --git a/packages/ui/src/elements/TableColumns/getInitialColumns.ts b/packages/ui/src/providers/TableColumns/getInitialColumns.ts similarity index 100% rename from packages/ui/src/elements/TableColumns/getInitialColumns.ts rename to packages/ui/src/providers/TableColumns/getInitialColumns.ts diff --git a/packages/ui/src/elements/TableColumns/index.tsx b/packages/ui/src/providers/TableColumns/index.tsx similarity index 92% rename from packages/ui/src/elements/TableColumns/index.tsx rename to packages/ui/src/providers/TableColumns/index.tsx index 52c9cec4ea..3bb873e730 100644 --- a/packages/ui/src/elements/TableColumns/index.tsx +++ b/packages/ui/src/providers/TableColumns/index.tsx @@ -1,9 +1,9 @@ 'use client' import { type Column } from 'payload' import { transformColumnsToSearchParams } from 'payload/shared' -import React, { startTransition, useCallback } from 'react' +import React, { startTransition, useCallback, useRef } from 'react' -import type { TableColumnsProviderProps } from './types.js' +import type { ITableColumns, TableColumnsProviderProps } from './types.js' import { useConfig } from '../../providers/Config/index.js' import { useListQuery } from '../../providers/ListQuery/index.js' @@ -29,6 +29,8 @@ export const TableColumnsProvider: React.FC = ({ (state, action: Column[]) => action, ) + const contextRef = useRef({} as ITableColumns) + const toggleColumn = useCallback( async (column: string) => { const newColumnState = (columnState || []).map((col) => { @@ -98,6 +100,7 @@ export const TableColumnsProvider: React.FC = ({ resetColumnsState, setActiveColumns, toggleColumn, + ...contextRef.current, }} > {children} diff --git a/packages/ui/src/elements/TableColumns/types.ts b/packages/ui/src/providers/TableColumns/types.ts similarity index 93% rename from packages/ui/src/elements/TableColumns/types.ts rename to packages/ui/src/providers/TableColumns/types.ts index 3cd66cca57..1b593f4952 100644 --- a/packages/ui/src/elements/TableColumns/types.ts +++ b/packages/ui/src/providers/TableColumns/types.ts @@ -1,6 +1,6 @@ import type { Column, ListPreferences } from 'payload' -import type { SortColumnProps } from '../SortColumn/index.js' +import type { SortColumnProps } from '../../elements/SortColumn/index.js' export interface ITableColumns { columns: Column[] diff --git a/packages/ui/src/utilities/renderTable.tsx b/packages/ui/src/utilities/renderTable.tsx index 9ef3a6d154..1699672972 100644 --- a/packages/ui/src/utilities/renderTable.tsx +++ b/packages/ui/src/utilities/renderTable.tsx @@ -18,10 +18,10 @@ import { fieldAffectsData, fieldIsHiddenOrDisabled, flattenTopLevelFields } from import type { Column } from '../exports/client/index.js' import { RenderServerComponent } from '../elements/RenderServerComponent/index.js' -import { buildColumnState } from '../elements/TableColumns/buildColumnState.js' -import { buildPolymorphicColumnState } from '../elements/TableColumns/buildPolymorphicColumnState.js' -import { filterFields } from '../elements/TableColumns/filterFields.js' -import { getInitialColumns } from '../elements/TableColumns/getInitialColumns.js' +import { buildColumnState } from '../providers/TableColumns/buildColumnState.js' +import { buildPolymorphicColumnState } from '../providers/TableColumns/buildPolymorphicColumnState.js' +import { filterFields } from '../providers/TableColumns/filterFields.js' +import { getInitialColumns } from '../providers/TableColumns/getInitialColumns.js' // eslint-disable-next-line payload/no-imports-from-exports-dir import { Pill, SelectAll, SelectRow, Table } from '../exports/client/index.js' diff --git a/packages/ui/src/utilities/upsertPreferences.ts b/packages/ui/src/utilities/upsertPreferences.ts index 375d255660..26e51ac814 100644 --- a/packages/ui/src/utilities/upsertPreferences.ts +++ b/packages/ui/src/utilities/upsertPreferences.ts @@ -53,14 +53,23 @@ export const getPreferences = cache( * @param value - The new value to merge with the existing preferences */ export const upsertPreferences = async | string>({ + customMerge, key, req, value: incomingValue, }: { key: string req: PayloadRequest - value: T -}): Promise => { +} & ( + | { + customMerge: (existingValue: T) => T + value?: never + } + | { + customMerge?: never + value: T + } +)): Promise => { const existingPrefs: { id?: DefaultDocumentIDType; value?: T } = req.user ? await getPreferences(key, req.payload, req.user.id, req.user.collection) : {} @@ -83,14 +92,20 @@ export const upsertPreferences = async | stri user: req.user, }) } else { - // Strings are valid JSON, i.e. `locale` saved as a string to the locale preferences - const mergedPrefs = - typeof incomingValue === 'object' - ? { - ...(typeof existingPrefs.value === 'object' ? existingPrefs?.value : {}), // Shallow merge existing prefs to acquire any missing keys from incoming value - ...removeUndefined(incomingValue || {}), - } - : incomingValue + let mergedPrefs: T + + if (typeof customMerge === 'function') { + mergedPrefs = customMerge(existingPrefs.value) + } else { + // Strings are valid JSON, i.e. `locale` saved as a string to the locale preferences + mergedPrefs = + typeof incomingValue === 'object' + ? ({ + ...(typeof existingPrefs.value === 'object' ? existingPrefs?.value : {}), // Shallow merge existing prefs to acquire any missing keys from incoming value + ...removeUndefined(incomingValue || {}), + } as T) + : incomingValue + } if (!dequal(mergedPrefs, existingPrefs.value)) { newPrefs = await req.payload diff --git a/packages/ui/src/views/Edit/index.tsx b/packages/ui/src/views/Edit/index.tsx index 9dd7938655..78a054cb39 100644 --- a/packages/ui/src/views/Edit/index.tsx +++ b/packages/ui/src/views/Edit/index.tsx @@ -73,6 +73,7 @@ export function DefaultEditView({ isEditing, isInitializing, lastUpdateTime, + redirectAfterCreate, redirectAfterDelete, redirectAfterDuplicate, savedDocumentData, @@ -254,7 +255,7 @@ export function DefaultEditView({ }) } - if (!isEditing && depth < 2) { + if (!isEditing && depth < 2 && redirectAfterCreate !== false) { // Redirect to the same locale if it's been set const redirectRoute = formatAdminURL({ adminRoute, diff --git a/packages/ui/src/views/List/index.tsx b/packages/ui/src/views/List/index.tsx index 405a123481..cd5b2c2a51 100644 --- a/packages/ui/src/views/List/index.tsx +++ b/packages/ui/src/views/List/index.tsx @@ -20,12 +20,12 @@ import { RenderCustomComponent } from '../../elements/RenderCustomComponent/inde import { SelectMany } from '../../elements/SelectMany/index.js' import { useStepNav } from '../../elements/StepNav/index.js' import { RelationshipProvider } from '../../elements/Table/RelationshipProvider/index.js' -import { TableColumnsProvider } from '../../elements/TableColumns/index.js' import { ViewDescription } from '../../elements/ViewDescription/index.js' import { useAuth } from '../../providers/Auth/index.js' import { useConfig } from '../../providers/Config/index.js' import { useListQuery } from '../../providers/ListQuery/index.js' import { SelectionProvider } from '../../providers/Selection/index.js' +import { TableColumnsProvider } from '../../providers/TableColumns/index.js' import { useTranslation } from '../../providers/Translation/index.js' import { useWindowInfo } from '../../providers/WindowInfo/index.js' import { ListHeader } from './ListHeader/index.js' @@ -45,10 +45,13 @@ export function DefaultListView(props: ListViewClientProps) { Description, disableBulkDelete, disableBulkEdit, + disableQueryPresets, enableRowSelections, hasCreatePermission: hasCreatePermissionFromProps, listMenuItems, newDocumentURL, + queryPreset, + queryPresetPermissions, renderedFilters, resolvedFilterOptions, Table: InitialTable, @@ -189,7 +192,12 @@ export function DefaultListView(props: ListViewClientProps) { } collectionConfig={collectionConfig} collectionSlug={collectionSlug} + disableQueryPresets={ + collectionConfig?.enableQueryPresets !== true || disableQueryPresets + } listMenuItems={listMenuItems} + queryPreset={queryPreset} + queryPresetPermissions={queryPresetPermissions} renderedFilters={renderedFilters} resolvedFilterOptions={resolvedFilterOptions} /> diff --git a/test/admin/e2e/list-view/e2e.spec.ts b/test/admin/e2e/list-view/e2e.spec.ts index 4aeddcb2cd..796a21b3c8 100644 --- a/test/admin/e2e/list-view/e2e.spec.ts +++ b/test/admin/e2e/list-view/e2e.spec.ts @@ -392,7 +392,7 @@ describe('List View', () => { test('should reset filter value when a different field is selected', async () => { const id = (await page.locator('.cell-id').first().innerText()).replace('ID: ', '') - const whereBuilder = await addListFilter({ + const { whereBuilder } = await addListFilter({ page, fieldLabel: 'ID', operatorLabel: 'equals', @@ -416,7 +416,7 @@ describe('List View', () => { test('should remove condition from URL when value is cleared', async () => { await page.goto(postsUrl.list) - const whereBuilder = await addListFilter({ + const { whereBuilder } = await addListFilter({ page, fieldLabel: 'Relationship', operatorLabel: 'equals', @@ -431,16 +431,13 @@ describe('List View', () => { await whereBuilder.locator('.condition__value .clear-indicator').click() await page.waitForURL(new RegExp(encodedQueryString)) - }) - - test.skip('should remove condition from URL when a different field is selected', async () => { - // TODO: fix this bug and write this test + expect(true).toBe(true) }) test('should refresh relationship values when a different field is selected', async () => { await page.goto(postsUrl.list) - const whereBuilder = await addListFilter({ + const { whereBuilder } = await addListFilter({ page, fieldLabel: 'Relationship', operatorLabel: 'equals', @@ -600,7 +597,7 @@ describe('List View', () => { test('should reset filter values for every additional filter', async () => { await page.goto(postsUrl.list) - const whereBuilder = await addListFilter({ + const { whereBuilder } = await addListFilter({ page, fieldLabel: 'Tab 1 > Title', operatorLabel: 'equals', @@ -622,7 +619,7 @@ describe('List View', () => { test('should not re-render page upon typing in a value in the filter value field', async () => { await page.goto(postsUrl.list) - const whereBuilder = await addListFilter({ + const { whereBuilder } = await addListFilter({ page, fieldLabel: 'Tab 1 > Title', operatorLabel: 'equals', @@ -645,7 +642,7 @@ describe('List View', () => { test('should still show second filter if two filters exist and first filter is removed', async () => { await page.goto(postsUrl.list) - const whereBuilder = await addListFilter({ + const { whereBuilder } = await addListFilter({ page, fieldLabel: 'Tab 1 > Title', operatorLabel: 'equals', @@ -739,7 +736,7 @@ describe('List View', () => { test('should properly paginate many documents', async () => { await page.goto(with300DocumentsUrl.list) - const whereBuilder = await addListFilter({ + const { whereBuilder } = await addListFilter({ page, fieldLabel: 'Self Relation', operatorLabel: 'equals', diff --git a/test/fields-relationship/e2e.spec.ts b/test/fields-relationship/e2e.spec.ts index ef3d48d692..245709e55d 100644 --- a/test/fields-relationship/e2e.spec.ts +++ b/test/fields-relationship/e2e.spec.ts @@ -332,7 +332,7 @@ describe('Relationship Field', () => { // now ensure that the same filter options are applied in the list view await page.goto(url.list) - const whereBuilder = await addListFilter({ + const { whereBuilder } = await addListFilter({ page, fieldLabel: 'Relationship Filtered By Field', operatorLabel: 'equals', @@ -367,7 +367,7 @@ describe('Relationship Field', () => { // now ensure that the same filter options are applied in the list view await page.goto(url.list) - const whereBuilder = await addListFilter({ + const { whereBuilder } = await addListFilter({ page, fieldLabel: 'Collapsible > Nested Relationship Filtered By Field', operatorLabel: 'equals', diff --git a/test/fields/collections/Array/e2e.spec.ts b/test/fields/collections/Array/e2e.spec.ts index 72573dc97c..d65b67f986 100644 --- a/test/fields/collections/Array/e2e.spec.ts +++ b/test/fields/collections/Array/e2e.spec.ts @@ -114,7 +114,6 @@ describe('Array', () => { await expect(page.locator('#field-customArrayField__0__text')).toBeVisible() }) - test('should bypass min rows validation when no rows present and field is not required', async () => { await page.goto(url.create) await saveDocAndAssert(page) diff --git a/test/fields/collections/Text/e2e.spec.ts b/test/fields/collections/Text/e2e.spec.ts index 935c80cd6d..c5261ae944 100644 --- a/test/fields/collections/Text/e2e.spec.ts +++ b/test/fields/collections/Text/e2e.spec.ts @@ -79,7 +79,7 @@ describe('Text', () => { await expect(page.locator('.cell-hiddenTextField')).toBeHidden() await expect(page.locator('#heading-hiddenTextField')).toBeHidden() - const columnContainer = await openListColumns(page, {}) + const { columnContainer } = await openListColumns(page, {}) await expect( columnContainer.locator('.column-selector__column', { @@ -105,7 +105,7 @@ describe('Text', () => { await expect(page.locator('.cell-disabledTextField')).toBeHidden() await expect(page.locator('#heading-disabledTextField')).toBeHidden() - const columnContainer = await openListColumns(page, {}) + const { columnContainer } = await openListColumns(page, {}) await expect( columnContainer.locator('.column-selector__column', { @@ -133,7 +133,7 @@ describe('Text', () => { await expect(page.locator('.cell-adminHiddenTextField').first()).toBeVisible() await expect(page.locator('#heading-adminHiddenTextField')).toBeVisible() - const columnContainer = await openListColumns(page, {}) + const { columnContainer } = await openListColumns(page, {}) await expect( columnContainer.locator('.column-selector__column', { diff --git a/test/fields/payload-types.ts b/test/fields/payload-types.ts index 8a605cf6c0..b6babe2b1c 100644 --- a/test/fields/payload-types.ts +++ b/test/fields/payload-types.ts @@ -54,6 +54,7 @@ export type SupportedTimezones = | 'Asia/Singapore' | 'Asia/Tokyo' | 'Asia/Seoul' + | 'Australia/Brisbane' | 'Australia/Sydney' | 'Pacific/Guam' | 'Pacific/Noumea' diff --git a/test/helpers.ts b/test/helpers.ts index 6bb030183b..f5e830de46 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -245,7 +245,7 @@ export async function saveDocAndAssert( if (expectation === 'success') { await expect(page.locator('.payload-toast-container')).toContainText('successfully') - await expect.poll(() => page.url(), { timeout: POLL_TOPASS_TIMEOUT }).not.toContain('create') + await expect.poll(() => page.url(), { timeout: POLL_TOPASS_TIMEOUT }).not.toContain('/create') } else { await expect(page.locator('.payload-toast-container .toast-error')).toBeVisible() } diff --git a/test/helpers/e2e/addListFilter.ts b/test/helpers/e2e/addListFilter.ts index 3cc9dcd83f..d8f6e9e6f3 100644 --- a/test/helpers/e2e/addListFilter.ts +++ b/test/helpers/e2e/addListFilter.ts @@ -18,7 +18,9 @@ export const addListFilter = async ({ replaceExisting?: boolean skipValueInput?: boolean value?: string -}): Promise => { +}): Promise<{ + whereBuilder: Locator +}> => { await openListFilters(page, {}) const whereBuilder = page.locator('.where-builder') @@ -53,5 +55,5 @@ export const addListFilter = async ({ } } - return whereBuilder + return { whereBuilder } } diff --git a/test/helpers/e2e/openListColumns.ts b/test/helpers/e2e/openListColumns.ts index a9664e58cd..2377920756 100644 --- a/test/helpers/e2e/openListColumns.ts +++ b/test/helpers/e2e/openListColumns.ts @@ -1,4 +1,4 @@ -import type { Page } from '@playwright/test' +import type { Locator, Page } from '@playwright/test' import { expect } from '@playwright/test' @@ -11,7 +11,9 @@ export const openListColumns = async ( columnContainerSelector?: string togglerSelector?: string }, -): Promise => { +): Promise<{ + columnContainer: Locator +}> => { const columnContainer = page.locator(columnContainerSelector).first() const isAlreadyOpen = await columnContainer.isVisible() @@ -22,5 +24,5 @@ export const openListColumns = async ( await expect(page.locator(`${columnContainerSelector}.rah-static--height-auto`)).toBeVisible() - return columnContainer + return { columnContainer } } diff --git a/test/helpers/e2e/openListFilters.ts b/test/helpers/e2e/openListFilters.ts index 3533195181..5598e6683c 100644 --- a/test/helpers/e2e/openListFilters.ts +++ b/test/helpers/e2e/openListFilters.ts @@ -1,4 +1,4 @@ -import type { Page } from '@playwright/test' +import type { Locator, Page } from '@playwright/test' import { expect } from '@playwright/test' @@ -11,10 +11,12 @@ export const openListFilters = async ( filterContainerSelector?: string togglerSelector?: string }, -) => { - const columnContainer = page.locator(filterContainerSelector).first() +): Promise<{ + filterContainer: Locator +}> => { + const filterContainer = page.locator(filterContainerSelector).first() - const isAlreadyOpen = await columnContainer.isVisible() + const isAlreadyOpen = await filterContainer.isVisible() if (!isAlreadyOpen) { await page.locator(togglerSelector).first().click() @@ -22,5 +24,5 @@ export const openListFilters = async ( await expect(page.locator(`${filterContainerSelector}.rah-static--height-auto`)).toBeVisible() - return columnContainer + return { filterContainer } } diff --git a/test/helpers/e2e/toggleColumn.ts b/test/helpers/e2e/toggleColumn.ts index 442ddea1d9..eb57bf2421 100644 --- a/test/helpers/e2e/toggleColumn.ts +++ b/test/helpers/e2e/toggleColumn.ts @@ -1,4 +1,4 @@ -import type { Page } from '@playwright/test' +import type { Locator, Page } from '@playwright/test' import { expect } from '@playwright/test' @@ -22,8 +22,13 @@ export const toggleColumn = async ( targetState?: 'off' | 'on' togglerSelector?: string }, -): Promise => { - const columnContainer = await openListColumns(page, { togglerSelector, columnContainerSelector }) +): Promise<{ + columnContainer: Locator +}> => { + const { columnContainer } = await openListColumns(page, { + togglerSelector, + columnContainerSelector, + }) const column = columnContainer.locator(`.column-selector .column-selector__column`, { hasText: exactText(columnLabel), @@ -57,7 +62,7 @@ export const toggleColumn = async ( await waitForColumnInURL({ page, columnName, state: targetState }) } - return column + return { columnContainer } } export const waitForColumnInURL = async ({ diff --git a/test/helpers/e2e/toggleListMenu.ts b/test/helpers/e2e/toggleListMenu.ts new file mode 100644 index 0000000000..a91d961b81 --- /dev/null +++ b/test/helpers/e2e/toggleListMenu.ts @@ -0,0 +1,26 @@ +import type { Page } from '@playwright/test' + +import { expect } from '@playwright/test' +import { exactText } from 'helpers.js' + +export async function openListMenu({ page }: { page: Page }) { + const listMenu = page.locator('#list-menu') + await listMenu.locator('button.popup-button').click() + await expect(listMenu.locator('.popup__content')).toBeVisible() +} + +export async function clickListMenuItem({ + page, + menuItemLabel, +}: { + menuItemLabel: string + page: Page +}) { + await openListMenu({ page }) + + const menuItem = page.locator('.popup__content').locator('button', { + hasText: exactText(menuItemLabel), + }) + + await menuItem.click() +} diff --git a/test/helpers/sdk/types.ts b/test/helpers/sdk/types.ts index 79bf3500cc..0a6de84d0d 100644 --- a/test/helpers/sdk/types.ts +++ b/test/helpers/sdk/types.ts @@ -75,7 +75,7 @@ export type UpdateManyArgs< TSlug extends keyof TGeneratedTypes['collections'], > = { id: never - where?: WhereField + where?: Where } & UpdateBaseArgs export type UpdateBaseArgs< diff --git a/test/locked-documents/collections/Pages/index.ts b/test/locked-documents/collections/Pages/index.ts index 96416b26a6..fa0301ed36 100644 --- a/test/locked-documents/collections/Pages/index.ts +++ b/test/locked-documents/collections/Pages/index.ts @@ -1,6 +1,6 @@ import type { CollectionConfig } from 'payload' -export const pagesSlug = 'pages' +import { pagesSlug } from '../../slugs.js' export const PagesCollection: CollectionConfig = { slug: pagesSlug, diff --git a/test/locked-documents/collections/Posts/index.ts b/test/locked-documents/collections/Posts/index.ts index 02eb7a89f1..18f2c757a6 100644 --- a/test/locked-documents/collections/Posts/index.ts +++ b/test/locked-documents/collections/Posts/index.ts @@ -1,6 +1,6 @@ import type { CollectionConfig } from 'payload' -export const postsSlug = 'posts' +import { postsSlug } from '../../slugs.js' export const PostsCollection: CollectionConfig = { slug: postsSlug, diff --git a/test/locked-documents/collections/Users/index.ts b/test/locked-documents/collections/Users/index.ts index 7fe7f5e6c9..136bea72e1 100644 --- a/test/locked-documents/collections/Users/index.ts +++ b/test/locked-documents/collections/Users/index.ts @@ -1,7 +1,9 @@ import type { CollectionConfig } from 'payload' +import { usersSlug } from '../../slugs.js' + export const Users: CollectionConfig = { - slug: 'users', + slug: usersSlug, admin: { useAsTitle: 'name', }, diff --git a/test/locked-documents/config.ts b/test/locked-documents/config.ts index 0fe077fb52..1967cb3e17 100644 --- a/test/locked-documents/config.ts +++ b/test/locked-documents/config.ts @@ -2,13 +2,13 @@ import { fileURLToPath } from 'node:url' import path from 'path' import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' -import { devUser, regularUser } from '../credentials.js' -import { PagesCollection, pagesSlug } from './collections/Pages/index.js' -import { PostsCollection, postsSlug } from './collections/Posts/index.js' +import { PagesCollection } from './collections/Pages/index.js' +import { PostsCollection } from './collections/Posts/index.js' import { TestsCollection } from './collections/Tests/index.js' import { Users } from './collections/Users/index.js' import { AdminGlobal } from './globals/Admin/index.js' import { MenuGlobal } from './globals/Menu/index.js' +import { seed } from './seed.js' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) @@ -23,39 +23,7 @@ export default buildConfigWithDefaults({ globals: [AdminGlobal, MenuGlobal], onInit: async (payload) => { if (process.env.SEED_IN_CONFIG_ONINIT !== 'false') { - await payload.create({ - collection: 'users', - data: { - email: devUser.email, - password: devUser.password, - name: 'Admin', - roles: ['is_admin', 'is_user'], - }, - }) - - await payload.create({ - collection: 'users', - data: { - email: regularUser.email, - password: regularUser.password, - name: 'Dev', - roles: ['is_user'], - }, - }) - - await payload.create({ - collection: pagesSlug, - data: { - text: 'example page', - }, - }) - - await payload.create({ - collection: postsSlug, - data: { - text: 'example post', - }, - }) + await seed(payload) } }, typescript: { diff --git a/test/locked-documents/int.spec.ts b/test/locked-documents/int.spec.ts index 5c0bc9c4bf..560569104b 100644 --- a/test/locked-documents/int.spec.ts +++ b/test/locked-documents/int.spec.ts @@ -5,35 +5,29 @@ import { Locked, NotFound } from 'payload' import { wait } from 'payload/shared' import { fileURLToPath } from 'url' -import type { NextRESTClient } from '../helpers/NextRESTClient.js' -import type { Menu, Page, Post, User } from './payload-types.js' +import type { Post, User } from './payload-types.js' import { devUser } from '../credentials.js' import { initPayloadInt } from '../helpers/initPayloadInt.js' -import { pagesSlug } from './collections/Pages/index.js' -import { postsSlug } from './collections/Posts/index.js' import { menuSlug } from './globals/Menu/index.js' +import { pagesSlug, postsSlug } from './slugs.js' const lockedDocumentCollection = 'payload-locked-documents' let payload: Payload -let token: string -let restClient: NextRESTClient const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) describe('Locked documents', () => { let post: Post - let page: Page - let menu: Menu let user: any let user2: any let postConfig: SanitizedCollectionConfig beforeAll(async () => { // @ts-expect-error: initPayloadInt does not have a proper type definition - ;({ payload, restClient } = await initPayloadInt(dirname)) + ;({ payload } = await initPayloadInt(dirname)) postConfig = payload.config.collections.find( ({ slug }) => slug === postsSlug, @@ -49,8 +43,6 @@ describe('Locked documents', () => { user = loginResult.user - token = loginResult.token as string - user2 = await payload.create({ collection: 'users', data: { @@ -66,14 +58,14 @@ describe('Locked documents', () => { }, }) - page = await payload.create({ + await payload.create({ collection: pagesSlug, data: { text: 'some page', }, }) - menu = await payload.updateGlobal({ + await payload.updateGlobal({ slug: menuSlug, data: { globalText: 'global text', diff --git a/test/locked-documents/seed.ts b/test/locked-documents/seed.ts new file mode 100644 index 0000000000..0a7f578f59 --- /dev/null +++ b/test/locked-documents/seed.ts @@ -0,0 +1,57 @@ +import type { Payload } from 'payload' + +import { devUser, regularUser } from '../credentials.js' +import { executePromises } from '../helpers/executePromises.js' +import { seedDB } from '../helpers/seed.js' +import { collectionSlugs, pagesSlug, postsSlug } from './slugs.js' + +export const seed = async (_payload: Payload) => { + await executePromises( + [ + () => + _payload.create({ + collection: 'users', + data: { + email: devUser.email, + password: devUser.password, + name: 'Admin', + roles: ['is_admin', 'is_user'], + }, + }), + () => + _payload.create({ + collection: 'users', + data: { + email: regularUser.email, + password: regularUser.password, + name: 'Dev', + roles: ['is_user'], + }, + }), + () => + _payload.create({ + collection: pagesSlug, + data: { + text: 'example page', + }, + }), + () => + _payload.create({ + collection: postsSlug, + data: { + text: 'example post', + }, + }), + ], + false, + ) +} + +export async function clearAndSeedEverything(_payload: Payload) { + return await seedDB({ + _payload, + collectionSlugs, + seedFunction: seed, + snapshotKey: 'adminTests', + }) +} diff --git a/test/locked-documents/slugs.ts b/test/locked-documents/slugs.ts new file mode 100644 index 0000000000..227969b836 --- /dev/null +++ b/test/locked-documents/slugs.ts @@ -0,0 +1,7 @@ +export const pagesSlug = 'pages' + +export const postsSlug = 'posts' + +export const usersSlug = 'users' + +export const collectionSlugs = [pagesSlug, postsSlug, usersSlug] diff --git a/test/query-presets/.gitignore b/test/query-presets/.gitignore new file mode 100644 index 0000000000..cce01755f4 --- /dev/null +++ b/test/query-presets/.gitignore @@ -0,0 +1,2 @@ +/media +/media-gif diff --git a/test/query-presets/collections/Pages/index.ts b/test/query-presets/collections/Pages/index.ts new file mode 100644 index 0000000000..7bd8a3659a --- /dev/null +++ b/test/query-presets/collections/Pages/index.ts @@ -0,0 +1,21 @@ +import type { CollectionConfig } from 'payload' + +import { pagesSlug } from '../../slugs.js' + +export const Pages: CollectionConfig = { + slug: pagesSlug, + admin: { + useAsTitle: 'text', + }, + enableQueryPresets: true, + lockDocuments: false, + fields: [ + { + name: 'text', + type: 'text', + }, + ], + versions: { + drafts: true, + }, +} diff --git a/test/query-presets/collections/Users/index.ts b/test/query-presets/collections/Users/index.ts new file mode 100644 index 0000000000..2d13acb813 --- /dev/null +++ b/test/query-presets/collections/Users/index.ts @@ -0,0 +1,19 @@ +import type { CollectionConfig } from 'payload' + +import { roles } from '../../fields/roles.js' +import { usersSlug } from '../../slugs.js' + +export const Users: CollectionConfig = { + slug: usersSlug, + admin: { + useAsTitle: 'name', + }, + auth: true, + fields: [ + { + name: 'name', + type: 'text', + }, + roles, + ], +} diff --git a/test/query-presets/config.ts b/test/query-presets/config.ts new file mode 100644 index 0000000000..bf0e4d4e05 --- /dev/null +++ b/test/query-presets/config.ts @@ -0,0 +1,66 @@ +import { fileURLToPath } from 'node:url' +import path from 'path' + +import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' +import { Pages } from './collections/Pages/index.js' +import { Users } from './collections/Users/index.js' +import { roles } from './fields/roles.js' +import { seed } from './seed.js' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfigWithDefaults({ + admin: { + importMap: { + baseDir: path.resolve(dirname), + }, + }, + queryPresets: { + // labels: { + // singular: 'Report', + // plural: 'Reports', + // }, + access: { + read: ({ req: { user } }) => + user ? !user?.roles?.some((role) => role === 'anonymous') : false, + update: ({ req: { user } }) => + user ? !user?.roles?.some((role) => role === 'anonymous') : false, + }, + constraints: { + read: [ + { + label: 'Specific Roles', + value: 'specificRoles', + fields: [roles], + access: ({ req: { user } }) => ({ + 'access.read.roles': { + in: user?.roles || [], + }, + }), + }, + ], + update: [ + { + label: 'Specific Roles', + value: 'specificRoles', + fields: [roles], + access: ({ req: { user } }) => ({ + 'access.update.roles': { + in: user?.roles || [], + }, + }), + }, + ], + }, + }, + collections: [Pages, Users], + onInit: async (payload) => { + if (process.env.SEED_IN_CONFIG_ONINIT !== 'false') { + await seed(payload) + } + }, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, +}) diff --git a/test/query-presets/e2e.spec.ts b/test/query-presets/e2e.spec.ts new file mode 100644 index 0000000000..30c19de3d4 --- /dev/null +++ b/test/query-presets/e2e.spec.ts @@ -0,0 +1,392 @@ +import type { BrowserContext, Page } from '@playwright/test' + +import { expect, test } from '@playwright/test' +import { devUser } from 'credentials.js' +import { openListColumns } from 'helpers/e2e/openListColumns.js' +import { toggleColumn } from 'helpers/e2e/toggleColumn.js' +import * as path from 'path' +import { fileURLToPath } from 'url' + +import type { PayloadTestSDK } from '../helpers/sdk/index.js' +import type { Config } from './payload-types.js' + +import { + ensureCompilationIsDone, + exactText, + initPageConsoleErrorCatch, + saveDocAndAssert, + // throttleTest, +} from '../helpers.js' +import { AdminUrlUtil } from '../helpers/adminUrlUtil.js' +import { clickListMenuItem, openListMenu } from '../helpers/e2e/toggleListMenu.js' +import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' +import { TEST_TIMEOUT_LONG } from '../playwright.config.js' +import { assertURLParams } from './helpers/assertURLParams.js' +import { openQueryPresetDrawer } from './helpers/openQueryPresetDrawer.js' +import { clearSelectedPreset, selectPreset } from './helpers/togglePreset.js' +import { seedData } from './seed.js' +import { pagesSlug } from './slugs.js' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +const { beforeAll, describe, beforeEach } = test + +let page: Page +let pagesUrl: AdminUrlUtil +let payload: PayloadTestSDK +let serverURL: string +let everyoneID: string | undefined +let context: BrowserContext +let user: any + +describe('Query Presets', () => { + beforeAll(async ({ browser }, testInfo) => { + testInfo.setTimeout(TEST_TIMEOUT_LONG) + ;({ payload, serverURL } = await initPayloadE2ENoConfig({ dirname })) + + pagesUrl = new AdminUrlUtil(serverURL, pagesSlug) + + context = await browser.newContext() + page = await context.newPage() + + user = await payload + .login({ + collection: 'users', + data: { + email: devUser.email, + password: devUser.password, + }, + }) + ?.then((res) => res.user) // TODO: this type is wrong + + initPageConsoleErrorCatch(page) + + await ensureCompilationIsDone({ page, serverURL }) + }) + + beforeEach(async () => { + // await throttleTest({ + // page, + // context, + // delay: 'Fast 4G', + // }) + + // clear and reseed everything + try { + await payload.delete({ + collection: 'payload-query-presets', + where: { + id: { + exists: true, + }, + }, + }) + + const [, everyone] = await Promise.all([ + payload.delete({ + collection: 'payload-preferences', + where: { + and: [ + { + key: { equals: 'pages-list' }, + }, + { + 'user.relationTo': { + equals: 'users', + }, + }, + { + 'user.value': { + equals: user.id, + }, + }, + ], + }, + }), + payload.create({ + collection: 'payload-query-presets', + data: seedData.everyone, + }), + payload.create({ + collection: 'payload-query-presets', + data: seedData.onlyMe, + }), + payload.create({ + collection: 'payload-query-presets', + data: seedData.specificUsers({ userID: user?.id || '' }), + }), + ]) + + everyoneID = everyone.id + } catch (error) { + console.error('Error in beforeEach:', error) + } + }) + + test('should select preset and apply filters', async () => { + await page.goto(pagesUrl.list) + await selectPreset({ page, presetTitle: seedData.everyone.title }) + + await assertURLParams({ + page, + columns: seedData.everyone.columns, + where: seedData.everyone.where, + presetID: everyoneID, + }) + + expect(true).toBe(true) + }) + + test('should clear selected preset and reset filters', async () => { + await page.goto(pagesUrl.list) + await selectPreset({ page, presetTitle: seedData.everyone.title }) + await clearSelectedPreset({ page }) + expect(true).toBe(true) + }) + + test('should delete a preset, clear selection, and reset changes', async () => { + await page.goto(pagesUrl.list) + await selectPreset({ page, presetTitle: seedData.everyone.title }) + await openListMenu({ page }) + + await clickListMenuItem({ page, menuItemLabel: 'Delete' }) + + await page.locator('#confirm-delete-preset #confirm-action').click() + + const regex = /columns=/ + + await page.waitForURL((url) => !regex.test(url.search), { + timeout: TEST_TIMEOUT_LONG, + }) + + await expect( + page.locator('button#select-preset', { + hasText: exactText('Select Preset'), + }), + ).toBeVisible() + + await openQueryPresetDrawer({ page }) + const modal = page.locator('[id^=list-drawer_0_]') + await expect(modal).toBeVisible() + + await expect( + modal.locator('tbody tr td button', { + hasText: exactText(seedData.everyone.title), + }), + ).toBeHidden() + }) + + test('should save last used preset to preferences and load on initial render', async () => { + await page.goto(pagesUrl.list) + await selectPreset({ page, presetTitle: seedData.everyone.title }) + + await page.reload() + + await assertURLParams({ + page, + columns: seedData.everyone.columns, + where: seedData.everyone.where, + // presetID: everyoneID, + }) + + expect(true).toBe(true) + }) + + test('should only show "edit" and "delete" controls when there is an active preset', async () => { + await page.goto(pagesUrl.list) + await openListMenu({ page }) + + await expect( + page.locator('#list-menu .popup__content .popup-button-list__button', { + hasText: exactText('Edit'), + }), + ).toBeHidden() + + await expect( + page.locator('#list-menu .popup__content .popup-button-list__button', { + hasText: exactText('Delete'), + }), + ).toBeHidden() + + await selectPreset({ page, presetTitle: seedData.everyone.title }) + + await openListMenu({ page }) + + await expect( + page.locator('#list-menu .popup__content .popup-button-list__button', { + hasText: exactText('Edit'), + }), + ).toBeVisible() + + await expect( + page.locator('#list-menu .popup__content .popup-button-list__button', { + hasText: exactText('Delete'), + }), + ).toBeVisible() + }) + + test('should only show "reset" and "save" controls when there is an active preset and changes have been made', async () => { + await page.goto(pagesUrl.list) + + await openListMenu({ page }) + + await expect( + page.locator('#list-menu .popup__content .popup-button-list__button', { + hasText: exactText('Reset'), + }), + ).toBeHidden() + + await expect( + page.locator('#list-menu .popup__content .popup-button-list__button', { + hasText: exactText('Update for everyone'), + }), + ).toBeHidden() + + await expect( + page.locator('#list-menu .popup__content .popup-button-list__button', { + hasText: exactText('Save'), + }), + ).toBeHidden() + + await selectPreset({ page, presetTitle: seedData.onlyMe.title }) + + await toggleColumn(page, { columnLabel: 'ID' }) + + await openListMenu({ page }) + + await expect( + page.locator('#list-menu .popup__content .popup-button-list__button', { + hasText: exactText('Reset'), + }), + ).toBeVisible() + + await expect( + page.locator('#list-menu .popup__content .popup-button-list__button', { + hasText: exactText('Save'), + }), + ).toBeVisible() + }) + + test('should conditionally render "update for everyone" label based on if preset is shared', async () => { + await page.goto(pagesUrl.list) + + await selectPreset({ page, presetTitle: seedData.onlyMe.title }) + + await toggleColumn(page, { columnLabel: 'ID' }) + + await openListMenu({ page }) + + // When not shared, the label is "Save" + await expect( + page.locator('#list-menu .popup__content .popup-button-list__button', { + hasText: exactText('Save'), + }), + ).toBeVisible() + + await selectPreset({ page, presetTitle: seedData.everyone.title }) + + await toggleColumn(page, { columnLabel: 'ID' }) + + await openListMenu({ page }) + + // When shared, the label is "Update for everyone" + await expect( + page.locator('#list-menu .popup__content .popup-button-list__button', { + hasText: exactText('Update for everyone'), + }), + ).toBeVisible() + }) + + test('should reset active changes', async () => { + await page.goto(pagesUrl.list) + await selectPreset({ page, presetTitle: seedData.everyone.title }) + + const { columnContainer } = await toggleColumn(page, { columnLabel: 'ID' }) + + const column = columnContainer.locator(`.column-selector .column-selector__column`, { + hasText: exactText('ID'), + }) + + await openListMenu({ page }) + await clickListMenuItem({ page, menuItemLabel: 'Reset' }) + + await openListColumns(page, {}) + await expect(column).toHaveClass(/column-selector__column--active/) + }) + + test('should only enter modified state when changes are made to an active preset', async () => { + await page.goto(pagesUrl.list) + await expect(page.locator('.list-controls__modified')).toBeHidden() + await selectPreset({ page, presetTitle: seedData.everyone.title }) + await expect(page.locator('.list-controls__modified')).toBeHidden() + await toggleColumn(page, { columnLabel: 'ID' }) + await expect(page.locator('.list-controls__modified')).toBeVisible() + await openListMenu({ page }) + await clickListMenuItem({ page, menuItemLabel: 'Update for everyone' }) + await expect(page.locator('.list-controls__modified')).toBeHidden() + await toggleColumn(page, { columnLabel: 'ID' }) + await expect(page.locator('.list-controls__modified')).toBeVisible() + await openListMenu({ page }) + await clickListMenuItem({ page, menuItemLabel: 'Reset' }) + await expect(page.locator('.list-controls__modified')).toBeHidden() + }) + + test('can edit a preset through the document drawer', async () => { + const presetTitle = 'New Preset' + + await page.goto(pagesUrl.list) + + await selectPreset({ page, presetTitle: seedData.everyone.title }) + await clickListMenuItem({ page, menuItemLabel: 'Edit' }) + + const drawer = page.locator('[id^=doc-drawer_payload-query-presets_0_]') + const titleValue = drawer.locator('input[name="title"]') + await expect(titleValue).toHaveValue(seedData.everyone.title) + + const newTitle = `${seedData.everyone.title} (Updated)` + await drawer.locator('input[name="title"]').fill(newTitle) + + await saveDocAndAssert(page) + + await drawer.locator('button.doc-drawer__header-close').click() + await expect(drawer).toBeHidden() + + await expect(page.locator('button#select-preset')).toHaveText(newTitle) + }) + + test('should not display query presets when admin.enableQueryPresets is not true', async () => { + // go to users list view and ensure the query presets select is not visible + const usersURL = new AdminUrlUtil(serverURL, 'users') + await page.goto(usersURL.list) + await expect(page.locator('#select-preset')).toBeHidden() + }) + + // eslint-disable-next-line playwright/no-skipped-test, playwright/expect-expect + test.skip('can save a preset', () => { + // select a preset, make a change to the presets, click "save for everyone" or "save", and ensure the changes persist + }) + + test('can create new preset', async () => { + await page.goto(pagesUrl.list) + + const presetTitle = 'New Preset' + + await clickListMenuItem({ page, menuItemLabel: 'Create New' }) + const modal = page.locator('[id^=doc-drawer_payload-query-presets_0_]') + await expect(modal).toBeVisible() + await modal.locator('input[name="title"]').fill(presetTitle) + + const currentURL = page.url() + await saveDocAndAssert(page) + await expect(modal).toBeHidden() + + await page.waitForURL(() => page.url() !== currentURL) + + await expect( + page.locator('button#select-preset', { + hasText: exactText(presetTitle), + }), + ).toBeVisible() + }) +}) diff --git a/test/query-presets/eslint.config.js b/test/query-presets/eslint.config.js new file mode 100644 index 0000000000..d7ebe5c4d3 --- /dev/null +++ b/test/query-presets/eslint.config.js @@ -0,0 +1,23 @@ +import { rootParserOptions } from '../../eslint.config.js' +import { testEslintConfig } from '../eslint.config.js' + +/** @typedef {import('eslint').Linter.Config} Config */ + +/** @type {Config[]} */ +export const index = [ + ...testEslintConfig, + { + languageOptions: { + parserOptions: { + projectService: { + allowDefaultProject: ['./*.ts', './*.tsx'], + defaultProject: './tsconfig.json', + }, + tsconfigDirName: import.meta.dirname, + ...rootParserOptions, + }, + }, + }, +] + +export default index diff --git a/test/query-presets/fields/roles.ts b/test/query-presets/fields/roles.ts new file mode 100644 index 0000000000..ad5ff3a66c --- /dev/null +++ b/test/query-presets/fields/roles.ts @@ -0,0 +1,21 @@ +import type { Field } from 'payload' + +export const roles: Field = { + name: 'roles', + type: 'select', + hasMany: true, + options: [ + { + label: 'Admin', + value: 'admin', + }, + { + label: 'User', + value: 'user', + }, + { + label: 'Anonymous', + value: 'anonymous', + }, + ], +} diff --git a/test/query-presets/helpers/assertURLParams.ts b/test/query-presets/helpers/assertURLParams.ts new file mode 100644 index 0000000000..2e9bf1b166 --- /dev/null +++ b/test/query-presets/helpers/assertURLParams.ts @@ -0,0 +1,39 @@ +import type { Page } from '@playwright/test' +import type { ColumnPreference, Where } from 'payload' + +// import { transformColumnsToSearchParams, transformWhereQuery } from 'payload/shared' +// import * as qs from 'qs-esm' + +import { transformColumnsToSearchParams } from 'payload/shared' + +export async function assertURLParams({ + page, + columns, + where, + presetID, +}: { + columns?: ColumnPreference[] + page: Page + presetID?: string | undefined + where: Where +}) { + if (where) { + // TODO: can't get columns to encode correctly + // const whereQuery = qs.stringify(transformWhereQuery(where)) + // const encodedWhere = encodeURIComponent(whereQuery) + } + + if (columns) { + const escapedColumns = encodeURIComponent( + JSON.stringify(transformColumnsToSearchParams(columns)), + ) + + const columnsRegex = new RegExp(`columns=${escapedColumns}`) + await page.waitForURL(columnsRegex) + } + + if (presetID) { + const presetRegex = new RegExp(`preset=${presetID}`) + await page.waitForURL(presetRegex) + } +} diff --git a/test/query-presets/helpers/openQueryPresetDrawer.ts b/test/query-presets/helpers/openQueryPresetDrawer.ts new file mode 100644 index 0000000000..e9c5db1f1a --- /dev/null +++ b/test/query-presets/helpers/openQueryPresetDrawer.ts @@ -0,0 +1,5 @@ +import type { Page } from '@playwright/test' + +export async function openQueryPresetDrawer({ page }: { page: Page }) { + await page.click('button#select-preset') +} diff --git a/test/query-presets/helpers/togglePreset.ts b/test/query-presets/helpers/togglePreset.ts new file mode 100644 index 0000000000..258c2b0702 --- /dev/null +++ b/test/query-presets/helpers/togglePreset.ts @@ -0,0 +1,53 @@ +import type { Page } from '@playwright/test' + +import { expect } from '@playwright/test' +import { exactText } from 'helpers.js' +import { TEST_TIMEOUT_LONG } from 'playwright.config.js' + +import { openQueryPresetDrawer } from './openQueryPresetDrawer.js' + +export async function selectPreset({ page, presetTitle }: { page: Page; presetTitle: string }) { + await openQueryPresetDrawer({ page }) + const modal = page.locator('[id^=list-drawer_0_]') + await expect(modal).toBeVisible() + + const currentURL = page.url() + + await modal + .locator('tbody tr td button', { + hasText: exactText(presetTitle), + }) + .first() + .click() + + await page.waitForURL(() => page.url() !== currentURL) + + await expect( + page.locator('button#select-preset', { + hasText: exactText(presetTitle), + }), + ).toBeVisible() +} + +export async function clearSelectedPreset({ page }: { page: Page }) { + const queryPresetsControl = page.locator('button#select-preset') + const clearButton = queryPresetsControl.locator('#clear-preset') + + if (await clearButton.isVisible()) { + await clearButton.click() + } + + const regex = /columns=/ + + await page.waitForURL((url) => !regex.test(url.search), { + timeout: TEST_TIMEOUT_LONG, + }) + + await expect(queryPresetsControl.locator('#clear-preset')).toBeHidden() + + await expect( + page.locator('button#select-preset', { + hasText: exactText('Select Preset'), + }), + ).toBeVisible() +} diff --git a/test/query-presets/int.spec.ts b/test/query-presets/int.spec.ts new file mode 100644 index 0000000000..3fba8f4f65 --- /dev/null +++ b/test/query-presets/int.spec.ts @@ -0,0 +1,568 @@ +import type { NextRESTClient } from 'helpers/NextRESTClient.js' +import type { Payload, User } from 'payload' + +import path from 'path' +import { fileURLToPath } from 'url' + +import { devUser, regularUser } from '../credentials.js' +import { initPayloadInt } from '../helpers/initPayloadInt.js' + +const queryPresetsCollectionSlug = 'payload-query-presets' + +let payload: Payload +let restClient: NextRESTClient +let user: User +let user2: User +let anonymousUser: User + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +describe('Query Presets', () => { + beforeAll(async () => { + // @ts-expect-error: initPayloadInt does not have a proper type definition + ;({ payload, restClient } = await initPayloadInt(dirname)) + + user = await payload + .login({ + collection: 'users', + data: { + email: devUser.email, + password: devUser.password, + }, + }) + ?.then((result) => result.user) + + user2 = await payload + .login({ + collection: 'users', + data: { + email: regularUser.email, + password: regularUser.password, + }, + }) + ?.then((result) => result.user) + + anonymousUser = await payload + .login({ + collection: 'users', + data: { + email: 'anonymous@email.com', + password: regularUser.password, + }, + }) + ?.then((result) => result.user) + }) + + afterAll(async () => { + if (typeof payload.db.destroy === 'function') { + await payload.db.destroy() + } + }) + + describe('default access control', () => { + it('should only allow logged in users to perform actions', async () => { + // create + try { + const result = await payload.create({ + collection: queryPresetsCollectionSlug, + user: undefined, + overrideAccess: false, + data: { + title: 'Only Logged In Users', + relatedCollection: 'pages', + }, + }) + + expect(result).toBeFalsy() + } catch (error: unknown) { + expect((error as Error).message).toBe('You are not allowed to perform this action.') + } + + const { id } = await payload.create({ + collection: queryPresetsCollectionSlug, + data: { + title: 'Only Logged In Users', + relatedCollection: 'pages', + }, + }) + + // read + try { + const result = await payload.findByID({ + collection: queryPresetsCollectionSlug, + depth: 0, + user: undefined, + overrideAccess: false, + id, + }) + + expect(result).toBeFalsy() + } catch (error: unknown) { + expect((error as Error).message).toBe('You are not allowed to perform this action.') + } + + // update + try { + const result = await payload.update({ + collection: queryPresetsCollectionSlug, + id, + user: undefined, + overrideAccess: false, + data: { + title: 'Only Logged In Users (Updated)', + }, + }) + + expect(result).toBeFalsy() + } catch (error: unknown) { + expect((error as Error).message).toBe('You are not allowed to perform this action.') + + // make sure the update didn't go through + const preset = await payload.findByID({ + collection: queryPresetsCollectionSlug, + depth: 0, + id, + }) + + expect(preset.title).toBe('Only Logged In Users') + } + + // delete + try { + const result = await payload.delete({ + collection: queryPresetsCollectionSlug, + id: 'some-id', + user: undefined, + overrideAccess: false, + }) + + expect(result).toBeFalsy() + } catch (error: unknown) { + expect((error as Error).message).toBe('You are not allowed to perform this action.') + + // make sure the delete didn't go through + const preset = await payload.findByID({ + collection: queryPresetsCollectionSlug, + depth: 0, + id, + }) + + expect(preset.title).toBe('Only Logged In Users') + } + }) + + it('should respect access when set to "specificUsers"', async () => { + const presetForSpecificUsers = await payload.create({ + collection: queryPresetsCollectionSlug, + user, + data: { + title: 'Specific Users', + where: { + text: { + equals: 'example page', + }, + }, + access: { + read: { + constraint: 'specificUsers', + users: [user.id], + }, + update: { + constraint: 'specificUsers', + users: [user.id], + }, + }, + relatedCollection: 'pages', + }, + }) + + const foundPresetWithUser1 = await payload.findByID({ + collection: queryPresetsCollectionSlug, + depth: 0, + user, + overrideAccess: false, + id: presetForSpecificUsers.id, + }) + + expect(foundPresetWithUser1.id).toBe(presetForSpecificUsers.id) + + try { + const foundPresetWithUser2 = await payload.findByID({ + collection: queryPresetsCollectionSlug, + depth: 0, + user: user2, + overrideAccess: false, + id: presetForSpecificUsers.id, + }) + + expect(foundPresetWithUser2).toBeFalsy() + } catch (error: unknown) { + expect((error as Error).message).toBe('Not Found') + } + + const presetUpdatedByUser1 = await payload.update({ + collection: queryPresetsCollectionSlug, + id: presetForSpecificUsers.id, + user, + overrideAccess: false, + data: { + title: 'Specific Users (Updated)', + }, + }) + + expect(presetUpdatedByUser1.title).toBe('Specific Users (Updated)') + + try { + const presetUpdatedByUser2 = await payload.update({ + collection: queryPresetsCollectionSlug, + id: presetForSpecificUsers.id, + user: user2, + overrideAccess: false, + data: { + title: 'Specific Users (Updated)', + }, + }) + + expect(presetUpdatedByUser2).toBeFalsy() + } catch (error: unknown) { + expect((error as Error).message).toBe('You are not allowed to perform this action.') + } + }) + + it('should respect access when set to "onlyMe"', async () => { + // create a new doc so that the creating user is the owner + const presetForOnlyMe = await payload.create({ + collection: queryPresetsCollectionSlug, + user, + data: { + title: 'Only Me', + where: { + text: { + equals: 'example page', + }, + }, + access: { + read: { + constraint: 'onlyMe', + }, + update: { + constraint: 'onlyMe', + }, + }, + relatedCollection: 'pages', + }, + }) + + const foundPresetWithUser1 = await payload.findByID({ + collection: queryPresetsCollectionSlug, + depth: 0, + user, + overrideAccess: false, + id: presetForOnlyMe.id, + }) + + expect(foundPresetWithUser1.id).toBe(presetForOnlyMe.id) + + try { + const foundPresetWithUser2 = await payload.findByID({ + collection: queryPresetsCollectionSlug, + depth: 0, + user: user2, + overrideAccess: false, + id: presetForOnlyMe.id, + }) + + expect(foundPresetWithUser2).toBeFalsy() + } catch (error: unknown) { + expect((error as Error).message).toBe('Not Found') + } + + const presetUpdatedByUser1 = await payload.update({ + collection: queryPresetsCollectionSlug, + id: presetForOnlyMe.id, + user, + overrideAccess: false, + data: { + title: 'Only Me (Updated)', + }, + }) + + expect(presetUpdatedByUser1.title).toBe('Only Me (Updated)') + + try { + const presetUpdatedByUser2 = await payload.update({ + collection: queryPresetsCollectionSlug, + id: presetForOnlyMe.id, + user: user2, + overrideAccess: false, + data: { + title: 'Only Me (Updated)', + }, + }) + + expect(presetUpdatedByUser2).toBeFalsy() + } catch (error: unknown) { + expect((error as Error).message).toBe('You are not allowed to perform this action.') + } + }) + + it('should respect access when set to "everyone"', async () => { + const presetForEveryone = await payload.create({ + collection: queryPresetsCollectionSlug, + user, + data: { + title: 'Everyone', + where: { + text: { + equals: 'example page', + }, + }, + access: { + read: { + constraint: 'everyone', + }, + update: { + constraint: 'everyone', + }, + delete: { + constraint: 'everyone', + }, + }, + relatedCollection: 'pages', + }, + }) + + const foundPresetWithUser1 = await payload.findByID({ + collection: queryPresetsCollectionSlug, + depth: 0, + user, + overrideAccess: false, + id: presetForEveryone.id, + }) + + expect(foundPresetWithUser1.id).toBe(presetForEveryone.id) + + const foundPresetWithUser2 = await payload.findByID({ + collection: queryPresetsCollectionSlug, + depth: 0, + user: user2, + overrideAccess: false, + id: presetForEveryone.id, + }) + + expect(foundPresetWithUser2.id).toBe(presetForEveryone.id) + + const presetUpdatedByUser1 = await payload.update({ + collection: queryPresetsCollectionSlug, + id: presetForEveryone.id, + user, + overrideAccess: false, + data: { + title: 'Everyone (Update 1)', + }, + }) + + expect(presetUpdatedByUser1.title).toBe('Everyone (Update 1)') + + const presetUpdatedByUser2 = await payload.update({ + collection: queryPresetsCollectionSlug, + id: presetForEveryone.id, + user: user2, + overrideAccess: false, + data: { + title: 'Everyone (Update 2)', + }, + }) + + expect(presetUpdatedByUser2.title).toBe('Everyone (Update 2)') + }) + }) + + describe('user-defined access control', () => { + it('should respect top-level access control overrides', async () => { + const preset = await payload.create({ + collection: queryPresetsCollectionSlug, + user, + data: { + title: 'Top-Level Access Control Override', + relatedCollection: 'pages', + access: { + read: { + constraint: 'everyone', + }, + update: { + constraint: 'everyone', + }, + delete: { + constraint: 'everyone', + }, + }, + }, + }) + + const foundPresetWithUser1 = await payload.findByID({ + collection: queryPresetsCollectionSlug, + depth: 0, + user, + overrideAccess: false, + id: preset.id, + }) + + expect(foundPresetWithUser1.id).toBe(preset.id) + + try { + const foundPresetWithAnonymousUser = await payload.findByID({ + collection: queryPresetsCollectionSlug, + depth: 0, + user: anonymousUser, + overrideAccess: false, + id: preset.id, + }) + + expect(foundPresetWithAnonymousUser).toBeFalsy() + } catch (error: unknown) { + expect((error as Error).message).toBe('You are not allowed to perform this action.') + } + }) + + it('should respect access when set to "specificRoles"', async () => { + const presetForSpecificRoles = await payload.create({ + collection: queryPresetsCollectionSlug, + user, + data: { + title: 'Specific Roles', + where: { + text: { + equals: 'example page', + }, + }, + access: { + read: { + constraint: 'specificRoles', + roles: ['admin'], + }, + update: { + constraint: 'specificRoles', + roles: ['admin'], + }, + }, + relatedCollection: 'pages', + }, + }) + + const foundPresetWithUser1 = await payload.findByID({ + collection: queryPresetsCollectionSlug, + depth: 0, + user, + overrideAccess: false, + id: presetForSpecificRoles.id, + }) + + expect(foundPresetWithUser1.id).toBe(presetForSpecificRoles.id) + + try { + const foundPresetWithUser2 = await payload.findByID({ + collection: queryPresetsCollectionSlug, + depth: 0, + user: user2, + overrideAccess: false, + id: presetForSpecificRoles.id, + }) + + expect(foundPresetWithUser2).toBeFalsy() + } catch (error: unknown) { + expect((error as Error).message).toBe('Not Found') + } + + const presetUpdatedByUser1 = await payload.update({ + collection: queryPresetsCollectionSlug, + id: presetForSpecificRoles.id, + user, + overrideAccess: false, + data: { + title: 'Specific Roles (Updated)', + }, + }) + + expect(presetUpdatedByUser1.title).toBe('Specific Roles (Updated)') + + try { + const presetUpdatedByUser2 = await payload.update({ + collection: queryPresetsCollectionSlug, + id: presetForSpecificRoles.id, + user: user2, + overrideAccess: false, + data: { + title: 'Specific Roles (Updated)', + }, + }) + + expect(presetUpdatedByUser2).toBeFalsy() + } catch (error: unknown) { + expect((error as Error).message).toBe('You are not allowed to perform this action.') + } + }) + }) + + it.skip('should disable query presets when "enabledQueryPresets" is not true on the collection', async () => { + try { + const result = await payload.create({ + collection: 'payload-query-presets', + user, + data: { + title: 'Disabled Query Presets', + relatedCollection: 'pages', + }, + }) + + // TODO: this test always passes because this expect throws an error which is caught and passes the 'catch' block + expect(result).toBeFalsy() + } catch (error) { + expect(error).toBeDefined() + } + }) + + describe('Where object formatting', () => { + it('transforms "where" query objects into the "and" / "or" format', async () => { + const result = await payload.create({ + collection: queryPresetsCollectionSlug, + user, + data: { + title: 'Where Object Formatting', + where: { + text: { + equals: 'example page', + }, + }, + access: { + read: { + constraint: 'everyone', + }, + update: { + constraint: 'everyone', + }, + delete: { + constraint: 'everyone', + }, + }, + relatedCollection: 'pages', + }, + }) + + expect(result.where).toMatchObject({ + or: [ + { + and: [ + { + text: { + equals: 'example page', + }, + }, + ], + }, + ], + }) + }) + }) +}) diff --git a/test/query-presets/payload-types.ts b/test/query-presets/payload-types.ts new file mode 100644 index 0000000000..20fbd0a7b8 --- /dev/null +++ b/test/query-presets/payload-types.ts @@ -0,0 +1,359 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * This file was automatically generated by Payload. + * DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config, + * and re-run `payload generate:types` to regenerate this file. + */ + +/** + * Supported timezones in IANA format. + * + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "supportedTimezones". + */ +export type SupportedTimezones = + | 'Pacific/Midway' + | 'Pacific/Niue' + | 'Pacific/Honolulu' + | 'Pacific/Rarotonga' + | 'America/Anchorage' + | 'Pacific/Gambier' + | 'America/Los_Angeles' + | 'America/Tijuana' + | 'America/Denver' + | 'America/Phoenix' + | 'America/Chicago' + | 'America/Guatemala' + | 'America/New_York' + | 'America/Bogota' + | 'America/Caracas' + | 'America/Santiago' + | 'America/Buenos_Aires' + | 'America/Sao_Paulo' + | 'Atlantic/South_Georgia' + | 'Atlantic/Azores' + | 'Atlantic/Cape_Verde' + | 'Europe/London' + | 'Europe/Berlin' + | 'Africa/Lagos' + | 'Europe/Athens' + | 'Africa/Cairo' + | 'Europe/Moscow' + | 'Asia/Riyadh' + | 'Asia/Dubai' + | 'Asia/Baku' + | 'Asia/Karachi' + | 'Asia/Tashkent' + | 'Asia/Calcutta' + | 'Asia/Dhaka' + | 'Asia/Almaty' + | 'Asia/Jakarta' + | 'Asia/Bangkok' + | 'Asia/Shanghai' + | 'Asia/Singapore' + | 'Asia/Tokyo' + | 'Asia/Seoul' + | 'Australia/Brisbane' + | 'Australia/Sydney' + | 'Pacific/Guam' + | 'Pacific/Noumea' + | 'Pacific/Auckland' + | 'Pacific/Fiji'; + +export interface Config { + auth: { + users: UserAuthOperations; + }; + blocks: {}; + collections: { + pages: Page; + users: User; + 'payload-locked-documents': PayloadLockedDocument; + 'payload-preferences': PayloadPreference; + 'payload-migrations': PayloadMigration; + 'payload-query-presets': PayloadQueryPreset; + }; + collectionsJoins: {}; + collectionsSelect: { + pages: PagesSelect | PagesSelect; + users: UsersSelect | UsersSelect; + 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; + 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; + 'payload-migrations': PayloadMigrationsSelect | PayloadMigrationsSelect; + 'payload-query-presets': PayloadQueryPresetsSelect | PayloadQueryPresetsSelect; + }; + db: { + defaultIDType: number; + }; + globals: {}; + globalsSelect: {}; + locale: null; + user: User & { + collection: 'users'; + }; + jobs: { + tasks: unknown; + workflows: unknown; + }; +} +export interface UserAuthOperations { + forgotPassword: { + email: string; + password: string; + }; + login: { + email: string; + password: string; + }; + registerFirstUser: { + email: string; + password: string; + }; + unlock: { + email: string; + password: string; + }; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "pages". + */ +export interface Page { + id: number; + text?: string | null; + updatedAt: string; + createdAt: string; + _status?: ('draft' | 'published') | null; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "users". + */ +export interface User { + id: number; + name?: string | null; + roles?: ('admin' | 'user' | 'anonymous')[] | null; + updatedAt: string; + createdAt: string; + email: string; + resetPasswordToken?: string | null; + resetPasswordExpiration?: string | null; + salt?: string | null; + hash?: string | null; + loginAttempts?: number | null; + lockUntil?: string | null; + password?: string | null; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-locked-documents". + */ +export interface PayloadLockedDocument { + id: number; + document?: + | ({ + relationTo: 'pages'; + value: number | Page; + } | null) + | ({ + relationTo: 'users'; + value: number | User; + } | null); + globalSlug?: string | null; + user: { + relationTo: 'users'; + value: number | User; + }; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-preferences". + */ +export interface PayloadPreference { + id: number; + user: { + relationTo: 'users'; + value: number | User; + }; + key?: string | null; + value?: + | { + [k: string]: unknown; + } + | unknown[] + | string + | number + | boolean + | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-migrations". + */ +export interface PayloadMigration { + id: number; + name?: string | null; + batch?: number | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-query-presets". + */ +export interface PayloadQueryPreset { + id: number; + title: string; + isShared?: boolean | null; + access?: { + read?: { + constraint?: ('everyone' | 'onlyMe' | 'specificUsers' | 'specificRoles') | null; + users?: (number | User)[] | null; + roles?: ('admin' | 'user' | 'anonymous')[] | null; + }; + update?: { + constraint?: ('everyone' | 'onlyMe' | 'specificUsers' | 'specificRoles') | null; + users?: (number | User)[] | null; + roles?: ('admin' | 'user' | 'anonymous')[] | null; + }; + delete?: { + constraint?: ('everyone' | 'onlyMe' | 'specificUsers') | null; + users?: (number | User)[] | null; + }; + }; + where?: + | { + [k: string]: unknown; + } + | unknown[] + | string + | number + | boolean + | null; + columns?: + | { + [k: string]: unknown; + } + | unknown[] + | string + | number + | boolean + | null; + relatedCollection: 'pages'; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "pages_select". + */ +export interface PagesSelect { + text?: T; + updatedAt?: T; + createdAt?: T; + _status?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "users_select". + */ +export interface UsersSelect { + name?: T; + roles?: T; + updatedAt?: T; + createdAt?: T; + email?: T; + resetPasswordToken?: T; + resetPasswordExpiration?: T; + salt?: T; + hash?: T; + loginAttempts?: T; + lockUntil?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-locked-documents_select". + */ +export interface PayloadLockedDocumentsSelect { + document?: T; + globalSlug?: T; + user?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-preferences_select". + */ +export interface PayloadPreferencesSelect { + user?: T; + key?: T; + value?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-migrations_select". + */ +export interface PayloadMigrationsSelect { + name?: T; + batch?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-query-presets_select". + */ +export interface PayloadQueryPresetsSelect { + title?: T; + isShared?: T; + access?: + | T + | { + read?: + | T + | { + constraint?: T; + users?: T; + roles?: T; + }; + update?: + | T + | { + constraint?: T; + users?: T; + roles?: T; + }; + delete?: + | T + | { + constraint?: T; + users?: T; + }; + }; + where?: T; + columns?: T; + relatedCollection?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "auth". + */ +export interface Auth { + [k: string]: unknown; +} + + +declare module 'payload' { + // @ts-ignore + export interface GeneratedTypes extends Config {} +} \ No newline at end of file diff --git a/test/query-presets/schema.graphql b/test/query-presets/schema.graphql new file mode 100644 index 0000000000..ef6cee9169 --- /dev/null +++ b/test/query-presets/schema.graphql @@ -0,0 +1,2693 @@ +type Query { + Page(id: String!, draft: Boolean): Page + Pages(draft: Boolean, where: Page_where, limit: Int, page: Int, pagination: Boolean, sort: String): Pages + countPages(draft: Boolean, where: Page_where): countPages + docAccessPage(id: String!): pagesDocAccess + versionPage(id: String): PageVersion + versionsPages(where: versionsPage_where, limit: Int, page: Int, pagination: Boolean, sort: String): versionsPages + User(id: String!, draft: Boolean): User + Users(draft: Boolean, where: User_where, limit: Int, page: Int, pagination: Boolean, sort: String): Users + countUsers(draft: Boolean, where: User_where): countUsers + docAccessUser(id: String!): usersDocAccess + meUser: usersMe + initializedUser: Boolean + PayloadLockedDocument(id: String!, draft: Boolean): PayloadLockedDocument + PayloadLockedDocuments(draft: Boolean, where: PayloadLockedDocument_where, limit: Int, page: Int, pagination: Boolean, sort: String): PayloadLockedDocuments + countPayloadLockedDocuments(draft: Boolean, where: PayloadLockedDocument_where): countPayloadLockedDocuments + docAccessPayloadLockedDocument(id: String!): payload_locked_documentsDocAccess + PayloadPreference(id: String!, draft: Boolean): PayloadPreference + PayloadPreferences(draft: Boolean, where: PayloadPreference_where, limit: Int, page: Int, pagination: Boolean, sort: String): PayloadPreferences + countPayloadPreferences(draft: Boolean, where: PayloadPreference_where): countPayloadPreferences + docAccessPayloadPreference(id: String!): payload_preferencesDocAccess + PayloadListFilter(id: String!, draft: Boolean): PayloadListFilter + PayloadListFilters(draft: Boolean, where: PayloadListFilter_where, limit: Int, page: Int, pagination: Boolean, sort: String): PayloadListFilters + countPayloadListFilters(draft: Boolean, where: PayloadListFilter_where): countPayloadListFilters + docAccessPayloadListFilter(id: String!): payload_list_filtersDocAccess + Access: Access +} + +type Page { + id: String! + text: String + updatedAt: DateTime + createdAt: DateTime + _status: Page__status +} + +""" +A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `date-time` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar. +""" +scalar DateTime + +enum Page__status { + draft + published +} + +type Pages { + docs: [Page] + hasNextPage: Boolean + hasPrevPage: Boolean + limit: Int + nextPage: Int + offset: Int + page: Int + pagingCounter: Int + prevPage: Int + totalDocs: Int + totalPages: Int +} + +input Page_where { + text: Page_text_operator + updatedAt: Page_updatedAt_operator + createdAt: Page_createdAt_operator + _status: Page__status_operator + id: Page_id_operator + AND: [Page_where_and] + OR: [Page_where_or] +} + +input Page_text_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Page_updatedAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input Page_createdAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input Page__status_operator { + equals: Page__status_Input + not_equals: Page__status_Input + in: [Page__status_Input] + not_in: [Page__status_Input] + all: [Page__status_Input] + exists: Boolean +} + +enum Page__status_Input { + draft + published +} + +input Page_id_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Page_where_and { + text: Page_text_operator + updatedAt: Page_updatedAt_operator + createdAt: Page_createdAt_operator + _status: Page__status_operator + id: Page_id_operator + AND: [Page_where_and] + OR: [Page_where_or] +} + +input Page_where_or { + text: Page_text_operator + updatedAt: Page_updatedAt_operator + createdAt: Page_createdAt_operator + _status: Page__status_operator + id: Page_id_operator + AND: [Page_where_and] + OR: [Page_where_or] +} + +type countPages { + totalDocs: Int +} + +type pagesDocAccess { + fields: PagesDocAccessFields + create: PagesCreateDocAccess + read: PagesReadDocAccess + update: PagesUpdateDocAccess + delete: PagesDeleteDocAccess + readVersions: PagesReadVersionsDocAccess +} + +type PagesDocAccessFields { + text: PagesDocAccessFields_text + updatedAt: PagesDocAccessFields_updatedAt + createdAt: PagesDocAccessFields_createdAt + _status: PagesDocAccessFields__status +} + +type PagesDocAccessFields_text { + create: PagesDocAccessFields_text_Create + read: PagesDocAccessFields_text_Read + update: PagesDocAccessFields_text_Update + delete: PagesDocAccessFields_text_Delete +} + +type PagesDocAccessFields_text_Create { + permission: Boolean! +} + +type PagesDocAccessFields_text_Read { + permission: Boolean! +} + +type PagesDocAccessFields_text_Update { + permission: Boolean! +} + +type PagesDocAccessFields_text_Delete { + permission: Boolean! +} + +type PagesDocAccessFields_updatedAt { + create: PagesDocAccessFields_updatedAt_Create + read: PagesDocAccessFields_updatedAt_Read + update: PagesDocAccessFields_updatedAt_Update + delete: PagesDocAccessFields_updatedAt_Delete +} + +type PagesDocAccessFields_updatedAt_Create { + permission: Boolean! +} + +type PagesDocAccessFields_updatedAt_Read { + permission: Boolean! +} + +type PagesDocAccessFields_updatedAt_Update { + permission: Boolean! +} + +type PagesDocAccessFields_updatedAt_Delete { + permission: Boolean! +} + +type PagesDocAccessFields_createdAt { + create: PagesDocAccessFields_createdAt_Create + read: PagesDocAccessFields_createdAt_Read + update: PagesDocAccessFields_createdAt_Update + delete: PagesDocAccessFields_createdAt_Delete +} + +type PagesDocAccessFields_createdAt_Create { + permission: Boolean! +} + +type PagesDocAccessFields_createdAt_Read { + permission: Boolean! +} + +type PagesDocAccessFields_createdAt_Update { + permission: Boolean! +} + +type PagesDocAccessFields_createdAt_Delete { + permission: Boolean! +} + +type PagesDocAccessFields__status { + create: PagesDocAccessFields__status_Create + read: PagesDocAccessFields__status_Read + update: PagesDocAccessFields__status_Update + delete: PagesDocAccessFields__status_Delete +} + +type PagesDocAccessFields__status_Create { + permission: Boolean! +} + +type PagesDocAccessFields__status_Read { + permission: Boolean! +} + +type PagesDocAccessFields__status_Update { + permission: Boolean! +} + +type PagesDocAccessFields__status_Delete { + permission: Boolean! +} + +type PagesCreateDocAccess { + permission: Boolean! + where: JSONObject +} + +""" +The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). +""" +scalar JSONObject @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf") + +type PagesReadDocAccess { + permission: Boolean! + where: JSONObject +} + +type PagesUpdateDocAccess { + permission: Boolean! + where: JSONObject +} + +type PagesDeleteDocAccess { + permission: Boolean! + where: JSONObject +} + +type PagesReadVersionsDocAccess { + permission: Boolean! + where: JSONObject +} + +type PageVersion { + parent(draft: Boolean): Page + version: PageVersion_Version + createdAt: DateTime + updatedAt: DateTime + latest: Boolean + id: String +} + +type PageVersion_Version { + text: String + updatedAt: DateTime + createdAt: DateTime + _status: PageVersion_Version__status +} + +enum PageVersion_Version__status { + draft + published +} + +type versionsPages { + docs: [PageVersion] + hasNextPage: Boolean + hasPrevPage: Boolean + limit: Int + nextPage: Int + offset: Int + page: Int + pagingCounter: Int + prevPage: Int + totalDocs: Int + totalPages: Int +} + +input versionsPage_where { + parent: versionsPage_parent_operator + version__text: versionsPage_version__text_operator + version__updatedAt: versionsPage_version__updatedAt_operator + version__createdAt: versionsPage_version__createdAt_operator + version___status: versionsPage_version___status_operator + createdAt: versionsPage_createdAt_operator + updatedAt: versionsPage_updatedAt_operator + latest: versionsPage_latest_operator + id: versionsPage_id_operator + AND: [versionsPage_where_and] + OR: [versionsPage_where_or] +} + +input versionsPage_parent_operator { + equals: JSON + not_equals: JSON + in: [JSON] + not_in: [JSON] + all: [JSON] + exists: Boolean +} + +""" +The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). +""" +scalar JSON @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf") + +input versionsPage_version__text_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input versionsPage_version__updatedAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input versionsPage_version__createdAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input versionsPage_version___status_operator { + equals: versionsPage_version___status_Input + not_equals: versionsPage_version___status_Input + in: [versionsPage_version___status_Input] + not_in: [versionsPage_version___status_Input] + all: [versionsPage_version___status_Input] + exists: Boolean +} + +enum versionsPage_version___status_Input { + draft + published +} + +input versionsPage_createdAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input versionsPage_updatedAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input versionsPage_latest_operator { + equals: Boolean + not_equals: Boolean + exists: Boolean +} + +input versionsPage_id_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input versionsPage_where_and { + parent: versionsPage_parent_operator + version__text: versionsPage_version__text_operator + version__updatedAt: versionsPage_version__updatedAt_operator + version__createdAt: versionsPage_version__createdAt_operator + version___status: versionsPage_version___status_operator + createdAt: versionsPage_createdAt_operator + updatedAt: versionsPage_updatedAt_operator + latest: versionsPage_latest_operator + id: versionsPage_id_operator + AND: [versionsPage_where_and] + OR: [versionsPage_where_or] +} + +input versionsPage_where_or { + parent: versionsPage_parent_operator + version__text: versionsPage_version__text_operator + version__updatedAt: versionsPage_version__updatedAt_operator + version__createdAt: versionsPage_version__createdAt_operator + version___status: versionsPage_version___status_operator + createdAt: versionsPage_createdAt_operator + updatedAt: versionsPage_updatedAt_operator + latest: versionsPage_latest_operator + id: versionsPage_id_operator + AND: [versionsPage_where_and] + OR: [versionsPage_where_or] +} + +type User { + id: String! + name: String + roles: [User_roles!] + updatedAt: DateTime + createdAt: DateTime + email: EmailAddress! + resetPasswordToken: String + resetPasswordExpiration: DateTime + salt: String + hash: String + loginAttempts: Float + lockUntil: DateTime +} + +enum User_roles { + is_user + is_admin +} + +""" +A field whose value conforms to the standard internet email address format as specified in HTML Spec: https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address. +""" +scalar EmailAddress @specifiedBy(url: "https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address") + +type Users { + docs: [User] + hasNextPage: Boolean + hasPrevPage: Boolean + limit: Int + nextPage: Int + offset: Int + page: Int + pagingCounter: Int + prevPage: Int + totalDocs: Int + totalPages: Int +} + +input User_where { + name: User_name_operator + roles: User_roles_operator + updatedAt: User_updatedAt_operator + createdAt: User_createdAt_operator + email: User_email_operator + id: User_id_operator + AND: [User_where_and] + OR: [User_where_or] +} + +input User_name_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input User_roles_operator { + equals: User_roles_Input + not_equals: User_roles_Input + in: [User_roles_Input] + not_in: [User_roles_Input] + all: [User_roles_Input] + exists: Boolean +} + +enum User_roles_Input { + is_user + is_admin +} + +input User_updatedAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input User_createdAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input User_email_operator { + equals: EmailAddress + not_equals: EmailAddress + like: EmailAddress + contains: EmailAddress + in: [EmailAddress] + not_in: [EmailAddress] + all: [EmailAddress] +} + +input User_id_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input User_where_and { + name: User_name_operator + roles: User_roles_operator + updatedAt: User_updatedAt_operator + createdAt: User_createdAt_operator + email: User_email_operator + id: User_id_operator + AND: [User_where_and] + OR: [User_where_or] +} + +input User_where_or { + name: User_name_operator + roles: User_roles_operator + updatedAt: User_updatedAt_operator + createdAt: User_createdAt_operator + email: User_email_operator + id: User_id_operator + AND: [User_where_and] + OR: [User_where_or] +} + +type countUsers { + totalDocs: Int +} + +type usersDocAccess { + fields: UsersDocAccessFields + create: UsersCreateDocAccess + read: UsersReadDocAccess + update: UsersUpdateDocAccess + delete: UsersDeleteDocAccess + unlock: UsersUnlockDocAccess +} + +type UsersDocAccessFields { + name: UsersDocAccessFields_name + roles: UsersDocAccessFields_roles + updatedAt: UsersDocAccessFields_updatedAt + createdAt: UsersDocAccessFields_createdAt + email: UsersDocAccessFields_email +} + +type UsersDocAccessFields_name { + create: UsersDocAccessFields_name_Create + read: UsersDocAccessFields_name_Read + update: UsersDocAccessFields_name_Update + delete: UsersDocAccessFields_name_Delete +} + +type UsersDocAccessFields_name_Create { + permission: Boolean! +} + +type UsersDocAccessFields_name_Read { + permission: Boolean! +} + +type UsersDocAccessFields_name_Update { + permission: Boolean! +} + +type UsersDocAccessFields_name_Delete { + permission: Boolean! +} + +type UsersDocAccessFields_roles { + create: UsersDocAccessFields_roles_Create + read: UsersDocAccessFields_roles_Read + update: UsersDocAccessFields_roles_Update + delete: UsersDocAccessFields_roles_Delete +} + +type UsersDocAccessFields_roles_Create { + permission: Boolean! +} + +type UsersDocAccessFields_roles_Read { + permission: Boolean! +} + +type UsersDocAccessFields_roles_Update { + permission: Boolean! +} + +type UsersDocAccessFields_roles_Delete { + permission: Boolean! +} + +type UsersDocAccessFields_updatedAt { + create: UsersDocAccessFields_updatedAt_Create + read: UsersDocAccessFields_updatedAt_Read + update: UsersDocAccessFields_updatedAt_Update + delete: UsersDocAccessFields_updatedAt_Delete +} + +type UsersDocAccessFields_updatedAt_Create { + permission: Boolean! +} + +type UsersDocAccessFields_updatedAt_Read { + permission: Boolean! +} + +type UsersDocAccessFields_updatedAt_Update { + permission: Boolean! +} + +type UsersDocAccessFields_updatedAt_Delete { + permission: Boolean! +} + +type UsersDocAccessFields_createdAt { + create: UsersDocAccessFields_createdAt_Create + read: UsersDocAccessFields_createdAt_Read + update: UsersDocAccessFields_createdAt_Update + delete: UsersDocAccessFields_createdAt_Delete +} + +type UsersDocAccessFields_createdAt_Create { + permission: Boolean! +} + +type UsersDocAccessFields_createdAt_Read { + permission: Boolean! +} + +type UsersDocAccessFields_createdAt_Update { + permission: Boolean! +} + +type UsersDocAccessFields_createdAt_Delete { + permission: Boolean! +} + +type UsersDocAccessFields_email { + create: UsersDocAccessFields_email_Create + read: UsersDocAccessFields_email_Read + update: UsersDocAccessFields_email_Update + delete: UsersDocAccessFields_email_Delete +} + +type UsersDocAccessFields_email_Create { + permission: Boolean! +} + +type UsersDocAccessFields_email_Read { + permission: Boolean! +} + +type UsersDocAccessFields_email_Update { + permission: Boolean! +} + +type UsersDocAccessFields_email_Delete { + permission: Boolean! +} + +type UsersCreateDocAccess { + permission: Boolean! + where: JSONObject +} + +type UsersReadDocAccess { + permission: Boolean! + where: JSONObject +} + +type UsersUpdateDocAccess { + permission: Boolean! + where: JSONObject +} + +type UsersDeleteDocAccess { + permission: Boolean! + where: JSONObject +} + +type UsersUnlockDocAccess { + permission: Boolean! + where: JSONObject +} + +type usersMe { + collection: String + exp: Int + strategy: String + token: String + user: User +} + +type PayloadLockedDocument { + id: String! + document(draft: Boolean): PayloadLockedDocument_Document_Relationship + globalSlug: String + user: PayloadLockedDocument_User_Relationship! + updatedAt: DateTime + createdAt: DateTime +} + +type PayloadLockedDocument_Document_Relationship { + relationTo: PayloadLockedDocument_Document_RelationTo + value: PayloadLockedDocument_Document +} + +enum PayloadLockedDocument_Document_RelationTo { + pages + users +} + +union PayloadLockedDocument_Document = Page | User + +type PayloadLockedDocument_User_Relationship { + relationTo: PayloadLockedDocument_User_RelationTo + value: PayloadLockedDocument_User +} + +enum PayloadLockedDocument_User_RelationTo { + users +} + +union PayloadLockedDocument_User = User + +type PayloadLockedDocuments { + docs: [PayloadLockedDocument] + hasNextPage: Boolean + hasPrevPage: Boolean + limit: Int + nextPage: Int + offset: Int + page: Int + pagingCounter: Int + prevPage: Int + totalDocs: Int + totalPages: Int +} + +input PayloadLockedDocument_where { + document: PayloadLockedDocument_document_Relation + globalSlug: PayloadLockedDocument_globalSlug_operator + user: PayloadLockedDocument_user_Relation + updatedAt: PayloadLockedDocument_updatedAt_operator + createdAt: PayloadLockedDocument_createdAt_operator + id: PayloadLockedDocument_id_operator + AND: [PayloadLockedDocument_where_and] + OR: [PayloadLockedDocument_where_or] +} + +input PayloadLockedDocument_document_Relation { + relationTo: PayloadLockedDocument_document_Relation_RelationTo + value: JSON +} + +enum PayloadLockedDocument_document_Relation_RelationTo { + pages + users +} + +input PayloadLockedDocument_globalSlug_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input PayloadLockedDocument_user_Relation { + relationTo: PayloadLockedDocument_user_Relation_RelationTo + value: JSON +} + +enum PayloadLockedDocument_user_Relation_RelationTo { + users +} + +input PayloadLockedDocument_updatedAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input PayloadLockedDocument_createdAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input PayloadLockedDocument_id_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input PayloadLockedDocument_where_and { + document: PayloadLockedDocument_document_Relation + globalSlug: PayloadLockedDocument_globalSlug_operator + user: PayloadLockedDocument_user_Relation + updatedAt: PayloadLockedDocument_updatedAt_operator + createdAt: PayloadLockedDocument_createdAt_operator + id: PayloadLockedDocument_id_operator + AND: [PayloadLockedDocument_where_and] + OR: [PayloadLockedDocument_where_or] +} + +input PayloadLockedDocument_where_or { + document: PayloadLockedDocument_document_Relation + globalSlug: PayloadLockedDocument_globalSlug_operator + user: PayloadLockedDocument_user_Relation + updatedAt: PayloadLockedDocument_updatedAt_operator + createdAt: PayloadLockedDocument_createdAt_operator + id: PayloadLockedDocument_id_operator + AND: [PayloadLockedDocument_where_and] + OR: [PayloadLockedDocument_where_or] +} + +type countPayloadLockedDocuments { + totalDocs: Int +} + +type payload_locked_documentsDocAccess { + fields: PayloadLockedDocumentsDocAccessFields + create: PayloadLockedDocumentsCreateDocAccess + read: PayloadLockedDocumentsReadDocAccess + update: PayloadLockedDocumentsUpdateDocAccess + delete: PayloadLockedDocumentsDeleteDocAccess +} + +type PayloadLockedDocumentsDocAccessFields { + document: PayloadLockedDocumentsDocAccessFields_document + globalSlug: PayloadLockedDocumentsDocAccessFields_globalSlug + user: PayloadLockedDocumentsDocAccessFields_user + updatedAt: PayloadLockedDocumentsDocAccessFields_updatedAt + createdAt: PayloadLockedDocumentsDocAccessFields_createdAt +} + +type PayloadLockedDocumentsDocAccessFields_document { + create: PayloadLockedDocumentsDocAccessFields_document_Create + read: PayloadLockedDocumentsDocAccessFields_document_Read + update: PayloadLockedDocumentsDocAccessFields_document_Update + delete: PayloadLockedDocumentsDocAccessFields_document_Delete +} + +type PayloadLockedDocumentsDocAccessFields_document_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_document_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_document_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_document_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_globalSlug { + create: PayloadLockedDocumentsDocAccessFields_globalSlug_Create + read: PayloadLockedDocumentsDocAccessFields_globalSlug_Read + update: PayloadLockedDocumentsDocAccessFields_globalSlug_Update + delete: PayloadLockedDocumentsDocAccessFields_globalSlug_Delete +} + +type PayloadLockedDocumentsDocAccessFields_globalSlug_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_globalSlug_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_globalSlug_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_globalSlug_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_user { + create: PayloadLockedDocumentsDocAccessFields_user_Create + read: PayloadLockedDocumentsDocAccessFields_user_Read + update: PayloadLockedDocumentsDocAccessFields_user_Update + delete: PayloadLockedDocumentsDocAccessFields_user_Delete +} + +type PayloadLockedDocumentsDocAccessFields_user_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_user_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_user_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_user_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_updatedAt { + create: PayloadLockedDocumentsDocAccessFields_updatedAt_Create + read: PayloadLockedDocumentsDocAccessFields_updatedAt_Read + update: PayloadLockedDocumentsDocAccessFields_updatedAt_Update + delete: PayloadLockedDocumentsDocAccessFields_updatedAt_Delete +} + +type PayloadLockedDocumentsDocAccessFields_updatedAt_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_updatedAt_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_updatedAt_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_updatedAt_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_createdAt { + create: PayloadLockedDocumentsDocAccessFields_createdAt_Create + read: PayloadLockedDocumentsDocAccessFields_createdAt_Read + update: PayloadLockedDocumentsDocAccessFields_createdAt_Update + delete: PayloadLockedDocumentsDocAccessFields_createdAt_Delete +} + +type PayloadLockedDocumentsDocAccessFields_createdAt_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_createdAt_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_createdAt_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_createdAt_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsCreateDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsReadDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsUpdateDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsDeleteDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreference { + id: String! + user: PayloadPreference_User_Relationship! + key: String + value: JSON + updatedAt: DateTime + createdAt: DateTime +} + +type PayloadPreference_User_Relationship { + relationTo: PayloadPreference_User_RelationTo + value: PayloadPreference_User +} + +enum PayloadPreference_User_RelationTo { + users +} + +union PayloadPreference_User = User + +type PayloadPreferences { + docs: [PayloadPreference] + hasNextPage: Boolean + hasPrevPage: Boolean + limit: Int + nextPage: Int + offset: Int + page: Int + pagingCounter: Int + prevPage: Int + totalDocs: Int + totalPages: Int +} + +input PayloadPreference_where { + user: PayloadPreference_user_Relation + key: PayloadPreference_key_operator + value: PayloadPreference_value_operator + updatedAt: PayloadPreference_updatedAt_operator + createdAt: PayloadPreference_createdAt_operator + id: PayloadPreference_id_operator + AND: [PayloadPreference_where_and] + OR: [PayloadPreference_where_or] +} + +input PayloadPreference_user_Relation { + relationTo: PayloadPreference_user_Relation_RelationTo + value: JSON +} + +enum PayloadPreference_user_Relation_RelationTo { + users +} + +input PayloadPreference_key_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input PayloadPreference_value_operator { + equals: JSON + not_equals: JSON + like: JSON + contains: JSON + within: JSON + intersects: JSON + exists: Boolean +} + +input PayloadPreference_updatedAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input PayloadPreference_createdAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input PayloadPreference_id_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input PayloadPreference_where_and { + user: PayloadPreference_user_Relation + key: PayloadPreference_key_operator + value: PayloadPreference_value_operator + updatedAt: PayloadPreference_updatedAt_operator + createdAt: PayloadPreference_createdAt_operator + id: PayloadPreference_id_operator + AND: [PayloadPreference_where_and] + OR: [PayloadPreference_where_or] +} + +input PayloadPreference_where_or { + user: PayloadPreference_user_Relation + key: PayloadPreference_key_operator + value: PayloadPreference_value_operator + updatedAt: PayloadPreference_updatedAt_operator + createdAt: PayloadPreference_createdAt_operator + id: PayloadPreference_id_operator + AND: [PayloadPreference_where_and] + OR: [PayloadPreference_where_or] +} + +type countPayloadPreferences { + totalDocs: Int +} + +type payload_preferencesDocAccess { + fields: PayloadPreferencesDocAccessFields + create: PayloadPreferencesCreateDocAccess + read: PayloadPreferencesReadDocAccess + update: PayloadPreferencesUpdateDocAccess + delete: PayloadPreferencesDeleteDocAccess +} + +type PayloadPreferencesDocAccessFields { + user: PayloadPreferencesDocAccessFields_user + key: PayloadPreferencesDocAccessFields_key + value: PayloadPreferencesDocAccessFields_value + updatedAt: PayloadPreferencesDocAccessFields_updatedAt + createdAt: PayloadPreferencesDocAccessFields_createdAt +} + +type PayloadPreferencesDocAccessFields_user { + create: PayloadPreferencesDocAccessFields_user_Create + read: PayloadPreferencesDocAccessFields_user_Read + update: PayloadPreferencesDocAccessFields_user_Update + delete: PayloadPreferencesDocAccessFields_user_Delete +} + +type PayloadPreferencesDocAccessFields_user_Create { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_user_Read { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_user_Update { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_user_Delete { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_key { + create: PayloadPreferencesDocAccessFields_key_Create + read: PayloadPreferencesDocAccessFields_key_Read + update: PayloadPreferencesDocAccessFields_key_Update + delete: PayloadPreferencesDocAccessFields_key_Delete +} + +type PayloadPreferencesDocAccessFields_key_Create { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_key_Read { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_key_Update { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_key_Delete { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_value { + create: PayloadPreferencesDocAccessFields_value_Create + read: PayloadPreferencesDocAccessFields_value_Read + update: PayloadPreferencesDocAccessFields_value_Update + delete: PayloadPreferencesDocAccessFields_value_Delete +} + +type PayloadPreferencesDocAccessFields_value_Create { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_value_Read { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_value_Update { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_value_Delete { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_updatedAt { + create: PayloadPreferencesDocAccessFields_updatedAt_Create + read: PayloadPreferencesDocAccessFields_updatedAt_Read + update: PayloadPreferencesDocAccessFields_updatedAt_Update + delete: PayloadPreferencesDocAccessFields_updatedAt_Delete +} + +type PayloadPreferencesDocAccessFields_updatedAt_Create { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_updatedAt_Read { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_updatedAt_Update { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_updatedAt_Delete { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_createdAt { + create: PayloadPreferencesDocAccessFields_createdAt_Create + read: PayloadPreferencesDocAccessFields_createdAt_Read + update: PayloadPreferencesDocAccessFields_createdAt_Update + delete: PayloadPreferencesDocAccessFields_createdAt_Delete +} + +type PayloadPreferencesDocAccessFields_createdAt_Create { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_createdAt_Read { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_createdAt_Update { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_createdAt_Delete { + permission: Boolean! +} + +type PayloadPreferencesCreateDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesReadDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesUpdateDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesDeleteDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadListFilter { + id: String! + Name: String! + Where: JSON! + Columns: JSON + Collection: PayloadListFilter_Collection! + updatedAt: DateTime + createdAt: DateTime +} + +enum PayloadListFilter_Collection { + pages + users + payload_locked_documents + payload_preferences +} + +type PayloadListFilters { + docs: [PayloadListFilter] + hasNextPage: Boolean + hasPrevPage: Boolean + limit: Int + nextPage: Int + offset: Int + page: Int + pagingCounter: Int + prevPage: Int + totalDocs: Int + totalPages: Int +} + +input PayloadListFilter_where { + Name: PayloadListFilter_Name_operator + Where: PayloadListFilter_Where_operator + Columns: PayloadListFilter_Columns_operator + Collection: PayloadListFilter_Collection_operator + updatedAt: PayloadListFilter_updatedAt_operator + createdAt: PayloadListFilter_createdAt_operator + id: PayloadListFilter_id_operator + AND: [PayloadListFilter_where_and] + OR: [PayloadListFilter_where_or] +} + +input PayloadListFilter_Name_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] +} + +input PayloadListFilter_Where_operator { + equals: JSON + not_equals: JSON + like: JSON + contains: JSON + within: JSON + intersects: JSON +} + +input PayloadListFilter_Columns_operator { + equals: JSON + not_equals: JSON + like: JSON + contains: JSON + within: JSON + intersects: JSON + exists: Boolean +} + +input PayloadListFilter_Collection_operator { + equals: PayloadListFilter_Collection_Input + not_equals: PayloadListFilter_Collection_Input + in: [PayloadListFilter_Collection_Input] + not_in: [PayloadListFilter_Collection_Input] + all: [PayloadListFilter_Collection_Input] +} + +enum PayloadListFilter_Collection_Input { + pages + users + payload_locked_documents + payload_preferences +} + +input PayloadListFilter_updatedAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input PayloadListFilter_createdAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input PayloadListFilter_id_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input PayloadListFilter_where_and { + Name: PayloadListFilter_Name_operator + Where: PayloadListFilter_Where_operator + Columns: PayloadListFilter_Columns_operator + Collection: PayloadListFilter_Collection_operator + updatedAt: PayloadListFilter_updatedAt_operator + createdAt: PayloadListFilter_createdAt_operator + id: PayloadListFilter_id_operator + AND: [PayloadListFilter_where_and] + OR: [PayloadListFilter_where_or] +} + +input PayloadListFilter_where_or { + Name: PayloadListFilter_Name_operator + Where: PayloadListFilter_Where_operator + Columns: PayloadListFilter_Columns_operator + Collection: PayloadListFilter_Collection_operator + updatedAt: PayloadListFilter_updatedAt_operator + createdAt: PayloadListFilter_createdAt_operator + id: PayloadListFilter_id_operator + AND: [PayloadListFilter_where_and] + OR: [PayloadListFilter_where_or] +} + +type countPayloadListFilters { + totalDocs: Int +} + +type payload_list_filtersDocAccess { + fields: PayloadListFiltersDocAccessFields + create: PayloadListFiltersCreateDocAccess + read: PayloadListFiltersReadDocAccess + update: PayloadListFiltersUpdateDocAccess + delete: PayloadListFiltersDeleteDocAccess +} + +type PayloadListFiltersDocAccessFields { + Name: PayloadListFiltersDocAccessFields_Name + Where: PayloadListFiltersDocAccessFields_Where + Columns: PayloadListFiltersDocAccessFields_Columns + Collection: PayloadListFiltersDocAccessFields_Collection + updatedAt: PayloadListFiltersDocAccessFields_updatedAt + createdAt: PayloadListFiltersDocAccessFields_createdAt +} + +type PayloadListFiltersDocAccessFields_Name { + create: PayloadListFiltersDocAccessFields_Name_Create + read: PayloadListFiltersDocAccessFields_Name_Read + update: PayloadListFiltersDocAccessFields_Name_Update + delete: PayloadListFiltersDocAccessFields_Name_Delete +} + +type PayloadListFiltersDocAccessFields_Name_Create { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_Name_Read { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_Name_Update { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_Name_Delete { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_Where { + create: PayloadListFiltersDocAccessFields_Where_Create + read: PayloadListFiltersDocAccessFields_Where_Read + update: PayloadListFiltersDocAccessFields_Where_Update + delete: PayloadListFiltersDocAccessFields_Where_Delete +} + +type PayloadListFiltersDocAccessFields_Where_Create { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_Where_Read { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_Where_Update { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_Where_Delete { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_Columns { + create: PayloadListFiltersDocAccessFields_Columns_Create + read: PayloadListFiltersDocAccessFields_Columns_Read + update: PayloadListFiltersDocAccessFields_Columns_Update + delete: PayloadListFiltersDocAccessFields_Columns_Delete +} + +type PayloadListFiltersDocAccessFields_Columns_Create { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_Columns_Read { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_Columns_Update { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_Columns_Delete { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_Collection { + create: PayloadListFiltersDocAccessFields_Collection_Create + read: PayloadListFiltersDocAccessFields_Collection_Read + update: PayloadListFiltersDocAccessFields_Collection_Update + delete: PayloadListFiltersDocAccessFields_Collection_Delete +} + +type PayloadListFiltersDocAccessFields_Collection_Create { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_Collection_Read { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_Collection_Update { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_Collection_Delete { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_updatedAt { + create: PayloadListFiltersDocAccessFields_updatedAt_Create + read: PayloadListFiltersDocAccessFields_updatedAt_Read + update: PayloadListFiltersDocAccessFields_updatedAt_Update + delete: PayloadListFiltersDocAccessFields_updatedAt_Delete +} + +type PayloadListFiltersDocAccessFields_updatedAt_Create { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_updatedAt_Read { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_updatedAt_Update { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_updatedAt_Delete { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_createdAt { + create: PayloadListFiltersDocAccessFields_createdAt_Create + read: PayloadListFiltersDocAccessFields_createdAt_Read + update: PayloadListFiltersDocAccessFields_createdAt_Update + delete: PayloadListFiltersDocAccessFields_createdAt_Delete +} + +type PayloadListFiltersDocAccessFields_createdAt_Create { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_createdAt_Read { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_createdAt_Update { + permission: Boolean! +} + +type PayloadListFiltersDocAccessFields_createdAt_Delete { + permission: Boolean! +} + +type PayloadListFiltersCreateDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadListFiltersReadDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadListFiltersUpdateDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadListFiltersDeleteDocAccess { + permission: Boolean! + where: JSONObject +} + +type Access { + canAccessAdmin: Boolean! + pages: pagesAccess + users: usersAccess + payload_locked_documents: payload_locked_documentsAccess + payload_preferences: payload_preferencesAccess + payload_list_filters: payload_list_filtersAccess +} + +type pagesAccess { + fields: PagesFields + create: PagesCreateAccess + read: PagesReadAccess + update: PagesUpdateAccess + delete: PagesDeleteAccess + readVersions: PagesReadVersionsAccess +} + +type PagesFields { + text: PagesFields_text + updatedAt: PagesFields_updatedAt + createdAt: PagesFields_createdAt + _status: PagesFields__status +} + +type PagesFields_text { + create: PagesFields_text_Create + read: PagesFields_text_Read + update: PagesFields_text_Update + delete: PagesFields_text_Delete +} + +type PagesFields_text_Create { + permission: Boolean! +} + +type PagesFields_text_Read { + permission: Boolean! +} + +type PagesFields_text_Update { + permission: Boolean! +} + +type PagesFields_text_Delete { + permission: Boolean! +} + +type PagesFields_updatedAt { + create: PagesFields_updatedAt_Create + read: PagesFields_updatedAt_Read + update: PagesFields_updatedAt_Update + delete: PagesFields_updatedAt_Delete +} + +type PagesFields_updatedAt_Create { + permission: Boolean! +} + +type PagesFields_updatedAt_Read { + permission: Boolean! +} + +type PagesFields_updatedAt_Update { + permission: Boolean! +} + +type PagesFields_updatedAt_Delete { + permission: Boolean! +} + +type PagesFields_createdAt { + create: PagesFields_createdAt_Create + read: PagesFields_createdAt_Read + update: PagesFields_createdAt_Update + delete: PagesFields_createdAt_Delete +} + +type PagesFields_createdAt_Create { + permission: Boolean! +} + +type PagesFields_createdAt_Read { + permission: Boolean! +} + +type PagesFields_createdAt_Update { + permission: Boolean! +} + +type PagesFields_createdAt_Delete { + permission: Boolean! +} + +type PagesFields__status { + create: PagesFields__status_Create + read: PagesFields__status_Read + update: PagesFields__status_Update + delete: PagesFields__status_Delete +} + +type PagesFields__status_Create { + permission: Boolean! +} + +type PagesFields__status_Read { + permission: Boolean! +} + +type PagesFields__status_Update { + permission: Boolean! +} + +type PagesFields__status_Delete { + permission: Boolean! +} + +type PagesCreateAccess { + permission: Boolean! + where: JSONObject +} + +type PagesReadAccess { + permission: Boolean! + where: JSONObject +} + +type PagesUpdateAccess { + permission: Boolean! + where: JSONObject +} + +type PagesDeleteAccess { + permission: Boolean! + where: JSONObject +} + +type PagesReadVersionsAccess { + permission: Boolean! + where: JSONObject +} + +type usersAccess { + fields: UsersFields + create: UsersCreateAccess + read: UsersReadAccess + update: UsersUpdateAccess + delete: UsersDeleteAccess + unlock: UsersUnlockAccess +} + +type UsersFields { + name: UsersFields_name + roles: UsersFields_roles + updatedAt: UsersFields_updatedAt + createdAt: UsersFields_createdAt + email: UsersFields_email +} + +type UsersFields_name { + create: UsersFields_name_Create + read: UsersFields_name_Read + update: UsersFields_name_Update + delete: UsersFields_name_Delete +} + +type UsersFields_name_Create { + permission: Boolean! +} + +type UsersFields_name_Read { + permission: Boolean! +} + +type UsersFields_name_Update { + permission: Boolean! +} + +type UsersFields_name_Delete { + permission: Boolean! +} + +type UsersFields_roles { + create: UsersFields_roles_Create + read: UsersFields_roles_Read + update: UsersFields_roles_Update + delete: UsersFields_roles_Delete +} + +type UsersFields_roles_Create { + permission: Boolean! +} + +type UsersFields_roles_Read { + permission: Boolean! +} + +type UsersFields_roles_Update { + permission: Boolean! +} + +type UsersFields_roles_Delete { + permission: Boolean! +} + +type UsersFields_updatedAt { + create: UsersFields_updatedAt_Create + read: UsersFields_updatedAt_Read + update: UsersFields_updatedAt_Update + delete: UsersFields_updatedAt_Delete +} + +type UsersFields_updatedAt_Create { + permission: Boolean! +} + +type UsersFields_updatedAt_Read { + permission: Boolean! +} + +type UsersFields_updatedAt_Update { + permission: Boolean! +} + +type UsersFields_updatedAt_Delete { + permission: Boolean! +} + +type UsersFields_createdAt { + create: UsersFields_createdAt_Create + read: UsersFields_createdAt_Read + update: UsersFields_createdAt_Update + delete: UsersFields_createdAt_Delete +} + +type UsersFields_createdAt_Create { + permission: Boolean! +} + +type UsersFields_createdAt_Read { + permission: Boolean! +} + +type UsersFields_createdAt_Update { + permission: Boolean! +} + +type UsersFields_createdAt_Delete { + permission: Boolean! +} + +type UsersFields_email { + create: UsersFields_email_Create + read: UsersFields_email_Read + update: UsersFields_email_Update + delete: UsersFields_email_Delete +} + +type UsersFields_email_Create { + permission: Boolean! +} + +type UsersFields_email_Read { + permission: Boolean! +} + +type UsersFields_email_Update { + permission: Boolean! +} + +type UsersFields_email_Delete { + permission: Boolean! +} + +type UsersCreateAccess { + permission: Boolean! + where: JSONObject +} + +type UsersReadAccess { + permission: Boolean! + where: JSONObject +} + +type UsersUpdateAccess { + permission: Boolean! + where: JSONObject +} + +type UsersDeleteAccess { + permission: Boolean! + where: JSONObject +} + +type UsersUnlockAccess { + permission: Boolean! + where: JSONObject +} + +type payload_locked_documentsAccess { + fields: PayloadLockedDocumentsFields + create: PayloadLockedDocumentsCreateAccess + read: PayloadLockedDocumentsReadAccess + update: PayloadLockedDocumentsUpdateAccess + delete: PayloadLockedDocumentsDeleteAccess +} + +type PayloadLockedDocumentsFields { + document: PayloadLockedDocumentsFields_document + globalSlug: PayloadLockedDocumentsFields_globalSlug + user: PayloadLockedDocumentsFields_user + updatedAt: PayloadLockedDocumentsFields_updatedAt + createdAt: PayloadLockedDocumentsFields_createdAt +} + +type PayloadLockedDocumentsFields_document { + create: PayloadLockedDocumentsFields_document_Create + read: PayloadLockedDocumentsFields_document_Read + update: PayloadLockedDocumentsFields_document_Update + delete: PayloadLockedDocumentsFields_document_Delete +} + +type PayloadLockedDocumentsFields_document_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_document_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_document_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_document_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_globalSlug { + create: PayloadLockedDocumentsFields_globalSlug_Create + read: PayloadLockedDocumentsFields_globalSlug_Read + update: PayloadLockedDocumentsFields_globalSlug_Update + delete: PayloadLockedDocumentsFields_globalSlug_Delete +} + +type PayloadLockedDocumentsFields_globalSlug_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_globalSlug_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_globalSlug_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_globalSlug_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_user { + create: PayloadLockedDocumentsFields_user_Create + read: PayloadLockedDocumentsFields_user_Read + update: PayloadLockedDocumentsFields_user_Update + delete: PayloadLockedDocumentsFields_user_Delete +} + +type PayloadLockedDocumentsFields_user_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_user_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_user_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_user_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_updatedAt { + create: PayloadLockedDocumentsFields_updatedAt_Create + read: PayloadLockedDocumentsFields_updatedAt_Read + update: PayloadLockedDocumentsFields_updatedAt_Update + delete: PayloadLockedDocumentsFields_updatedAt_Delete +} + +type PayloadLockedDocumentsFields_updatedAt_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_updatedAt_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_updatedAt_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_updatedAt_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_createdAt { + create: PayloadLockedDocumentsFields_createdAt_Create + read: PayloadLockedDocumentsFields_createdAt_Read + update: PayloadLockedDocumentsFields_createdAt_Update + delete: PayloadLockedDocumentsFields_createdAt_Delete +} + +type PayloadLockedDocumentsFields_createdAt_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_createdAt_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_createdAt_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_createdAt_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsCreateAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsReadAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsUpdateAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsDeleteAccess { + permission: Boolean! + where: JSONObject +} + +type payload_preferencesAccess { + fields: PayloadPreferencesFields + create: PayloadPreferencesCreateAccess + read: PayloadPreferencesReadAccess + update: PayloadPreferencesUpdateAccess + delete: PayloadPreferencesDeleteAccess +} + +type PayloadPreferencesFields { + user: PayloadPreferencesFields_user + key: PayloadPreferencesFields_key + value: PayloadPreferencesFields_value + updatedAt: PayloadPreferencesFields_updatedAt + createdAt: PayloadPreferencesFields_createdAt +} + +type PayloadPreferencesFields_user { + create: PayloadPreferencesFields_user_Create + read: PayloadPreferencesFields_user_Read + update: PayloadPreferencesFields_user_Update + delete: PayloadPreferencesFields_user_Delete +} + +type PayloadPreferencesFields_user_Create { + permission: Boolean! +} + +type PayloadPreferencesFields_user_Read { + permission: Boolean! +} + +type PayloadPreferencesFields_user_Update { + permission: Boolean! +} + +type PayloadPreferencesFields_user_Delete { + permission: Boolean! +} + +type PayloadPreferencesFields_key { + create: PayloadPreferencesFields_key_Create + read: PayloadPreferencesFields_key_Read + update: PayloadPreferencesFields_key_Update + delete: PayloadPreferencesFields_key_Delete +} + +type PayloadPreferencesFields_key_Create { + permission: Boolean! +} + +type PayloadPreferencesFields_key_Read { + permission: Boolean! +} + +type PayloadPreferencesFields_key_Update { + permission: Boolean! +} + +type PayloadPreferencesFields_key_Delete { + permission: Boolean! +} + +type PayloadPreferencesFields_value { + create: PayloadPreferencesFields_value_Create + read: PayloadPreferencesFields_value_Read + update: PayloadPreferencesFields_value_Update + delete: PayloadPreferencesFields_value_Delete +} + +type PayloadPreferencesFields_value_Create { + permission: Boolean! +} + +type PayloadPreferencesFields_value_Read { + permission: Boolean! +} + +type PayloadPreferencesFields_value_Update { + permission: Boolean! +} + +type PayloadPreferencesFields_value_Delete { + permission: Boolean! +} + +type PayloadPreferencesFields_updatedAt { + create: PayloadPreferencesFields_updatedAt_Create + read: PayloadPreferencesFields_updatedAt_Read + update: PayloadPreferencesFields_updatedAt_Update + delete: PayloadPreferencesFields_updatedAt_Delete +} + +type PayloadPreferencesFields_updatedAt_Create { + permission: Boolean! +} + +type PayloadPreferencesFields_updatedAt_Read { + permission: Boolean! +} + +type PayloadPreferencesFields_updatedAt_Update { + permission: Boolean! +} + +type PayloadPreferencesFields_updatedAt_Delete { + permission: Boolean! +} + +type PayloadPreferencesFields_createdAt { + create: PayloadPreferencesFields_createdAt_Create + read: PayloadPreferencesFields_createdAt_Read + update: PayloadPreferencesFields_createdAt_Update + delete: PayloadPreferencesFields_createdAt_Delete +} + +type PayloadPreferencesFields_createdAt_Create { + permission: Boolean! +} + +type PayloadPreferencesFields_createdAt_Read { + permission: Boolean! +} + +type PayloadPreferencesFields_createdAt_Update { + permission: Boolean! +} + +type PayloadPreferencesFields_createdAt_Delete { + permission: Boolean! +} + +type PayloadPreferencesCreateAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesReadAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesUpdateAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesDeleteAccess { + permission: Boolean! + where: JSONObject +} + +type payload_list_filtersAccess { + fields: PayloadListFiltersFields + create: PayloadListFiltersCreateAccess + read: PayloadListFiltersReadAccess + update: PayloadListFiltersUpdateAccess + delete: PayloadListFiltersDeleteAccess +} + +type PayloadListFiltersFields { + Name: PayloadListFiltersFields_Name + Where: PayloadListFiltersFields_Where + Columns: PayloadListFiltersFields_Columns + Collection: PayloadListFiltersFields_Collection + updatedAt: PayloadListFiltersFields_updatedAt + createdAt: PayloadListFiltersFields_createdAt +} + +type PayloadListFiltersFields_Name { + create: PayloadListFiltersFields_Name_Create + read: PayloadListFiltersFields_Name_Read + update: PayloadListFiltersFields_Name_Update + delete: PayloadListFiltersFields_Name_Delete +} + +type PayloadListFiltersFields_Name_Create { + permission: Boolean! +} + +type PayloadListFiltersFields_Name_Read { + permission: Boolean! +} + +type PayloadListFiltersFields_Name_Update { + permission: Boolean! +} + +type PayloadListFiltersFields_Name_Delete { + permission: Boolean! +} + +type PayloadListFiltersFields_Where { + create: PayloadListFiltersFields_Where_Create + read: PayloadListFiltersFields_Where_Read + update: PayloadListFiltersFields_Where_Update + delete: PayloadListFiltersFields_Where_Delete +} + +type PayloadListFiltersFields_Where_Create { + permission: Boolean! +} + +type PayloadListFiltersFields_Where_Read { + permission: Boolean! +} + +type PayloadListFiltersFields_Where_Update { + permission: Boolean! +} + +type PayloadListFiltersFields_Where_Delete { + permission: Boolean! +} + +type PayloadListFiltersFields_Columns { + create: PayloadListFiltersFields_Columns_Create + read: PayloadListFiltersFields_Columns_Read + update: PayloadListFiltersFields_Columns_Update + delete: PayloadListFiltersFields_Columns_Delete +} + +type PayloadListFiltersFields_Columns_Create { + permission: Boolean! +} + +type PayloadListFiltersFields_Columns_Read { + permission: Boolean! +} + +type PayloadListFiltersFields_Columns_Update { + permission: Boolean! +} + +type PayloadListFiltersFields_Columns_Delete { + permission: Boolean! +} + +type PayloadListFiltersFields_Collection { + create: PayloadListFiltersFields_Collection_Create + read: PayloadListFiltersFields_Collection_Read + update: PayloadListFiltersFields_Collection_Update + delete: PayloadListFiltersFields_Collection_Delete +} + +type PayloadListFiltersFields_Collection_Create { + permission: Boolean! +} + +type PayloadListFiltersFields_Collection_Read { + permission: Boolean! +} + +type PayloadListFiltersFields_Collection_Update { + permission: Boolean! +} + +type PayloadListFiltersFields_Collection_Delete { + permission: Boolean! +} + +type PayloadListFiltersFields_updatedAt { + create: PayloadListFiltersFields_updatedAt_Create + read: PayloadListFiltersFields_updatedAt_Read + update: PayloadListFiltersFields_updatedAt_Update + delete: PayloadListFiltersFields_updatedAt_Delete +} + +type PayloadListFiltersFields_updatedAt_Create { + permission: Boolean! +} + +type PayloadListFiltersFields_updatedAt_Read { + permission: Boolean! +} + +type PayloadListFiltersFields_updatedAt_Update { + permission: Boolean! +} + +type PayloadListFiltersFields_updatedAt_Delete { + permission: Boolean! +} + +type PayloadListFiltersFields_createdAt { + create: PayloadListFiltersFields_createdAt_Create + read: PayloadListFiltersFields_createdAt_Read + update: PayloadListFiltersFields_createdAt_Update + delete: PayloadListFiltersFields_createdAt_Delete +} + +type PayloadListFiltersFields_createdAt_Create { + permission: Boolean! +} + +type PayloadListFiltersFields_createdAt_Read { + permission: Boolean! +} + +type PayloadListFiltersFields_createdAt_Update { + permission: Boolean! +} + +type PayloadListFiltersFields_createdAt_Delete { + permission: Boolean! +} + +type PayloadListFiltersCreateAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadListFiltersReadAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadListFiltersUpdateAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadListFiltersDeleteAccess { + permission: Boolean! + where: JSONObject +} + +type Mutation { + createPage(data: mutationPageInput!, draft: Boolean): Page + updatePage(id: String!, autosave: Boolean, data: mutationPageUpdateInput!, draft: Boolean): Page + deletePage(id: String!): Page + duplicatePage(id: String!, data: mutationPageInput!): Page + restoreVersionPage(id: String, draft: Boolean): Page + createUser(data: mutationUserInput!, draft: Boolean): User + updateUser(id: String!, autosave: Boolean, data: mutationUserUpdateInput!, draft: Boolean): User + deleteUser(id: String!): User + refreshTokenUser: usersRefreshedUser + logoutUser: String + unlockUser(email: String!): Boolean! + loginUser(email: String!, password: String): usersLoginResult + forgotPasswordUser(disableEmail: Boolean, expiration: Int, email: String!): Boolean! + resetPasswordUser(password: String, token: String): usersResetPassword + verifyEmailUser(token: String): Boolean + createPayloadLockedDocument(data: mutationPayloadLockedDocumentInput!, draft: Boolean): PayloadLockedDocument + updatePayloadLockedDocument(id: String!, autosave: Boolean, data: mutationPayloadLockedDocumentUpdateInput!, draft: Boolean): PayloadLockedDocument + deletePayloadLockedDocument(id: String!): PayloadLockedDocument + duplicatePayloadLockedDocument(id: String!, data: mutationPayloadLockedDocumentInput!): PayloadLockedDocument + createPayloadPreference(data: mutationPayloadPreferenceInput!, draft: Boolean): PayloadPreference + updatePayloadPreference(id: String!, autosave: Boolean, data: mutationPayloadPreferenceUpdateInput!, draft: Boolean): PayloadPreference + deletePayloadPreference(id: String!): PayloadPreference + duplicatePayloadPreference(id: String!, data: mutationPayloadPreferenceInput!): PayloadPreference + createPayloadListFilter(data: mutationPayloadListFilterInput!, draft: Boolean): PayloadListFilter + updatePayloadListFilter(id: String!, autosave: Boolean, data: mutationPayloadListFilterUpdateInput!, draft: Boolean): PayloadListFilter + deletePayloadListFilter(id: String!): PayloadListFilter + duplicatePayloadListFilter(id: String!, data: mutationPayloadListFilterInput!): PayloadListFilter +} + +input mutationPageInput { + text: String + updatedAt: String + createdAt: String + _status: Page__status_MutationInput +} + +enum Page__status_MutationInput { + draft + published +} + +input mutationPageUpdateInput { + text: String + updatedAt: String + createdAt: String + _status: PageUpdate__status_MutationInput +} + +enum PageUpdate__status_MutationInput { + draft + published +} + +input mutationUserInput { + name: String + roles: [User_roles_MutationInput] + updatedAt: String + createdAt: String + email: String! + resetPasswordToken: String + resetPasswordExpiration: String + salt: String + hash: String + loginAttempts: Float + lockUntil: String + password: String! +} + +enum User_roles_MutationInput { + is_user + is_admin +} + +input mutationUserUpdateInput { + name: String + roles: [UserUpdate_roles_MutationInput] + updatedAt: String + createdAt: String + email: String + resetPasswordToken: String + resetPasswordExpiration: String + salt: String + hash: String + loginAttempts: Float + lockUntil: String + password: String +} + +enum UserUpdate_roles_MutationInput { + is_user + is_admin +} + +type usersRefreshedUser { + exp: Int + refreshedToken: String + strategy: String + user: usersJWT +} + +type usersJWT { + email: EmailAddress! + collection: String! +} + +type usersLoginResult { + exp: Int + token: String + user: User +} + +type usersResetPassword { + token: String + user: User +} + +input mutationPayloadLockedDocumentInput { + document: PayloadLockedDocument_DocumentRelationshipInput + globalSlug: String + user: PayloadLockedDocument_UserRelationshipInput + updatedAt: String + createdAt: String +} + +input PayloadLockedDocument_DocumentRelationshipInput { + relationTo: PayloadLockedDocument_DocumentRelationshipInputRelationTo + value: JSON +} + +enum PayloadLockedDocument_DocumentRelationshipInputRelationTo { + pages + users +} + +input PayloadLockedDocument_UserRelationshipInput { + relationTo: PayloadLockedDocument_UserRelationshipInputRelationTo + value: JSON +} + +enum PayloadLockedDocument_UserRelationshipInputRelationTo { + users +} + +input mutationPayloadLockedDocumentUpdateInput { + document: PayloadLockedDocumentUpdate_DocumentRelationshipInput + globalSlug: String + user: PayloadLockedDocumentUpdate_UserRelationshipInput + updatedAt: String + createdAt: String +} + +input PayloadLockedDocumentUpdate_DocumentRelationshipInput { + relationTo: PayloadLockedDocumentUpdate_DocumentRelationshipInputRelationTo + value: JSON +} + +enum PayloadLockedDocumentUpdate_DocumentRelationshipInputRelationTo { + pages + users +} + +input PayloadLockedDocumentUpdate_UserRelationshipInput { + relationTo: PayloadLockedDocumentUpdate_UserRelationshipInputRelationTo + value: JSON +} + +enum PayloadLockedDocumentUpdate_UserRelationshipInputRelationTo { + users +} + +input mutationPayloadPreferenceInput { + user: PayloadPreference_UserRelationshipInput + key: String + value: JSON + updatedAt: String + createdAt: String +} + +input PayloadPreference_UserRelationshipInput { + relationTo: PayloadPreference_UserRelationshipInputRelationTo + value: JSON +} + +enum PayloadPreference_UserRelationshipInputRelationTo { + users +} + +input mutationPayloadPreferenceUpdateInput { + user: PayloadPreferenceUpdate_UserRelationshipInput + key: String + value: JSON + updatedAt: String + createdAt: String +} + +input PayloadPreferenceUpdate_UserRelationshipInput { + relationTo: PayloadPreferenceUpdate_UserRelationshipInputRelationTo + value: JSON +} + +enum PayloadPreferenceUpdate_UserRelationshipInputRelationTo { + users +} + +input mutationPayloadListFilterInput { + Name: String! + Where: JSON! + Columns: JSON + Collection: PayloadListFilter_Collection_MutationInput! + updatedAt: String + createdAt: String +} + +enum PayloadListFilter_Collection_MutationInput { + pages + users + payload_locked_documents + payload_preferences +} + +input mutationPayloadListFilterUpdateInput { + Name: String + Where: JSON + Columns: JSON + Collection: PayloadListFilterUpdate_Collection_MutationInput + updatedAt: String + createdAt: String +} + +enum PayloadListFilterUpdate_Collection_MutationInput { + pages + users + payload_locked_documents + payload_preferences +} \ No newline at end of file diff --git a/test/query-presets/seed.ts b/test/query-presets/seed.ts new file mode 100644 index 0000000000..38f116f67e --- /dev/null +++ b/test/query-presets/seed.ts @@ -0,0 +1,182 @@ +import type { Payload, QueryPreset } from 'payload' + +import { devUser as devCredentials, regularUser as regularCredentials } from '../credentials.js' +import { executePromises } from '../helpers/executePromises.js' +import { seedDB } from '../helpers/seed.js' +import { collectionSlugs, pagesSlug, usersSlug } from './slugs.js' + +type SeededQueryPreset = { + relatedCollection: 'pages' +} & Omit + +export const seedData: { + everyone: SeededQueryPreset + onlyMe: SeededQueryPreset + specificUsers: (args: { userID: string }) => SeededQueryPreset +} = { + onlyMe: { + relatedCollection: pagesSlug, + isShared: false, + title: 'Only Me', + columns: [ + { + accessor: 'text', + active: true, + }, + ], + access: { + delete: { + constraint: 'onlyMe', + }, + update: { + constraint: 'onlyMe', + }, + read: { + constraint: 'onlyMe', + }, + }, + where: { + text: { + equals: 'example page', + }, + }, + }, + everyone: { + relatedCollection: pagesSlug, + isShared: true, + title: 'Everyone', + access: { + delete: { + constraint: 'everyone', + }, + update: { + constraint: 'everyone', + }, + read: { + constraint: 'everyone', + }, + }, + columns: [ + { + accessor: 'text', + active: true, + }, + ], + where: { + text: { + equals: 'example page', + }, + }, + }, + specificUsers: ({ userID }: { userID: string }) => ({ + title: 'Specific Users', + isShared: true, + where: { + text: { + equals: 'example page', + }, + }, + access: { + read: { + constraint: 'specificUsers', + users: [userID], + }, + update: { + constraint: 'specificUsers', + users: [userID], + }, + delete: { + constraint: 'specificUsers', + users: [userID], + }, + }, + columns: [ + { + accessor: 'text', + active: true, + }, + ], + relatedCollection: pagesSlug, + }), +} + +export const seed = async (_payload: Payload) => { + const [devUser] = await executePromises( + [ + () => + _payload.create({ + collection: usersSlug, + data: { + email: devCredentials.email, + password: devCredentials.password, + name: 'Admin', + roles: ['admin'], + }, + }), + () => + _payload.create({ + collection: usersSlug, + data: { + email: regularCredentials.email, + password: regularCredentials.password, + name: 'User', + roles: ['user'], + }, + }), + () => + _payload.create({ + collection: usersSlug, + data: { + email: 'anonymous@email.com', + password: regularCredentials.password, + name: 'User', + roles: ['anonymous'], + }, + }), + ], + false, + ) + + await executePromises( + [ + () => + _payload.create({ + collection: pagesSlug, + data: { + text: 'example page', + }, + }), + () => + _payload.create({ + collection: 'payload-query-presets', + user: devUser, + overrideAccess: false, + data: seedData.specificUsers({ userID: devUser?.id || '' }), + }), + () => + _payload.create({ + collection: 'payload-query-presets', + user: devUser, + overrideAccess: false, + data: seedData.everyone, + }), + () => + _payload.create({ + collection: 'payload-query-presets', + user: devUser, + overrideAccess: false, + data: seedData.onlyMe, + }), + ], + false, + ) +} + +export async function clearAndSeedEverything(_payload: Payload) { + return await seedDB({ + _payload, + collectionSlugs, + seedFunction: seed, + snapshotKey: 'adminTests', + }) +} diff --git a/test/query-presets/slugs.ts b/test/query-presets/slugs.ts new file mode 100644 index 0000000000..85c6ec36fd --- /dev/null +++ b/test/query-presets/slugs.ts @@ -0,0 +1,5 @@ +export const usersSlug = 'users' + +export const pagesSlug = 'pages' + +export const collectionSlugs = [usersSlug, pagesSlug] diff --git a/test/query-presets/tsconfig.eslint.json b/test/query-presets/tsconfig.eslint.json new file mode 100644 index 0000000000..b34cc7afbb --- /dev/null +++ b/test/query-presets/tsconfig.eslint.json @@ -0,0 +1,13 @@ +{ + // extend your base config to share compilerOptions, etc + //"extends": "./tsconfig.json", + "compilerOptions": { + // ensure that nobody can accidentally use this config for a build + "noEmit": true + }, + "include": [ + // whatever paths you intend to lint + "./**/*.ts", + "./**/*.tsx" + ] +} diff --git a/test/query-presets/tsconfig.json b/test/query-presets/tsconfig.json new file mode 100644 index 0000000000..3c43903cfd --- /dev/null +++ b/test/query-presets/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../tsconfig.json" +} diff --git a/test/sort/int.spec.ts b/test/sort/int.spec.ts index 730f7b4895..805370aa11 100644 --- a/test/sort/int.spec.ts +++ b/test/sort/int.spec.ts @@ -15,8 +15,8 @@ const dirname = path.dirname(filename) describe('Sort', () => { beforeAll(async () => { - const initialized = await initPayloadInt(dirname) - ;({ payload, restClient } = initialized) + // @ts-expect-error: initPayloadInt does not have a proper type definition + ;({ payload, restClient } = await initPayloadInt(dirname)) }) afterAll(async () => { diff --git a/tsconfig.base.json b/tsconfig.base.json index c9793d25c6..daa36c7211 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -31,7 +31,7 @@ } ], "paths": { - "@payload-config": ["./test/_community/config.ts"], + "@payload-config": ["./test/query-presets/config.ts"], "@payloadcms/admin-bar": ["./packages/admin-bar/src"], "@payloadcms/live-preview": ["./packages/live-preview/src"], "@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"], From 8d374cb57d939c23564a0818b08102ffe2ceec81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Mon, 24 Mar 2025 14:31:09 -0300 Subject: [PATCH 05/77] chore(admin-bar): enable TypeScript strict (#11834) Looks like this one was bug-free! I don't know why strict was disabled --- packages/admin-bar/tsconfig.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/admin-bar/tsconfig.json b/packages/admin-bar/tsconfig.json index 14564e0715..45209999a2 100644 --- a/packages/admin-bar/tsconfig.json +++ b/packages/admin-bar/tsconfig.json @@ -1,9 +1,4 @@ { "extends": "../../tsconfig.base.json", - "compilerOptions": { - /* TODO: remove the following lines */ - "strict": false, - "noUncheckedIndexedAccess": false, - }, "references": [{ "path": "../payload" }] } From fb01b4046dbc769bd36c962738c412935c3ae17d Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Mon, 24 Mar 2025 14:08:26 -0600 Subject: [PATCH 06/77] fix(richtext-lexical): ensure initial state for nested lexical fields (#11837) Lexical fields nested in other fields (e.g. groups, blocks, arrays) did not have their initial sub-field states generated, leading in multiple client-side fetches to fetch initial state when the page is loaded. Before: https://github.com/user-attachments/assets/c1d808ef-1bd3-4fb1-a9d6-d5ef81cef16d After: https://github.com/user-attachments/assets/0dcda515-ce68-4107-ba29-a08fff851ae3 --- .../richtext-lexical/src/field/rscEntry.tsx | 4 +-- .../Lexical/e2e/blocks/e2e.spec.ts | 18 ++++++++++ .../collections/LexicalInBlock/index.ts | 17 +++++++++ test/fields/seed.ts | 36 +++++++++++++++++++ 4 files changed, 73 insertions(+), 2 deletions(-) diff --git a/packages/richtext-lexical/src/field/rscEntry.tsx b/packages/richtext-lexical/src/field/rscEntry.tsx index a232efcfff..6c3f663e2f 100644 --- a/packages/richtext-lexical/src/field/rscEntry.tsx +++ b/packages/richtext-lexical/src/field/rscEntry.tsx @@ -50,7 +50,7 @@ export const RscEntryLexicalField: React.FC< }) let initialLexicalFormState = {} - if (args.data?.[field.name]?.root?.children?.length) { + if (args.siblingData?.[field.name]?.root?.children?.length) { initialLexicalFormState = await buildInitialState({ context: { id: args.id, @@ -66,7 +66,7 @@ export const RscEntryLexicalField: React.FC< renderFieldFn: renderField, req: args.req, }, - nodeData: args.data?.[field.name]?.root?.children as SerializedLexicalNode[], + nodeData: args.siblingData?.[field.name]?.root?.children as SerializedLexicalNode[], }) } diff --git a/test/fields/collections/Lexical/e2e/blocks/e2e.spec.ts b/test/fields/collections/Lexical/e2e/blocks/e2e.spec.ts index b9ea5af62f..9a910b0002 100644 --- a/test/fields/collections/Lexical/e2e/blocks/e2e.spec.ts +++ b/test/fields/collections/Lexical/e2e/blocks/e2e.spec.ts @@ -1507,6 +1507,24 @@ describe('lexicalBlocks', () => { ), ).toHaveText('Some Description') }) + + test('ensure individual inline blocks in lexical editor within a block have initial state on initial load', async () => { + await page.goto('http://localhost:3000/admin/collections/LexicalInBlock?limit=10') + + await assertNetworkRequests( + page, + '/collections/LexicalInBlock/', + async () => { + await page.locator('.cell-id a').first().click() + await page.waitForURL(`**/collections/LexicalInBlock/**`) + + await expect( + page.locator('.inline-block:has-text("Inline Block In Lexical")'), + ).toHaveCount(20) + }, + { allowedNumberOfRequests: 1 }, + ) + }) }) describe('inline blocks', () => { diff --git a/test/fields/collections/LexicalInBlock/index.ts b/test/fields/collections/LexicalInBlock/index.ts index 81bb3ca737..b454738345 100644 --- a/test/fields/collections/LexicalInBlock/index.ts +++ b/test/fields/collections/LexicalInBlock/index.ts @@ -42,6 +42,23 @@ export const LexicalInBlock: CollectionConfig = { { name: 'lexical', type: 'richText', + editor: lexicalEditor({ + features: [ + BlocksFeature({ + inlineBlocks: [ + { + slug: 'inlineBlockInLexical', + fields: [ + { + name: 'text', + type: 'text', + }, + ], + }, + ], + }), + ], + }), }, ], }, diff --git a/test/fields/seed.ts b/test/fields/seed.ts index 597ed485ac..ead7d9100a 100644 --- a/test/fields/seed.ts +++ b/test/fields/seed.ts @@ -511,6 +511,16 @@ export const seed = async (_payload: Payload) => { depth: 0, }) + const getInlineBlock = () => ({ + type: 'inlineBlock', + fields: { + id: Math.random().toString(36).substring(2, 15), + text: 'text', + blockType: 'inlineBlockInLexical', + }, + version: 1, + }) + await _payload.create({ collection: 'LexicalInBlock', depth: 0, @@ -548,6 +558,32 @@ export const seed = async (_payload: Payload) => { blockName: '2', lexical: textToLexicalJSON({ text: '2' }), }, + { + blockType: 'lexicalInBlock2', + lexical: { + root: { + children: [ + { + children: [...Array.from({ length: 20 }, () => getInlineBlock())], + direction: null, + format: '', + indent: 0, + type: 'paragraph', + version: 1, + textFormat: 0, + textStyle: '', + }, + ], + direction: null, + format: '', + indent: 0, + type: 'root', + version: 1, + }, + }, + id: '67e1af0b78de3228e23ef1d5', + blockName: '1', + }, ], }, }) From 3c4b3ee527137b59cedbcbc8b794c28949d9c6db Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Mon, 24 Mar 2025 14:57:36 -0600 Subject: [PATCH 07/77] fix(next): version view breaking for deeply nested tabs, rows and collapsibles (#11808) Fixes #11458 Some complex, nested fields were receiving incorrect field paths and schema paths, leading to a `"Error: No client field found"` error. This PR ensures field paths are calculated correctly, by matching it to how they're calculated in payload hooks. --- .../RenderFieldsToDiff/buildVersionFields.tsx | 19 +++--- .../utilities/getFieldPathsModified.ts | 12 +--- .../src/fields/utilities/getFieldPaths.ts | 0 test/versions/collections/Diff.ts | 58 +++++++++++++++++++ test/versions/e2e.spec.ts | 56 ++++++++++++++++++ test/versions/payload-types.ts | 51 ++++++++++++++-- test/versions/seed.ts | 24 ++++++++ 7 files changed, 194 insertions(+), 26 deletions(-) delete mode 100644 packages/payload/src/fields/utilities/getFieldPaths.ts diff --git a/packages/next/src/views/Version/RenderFieldsToDiff/buildVersionFields.tsx b/packages/next/src/views/Version/RenderFieldsToDiff/buildVersionFields.tsx index 7accde08a0..9d448bf261 100644 --- a/packages/next/src/views/Version/RenderFieldsToDiff/buildVersionFields.tsx +++ b/packages/next/src/views/Version/RenderFieldsToDiff/buildVersionFields.tsx @@ -84,7 +84,7 @@ export const buildVersionFields = ({ const { indexPath, path, schemaPath } = getFieldPathsModified({ field, index: fieldIndex, - parentIndexPath: 'name' in field ? '' : parentIndexPath, + parentIndexPath, parentPath, parentSchemaPath, }) @@ -253,15 +253,14 @@ const buildVersionField = ({ tabIndex++ const isNamedTab = tabHasName(tab) + const tabAsField = { ...tab, type: 'tab' } + const { indexPath: tabIndexPath, path: tabPath, schemaPath: tabSchemaPath, } = getFieldPathsModified({ - field: { - ...tab, - type: 'tab', - }, + field: tabAsField, index: tabIndex, parentIndexPath: indexPath, parentPath, @@ -280,8 +279,8 @@ const buildVersionField = ({ modifiedOnly, parentIndexPath: isNamedTab ? '' : tabIndexPath, parentIsLocalized: parentIsLocalized || tab.localized, - parentPath: tabPath, - parentSchemaPath: tabSchemaPath, + parentPath: isNamedTab ? tabPath : path, + parentSchemaPath: isNamedTab ? tabSchemaPath : parentSchemaPath, req, selectedLocales, versionSiblingData: 'name' in tab ? versionValue?.[tab.name] : versionValue, @@ -289,7 +288,7 @@ const buildVersionField = ({ label: tab.label, }) } - } // At this point, we are dealing with a `row`, etc + } // At this point, we are dealing with a `row`, `collapsible`, etc else if ('fields' in field) { if (field.type === 'array' && versionValue) { const arrayValue = Array.isArray(versionValue) ? versionValue : [] @@ -328,8 +327,8 @@ const buildVersionField = ({ modifiedOnly, parentIndexPath: 'name' in field ? '' : indexPath, parentIsLocalized: parentIsLocalized || ('localized' in field && field.localized), - parentPath: path, - parentSchemaPath: schemaPath, + parentPath: 'name' in field ? path : parentPath, + parentSchemaPath: 'name' in field ? schemaPath : parentSchemaPath, req, selectedLocales, versionSiblingData: versionValue as object, diff --git a/packages/next/src/views/Version/RenderFieldsToDiff/utilities/getFieldPathsModified.ts b/packages/next/src/views/Version/RenderFieldsToDiff/utilities/getFieldPathsModified.ts index 417b1692be..2de168b134 100644 --- a/packages/next/src/views/Version/RenderFieldsToDiff/utilities/getFieldPathsModified.ts +++ b/packages/next/src/views/Version/RenderFieldsToDiff/utilities/getFieldPathsModified.ts @@ -42,19 +42,11 @@ export function getFieldPathsModified({ const parentPathToUse = parentIsUnnamed ? parentWithoutIndex : parentPath - const parentSchemaPathSegments = parentSchemaPath.split('.') - const parentSchemaIsUnnamed = - parentSchemaPathSegments[parentSchemaPathSegments.length - 1].startsWith('_index-') - const parentSchemaWithoutIndex = parentSchemaIsUnnamed - ? parentSchemaPathSegments.slice(0, -1).join('.') - : parentSchemaPath - const parentSchemaPathToUse = parentSchemaIsUnnamed ? parentSchemaWithoutIndex : parentSchemaPath - if ('name' in field) { return { indexPath: '', path: `${parentPathToUse ? parentPathToUse + '.' : ''}${field.name}`, - schemaPath: `${parentSchemaPathToUse ? parentSchemaPathToUse + '.' : ''}${field.name}`, + schemaPath: `${parentSchemaPath ? parentSchemaPath + '.' : ''}${field.name}`, } } @@ -63,6 +55,6 @@ export function getFieldPathsModified({ return { indexPath: `${parentIndexPath ? parentIndexPath + '-' : ''}${index}`, path: `${parentPathToUse ? parentPathToUse + '.' : ''}${indexSuffix}`, - schemaPath: `${!parentIsUnnamed && parentSchemaPathToUse ? parentSchemaPathToUse + '.' : ''}${indexSuffix}`, + schemaPath: `${!parentIsUnnamed && parentSchemaPath ? parentSchemaPath + '.' : ''}${indexSuffix}`, } } diff --git a/packages/payload/src/fields/utilities/getFieldPaths.ts b/packages/payload/src/fields/utilities/getFieldPaths.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/test/versions/collections/Diff.ts b/test/versions/collections/Diff.ts index eec2d3195a..727758c99b 100644 --- a/test/versions/collections/Diff.ts +++ b/test/versions/collections/Diff.ts @@ -39,6 +39,64 @@ export const Diff: CollectionConfig = { }, ], }, + { + slug: 'CollapsibleBlock', + fields: [ + { + type: 'collapsible', + label: 'Collapsible', + fields: [ + { + type: 'collapsible', + label: 'Nested Collapsible', + fields: [ + { + name: 'textInCollapsibleInCollapsibleBlock', + type: 'text', + }, + ], + }, + { + type: 'row', + fields: [ + { + name: 'textInRowInCollapsibleBlock', + type: 'text', + }, + ], + }, + ], + }, + ], + }, + { + slug: 'TabsBlock', + fields: [ + { + type: 'tabs', + tabs: [ + { + name: 'namedTab1InBlock', + fields: [ + { + name: 'textInNamedTab1InBlock', + type: 'text', + }, + ], + }, + { + label: 'Unnamed Tab 2 In Block', + fields: [ + { + name: 'textInUnnamedTab2InBlock', + type: 'text', + }, + ], + }, + ], + }, + ], + }, ], }, { diff --git a/test/versions/e2e.spec.ts b/test/versions/e2e.spec.ts index 88b2fc62c4..42b3ea139b 100644 --- a/test/versions/e2e.spec.ts +++ b/test/versions/e2e.spec.ts @@ -1213,6 +1213,62 @@ describe('Versions', () => { await expect(textInBlock.locator('tr').nth(1).locator('td').nth(3)).toHaveText('textInBlock2') }) + test('correctly renders diff for collapsibles within block fields', async () => { + await navigateToVersionFieldsDiff() + + const textInBlock = page.locator( + '[data-field-path="blocks.1.textInCollapsibleInCollapsibleBlock"]', + ) + + await expect(textInBlock.locator('tr').nth(1).locator('td').nth(1)).toHaveText( + 'textInCollapsibleInCollapsibleBlock', + ) + await expect(textInBlock.locator('tr').nth(1).locator('td').nth(3)).toHaveText( + 'textInCollapsibleInCollapsibleBlock2', + ) + }) + + test('correctly renders diff for rows within block fields', async () => { + await navigateToVersionFieldsDiff() + + const textInBlock = page.locator('[data-field-path="blocks.1.textInRowInCollapsibleBlock"]') + + await expect(textInBlock.locator('tr').nth(1).locator('td').nth(1)).toHaveText( + 'textInRowInCollapsibleBlock', + ) + await expect(textInBlock.locator('tr').nth(1).locator('td').nth(3)).toHaveText( + 'textInRowInCollapsibleBlock2', + ) + }) + + test('correctly renders diff for named tabs within block fields', async () => { + await navigateToVersionFieldsDiff() + + const textInBlock = page.locator( + '[data-field-path="blocks.2.namedTab1InBlock.textInNamedTab1InBlock"]', + ) + + await expect(textInBlock.locator('tr').nth(1).locator('td').nth(1)).toHaveText( + 'textInNamedTab1InBlock', + ) + await expect(textInBlock.locator('tr').nth(1).locator('td').nth(3)).toHaveText( + 'textInNamedTab1InBlock2', + ) + }) + + test('correctly renders diff for unnamed tabs within block fields', async () => { + await navigateToVersionFieldsDiff() + + const textInBlock = page.locator('[data-field-path="blocks.2.textInUnnamedTab2InBlock"]') + + await expect(textInBlock.locator('tr').nth(1).locator('td').nth(1)).toHaveText( + 'textInUnnamedTab2InBlock', + ) + await expect(textInBlock.locator('tr').nth(1).locator('td').nth(3)).toHaveText( + 'textInUnnamedTab2InBlock2', + ) + }) + test('correctly renders diff for checkbox fields', async () => { await navigateToVersionFieldsDiff() diff --git a/test/versions/payload-types.ts b/test/versions/payload-types.ts index ca3849e1d9..95ec5870e9 100644 --- a/test/versions/payload-types.ts +++ b/test/versions/payload-types.ts @@ -54,6 +54,7 @@ export type SupportedTimezones = | 'Asia/Singapore' | 'Asia/Tokyo' | 'Asia/Seoul' + | 'Australia/Brisbane' | 'Australia/Sydney' | 'Pacific/Guam' | 'Pacific/Noumea' @@ -312,12 +313,30 @@ export interface Diff { }[] | null; blocks?: - | { - textInBlock?: string | null; - id?: string | null; - blockName?: string | null; - blockType: 'TextBlock'; - }[] + | ( + | { + textInBlock?: string | null; + id?: string | null; + blockName?: string | null; + blockType: 'TextBlock'; + } + | { + textInCollapsibleInCollapsibleBlock?: string | null; + textInRowInCollapsibleBlock?: string | null; + id?: string | null; + blockName?: string | null; + blockType: 'CollapsibleBlock'; + } + | { + namedTab1InBlock?: { + textInNamedTab1InBlock?: string | null; + }; + textInUnnamedTab2InBlock?: string | null; + id?: string | null; + blockName?: string | null; + blockType: 'TabsBlock'; + } + )[] | null; checkbox?: boolean | null; code?: string | null; @@ -772,6 +791,26 @@ export interface DiffSelect { id?: T; blockName?: T; }; + CollapsibleBlock?: + | T + | { + textInCollapsibleInCollapsibleBlock?: T; + textInRowInCollapsibleBlock?: T; + id?: T; + blockName?: T; + }; + TabsBlock?: + | T + | { + namedTab1InBlock?: + | T + | { + textInNamedTab1InBlock?: T; + }; + textInUnnamedTab2InBlock?: T; + id?: T; + blockName?: T; + }; }; checkbox?: T; code?: T; diff --git a/test/versions/seed.ts b/test/versions/seed.ts index ff10f7af4e..6785d26ca1 100644 --- a/test/versions/seed.ts +++ b/test/versions/seed.ts @@ -138,6 +138,18 @@ export async function seed(_payload: Payload, parallel: boolean = false) { blockType: 'TextBlock', textInBlock: 'textInBlock', }, + { + blockType: 'CollapsibleBlock', + textInCollapsibleInCollapsibleBlock: 'textInCollapsibleInCollapsibleBlock', + textInRowInCollapsibleBlock: 'textInRowInCollapsibleBlock', + }, + { + blockType: 'TabsBlock', + namedTab1InBlock: { + textInNamedTab1InBlock: 'textInNamedTab1InBlock', + }, + textInUnnamedTab2InBlock: 'textInUnnamedTab2InBlock', + }, ], checkbox: true, code: 'code', @@ -186,6 +198,18 @@ export async function seed(_payload: Payload, parallel: boolean = false) { blockType: 'TextBlock', textInBlock: 'textInBlock2', }, + { + blockType: 'CollapsibleBlock', + textInCollapsibleInCollapsibleBlock: 'textInCollapsibleInCollapsibleBlock2', + textInRowInCollapsibleBlock: 'textInRowInCollapsibleBlock2', + }, + { + blockType: 'TabsBlock', + namedTab1InBlock: { + textInNamedTab1InBlock: 'textInNamedTab1InBlock2', + }, + textInUnnamedTab2InBlock: 'textInUnnamedTab2InBlock2', + }, ], checkbox: false, code: 'code2', From de0aaf6e91470964140a0bc48ca2a47690a5ab85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Mon, 24 Mar 2025 18:17:15 -0300 Subject: [PATCH 08/77] chore(db-vercel-postgres): enable TypeScript strict (#11833) same comment as in #11560, #11831, #11226: > In `src/index.ts` I see four more errors in my IDE that don't appear when I run the typecheck in the CLI with `tsc --noEmit`. --- packages/db-vercel-postgres/src/connect.ts | 9 +++++---- packages/db-vercel-postgres/src/index.ts | 10 ++++++++-- packages/db-vercel-postgres/tsconfig.json | 5 ----- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/db-vercel-postgres/src/connect.ts b/packages/db-vercel-postgres/src/connect.ts index eacda21770..0dd48780a7 100644 --- a/packages/db-vercel-postgres/src/connect.ts +++ b/packages/db-vercel-postgres/src/connect.ts @@ -1,5 +1,5 @@ import type { DrizzleAdapter } from '@payloadcms/drizzle/types' -import type { Connect } from 'payload' +import type { Connect, Migration } from 'payload' import { pushDevSchema } from '@payloadcms/drizzle' import { sql, VercelPool } from '@vercel/postgres' @@ -60,7 +60,8 @@ export const connect: Connect = async function connect( this.payload.logger.info('---- DROPPED TABLES ----') } } - } catch (err) { + } catch (error) { + const err = error instanceof Error ? error : new Error(String(error)) if (err.message?.match(/database .* does not exist/i) && !this.disableCreateDatabase) { // capitalize first char of the err msg this.payload.logger.info( @@ -69,7 +70,7 @@ export const connect: Connect = async function connect( const isCreated = await this.createDatabase() if (isCreated) { - await this.connect(options) + await this.connect?.(options) return } } else { @@ -101,6 +102,6 @@ export const connect: Connect = async function connect( } if (process.env.NODE_ENV === 'production' && this.prodMigrations) { - await this.migrate({ migrations: this.prodMigrations }) + await this.migrate({ migrations: this.prodMigrations as Migration[] }) } } diff --git a/packages/db-vercel-postgres/src/index.ts b/packages/db-vercel-postgres/src/index.ts index c8835a972f..a96892560a 100644 --- a/packages/db-vercel-postgres/src/index.ts +++ b/packages/db-vercel-postgres/src/index.ts @@ -1,3 +1,4 @@ +import type { PgTableFn } from 'drizzle-orm/pg-core' import type { DatabaseAdapterObj, Payload } from 'payload' import { @@ -80,10 +81,10 @@ export function vercelPostgresAdapter(args: Args = {}): DatabaseAdapterObj } } - const extensions = (args.extensions ?? []).reduce((acc, name) => { + const extensions = (args.extensions ?? []).reduce>((acc, name) => { acc[name] = true return acc }, {}) @@ -97,6 +98,7 @@ export function vercelPostgresAdapter(args: Args = {}): DatabaseAdapterObj Date: Mon, 24 Mar 2025 18:02:24 -0600 Subject: [PATCH 09/77] refactor(richtext-lexical): ensure field can be rendered outside EntityVisibilityProvider (#11842) This ensures that the lexical field can be rendered without having to wrap it inside an `EntityVisibilityProvider`, making it a bit easier to manually render the lexical field in a custom component. --- packages/richtext-lexical/src/exports/client/index.ts | 2 +- .../client/utils/EnabledRelationshipsCondition.tsx | 4 ++-- .../src/features/upload/client/component/index.tsx | 2 +- .../features/upload/client/{feature.client.tsx => index.tsx} | 0 .../src/features/upload/client/plugin/index.tsx | 2 +- .../src/features/upload/server/graphQLPopulationPromise.ts | 2 +- .../features/upload/server/{feature.server.ts => index.ts} | 2 +- .../richtext-lexical/src/features/upload/server/validate.ts | 2 +- packages/richtext-lexical/src/index.ts | 4 ++-- .../richtext-lexical/src/lexical/config/server/default.ts | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) rename packages/richtext-lexical/src/features/upload/client/{feature.client.tsx => index.tsx} (100%) rename packages/richtext-lexical/src/features/upload/server/{feature.server.ts => index.ts} (99%) diff --git a/packages/richtext-lexical/src/exports/client/index.ts b/packages/richtext-lexical/src/exports/client/index.ts index 541de82c28..22dbab89a1 100644 --- a/packages/richtext-lexical/src/exports/client/index.ts +++ b/packages/richtext-lexical/src/exports/client/index.ts @@ -43,7 +43,7 @@ export { ToolbarButton } from '../../features/toolbars/shared/ToolbarButton/inde export { TableFeatureClient } from '../../features/experimental_table/client/index.js' export { ToolbarDropdown } from '../../features/toolbars/shared/ToolbarDropdown/index.js' -export { UploadFeatureClient } from '../../features/upload/client/feature.client.js' +export { UploadFeatureClient } from '../../features/upload/client/index.js' export { RichTextField } from '../../field/index.js' export { diff --git a/packages/richtext-lexical/src/features/relationship/client/utils/EnabledRelationshipsCondition.tsx b/packages/richtext-lexical/src/features/relationship/client/utils/EnabledRelationshipsCondition.tsx index 9a0804572e..62cd311752 100644 --- a/packages/richtext-lexical/src/features/relationship/client/utils/EnabledRelationshipsCondition.tsx +++ b/packages/richtext-lexical/src/features/relationship/client/utils/EnabledRelationshipsCondition.tsx @@ -7,7 +7,7 @@ import * as React from 'react' type Options = { uploads: boolean user: ClientUser - visibleEntities: VisibleEntities + visibleEntities?: VisibleEntities } type FilteredCollectionsT = ( @@ -17,7 +17,7 @@ type FilteredCollectionsT = ( const filterRichTextCollections: FilteredCollectionsT = (collections, options) => { return collections.filter(({ slug, admin: { enableRichTextRelationship }, upload }) => { - if (!options?.visibleEntities.collections.includes(slug)) { + if (!options?.visibleEntities?.collections.includes(slug)) { return false } diff --git a/packages/richtext-lexical/src/features/upload/client/component/index.tsx b/packages/richtext-lexical/src/features/upload/client/component/index.tsx index b6d4460f57..47060249c2 100644 --- a/packages/richtext-lexical/src/features/upload/client/component/index.tsx +++ b/packages/richtext-lexical/src/features/upload/client/component/index.tsx @@ -17,7 +17,7 @@ import React, { useCallback, useId, useReducer, useRef, useState } from 'react' import type { BaseClientFeatureProps } from '../../../typesClient.js' import type { UploadData } from '../../server/nodes/UploadNode.js' -import type { UploadFeaturePropsClient } from '../feature.client.js' +import type { UploadFeaturePropsClient } from '../index.js' import type { UploadNode } from '../nodes/UploadNode.js' import { useEditorConfigContext } from '../../../../lexical/config/client/EditorConfigProvider.js' diff --git a/packages/richtext-lexical/src/features/upload/client/feature.client.tsx b/packages/richtext-lexical/src/features/upload/client/index.tsx similarity index 100% rename from packages/richtext-lexical/src/features/upload/client/feature.client.tsx rename to packages/richtext-lexical/src/features/upload/client/index.tsx diff --git a/packages/richtext-lexical/src/features/upload/client/plugin/index.tsx b/packages/richtext-lexical/src/features/upload/client/plugin/index.tsx index a01f20c0d9..7d0884433e 100644 --- a/packages/richtext-lexical/src/features/upload/client/plugin/index.tsx +++ b/packages/richtext-lexical/src/features/upload/client/plugin/index.tsx @@ -16,7 +16,7 @@ import React, { useEffect } from 'react' import type { PluginComponent } from '../../../typesClient.js' import type { UploadData } from '../../server/nodes/UploadNode.js' -import type { UploadFeaturePropsClient } from '../feature.client.js' +import type { UploadFeaturePropsClient } from '../index.js' import { UploadDrawer } from '../drawer/index.js' import { $createUploadNode, UploadNode } from '../nodes/UploadNode.js' diff --git a/packages/richtext-lexical/src/features/upload/server/graphQLPopulationPromise.ts b/packages/richtext-lexical/src/features/upload/server/graphQLPopulationPromise.ts index cf1b7bdc58..65d61a96dd 100644 --- a/packages/richtext-lexical/src/features/upload/server/graphQLPopulationPromise.ts +++ b/packages/richtext-lexical/src/features/upload/server/graphQLPopulationPromise.ts @@ -1,5 +1,5 @@ import type { PopulationPromise } from '../../typesServer.js' -import type { UploadFeatureProps } from './feature.server.js' +import type { UploadFeatureProps } from './index.js' import type { SerializedUploadNode } from './nodes/UploadNode.js' import { populate } from '../../../populateGraphQL/populate.js' diff --git a/packages/richtext-lexical/src/features/upload/server/feature.server.ts b/packages/richtext-lexical/src/features/upload/server/index.ts similarity index 99% rename from packages/richtext-lexical/src/features/upload/server/feature.server.ts rename to packages/richtext-lexical/src/features/upload/server/index.ts index af23f37099..a18ffb8977 100644 --- a/packages/richtext-lexical/src/features/upload/server/feature.server.ts +++ b/packages/richtext-lexical/src/features/upload/server/index.ts @@ -11,7 +11,7 @@ import type { import { sanitizeFields } from 'payload' -import type { UploadFeaturePropsClient } from '../client/feature.client.js' +import type { UploadFeaturePropsClient } from '../client/index.js' import { populate } from '../../../populateGraphQL/populate.js' import { createServerFeature } from '../../../utilities/createServerFeature.js' diff --git a/packages/richtext-lexical/src/features/upload/server/validate.ts b/packages/richtext-lexical/src/features/upload/server/validate.ts index d5dcd8866c..bbbdbca49e 100644 --- a/packages/richtext-lexical/src/features/upload/server/validate.ts +++ b/packages/richtext-lexical/src/features/upload/server/validate.ts @@ -2,7 +2,7 @@ import { fieldSchemasToFormState } from '@payloadcms/ui/forms/fieldSchemasToForm import { isValidID } from 'payload' import type { NodeValidation } from '../../typesServer.js' -import type { UploadFeatureProps } from './feature.server.js' +import type { UploadFeatureProps } from './index.js' import type { SerializedUploadNode } from './nodes/UploadNode.js' export const uploadValidation = ( diff --git a/packages/richtext-lexical/src/index.ts b/packages/richtext-lexical/src/index.ts index 7822a351ee..cffe78f7db 100644 --- a/packages/richtext-lexical/src/index.ts +++ b/packages/richtext-lexical/src/index.ts @@ -980,8 +980,8 @@ export type { export { createNode } from './features/typeUtilities.js' // Only useful in feature.server.ts -export { UploadFeature } from './features/upload/server/feature.server.js' -export type { UploadFeatureProps } from './features/upload/server/feature.server.js' +export { UploadFeature } from './features/upload/server/index.js' +export type { UploadFeatureProps } from './features/upload/server/index.js' export { type UploadData, UploadServerNode } from './features/upload/server/nodes/UploadNode.js' export type { EditorConfigContextType } from './lexical/config/client/EditorConfigProvider.js' diff --git a/packages/richtext-lexical/src/lexical/config/server/default.ts b/packages/richtext-lexical/src/lexical/config/server/default.ts index 40514ae746..13bd8f3a7f 100644 --- a/packages/richtext-lexical/src/lexical/config/server/default.ts +++ b/packages/richtext-lexical/src/lexical/config/server/default.ts @@ -22,7 +22,7 @@ import { UnorderedListFeature } from '../../../features/lists/unorderedList/serv import { ParagraphFeature } from '../../../features/paragraph/server/index.js' import { RelationshipFeature } from '../../../features/relationship/server/index.js' import { InlineToolbarFeature } from '../../../features/toolbars/inline/server/index.js' -import { UploadFeature } from '../../../features/upload/server/feature.server.js' +import { UploadFeature } from '../../../features/upload/server/index.js' import { LexicalEditorTheme } from '../../theme/EditorTheme.js' export const defaultEditorLexicalConfig: LexicalEditorConfig = { From fe9317a0dd0ebd26125d194b74b7b07f5b42b6b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Mon, 24 Mar 2025 23:41:07 -0300 Subject: [PATCH 10/77] chore(db-sqlite): enable TypeScript strict (#11831) - I installed `@types/uuid` because typescript required it in a file - In `packages/db-sqlite/src/index.ts` I see four more errors in my IDE that don't appear when I run the typecheck in the CLI with `tsc --noEmit`. The same thing happened in https://github.com/payloadcms/payload/pull/11560. Also referencing https://github.com/payloadcms/payload/pull/11226#issuecomment-2713898801 for traceability. --- packages/db-sqlite/package.json | 1 + .../db-sqlite/src/columnToCodeConverter.ts | 3 + packages/db-sqlite/src/connect.ts | 7 ++- packages/db-sqlite/src/countDistinct.ts | 4 +- .../db-sqlite/src/createJSONQuery/index.ts | 2 +- packages/db-sqlite/src/deleteWhere.ts | 9 ++- packages/db-sqlite/src/dropDatabase.ts | 12 ++-- packages/db-sqlite/src/execute.ts | 4 +- packages/db-sqlite/src/index.ts | 7 +++ packages/db-sqlite/src/init.ts | 2 +- packages/db-sqlite/src/insert.ts | 28 +++++----- .../db-sqlite/src/schema/buildDrizzleTable.ts | 5 +- packages/db-sqlite/tsconfig.json | 5 -- pnpm-lock.yaml | 55 +++++-------------- 14 files changed, 66 insertions(+), 78 deletions(-) diff --git a/packages/db-sqlite/package.json b/packages/db-sqlite/package.json index c0f75077dd..d7c0b0c003 100644 --- a/packages/db-sqlite/package.json +++ b/packages/db-sqlite/package.json @@ -85,6 +85,7 @@ "@payloadcms/eslint-config": "workspace:*", "@types/pg": "8.10.2", "@types/to-snake-case": "1.0.0", + "@types/uuid": "10.0.0", "payload": "workspace:*" }, "peerDependencies": { diff --git a/packages/db-sqlite/src/columnToCodeConverter.ts b/packages/db-sqlite/src/columnToCodeConverter.ts index b9c6e3d7f9..a42474e000 100644 --- a/packages/db-sqlite/src/columnToCodeConverter.ts +++ b/packages/db-sqlite/src/columnToCodeConverter.ts @@ -23,6 +23,9 @@ export const columnToCodeConverter: ColumnToCodeConverter = ({ case 'enum': { let options: string[] if ('locale' in column) { + if (!locales?.length) { + throw new Error('Locales must be defined for locale columns') + } options = locales } else { options = column.options diff --git a/packages/db-sqlite/src/connect.ts b/packages/db-sqlite/src/connect.ts index eb33717632..1222bcaaba 100644 --- a/packages/db-sqlite/src/connect.ts +++ b/packages/db-sqlite/src/connect.ts @@ -1,5 +1,5 @@ import type { DrizzleAdapter } from '@payloadcms/drizzle/types' -import type { Connect } from 'payload' +import type { Connect, Migration } from 'payload' import { createClient } from '@libsql/client' import { pushDevSchema } from '@payloadcms/drizzle' @@ -36,7 +36,8 @@ export const connect: Connect = async function connect( } } } catch (err) { - this.payload.logger.error({ err, msg: `Error: cannot connect to SQLite: ${err.message}` }) + const message = err instanceof Error ? err.message : String(err) + this.payload.logger.error({ err, msg: `Error: cannot connect to SQLite: ${message}` }) if (typeof this.rejectInitializing === 'function') { this.rejectInitializing() } @@ -57,6 +58,6 @@ export const connect: Connect = async function connect( } if (process.env.NODE_ENV === 'production' && this.prodMigrations) { - await this.migrate({ migrations: this.prodMigrations }) + await this.migrate({ migrations: this.prodMigrations as Migration[] }) } } diff --git a/packages/db-sqlite/src/countDistinct.ts b/packages/db-sqlite/src/countDistinct.ts index f9f55ad267..5a0ada7a9d 100644 --- a/packages/db-sqlite/src/countDistinct.ts +++ b/packages/db-sqlite/src/countDistinct.ts @@ -17,7 +17,7 @@ export const countDistinct: CountDistinct = async function countDistinct( }) .from(this.tables[tableName]) .where(where) - return Number(countResult[0].count) + return Number(countResult[0]?.count) } const chainedMethods: ChainedMethods = [] @@ -45,5 +45,5 @@ export const countDistinct: CountDistinct = async function countDistinct( .limit(1), }) - return Number(countResult[0].count) + return Number(countResult[0]?.count) } diff --git a/packages/db-sqlite/src/createJSONQuery/index.ts b/packages/db-sqlite/src/createJSONQuery/index.ts index 376ea58eaa..435ca62ce6 100644 --- a/packages/db-sqlite/src/createJSONQuery/index.ts +++ b/packages/db-sqlite/src/createJSONQuery/index.ts @@ -74,7 +74,7 @@ export const createJSONQuery = ({ treatAsArray, value, }: CreateJSONQueryArgs): string => { - if (treatAsArray.includes(pathSegments[1])) { + if (treatAsArray?.includes(pathSegments[1]!) && table) { return fromArray({ operator, pathSegments, diff --git a/packages/db-sqlite/src/deleteWhere.ts b/packages/db-sqlite/src/deleteWhere.ts index 7a1d0ac1c7..cc3d6ab46a 100644 --- a/packages/db-sqlite/src/deleteWhere.ts +++ b/packages/db-sqlite/src/deleteWhere.ts @@ -1,6 +1,11 @@ -import type { DeleteWhere } from './types.js' +import type { DeleteWhere, SQLiteAdapter } from './types.js' -export const deleteWhere: DeleteWhere = async function deleteWhere({ db, tableName, where }) { +export const deleteWhere: DeleteWhere = async function ( + // Here 'this' is not a parameter. See: + // https://www.typescriptlang.org/docs/handbook/2/classes.html#this-parameters + this: SQLiteAdapter, + { db, tableName, where }, +) { const table = this.tables[tableName] await db.delete(table).where(where) } diff --git a/packages/db-sqlite/src/dropDatabase.ts b/packages/db-sqlite/src/dropDatabase.ts index 81ae88db7a..fc7a5790b7 100644 --- a/packages/db-sqlite/src/dropDatabase.ts +++ b/packages/db-sqlite/src/dropDatabase.ts @@ -1,21 +1,23 @@ -import type { DropDatabase } from './types.js' +import type { Row } from '@libsql/client' -const getTables = (adapter) => { +import type { DropDatabase, SQLiteAdapter } from './types.js' + +const getTables = (adapter: SQLiteAdapter) => { return adapter.client.execute(`SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%';`) } -const dropTables = (adapter, rows) => { +const dropTables = (adapter: SQLiteAdapter, rows: Row[]) => { const multi = ` PRAGMA foreign_keys = OFF;\n - ${rows.map(({ name }) => `DROP TABLE IF EXISTS ${name}`).join(';\n ')};\n + ${rows.map(({ name }) => `DROP TABLE IF EXISTS ${name as string}`).join(';\n ')};\n PRAGMA foreign_keys = ON;` return adapter.client.executeMultiple(multi) } -export const dropDatabase: DropDatabase = async function dropDatabase({ adapter }) { +export const dropDatabase: DropDatabase = async function ({ adapter }) { const result = await getTables(adapter) await dropTables(adapter, result.rows) } diff --git a/packages/db-sqlite/src/execute.ts b/packages/db-sqlite/src/execute.ts index 398c6f4b74..3932360562 100644 --- a/packages/db-sqlite/src/execute.ts +++ b/packages/db-sqlite/src/execute.ts @@ -3,13 +3,13 @@ import { sql } from 'drizzle-orm' import type { Execute } from './types.js' export const execute: Execute = function execute({ db, drizzle, raw, sql: statement }) { - const executeFrom = db ?? drizzle + const executeFrom = (db ?? drizzle)! if (raw) { const result = executeFrom.run(sql.raw(raw)) return result } else { - const result = executeFrom.run(statement) + const result = executeFrom.run(statement!) return result } } diff --git a/packages/db-sqlite/src/index.ts b/packages/db-sqlite/src/index.ts index 7ed1185b44..f4ab2d6330 100644 --- a/packages/db-sqlite/src/index.ts +++ b/packages/db-sqlite/src/index.ts @@ -92,9 +92,11 @@ export function sqliteAdapter(args: Args): DatabaseAdapterObj { allowIDOnCreate, autoIncrement: args.autoIncrement ?? false, beforeSchemaInit: args.beforeSchemaInit ?? [], + // @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve client: undefined, clientConfig: args.client, defaultDrizzleSnapshot, + // @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve drizzle: undefined, features: { json: true, @@ -112,6 +114,7 @@ export function sqliteAdapter(args: Args): DatabaseAdapterObj { logger: args.logger, operators, prodMigrations: args.prodMigrations, + // @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve push: args.push, rawRelations: {}, rawTables: {}, @@ -122,6 +125,7 @@ export function sqliteAdapter(args: Args): DatabaseAdapterObj { sessions: {}, tableNameMap: new Map(), tables: {}, + // @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve transactionOptions: args.transactionOptions || undefined, updateMany, versionsSuffix: args.versionsSuffix || '_v', @@ -160,6 +164,7 @@ export function sqliteAdapter(args: Args): DatabaseAdapterObj { find, findGlobal, findGlobalVersions, + // @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve findOne, findVersions, indexes: new Set(), @@ -175,8 +180,10 @@ export function sqliteAdapter(args: Args): DatabaseAdapterObj { packageName: '@payloadcms/db-sqlite', payload, queryDrafts, + // @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve rejectInitializing, requireDrizzleKit, + // @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve resolveInitializing, rollbackTransaction, updateGlobal, diff --git a/packages/db-sqlite/src/init.ts b/packages/db-sqlite/src/init.ts index 00d9a1fa4b..14f16b9828 100644 --- a/packages/db-sqlite/src/init.ts +++ b/packages/db-sqlite/src/init.ts @@ -28,7 +28,7 @@ export const init: Init = async function init(this: SQLiteAdapter) { await executeSchemaHooks({ type: 'beforeSchemaInit', adapter: this }) for (const tableName in this.rawTables) { - buildDrizzleTable({ adapter, locales, rawTable: this.rawTables[tableName] }) + buildDrizzleTable({ adapter, locales: locales!, rawTable: this.rawTables[tableName]! }) } buildDrizzleRelations({ diff --git a/packages/db-sqlite/src/insert.ts b/packages/db-sqlite/src/insert.ts index 11060f10a2..be090a2597 100644 --- a/packages/db-sqlite/src/insert.ts +++ b/packages/db-sqlite/src/insert.ts @@ -1,19 +1,17 @@ -import type { Insert } from './types.js' +import type { Insert, SQLiteAdapter } from './types.js' -export const insert: Insert = async function insert({ - db, - onConflictDoUpdate, - tableName, - values, -}): Promise[]> { +export const insert: Insert = async function ( + // Here 'this' is not a parameter. See: + // https://www.typescriptlang.org/docs/handbook/2/classes.html#this-parameters + this: SQLiteAdapter, + { db, onConflictDoUpdate, tableName, values }, +): Promise[]> { const table = this.tables[tableName] - let result - if (onConflictDoUpdate) { - result = db.insert(table).values(values).onConflictDoUpdate(onConflictDoUpdate).returning() - } else { - result = db.insert(table).values(values).returning() - } - result = await result - return result + const result = onConflictDoUpdate + ? await db.insert(table).values(values).onConflictDoUpdate(onConflictDoUpdate).returning() + : await db.insert(table).values(values).returning() + + // See https://github.com/payloadcms/payload/pull/11831#discussion_r2010431908 + return result as Record[] } diff --git a/packages/db-sqlite/src/schema/buildDrizzleTable.ts b/packages/db-sqlite/src/schema/buildDrizzleTable.ts index 8a9ae0ac42..12f4f56e9e 100644 --- a/packages/db-sqlite/src/schema/buildDrizzleTable.ts +++ b/packages/db-sqlite/src/schema/buildDrizzleTable.ts @@ -81,8 +81,9 @@ export const buildDrizzleTable: BuildDrizzleTable = ({ adapter, locales, rawTabl } if (column.reference) { - columns[key].references(() => adapter.tables[column.reference.table][column.reference.name], { - onDelete: column.reference.onDelete, + const ref = column.reference + columns[key].references(() => adapter.tables[ref.table][ref.name], { + onDelete: ref.onDelete, }) } diff --git a/packages/db-sqlite/tsconfig.json b/packages/db-sqlite/tsconfig.json index 9aa0b22755..760627a1b1 100644 --- a/packages/db-sqlite/tsconfig.json +++ b/packages/db-sqlite/tsconfig.json @@ -1,10 +1,5 @@ { "extends": "../../tsconfig.base.json", - "compilerOptions": { - /* TODO: remove the following lines */ - "strict": false, - "noUncheckedIndexedAccess": false, - }, "references": [ { "path": "../payload" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 71a36256c7..830c730465 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,7 +45,7 @@ importers: version: 1.50.0 '@sentry/nextjs': specifier: ^8.33.1 - version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15))) + version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15))) '@sentry/node': specifier: ^8.33.1 version: 8.37.1 @@ -135,7 +135,7 @@ importers: version: 10.1.3(@aws-sdk/credential-providers@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)))(socks@2.8.3) next: specifier: 15.2.3 - version: 15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + version: 15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) open: specifier: ^10.1.0 version: 10.1.0 @@ -387,6 +387,9 @@ importers: '@types/to-snake-case': specifier: 1.0.0 version: 1.0.0 + '@types/uuid': + specifier: 10.0.0 + version: 10.0.0 payload: specifier: workspace:* version: link:../payload @@ -1073,7 +1076,7 @@ importers: dependencies: next: specifier: ^15.2.3 - version: 15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + version: 15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) devDependencies: '@payloadcms/eslint-config': specifier: workspace:* @@ -1138,7 +1141,7 @@ importers: dependencies: '@sentry/nextjs': specifier: ^8.33.1 - version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15))) + version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15))) '@sentry/types': specifier: ^8.33.1 version: 8.37.1 @@ -1497,7 +1500,7 @@ importers: version: link:../plugin-cloud-storage uploadthing: specifier: 7.3.0 - version: 7.3.0(next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4)) + version: 7.3.0(next@15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4)) devDependencies: payload: specifier: workspace:* @@ -1783,7 +1786,7 @@ importers: version: link:../packages/ui '@sentry/nextjs': specifier: ^8.33.1 - version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15))) + version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15))) '@sentry/react': specifier: ^7.77.0 version: 7.119.2(react@19.0.0) @@ -1840,7 +1843,7 @@ importers: version: 8.9.5(@aws-sdk/credential-providers@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)))(socks@2.8.3) next: specifier: 15.2.3 - version: 15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + version: 15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) nodemailer: specifier: 6.9.16 version: 6.9.16 @@ -7899,6 +7902,7 @@ packages: libsql@0.4.7: resolution: {integrity: sha512-T9eIRCs6b0J1SHKYIvD8+KCJMcWZ900iZyxdnSCdqxN12Z1ijzT+jY5nrk72Jw4B0HGzms2NgpryArlJqvc3Lw==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] lie@3.1.1: @@ -13588,7 +13592,7 @@ snapshots: '@sentry/utils': 7.119.2 localforage: 1.10.0 - '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15)))': + '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15)))': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation-http': 0.53.0(@opentelemetry/api@1.9.0) @@ -13604,7 +13608,7 @@ snapshots: '@sentry/vercel-edge': 8.37.1 '@sentry/webpack-plugin': 2.22.6(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15))) chalk: 3.0.0 - next: 15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + next: 15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) resolve: 1.22.8 rollup: 3.29.5 stacktrace-parser: 0.1.10 @@ -18247,35 +18251,6 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4): - dependencies: - '@next/env': 15.2.3 - '@swc/counter': 0.1.3 - '@swc/helpers': 0.5.15 - busboy: 1.6.0 - caniuse-lite: 1.0.30001678 - postcss: 8.4.31 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - styled-jsx: 5.1.6(@babel/core@7.26.7)(babel-plugin-macros@3.1.0)(react@19.0.0) - optionalDependencies: - '@next/swc-darwin-arm64': 15.2.3 - '@next/swc-darwin-x64': 15.2.3 - '@next/swc-linux-arm64-gnu': 15.2.3 - '@next/swc-linux-arm64-musl': 15.2.3 - '@next/swc-linux-x64-gnu': 15.2.3 - '@next/swc-linux-x64-musl': 15.2.3 - '@next/swc-win32-arm64-msvc': 15.2.3 - '@next/swc-win32-x64-msvc': 15.2.3 - '@opentelemetry/api': 1.9.0 - '@playwright/test': 1.50.0 - babel-plugin-react-compiler: 19.0.0-beta-714736e-20250131 - sass: 1.77.4 - sharp: 0.33.5 - transitivePeerDependencies: - - '@babel/core' - - babel-plugin-macros - node-abi@3.71.0: dependencies: semver: 7.6.3 @@ -19934,14 +19909,14 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - uploadthing@7.3.0(next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4)): + uploadthing@7.3.0(next@15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4)): dependencies: '@effect/platform': 0.69.8(effect@3.10.3) '@uploadthing/mime-types': 0.3.2 '@uploadthing/shared': 7.1.1 effect: 3.10.3 optionalDependencies: - next: 15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + next: 15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) uri-js@4.4.1: dependencies: From 234df54446411383d6919ff2f69be2ed038f53fc Mon Sep 17 00:00:00 2001 From: Patrik Date: Tue, 25 Mar 2025 09:52:18 -0400 Subject: [PATCH 11/77] fix(next): adds safe redirect utility and apply to login redirects (#11814) This PR introduces a new utility function, `getSafeRedirect`, to sanitize and validate redirect paths used in the login flow. It replaces the previous use of `encodeURIComponent` and inline string checks with a centralized, reusable, and more secure approach. #### `getSafeRedirect` utility: - Ensures redirect paths start with a single `/` - Blocks protocol-relative URLs (e.g., `//evil.com`) - Blocks JavaScript schemes (e.g., `/javascript:alert(1)`) - Blocks full URL redirects like `/http:` or `/https:` --- .../next/src/utilities/getSafeRedirect.ts | 23 +++++++++++++++++++ .../next/src/views/Login/LoginForm/index.tsx | 9 ++------ packages/next/src/views/Login/index.tsx | 9 ++------ 3 files changed, 27 insertions(+), 14 deletions(-) create mode 100644 packages/next/src/utilities/getSafeRedirect.ts diff --git a/packages/next/src/utilities/getSafeRedirect.ts b/packages/next/src/utilities/getSafeRedirect.ts new file mode 100644 index 0000000000..963c6b51fe --- /dev/null +++ b/packages/next/src/utilities/getSafeRedirect.ts @@ -0,0 +1,23 @@ +export const getSafeRedirect = ( + redirectParam: string | string[], + fallback: string = '/', +): string => { + if (typeof redirectParam !== 'string') { + return fallback + } + + // Ensures that any leading or trailing whitespace doesn’t affect the checks + const redirectPath = redirectParam.trim() + + const isSafeRedirect = + // Must start with a single forward slash (e.g., "/admin") + redirectPath.startsWith('/') && + // Prevent protocol-relative URLs (e.g., "//evil.com") + !redirectPath.startsWith('//') && + // Prevent javascript-based schemes (e.g., "/javascript:alert(1)") + !redirectPath.toLowerCase().startsWith('/javascript:') && + // Prevent attempts to redirect to full URLs using "/http:" or "/https:" + !redirectPath.toLowerCase().startsWith('/http') + + return isSafeRedirect ? redirectPath : fallback +} diff --git a/packages/next/src/views/Login/LoginForm/index.tsx b/packages/next/src/views/Login/LoginForm/index.tsx index f737318bad..3ae336228d 100644 --- a/packages/next/src/views/Login/LoginForm/index.tsx +++ b/packages/next/src/views/Login/LoginForm/index.tsx @@ -20,6 +20,7 @@ import { formatAdminURL, getLoginOptions } from 'payload/shared' import type { LoginFieldProps } from '../LoginField/index.js' +import { getSafeRedirect } from '../../../utilities/getSafeRedirect.js' import { LoginField } from '../LoginField/index.js' import './index.scss' @@ -91,13 +92,7 @@ export const LoginForm: React.FC<{ initialState={initialState} method="POST" onSuccess={handleLogin} - redirect={ - typeof searchParams?.redirect === 'string' - ? searchParams.redirect.startsWith('/') - ? searchParams.redirect - : encodeURIComponent(searchParams.redirect) - : adminRoute - } + redirect={getSafeRedirect(searchParams?.redirect, adminRoute)} waitForAutocomplete >
diff --git a/packages/next/src/views/Login/index.tsx b/packages/next/src/views/Login/index.tsx index ecbda6e9b6..e3896a5ff5 100644 --- a/packages/next/src/views/Login/index.tsx +++ b/packages/next/src/views/Login/index.tsx @@ -5,9 +5,9 @@ import { redirect } from 'next/navigation.js' import React, { Fragment } from 'react' import { Logo } from '../../elements/Logo/index.js' +import { getSafeRedirect } from '../../utilities/getSafeRedirect.js' import { LoginForm } from './LoginForm/index.js' import './index.scss' - export const loginBaseClass = 'login' export function LoginView({ initPageResult, params, searchParams }: AdminViewServerProps) { @@ -25,12 +25,7 @@ export function LoginView({ initPageResult, params, searchParams }: AdminViewSer routes: { admin }, } = config - const redirectUrl = - typeof searchParams.redirect === 'string' - ? searchParams.redirect.startsWith('/') // If it's a relative path, keep it - ? searchParams.redirect - : encodeURIComponent(searchParams.redirect) // Otherwise, encode it - : admin + const redirectUrl = getSafeRedirect(searchParams.redirect, admin) if (user) { redirect(redirectUrl) From 1081b4a0ff72506956ff43040572742a09af08af Mon Sep 17 00:00:00 2001 From: Patrik Date: Tue, 25 Mar 2025 10:01:04 -0400 Subject: [PATCH 12/77] fix: add uuid fallback for non-secure contexts in JSON fields (#11839) ### What The `crypto.randomUUID()` function was causing errors in non-secure contexts (HTTP), as it is only available in secure contexts (HTTPS). ### How Added a fallback to generate UUIDs using the `uuid` library when `crypto.randomUUID()` is not available. Fixes #11825 --- packages/ui/src/fields/JSON/index.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/fields/JSON/index.tsx b/packages/ui/src/fields/JSON/index.tsx index 2cc811b6ef..75754cb181 100644 --- a/packages/ui/src/fields/JSON/index.tsx +++ b/packages/ui/src/fields/JSON/index.tsx @@ -3,6 +3,7 @@ import type { JSONFieldClientComponent } from 'payload' import { type OnMount } from '@monaco-editor/react' import React, { useCallback, useEffect, useMemo, useState } from 'react' +import { v4 as uuidv4 } from 'uuid' import { CodeEditor } from '../../elements/CodeEditor/index.js' import { RenderCustomComponent } from '../../elements/RenderCustomComponent/index.js' @@ -80,8 +81,8 @@ const JSONFieldComponent: JSONFieldClientComponent = (props) => { const uri = jsonSchema.uri const newUri = uri.includes('?') - ? `${uri}&${crypto.randomUUID()}` - : `${uri}?${crypto.randomUUID()}` + ? `${uri}&${crypto.randomUUID ? crypto.randomUUID() : uuidv4()}` + : `${uri}?${crypto.randomUUID ? crypto.randomUUID() : uuidv4()}` editor.setModel( monaco.editor.createModel(JSON.stringify(value, null, 2), 'json', monaco.Uri.parse(newUri)), From f61f6b73c762ed8c9062182f331b20b8bc7875bf Mon Sep 17 00:00:00 2001 From: Dan Ribbens Date: Tue, 25 Mar 2025 10:53:40 -0400 Subject: [PATCH 13/77] feat: add Armenian translation (#11857) Original PR https://github.com/payloadcms/payload/pull/11852 thanks to @lyovson --------- Co-authored-by: Rafa Lyovson --- packages/payload/src/exports/i18n/hy.ts | 1 + packages/translations/src/exports/all.ts | 2 + packages/translations/src/languages/hy.ts | 523 ++++++++++++++++++ packages/translations/src/types.ts | 1 + .../translations/src/utilities/languages.ts | 2 +- 5 files changed, 528 insertions(+), 1 deletion(-) create mode 100644 packages/payload/src/exports/i18n/hy.ts create mode 100644 packages/translations/src/languages/hy.ts diff --git a/packages/payload/src/exports/i18n/hy.ts b/packages/payload/src/exports/i18n/hy.ts new file mode 100644 index 0000000000..df0ea3f0ef --- /dev/null +++ b/packages/payload/src/exports/i18n/hy.ts @@ -0,0 +1 @@ +export { hy } from '@payloadcms/translations/languages/hy' diff --git a/packages/translations/src/exports/all.ts b/packages/translations/src/exports/all.ts index 79acac81cc..e4e4a8d1f9 100644 --- a/packages/translations/src/exports/all.ts +++ b/packages/translations/src/exports/all.ts @@ -15,6 +15,7 @@ import { fr } from '../languages/fr.js' import { he } from '../languages/he.js' import { hr } from '../languages/hr.js' import { hu } from '../languages/hu.js' +import { hy } from '../languages/hy.js' import { it } from '../languages/it.js' import { ja } from '../languages/ja.js' import { ko } from '../languages/ko.js' @@ -54,6 +55,7 @@ export const translations = { he, hr, hu, + hy, it, ja, ko, diff --git a/packages/translations/src/languages/hy.ts b/packages/translations/src/languages/hy.ts new file mode 100644 index 0000000000..977190f7ea --- /dev/null +++ b/packages/translations/src/languages/hy.ts @@ -0,0 +1,523 @@ +import type { DefaultTranslationsObject, Language } from '../types.js' + +export const hyTranslations: DefaultTranslationsObject = { + authentication: { + account: 'Հաշիվ', + accountOfCurrentUser: 'Ընթացիկ օգտատիրոջ հաշիվ', + accountVerified: 'Հաշիվը հաջողությամբ ստուգվել է։', + alreadyActivated: 'Արդեն ակտիվացված է', + alreadyLoggedIn: 'Արդեն մուտք եք գործել', + apiKey: 'API բանալի', + authenticated: 'Հաստատված', + backToLogin: 'Վերադառնալ մուտքի էջ', + beginCreateFirstUser: 'Սկսելու համար ստեղծեք Ձեր առաջին օգտահաշիվը', + changePassword: 'Փոխել գաղտնաբառը', + checkYourEmailForPasswordReset: + 'Եթե էլ. փոստի հասցեն կապված է հաշվի հետ, Դուք կարճ ժամանակում կստանաք գաղտնաբառը վերականգնելու հրահանգներ։ Խնդրում ենք ստուգել Ձեր սպամ կամ անցանկալի փոստի թղթապանակը, եթե էլ. նամակը մուտքի արկղում չէ։', + confirmGeneration: 'Հաստատել ստեղծումը', + confirmPassword: 'Հաստատել գաղտնաբառը', + createFirstUser: 'Ստեղծել առաջին օգտահաշիվը', + emailNotValid: 'Տրամադրված էլ. փոստը վավեր չէ', + emailOrUsername: 'Էլ. փոստ կամ օգտանուն', + emailSent: 'Էլ. նամակն ուղարկված է', + emailVerified: 'Էլ. փոստը հաջողությամբ ստուգվել է։', + enableAPIKey: 'Միացնել API բանալին', + failedToUnlock: 'Չհաջողվեց բացել', + forceUnlock: 'Հարկադրաբար բացել', + forgotPassword: 'Մոռացե՞լ եք գաղտնաբառը', + forgotPasswordEmailInstructions: + 'Խնդրում ենք մուտքագրել Ձեր էլ. փոստը։ Դուք կստանաք էլ. նամակ՝ գաղտնաբառը վերականգնելու հրահանգներով։', + forgotPasswordUsernameInstructions: + 'Խնդրում ենք ներքևում մուտքագրել Ձեր օգտանունը։ Գաղտնաբառը վերականգնելու հրահանգները կուղարկվեն Ձեր օգտանվան հետ կապված էլ. փոստի հասցեին։', + usernameNotValid: 'Տրամադրված օգտանունը վավեր չէ', + + forgotPasswordQuestion: 'Մոռացե՞լ եք գաղտնաբառը։', + generate: 'Ստեղծել', + generateNewAPIKey: 'Ստեղծել նոր API բանալի', + generatingNewAPIKeyWillInvalidate: + 'Նոր API բանալու ստեղծումը <1>անվավեր կդարձնի նախորդ բանալին։ Համոզվա՞ծ եք, որ ցանկանում եք շարունակել։', + lockUntil: 'Կողպել մինչև', + logBackIn: 'Կրկին մուտք գործել', + loggedIn: 'Այլ օգտանվամբ մուտք գործելու համար նախ <0>դուրս եկեք։', + loggedInChangePassword: + 'Գաղտնաբառը փոխելու համար գնացեք Ձեր <0>հաշիվ և այնտեղ խմբագրեք Ձեր գաղտնաբառը։', + loggedOutInactivity: 'Դուք դուրս եք եկել անգործության պատճառով։', + loggedOutSuccessfully: 'Դուք հաջողությամբ դուրս եք եկել համակարգից։', + loggingOut: 'Դուրս է գալիս...', + login: 'Մուտք', + loginAttempts: 'Մուտքի փորձեր', + loginUser: 'Մուտք գործել օգտատիրոջ համար', + loginWithAnotherUser: 'Այլ օգտանվամբ մուտք գործելու համար նախ <0>դուրս եկեք։', + logOut: 'Դուրս գալ', + logout: 'Դուրս գալ', + logoutSuccessful: 'Հաջողությամբ դուրս եք եկել։', + logoutUser: 'Դուրս բերել օգտատիրոջը համակարգից', + newAccountCreated: + 'Ձեզ համար նոր հաշիվ է ստեղծվել {{serverURL}} հասցեով մուտք գործելու համար։ Խնդրում ենք սեղմել հետևյալ հղման վրա կամ պատճենել ստորև նշված URL-ը բրաուզերում Ձեր էլ. փոստը հաստատելու համար՝ {{verificationURL}}
Էլ. փոստը հաստատելուց հետո Դուք կկարողանաք հաջողությամբ մուտք գործել։', + newAPIKeyGenerated: 'Նոր API բանալի ստեղծվել է։', + newPassword: 'Նոր գաղտնաբառ', + passed: 'Հաստատված է', + passwordResetSuccessfully: 'Գաղտնաբառը հաջողությամբ վերականգնվել է։', + resetPassword: 'Վերականգնել գաղտնաբառը', + resetPasswordExpiration: 'Գաղտնաբառի վերականգնման ժամկետի ավարտ', + resetPasswordToken: 'Գաղտնաբառի վերականգնման թոքեն', + resetYourPassword: 'Վերականգնել Ձեր գաղտնաբառը', + stayLoggedIn: 'Մնալ համակարգում', + successfullyRegisteredFirstUser: 'Առաջին օգտահաշիվը հաջողությամբ գրանցվել է։', + successfullyUnlocked: 'Հաջողությամբ բացվել է', + tokenRefreshSuccessful: 'Թոքենի թարմացումը հաջողվել է։', + unableToVerify: 'Հնարավոր չէ հաստատել', + username: 'Օգտանուն', + verified: 'Ստուգված', + verifiedSuccessfully: 'Հաջողությամբ ստուգված', + verify: 'Ստուգել', + verifyUser: 'Ստուգել օգտահաշիվը', + verifyYourEmail: 'Հաստատեք Ձեր էլ. փոստը', + youAreInactive: + 'Ձեր հաշիվը որոշ ժամանակ անգործ է եղել և համակարգը ձեզ շուտով ինքնաբերաբար դուրս կհանի Ձեր իսկ անվտանգության համար։ Ցանկանու՞մ եք մնալ համակարգում։', + youAreReceivingResetPassword: + 'Դուք ստացել եք սա, քանի որ Դուք (կամ ինչ-որ մեկը) խնդրել եք վերականգնել Ձեր հաշվի գաղտնաբառը։ Խնդրում ենք սեղմել հետևյալ հղման վրա կամ պատճենել այն բրաուզերում՝ գործընթացը ավարտելու համար։', + youDidNotRequestPassword: + 'Եթե Դուք չեք ուղարկել հարցումը, խնդրում ենք անտեսել այս էլ. նամակը, և Ձեր գաղտնաբառը կմնա անփոփոխ։', + }, + error: { + accountAlreadyActivated: 'Այս հաշիվն արդեն ակտիվացված է։', + autosaving: 'Այս փաստաթղթի ավտոմատ պահպանման ժամանակ խնդիր է առաջացել։', + correctInvalidFields: 'Խնդրում ենք ուղղել անվավեր դաշտերը։', + deletingFile: 'Ֆայլը ջնջելու ժամանակ սխալ է տեղի ունեցել։', + deletingTitle: + '{{title}}-ը ջնջելու ժամանակ սխալ է տեղի ունեցել։ Խնդրում ենք ստուգել Ձեր կապը և կրկին փորձել։', + emailOrPasswordIncorrect: 'Տրամադրված էլ. փոստը կամ գաղտնաբառը սխալ է։', + followingFieldsInvalid_one: 'Հետևյալ դաշտն անվավեր է։', + followingFieldsInvalid_other: 'Հետևյալ դաշտերն անվավեր են։', + incorrectCollection: 'Սխալ հավաքածու', + invalidFileType: 'Անվավեր ֆայլի տեսակ', + invalidFileTypeValue: 'Անվավեր ֆայլի տեսակ՝ {{value}}', + invalidRequestArgs: 'Հայտում փոխանցված անվավեր արգումենտներ՝ {{args}}', + loadingDocument: '{{id}} ID-ով փաստաթուղթը բեռնելու ժամանակ խնդիր է առաջացել։', + localesNotSaved_one: 'Հետևյալ լոկալը չի պահպանվել։', + localesNotSaved_other: 'Հետևյալ լոկալները չեն պահպանվել։', + logoutFailed: 'Դուրս գալը ձախողվել է։', + missingEmail: 'Էլ. փոստը բացակայում է։', + missingIDOfDocument: 'Թարմացման համար փաստաթղթի ID-ն բացակայում է։', + missingIDOfVersion: 'Տարբերակի ID-ն բացակայում է։', + missingRequiredData: 'Պահանջվող տվյալները բացակայում են։', + noFilesUploaded: 'Ֆայլեր չեն վերբեռնվել։', + noMatchedField: '"{{label}}"-ի համար համապատասխան դաշտ չի գտնվել', + notAllowedToAccessPage: 'Ձեզ թույլ չի տրվում մուտք գործել այս էջ։', + notAllowedToPerformAction: 'Ձեզ թույլ չի տրվում կատարել այս գործողությունը։', + notFound: 'Հայցված ռեսուրսը չի գտնվել։', + noUser: 'Օգտատեր չկա', + previewing: 'Այս փաստաթուղթը նախադիտելու ժամանակ խնդիր է առաջացել։', + problemUploadingFile: 'Ֆայլը վերբեռնելու ժամանակ խնդիր է առաջացել։', + tokenInvalidOrExpired: 'Թոքենն անվավեր է կամ ժամկետանց։', + tokenNotProvided: 'Թոքենը տրամադրված չէ։', + unableToDeleteCount: 'Հնարավոր չէ ջնջել {{count}}-ը {{total}} {{label}}-ից։', + unableToReindexCollection: + 'Հավաքածու {{collection}}-ը վերաինդեքսավորելու սխալ։ Գործողությունն ընդհատվել է։', + unableToUpdateCount: 'Հնարավոր չէ թարմացնել {{count}}-ը {{total}} {{label}}-ից։', + unauthorized: 'Չթույլատրված, Դուք պետք է մուտք գործեք այս հարցումը կատարելու համար։', + unauthorizedAdmin: 'Չթույլատրված, այս օգտատերը հասանելություն չունի կառավարման վահանակ։', + unknown: 'Անհայտ սխալ է տեղի ունեցել։', + unPublishingDocument: 'Այս փաստաթուղթը չհրապարակված դարձնելու ժամանակ խնդիր է առաջացել։', + unspecific: 'Սխալ է տեղի ունեցել։', + unverifiedEmail: 'Խնդրում ենք հաստատել Ձեր էլ. փոստը նախքան մուտք գործելը։', + userEmailAlreadyRegistered: 'Տվյալ էլ. փոստով օգտատեր արդեն գրանցված է։', + userLocked: 'Այս օգտանունը կողպված է՝ մուտքի բազմաթիվ անհաջող փորձերի պատճառով։', + usernameAlreadyRegistered: 'Տվյալ օգտանվամբ օգտատեր արդեն գրանցված է։', + usernameOrPasswordIncorrect: 'Տրամադրված օգտանունը կամ գաղտնաբառը սխալ է։', + valueMustBeUnique: 'Արժեքը պետք է եզակի լինի', + verificationTokenInvalid: 'Ստուգման թոքենն անվավեր է։', + }, + fields: { + addLabel: 'Ավելացնել {{label}}', + addLink: 'Ավելացնել հղում', + addNew: 'Ավելացնել նոր', + addNewLabel: 'Ավելացնել նոր {{label}}', + addRelationship: 'Ավելացնել հարաբերություն', + addUpload: 'Վերբեռնել', + block: 'բլոկ', + blocks: 'բլոկներ', + blockType: 'Բլոկի տեսակ', + chooseBetweenCustomTextOrDocument: + 'Ընտրեք՝ մուտքագրել հատուկ տեքստային URL, թե՞ կապել այլ փաստաթղթի հետ։', + chooseDocumentToLink: 'Ընտրեք կապակցվելիք փաստաթուղթը', + chooseFromExisting: 'Ընտրեք գոյություն ունեցողներից', + chooseLabel: 'Ընտրեք {{label}}', + collapseAll: 'Փակել բոլորը', + customURL: 'Հատուկ URL', + editLabelData: 'Խմբագրել {{label}} տվյալները', + editLink: 'Խմբագրել հղումը', + editRelationship: 'Խմբագրել հարաբերությունը', + enterURL: 'Մուտքագրեք URL', + internalLink: 'Ներքին հղում', + itemsAndMore: '{{items}} և {{count}} ավելին', + labelRelationship: '{{label}} հարաբերություն', + latitude: 'Լայնություն', + linkedTo: 'Կապված է <0>{{label}}-ի հետ', + linkType: 'Հղման տեսակ', + longitude: 'Երկայնություն', + newLabel: 'Նոր {{label}}', + openInNewTab: 'Բացել նոր ներդիրում', + passwordsDoNotMatch: 'Գաղտնաբառերը չեն համընկնում։', + relatedDocument: 'Հարակից փաստաթուղթ', + relationTo: 'Հարաբերվում է...', + removeRelationship: 'Հեռացնել հարաբերությունը', + removeUpload: 'Հեռացնել վերբեռնվածը', + saveChanges: 'Պահպանել փոփոխությունները', + searchForBlock: 'Որոնել բլոկ', + selectExistingLabel: 'Ընտրել գոյություն ունեցող {{label}}', + selectFieldsToEdit: 'Ընտրեք դաշտեր խմբագրման համար', + showAll: 'Ցուցադրել բոլորը', + swapRelationship: 'Փոխել հարաբերությունը', + swapUpload: 'Փոխել վերբեռնվածը', + textToDisplay: 'Ցուցադրվող տեքստ', + toggleBlock: 'Միացնել/անջատել բլոկը', + uploadNewLabel: 'Վերբեռնել նոր {{label}}', + }, + general: { + aboutToDelete: 'Դուք պատրաստվում եք ջնջել {{label}} <1>{{title}}-ը։ Համոզվա՞ծ եք։', + aboutToDeleteCount_many: 'Դուք պատրաստվում եք ջնջել {{count}} {{label}}', + aboutToDeleteCount_one: 'Դուք պատրաստվում եք ջնջել {{count}} {{label}}', + aboutToDeleteCount_other: 'Դուք պատրաստվում եք ջնջել {{count}} {{label}}', + addBelow: 'Ավելացնել ներքևում', + addFilter: 'Ավելացնել ֆիլտր', + adminTheme: 'Կառավարման թեմա', + all: 'Բոլորը', + allCollections: 'Բոլոր հավաքածուները', + and: 'Եվ', + anotherUser: 'Այլ օգտատեր', + anotherUserTakenOver: 'Այլ օգտատեր ստանձել է այս փաստաթղթի խմբագրումը։', + applyChanges: 'Կիրառել փոփոխությունները', + ascending: 'Աճող', + automatic: 'Ավտոմատ', + backToDashboard: 'Վերադառնալ վահանակ', + cancel: 'Չեղարկել', + changesNotSaved: + 'Ձեր փոփոխությունները չեն պահպանվել։ Եթե հիմա հեռանաք, կկորցնեք չպահպանված փոփոխությունները։', + clearAll: 'Մաքրել բոլորը', + close: 'Փակել', + collapse: 'Փակել', + collections: 'Հավաքածուներ', + columns: 'Սյունակներ', + columnToSort: 'Սյունակ՝ տեսակավորման համար', + confirm: 'Հաստատել', + confirmCopy: 'Հաստատել պատճենումը', + confirmDeletion: 'Հաստատել ջնջելը', + confirmDuplication: 'Հաստատել կրկնօրինակումը', + confirmReindex: 'Վերաինդեքսավորե՞լ բոլոր {{collections}}-ը։', + confirmReindexAll: 'Վերաինդեքսավորե՞լ բոլոր հավաքածուները։', + confirmReindexDescription: + 'Սա կհեռացնի գոյություն ունեցող ինդեքսները և կվերաինդեքսավորի փաստաթղթերը {{collections}} հավաքածուներում։', + confirmReindexDescriptionAll: + 'Սա կհեռացնի գոյություն ունեցող ինդեքսները և կվերաինդեքսավորի փաստաթղթերը բոլոր հավաքածուներում։', + copied: 'Պատճենված', + copy: 'Պատճենել', + copying: 'Պատճենվում է', + copyWarning: + 'Դուք պատրաստվում եք վերագրել {{to}}-ը {{from}}-ով {{label}} {{title}}-ի համար։ Համոզվա՞ծ եք։', + create: 'Ստեղծել', + created: 'Ստեղծված', + createdAt: 'Ստեղծման ժամանակ', + createNew: 'Ստեղծել նոր', + createNewLabel: 'Ստեղծել նոր {{label}}', + creating: 'Ստեղծվում է', + creatingNewLabel: 'Ստեղծվում է նոր {{label}}', + currentlyEditing: + 'ներկայումս խմբագրում է այս փաստաթուղթը։ Եթե Դուք ստանձնեք վերահսկողությունը, նա չի կարողանա շարունակել խմբագրումը և կարող է կորցնել չպահպանված փոփոխությունները։', + custom: 'Հատուկ', + dark: 'Մուգ', + dashboard: 'Վահանակ', + delete: 'Ջնջել', + deletedCountSuccessfully: '{{count}} {{label}} հաջողությամբ ջնջված է։', + deletedSuccessfully: 'Հաջողությամբ ջնջված է։', + deleting: 'Ջնջվում է...', + depth: 'Խորություն', + descending: 'Նվազող', + deselectAllRows: 'Հանել բոլոր տողերի ընտրությունը', + document: 'Փաստաթուղթ', + documentLocked: 'Փաստաթուղթը կողպված է', + documents: 'Փաստաթղթեր', + duplicate: 'Կրկնօրինակել', + duplicateWithoutSaving: 'Կրկնօրինակել առանց փոփոխությունները պահպանելու', + edit: 'Խմբագրել', + editAll: 'Խմբագրել բոլորը', + editedSince: 'Խմբագրվել է սկսած', + editing: 'Խմբագրում', + editingLabel_many: 'Խմբագրվում է {{count}} {{label}}', + editingLabel_one: 'Խմբագրվում է {{count}} {{label}}', + editingLabel_other: 'Խմբագրվում է {{count}} {{label}}', + editingTakenOver: 'Խմբագրումը ստանձնել է ուրիշ օգտատեր', + editLabel: 'Խմբագրել {{label}}', + email: 'Էլ. փոստ', + emailAddress: 'Էլ. փոստի հասցե', + enterAValue: 'Մուտքագրեք արժեք', + error: 'Սխալ', + errors: 'Սխալներ', + fallbackToDefaultLocale: 'Վերադառնալ լռելյայն լոկալին', + false: 'Կեղծ', + filter: 'Ֆիլտր', + filters: 'Ֆիլտրեր', + filterWhere: 'Ֆիլտրել {{label}}-ը, որտեղ', + globals: 'Համընդհանուրներ', + goBack: 'Հետ գնալ', + isEditing: 'խմբագրում է', + language: 'Լեզու', + lastModified: 'Վերջին փոփոխություն', + leaveAnyway: 'Այնուամենայնիվ հեռանալ', + leaveWithoutSaving: 'Հեռանալ առանց պահպանելու', + light: 'Լուսավոր', + livePreview: 'Լայվ նախադիտում', + loading: 'Բեռնում', + locale: 'Լոկալ', + locales: 'Լոկալներ', + menu: 'Մենյու', + moreOptions: 'Լրացուցիչ ընտրանքներ', + moveDown: 'Տեղափոխել ներքև', + moveUp: 'Տեղափոխել վերև', + newPassword: 'Նոր գաղտնաբառ', + next: 'Հաջորդ', + noDateSelected: 'Չկա ընտրված ամսաթիվ', + noFiltersSet: 'Ֆիլտրեր սահմանված չեն', + noLabel: '<Չկա {{label}}>', + none: 'Ոչ մեկը', + noOptions: 'Ընտրանքներ չկան', + noResults: + '{{label}}-ը չի գտնվել։ Կա՛մ դեռևս {{label}} չկա, կա՛մ ոչ մեկը չի համապատասխանում վերևում նշված ֆիլտրերին։', + notFound: 'Չի գտնվել', + nothingFound: 'Ոչինչ չի գտնվել', + noUpcomingEventsScheduled: 'Իրադարձություններ նախատեսված չեն։', + noValue: 'Արժեք չկա', + of: 'ի', + only: 'Միայն', + open: 'Բացել', + or: 'Կամ', + order: 'Հերթականություն', + overwriteExistingData: 'Վերագրել գոյություն ունեցող դաշտի տվյալները', + pageNotFound: 'Էջը չի գտնվել', + password: 'Գաղտնաբառ', + payloadSettings: 'Payload-ի կարգավորումներ', + perPage: 'Էջում՝ {{limit}}', + previous: 'Նախորդ', + reindex: 'Վերաինդեքսավորել', + reindexingAll: 'Վերաինդեքսավորվում են բոլոր {{collections}}-ները։', + remove: 'Հեռացնել', + reset: 'Վերակայել', + resetPreferences: 'Վերակայել նախընտրությունները', + resetPreferencesDescription: + 'Սա կվերակայի Ձեր բոլոր նախընտրությունները դեպի լռելյայն կարգավորումներ։', + resettingPreferences: 'Նախընտրությունները վերակայվում են', + row: 'Տող', + rows: 'Տողեր', + save: 'Պահպանել', + saving: 'Պահպանվում է...', + schedulePublishFor: 'Հրապարակման ժամանակ նշանակել {{title}}-ի համար', + searchBy: 'Որոնել ըստ {{label}}-ի', + selectAll: 'Ընտրել բոլոր {{count}} {{label}}', + selectAllRows: 'Ընտրել բոլոր տողերը', + selectedCount: '{{count}} {{label}} ընտրված է', + selectLabel: 'ընտրել {{label}}', + selectValue: 'Ընտրեք արժեք', + showAllLabel: 'Ցուցադրել բոլոր {{label}}-ները', + sorryNotFound: 'Ներողություն, Ձեր հարցմանը համապատասխան ոչինչ չկա։', + sort: 'Տեսակավորել', + sortByLabelDirection: 'Տեսակավորել ըստ {{label}} {{direction}}', + stayOnThisPage: 'Մնալ այս էջում', + submissionSuccessful: 'Հայտը հաջողությամբ ուղարկվել է։', + submit: 'Հաստատել', + submitting: 'Ուղարկվում է...', + success: 'Հաջողված է', + successfullyCreated: '{{label}} հաջողությամբ ստեղծվել է։', + successfullyDuplicated: '{{label}} հաջողությամբ կրկնօրինակվել է։', + successfullyReindexed: + 'Հաջողությամբ վերաինդեքսավորվել են {{count}}-ը {{total}} փաստաթղթերից {{collections}}-ում', + takeOver: 'Վերցնել վերահսկողությունը', + thisLanguage: 'Հայերեն', + time: 'Ժամ', + timezone: 'Ժամային գոտի', + titleDeleted: '{{label}} "{{title}}" հաջողությամբ ջնջվել է։', + true: 'Ճիշտ', + unauthorized: 'Չթույլատրված', + unsavedChanges: + 'Դուք ունեք չպահպանված փոփոխություններ։ Պահպանեք կամ հեռացեք նախքան շարունակելը։', + unsavedChangesDuplicate: + 'Դուք ունեք չպահպանված փոփոխություններ։ Ցանկանու՞մ եք շարունակել կրկնօրինակումը։', + untitled: 'Անվերնագիր', + upcomingEvents: 'Սպասվող իրադարձություններ', + updatedAt: 'Թարմացված է', + updatedCountSuccessfully: '{{count}} {{label}} հաջողությամբ թարմացվել է։', + updatedLabelSuccessfully: '', + updatedSuccessfully: 'Հաջողությամբ թարմացվել է։', + updateForEveryone: '', + updating: 'Թարմացում', + uploading: 'Վերբեռնվում է', + uploadingBulk: 'Վերբեռնվում է {{current}}-ը {{total}}-ից', + user: 'Օգտատեր', + username: 'Օգտանուն', + users: 'Օգտատերեր', + value: 'Արժեք', + viewReadOnly: '«Միայն կարդալու» ռեժիմ', + welcome: 'Բարի գալուստ', + }, + localization: { + cannotCopySameLocale: 'Հնարավոր չէ պատճենել նույն լոկալին', + copyFrom: 'Պատճենել սկսած', + copyFromTo: 'Պատճենվում է {{from}}-ից {{to}}', + copyTo: 'Պատճենել դեպի', + copyToLocale: 'Պատճենել լոկալին', + localeToPublish: 'Հրապարակման լոկալ', + selectLocaleToCopy: 'Ընտրեք լոկալ՝ պատճենելու համար', + }, + operators: { + contains: 'պարունակում է', + equals: 'հավասար է', + exists: 'գոյություն ունի', + intersects: 'հատվում է', + isGreaterThan: 'մեծ է, քան', + isGreaterThanOrEqualTo: 'մեծ է կամ հավասար', + isIn: 'գտնվում է', + isLessThan: 'փոքր է, քան', + isLessThanOrEqualTo: 'փոքր է կամ հավասար', + isLike: 'նման է', + isNotEqualTo: 'հավասար չէ', + isNotIn: 'չի գտնվում', + isNotLike: 'նման չէ', + near: 'մոտ', + within: 'ներսում', + }, + upload: { + addFile: 'Ավելացնել ֆայլ', + addFiles: 'Ավելացնել ֆայլեր', + bulkUpload: 'Զանգվածային վերբեռնում', + crop: 'Կտրել', + cropToolDescription: + 'Քաշեք ընտրված տարածքի անկյունները, նշեք նոր տարածք կամ կարգավորեք ստորև նշված արժեքները։', + dragAndDrop: 'Քաշեք և գցեք ֆայլը', + dragAndDropHere: 'կամ քաշեք և գցեք ֆայլն այստեղ', + editImage: 'Խմբագրել պատկերը', + fileName: 'Ֆայլի անուն', + fileSize: 'Ֆայլի չափ', + filesToUpload: 'Վերբեռնման ֆայլեր', + fileToUpload: 'Վերբեռնման ֆայլ', + focalPoint: 'Կիզակետ', + focalPointDescription: + 'Քաշեք կիզակետը անմիջապես նախադիտման վրա կամ կարգավորեք ստորև նշված արժեքները։', + height: 'Բարձրություն', + lessInfo: 'Ավելի քիչ տեղեկություն', + moreInfo: 'Ավելի շատ տեղեկություն', + noFile: 'Ֆայլ չկա', + pasteURL: 'Տեղադրել URL', + previewSizes: 'Նախադիտման չափեր', + selectCollectionToBrowse: 'Ընտրեք հավաքածու՝ դիտելու համար', + selectFile: 'Ընտրեք ֆայլ', + setCropArea: 'Սահմանել կտրվող տարածքի չափը', + setFocalPoint: 'Սահմանել կիզակետ', + sizes: 'Չափեր', + sizesFor: 'Չափեր {{label}}-ի համար', + width: 'Լայնություն', + }, + validation: { + emailAddress: 'Խնդրում ենք մուտքագրել վավեր էլ. փոստի հասցե։', + enterNumber: 'Խնդրում ենք մուտքագրել վավեր հեռախոսահամար։', + fieldHasNo: 'Այս դաշտում {{label}} չկա', + greaterThanMax: '{{value}}-ը մեծ է {{max}} {{label}}-ի թույլատրելի առավելագույնից։', + invalidInput: 'Ներմուծված արժեքն անվավեր է', + invalidSelection: 'Այս դաշտն ունի անվավեր ընտրություն։', + invalidSelections: 'Այս դաշտն ունի հետևյալ անվավեր ընտրությունները։', + lessThanMin: '{{value}}-ը փոքր է {{min}} {{label}}-ի թույլատրելի նվազագույն արժեքից։', + limitReached: + 'Դու հասել եք առավելագույն սահմանին, կարող են ավելացվել միայն {{max}} քանակի տարրեր։', + longerThanMin: + 'Այս արժեքը պետք է ավելի երկար լինի, քան {{minLength}} նիշերի նվազագույն երկարությունը։', + notValidDate: '"{{value}}"-ը վավեր ամսաթիվ չէ։', + required: 'Այս դաշտը պարտադիր է։', + requiresAtLeast: 'Այս դաշտը պահանջում է առնվազն {{count}} {{label}}։', + requiresNoMoreThan: 'Այս դաշտը պահանջում է ոչ ավելի, քան {{count}} {{label}}։', + requiresTwoNumbers: 'Այս դաշտը պահանջում է երկու թիվ։', + shorterThanMax: + 'Այս արժեքը պետք է ավելի կարճ լինի, քան {{maxLength}} նիշերի առավելագույն երկարությունը։', + timezoneRequired: 'Ժամային գոտին պարտադիր է։', + trueOrFalse: 'Այս դաշտի արժեքը կարող է միայն «ճիշտ» կամ «սխալ»։', + username: + 'Խնդրում ենք մուտքագրել վավեր օգտանուն։ Կարող է պարունակել տառեր, թվեր, գծիկներ, կետեր և ընդգծում։', + validUploadID: 'Այս դաշտը վավեր վերբեռնման ID չի պարունակում։', + }, + version: { + type: 'Տեսակ', + aboutToPublishSelection: + 'Դուք պատրաստվում եք հրապարակել ընտրության մեջ գտնվող բոլոր {{label}}-ները։ Համոզվա՞ծ եք։', + aboutToRestore: + 'Դուք պատրաստվում եք վերականգնել այս {{label}}-ի փաստաթուղթը {{versionDate}}-ի ժամանակ եղած վիճակին։', + aboutToRestoreGlobal: + 'Դուք պատրաստվում եք վերականգնել համընդհանուր {{label}}-ը {{versionDate}}-ի ժամանակ եղած վիճակին։', + aboutToRevertToPublished: + 'Դուք պատրաստվում եք հետ բերել այս փաստաթղթի փոփոխությունները դեպի իր հրապարակված վիճակին։ Համոզվա՞ծ եք։', + aboutToUnpublish: + 'Դուք պատրաստվում եք այս փաստաթուղթը բերել չհրապարակված վիճակի։ Համոզվա՞ծ եք։', + aboutToUnpublishSelection: + 'Դուք պատրաստվում եք ընտրության մեջ գտնվող բոլոր {{label}}-ները բերել չհրապարակված վիճակի։ Համոզվա՞ծ եք։', + autosave: 'Ինքնապահպանում', + autosavedSuccessfully: 'Հաջողությամբ ինքնապահպանվել է։', + autosavedVersion: 'Ինքնապահպանված տարբերակ', + changed: 'Փոփոխված', + changedFieldsCount_one: '{{count}} փոփոխված դաշտ', + changedFieldsCount_other: '{{count}} փոփոխված դաշտեր', + compareVersion: 'Համեմատել տարբերակը հետևյալի հետ՝', + confirmPublish: 'Հաստատել հրապարակումը', + confirmRevertToSaved: 'Հաստատել վերադարձը պահպանված վիճակին', + confirmUnpublish: 'Հաստատել վերադարձը չհրապարակված վիճակին։', + confirmVersionRestoration: 'Հաստատել տարբերակի վերականգնումը', + currentDocumentStatus: 'Ընթացիկ {{docStatus}} փաստաթուղթ', + currentDraft: 'Ընթացիկ սևագիր', + currentPublishedVersion: 'Ընթացիկ հրապարակված տարբերակ', + draft: 'Սևագիր', + draftSavedSuccessfully: 'Սևագիրը հաջողությամբ պահպանվել է։', + lastSavedAgo: 'Վերջին անգամ պահպանվել է {{distance}} առաջ', + modifiedOnly: 'Միայն փոփոխված', + noFurtherVersionsFound: 'Այլ տարբերակներ չեն գտնվել', + noRowsFound: ' Ոչ մի {{label}} չի գտնվել', + noRowsSelected: 'Ոչ մի {{label}} ընտրված չէ', + preview: 'Նախադիտում', + previouslyPublished: 'Նախկինում հրապարակված', + problemRestoringVersion: 'Այս տարբերակը վերականգնելու ժամանակ խնդիր է առաջացել', + publish: 'Հրապարակել', + publishAllLocales: 'Հրապարակել բոլոր լոկալներում', + publishChanges: 'Հրապարակել փոփոխությունները', + published: 'Հրապարակված', + publishIn: 'Հրապարակել {{locale}}-ում', + publishing: 'Հրապարակվում է', + restoreAsDraft: 'Վերականգնել որպես սևագիր', + restoredSuccessfully: 'Հաջողությամբ վերականգնված։', + restoreThisVersion: 'Վերականգնել այս տարբերակը', + restoring: 'Վերականգնվում է...', + reverting: 'Հետ է բերվում...', + revertToPublished: 'Հետ բերել հրապարակված վիճակին', + saveDraft: 'Պահպանել սևագիրը', + scheduledSuccessfully: 'Հաջողությամբ պլանավորված։', + schedulePublish: 'Պլանավորել հրապարակումը', + selectLocales: 'Ընտրեք ցուցադրման լոկալները', + selectVersionToCompare: 'Ընտրեք տարբերակ՝ համեմատելու համար', + showingVersionsFor: 'Ցուցադրված են տարբերակները՝', + showLocales: 'Ցուցադրել լոկալները՝', + status: 'Կարգավիճակ', + unpublish: 'Բերել չհրապարակված վիճակի։', + unpublishing: 'Բերվում է չհրապարակված վիճակի...', + version: 'Տարբերակ', + versionCount_many: 'Գտնվել են {{count}} տարբերակներ', + versionCount_none: 'Ոչ մի տարբերակ չի գտնվել', + versionCount_one: '{{count}} տարբերակ է գտնվել', + versionCount_other: '{{count}} տարբերակ է գտնվել', + versionCreatedOn: '{{version}}-ը ստեղծվել է՝', + versionID: 'Տարբերակի ID', + versions: 'Տարբերակներ', + viewingVersion: 'Ցույց է տրված {{entityLabel}} {{documentTitle}}-ի տարբերակը', + viewingVersionGlobal: 'Ցույց է տրված համընդհանուր {{entityLabel}}-ի տարբերակը', + viewingVersions: 'Ցույց է տրված {{entityLabel}} {{documentTitle}}-ի տարբերակները', + viewingVersionsGlobal: 'Ցույց է տրված համընդհանուր {{entityLabel}}-ի տարբերակները', + }, +} + +export const hy: Language = { + dateFNSKey: 'hy-AM', + translations: hyTranslations, +} diff --git a/packages/translations/src/types.ts b/packages/translations/src/types.ts index 82a945e789..f8ae412718 100644 --- a/packages/translations/src/types.ts +++ b/packages/translations/src/types.ts @@ -20,6 +20,7 @@ type DateFNSKeys = | 'he' | 'hr' | 'hu' + | 'hy-AM' | 'it' | 'ja' | 'ko' diff --git a/packages/translations/src/utilities/languages.ts b/packages/translations/src/utilities/languages.ts index 2c95bde2f3..83307abeca 100644 --- a/packages/translations/src/utilities/languages.ts +++ b/packages/translations/src/utilities/languages.ts @@ -18,6 +18,7 @@ export const acceptedLanguages = [ 'he', 'hr', 'hu', + 'hy', 'it', 'ja', 'ko', @@ -73,7 +74,6 @@ export const acceptedLanguages = [ * 'gu', * 'ha-Latn', * 'hi', - * 'hy', * 'id', * 'ig-Latn', * 'is', From 93cc66d7452da123d8d4c6c81796afc6c4ef6fdb Mon Sep 17 00:00:00 2001 From: Sasha <64744993+r1tsuu@users.noreply.github.com> Date: Tue, 25 Mar 2025 17:35:33 +0200 Subject: [PATCH 14/77] test: rearrange relationships test blocks properly (#11858) Previously, many test cases in `int/relationships` were wrapped to the "custom IDs" describe block even though they aren't related to custom IDs at all. This rearranges them as they should be. --- test/relationships/int.spec.ts | 508 +++++++++++++++++---------------- 1 file changed, 256 insertions(+), 252 deletions(-) diff --git a/test/relationships/int.spec.ts b/test/relationships/int.spec.ts index cf1b11db4b..1502409659 100644 --- a/test/relationships/int.spec.ts +++ b/test/relationships/int.spec.ts @@ -397,21 +397,7 @@ describe('Relationships', () => { expect(result.docs[0].id).toBe(id) }) - describe('Custom ID', () => { - it('should query a custom id relation', async () => { - const { customIdRelation } = await restClient - .GET(`/${slug}/${post.id}`) - .then((res) => res.json()) - expect(customIdRelation).toMatchObject({ id: generatedCustomId }) - }) - - it('should query a custom id number relation', async () => { - const { customIdNumberRelation } = await restClient - .GET(`/${slug}/${post.id}`) - .then((res) => res.json()) - expect(customIdNumberRelation).toMatchObject({ id: generatedCustomIdNumber }) - }) - + describe('hasMany relationships', () => { it('should retrieve totalDocs correctly with hasMany,', async () => { const movie1 = await payload.create({ collection: 'movies', @@ -592,47 +578,59 @@ describe('Relationships', () => { expect(query1.totalDocs).toStrictEqual(1) }) - it('should sort by a property of a hasMany relationship', async () => { - const movie1 = await payload.create({ - collection: 'movies', + it('should query using "in" by hasMany relationship field', async () => { + const tree1 = await payload.create({ + collection: treeSlug, data: { - name: 'Pulp Fiction', + text: 'Tree 1', }, }) - const movie2 = await payload.create({ - collection: 'movies', + const tree2 = await payload.create({ + collection: treeSlug, data: { - name: 'Inception', + parent: tree1.id, + text: 'Tree 2', }, }) - await payload.delete({ collection: 'directors', where: {} }) - - const director1 = await payload.create({ - collection: 'directors', + const tree3 = await payload.create({ + collection: treeSlug, data: { - name: 'Quentin Tarantino', - movies: [movie1.id], - }, - }) - const director2 = await payload.create({ - collection: 'directors', - data: { - name: 'Christopher Nolan', - movies: [movie2.id], + parent: tree2.id, + text: 'Tree 3', }, }) - const result = await payload.find({ - collection: 'directors', + const tree4 = await payload.create({ + collection: treeSlug, + data: { + parent: tree3.id, + text: 'Tree 4', + }, + }) + + const validParents = [tree2.id, tree3.id] + + const query = await payload.find({ + collection: treeSlug, depth: 0, - sort: '-movies.name', + sort: 'createdAt', + where: { + parent: { + in: validParents, + }, + }, }) + // should only return tree3 and tree4 - expect(result.docs[0].id).toStrictEqual(director1.id) + expect(query.totalDocs).toEqual(2) + expect(query.docs[0].text).toEqual('Tree 3') + expect(query.docs[1].text).toEqual('Tree 4') }) + }) + describe('sorting by relationships', () => { it('should sort by a property of a relationship', async () => { await payload.delete({ collection: 'directors', where: {} }) await payload.delete({ collection: 'movies', where: {} }) @@ -719,236 +717,61 @@ describe('Relationships', () => { expect(localized_res_2.docs).toStrictEqual([movie_1, movie_2]) }) - it('should query using "in" by hasMany relationship field', async () => { - const tree1 = await payload.create({ - collection: treeSlug, + it('should sort by a property of a hasMany relationship', async () => { + const movie1 = await payload.create({ + collection: 'movies', data: { - text: 'Tree 1', + name: 'Pulp Fiction', }, }) - const tree2 = await payload.create({ - collection: treeSlug, + const movie2 = await payload.create({ + collection: 'movies', data: { - parent: tree1.id, - text: 'Tree 2', + name: 'Inception', }, }) - const tree3 = await payload.create({ - collection: treeSlug, + await payload.delete({ collection: 'directors', where: {} }) + + const director1 = await payload.create({ + collection: 'directors', data: { - parent: tree2.id, - text: 'Tree 3', + name: 'Quentin Tarantino', + movies: [movie1.id], + }, + }) + const director2 = await payload.create({ + collection: 'directors', + data: { + name: 'Christopher Nolan', + movies: [movie2.id], }, }) - const tree4 = await payload.create({ - collection: treeSlug, - data: { - parent: tree3.id, - text: 'Tree 4', - }, - }) - - const validParents = [tree2.id, tree3.id] - - const query = await payload.find({ - collection: treeSlug, + const result = await payload.find({ + collection: 'directors', depth: 0, - sort: 'createdAt', - where: { - parent: { - in: validParents, - }, - }, + sort: '-movies.name', }) - // should only return tree3 and tree4 - expect(query.totalDocs).toEqual(2) - expect(query.docs[0].text).toEqual('Tree 3') - expect(query.docs[1].text).toEqual('Tree 4') + expect(result.docs[0].id).toStrictEqual(director1.id) + }) + }) + + describe('Custom ID', () => { + it('should query a custom id relation', async () => { + const { customIdRelation } = await restClient + .GET(`/${slug}/${post.id}`) + .then((res) => res.json()) + expect(customIdRelation).toMatchObject({ id: generatedCustomId }) }) - it('should validate the format of text id relationships', async () => { - await expect(async () => - createPost({ - // @ts-expect-error Sending bad data to test error handling - customIdRelation: 1234, - }), - ).rejects.toThrow('The following field is invalid: Custom Id Relation') - }) - - it('should validate the format of number id relationships', async () => { - await expect(async () => - createPost({ - // @ts-expect-error Sending bad data to test error handling - customIdNumberRelation: 'bad-input', - }), - ).rejects.toThrow('The following field is invalid: Custom Id Number Relation') - }) - - it('should allow update removing a relationship', async () => { - const response = await restClient.PATCH(`/${slug}/${post.id}`, { - body: JSON.stringify({ - customIdRelation: null, - relationField: null, - }), - }) - const doc = await response.json() - - expect(response.status).toEqual(200) - expect(doc.relationField).toBeFalsy() - }) - - it('should query a polymorphic relationship field with mixed custom ids and default', async () => { - const customIDNumber = await payload.create({ - collection: 'custom-id-number', - data: { id: 999 }, - }) - - const customIDText = await payload.create({ - collection: 'custom-id', - data: { id: 'custom-id' }, - }) - - const page = await payload.create({ - collection: 'pages', - data: {}, - }) - - const relToCustomIdText = await payload.create({ - collection: 'rels-to-pages-and-custom-text-ids', - data: { - rel: { - relationTo: 'custom-id', - value: customIDText.id, - }, - }, - }) - - const relToCustomIdNumber = await payload.create({ - collection: 'rels-to-pages-and-custom-text-ids', - data: { - rel: { - relationTo: 'custom-id-number', - value: customIDNumber.id, - }, - }, - }) - - const relToPage = await payload.create({ - collection: 'rels-to-pages-and-custom-text-ids', - data: { - rel: { - relationTo: 'pages', - value: page.id, - }, - }, - }) - - const pageResult = await payload.find({ - collection: 'rels-to-pages-and-custom-text-ids', - where: { - and: [ - { - 'rel.value': { - equals: page.id, - }, - }, - { - 'rel.relationTo': { - equals: 'pages', - }, - }, - ], - }, - }) - - expect(pageResult.totalDocs).toBe(1) - expect(pageResult.docs[0].id).toBe(relToPage.id) - - const customIDResult = await payload.find({ - collection: 'rels-to-pages-and-custom-text-ids', - where: { - and: [ - { - 'rel.value': { - equals: customIDText.id, - }, - }, - { - 'rel.relationTo': { - equals: 'custom-id', - }, - }, - ], - }, - }) - - expect(customIDResult.totalDocs).toBe(1) - expect(customIDResult.docs[0].id).toBe(relToCustomIdText.id) - - const customIDNumberResult = await payload.find({ - collection: 'rels-to-pages-and-custom-text-ids', - where: { - and: [ - { - 'rel.value': { - equals: customIDNumber.id, - }, - }, - { - 'rel.relationTo': { - equals: 'custom-id-number', - }, - }, - ], - }, - }) - - expect(customIDNumberResult.totalDocs).toBe(1) - expect(customIDNumberResult.docs[0].id).toBe(relToCustomIdNumber.id) - - const inResult_1 = await payload.find({ - collection: 'rels-to-pages-and-custom-text-ids', - where: { - 'rel.value': { - in: [page.id, customIDNumber.id], - }, - }, - }) - - expect(inResult_1.totalDocs).toBe(2) - expect(inResult_1.docs.some((each) => each.id === relToPage.id)).toBeTruthy() - expect(inResult_1.docs.some((each) => each.id === relToCustomIdNumber.id)).toBeTruthy() - - const inResult_2 = await payload.find({ - collection: 'rels-to-pages-and-custom-text-ids', - where: { - 'rel.value': { - in: [customIDNumber.id, customIDText.id], - }, - }, - }) - - expect(inResult_2.totalDocs).toBe(2) - expect(inResult_2.docs.some((each) => each.id === relToCustomIdText.id)).toBeTruthy() - expect(inResult_2.docs.some((each) => each.id === relToCustomIdNumber.id)).toBeTruthy() - - const inResult_3 = await payload.find({ - collection: 'rels-to-pages-and-custom-text-ids', - where: { - 'rel.value': { - in: [customIDNumber.id, customIDText.id, page.id], - }, - }, - }) - - expect(inResult_3.totalDocs).toBe(3) - expect(inResult_3.docs.some((each) => each.id === relToCustomIdText.id)).toBeTruthy() - expect(inResult_3.docs.some((each) => each.id === relToCustomIdNumber.id)).toBeTruthy() - expect(inResult_3.docs.some((each) => each.id === relToPage.id)).toBeTruthy() + it('should query a custom id number relation', async () => { + const { customIdNumberRelation } = await restClient + .GET(`/${slug}/${post.id}`) + .then((res) => res.json()) + expect(customIdNumberRelation).toMatchObject({ id: generatedCustomIdNumber }) }) }) @@ -1072,6 +895,19 @@ describe('Relationships', () => { expect(docs.map((doc) => doc?.id)).not.toContain(localizedPost2.id) }) }) + + it('should allow update removing a relationship', async () => { + const response = await restClient.PATCH(`/${slug}/${post.id}`, { + body: JSON.stringify({ + customIdRelation: null, + relationField: null, + }), + }) + const doc = await response.json() + + expect(response.status).toEqual(200) + expect(doc.relationField).toBeFalsy() + }) }) describe('Nested Querying', () => { @@ -1797,6 +1633,174 @@ describe('Relationships', () => { expect(updated.status).toBe('completed') }) + + it('should validate the format of text id relationships', async () => { + await expect(async () => + createPost({ + // @ts-expect-error Sending bad data to test error handling + customIdRelation: 1234, + }), + ).rejects.toThrow('The following field is invalid: Custom Id Relation') + }) + + it('should validate the format of number id relationships', async () => { + await expect(async () => + createPost({ + // @ts-expect-error Sending bad data to test error handling + customIdNumberRelation: 'bad-input', + }), + ).rejects.toThrow('The following field is invalid: Custom Id Number Relation') + }) + + it('should query a polymorphic relationship field with mixed custom ids and default', async () => { + const customIDNumber = await payload.create({ + collection: 'custom-id-number', + data: { id: 999 }, + }) + + const customIDText = await payload.create({ + collection: 'custom-id', + data: { id: 'custom-id' }, + }) + + const page = await payload.create({ + collection: 'pages', + data: {}, + }) + + const relToCustomIdText = await payload.create({ + collection: 'rels-to-pages-and-custom-text-ids', + data: { + rel: { + relationTo: 'custom-id', + value: customIDText.id, + }, + }, + }) + + const relToCustomIdNumber = await payload.create({ + collection: 'rels-to-pages-and-custom-text-ids', + data: { + rel: { + relationTo: 'custom-id-number', + value: customIDNumber.id, + }, + }, + }) + + const relToPage = await payload.create({ + collection: 'rels-to-pages-and-custom-text-ids', + data: { + rel: { + relationTo: 'pages', + value: page.id, + }, + }, + }) + + const pageResult = await payload.find({ + collection: 'rels-to-pages-and-custom-text-ids', + where: { + and: [ + { + 'rel.value': { + equals: page.id, + }, + }, + { + 'rel.relationTo': { + equals: 'pages', + }, + }, + ], + }, + }) + + expect(pageResult.totalDocs).toBe(1) + expect(pageResult.docs[0].id).toBe(relToPage.id) + + const customIDResult = await payload.find({ + collection: 'rels-to-pages-and-custom-text-ids', + where: { + and: [ + { + 'rel.value': { + equals: customIDText.id, + }, + }, + { + 'rel.relationTo': { + equals: 'custom-id', + }, + }, + ], + }, + }) + + expect(customIDResult.totalDocs).toBe(1) + expect(customIDResult.docs[0].id).toBe(relToCustomIdText.id) + + const customIDNumberResult = await payload.find({ + collection: 'rels-to-pages-and-custom-text-ids', + where: { + and: [ + { + 'rel.value': { + equals: customIDNumber.id, + }, + }, + { + 'rel.relationTo': { + equals: 'custom-id-number', + }, + }, + ], + }, + }) + + expect(customIDNumberResult.totalDocs).toBe(1) + expect(customIDNumberResult.docs[0].id).toBe(relToCustomIdNumber.id) + + const inResult_1 = await payload.find({ + collection: 'rels-to-pages-and-custom-text-ids', + where: { + 'rel.value': { + in: [page.id, customIDNumber.id], + }, + }, + }) + + expect(inResult_1.totalDocs).toBe(2) + expect(inResult_1.docs.some((each) => each.id === relToPage.id)).toBeTruthy() + expect(inResult_1.docs.some((each) => each.id === relToCustomIdNumber.id)).toBeTruthy() + + const inResult_2 = await payload.find({ + collection: 'rels-to-pages-and-custom-text-ids', + where: { + 'rel.value': { + in: [customIDNumber.id, customIDText.id], + }, + }, + }) + + expect(inResult_2.totalDocs).toBe(2) + expect(inResult_2.docs.some((each) => each.id === relToCustomIdText.id)).toBeTruthy() + expect(inResult_2.docs.some((each) => each.id === relToCustomIdNumber.id)).toBeTruthy() + + const inResult_3 = await payload.find({ + collection: 'rels-to-pages-and-custom-text-ids', + where: { + 'rel.value': { + in: [customIDNumber.id, customIDText.id, page.id], + }, + }, + }) + + expect(inResult_3.totalDocs).toBe(3) + expect(inResult_3.docs.some((each) => each.id === relToCustomIdText.id)).toBeTruthy() + expect(inResult_3.docs.some((each) => each.id === relToCustomIdNumber.id)).toBeTruthy() + expect(inResult_3.docs.some((each) => each.id === relToPage.id)).toBeTruthy() + }) }) }) From 61747082ef5a6b337006e6c40f60aed423ccc01a Mon Sep 17 00:00:00 2001 From: Diego Satelier Date: Tue, 25 Mar 2025 12:48:25 -0300 Subject: [PATCH 15/77] fix(plugin-seo): translation correction (#11817) Corrected the translations that were wrong. ![es-ts-before-after](https://github.com/user-attachments/assets/37932d18-9623-4a9e-9af0-b5d770268066) --- packages/plugin-seo/src/translations/es.ts | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/plugin-seo/src/translations/es.ts b/packages/plugin-seo/src/translations/es.ts index ed018b6b3f..fe0cc4c852 100644 --- a/packages/plugin-seo/src/translations/es.ts +++ b/packages/plugin-seo/src/translations/es.ts @@ -4,25 +4,25 @@ export const es: GenericTranslationsObject = { $schema: './translation-schema.json', 'plugin-seo': { almostThere: 'Ya casi está', - autoGenerate: 'Autogénerar', - bestPractices: 'mejores prácticas', - characterCount: '{{current}}/{{minLength}}-{{maxLength}} letras, ', - charactersLeftOver: '{{characters}} letras sobrantes', - charactersToGo: '{{characters}} letras sobrantes', - charactersTooMany: '{{characters}} letras demasiados', - checksPassing: '{{current}}/{{max}} las comprobaciones están pasando', + autoGenerate: 'Generar automáticamente', + bestPractices: 'Mejores prácticas', + characterCount: '{{current}}/{{minLength}}-{{maxLength}} caracteres, ', + charactersLeftOver: '{{characters}} restantes', + charactersToGo: '{{characters}} por completar', + charactersTooMany: '{{characters}} de más', + checksPassing: '{{current}}/{{max}} comprobaciones correctas', good: 'Bien', - imageAutoGenerationTip: 'La autogeneración recuperará la imagen de héroe seleccionada.', + imageAutoGenerationTip: 'La generación automática recuperará la imagen de héroe seleccionada', lengthTipDescription: - 'Esto debe estar entre {{minLength}} y {{maxLength}} caracteres. Para obtener ayuda sobre cómo escribir meta descripciones de calidad, consulte ', + 'Debe tener entre {{minLength}} y {{maxLength}} caracteres. Para obtener ayuda sobre cómo escribir meta descripciones de calidad, consulte ', lengthTipTitle: - 'Debe tener entre {{minLength}} y {{maxLength}} caracteres. Para obtener ayuda sobre cómo escribir metatítulos de calidad, consulte ', - missing: 'Falta', + 'Debe tener entre {{minLength}} y {{maxLength}} caracteres. Para obtener ayuda sobre cómo escribir meta títulos de calidad, consulte ', + missing: 'Faltante', noImage: 'Sin imagen', preview: 'Vista previa', previewDescription: - 'Las listas de resultados pueden variar segun la relevancia de buesqueda y el contenido.', + 'Las resultados exactos pueden variar en función del contenido y la relevancia de la búsqueda.', tooLong: 'Demasiado largo', tooShort: 'Demasiado corto', }, -} +} \ No newline at end of file From 7fb4b1324edfda4971ffffbad1ee15f5652fa1de Mon Sep 17 00:00:00 2001 From: Elliot DeNolf Date: Tue, 25 Mar 2025 11:54:00 -0400 Subject: [PATCH 16/77] ci: add license-check script (#11860) Add license check script to output all licenses in use. Run with `pnpm script:license-check`, output will be in `licenses.csv` at root. --- .gitignore | 2 + package.json | 1 + pnpm-lock.yaml | 325 +++++++++++++++++++- tools/releaser/src/lib/getPackageDetails.ts | 8 +- tools/scripts/package.json | 3 + tools/scripts/src/license-check.ts | 96 ++++++ 6 files changed, 421 insertions(+), 14 deletions(-) create mode 100644 tools/scripts/src/license-check.ts diff --git a/.gitignore b/.gitignore index fce7617d11..42146b6a63 100644 --- a/.gitignore +++ b/.gitignore @@ -323,3 +323,5 @@ test/databaseAdapter.js test/.localstack test/google-cloud-storage test/azurestoragedata/ + +licenses.csv diff --git a/package.json b/package.json index 3ee9f79572..def7bbf3cb 100644 --- a/package.json +++ b/package.json @@ -87,6 +87,7 @@ "runts": "cross-env NODE_OPTIONS=--no-deprecation node --no-deprecation --import @swc-node/register/esm-register", "script:build-template-with-local-pkgs": "pnpm --filter scripts build-template-with-local-pkgs", "script:gen-templates": "pnpm --filter scripts gen-templates", + "script:license-check": "pnpm --filter scripts license-check", "script:list-published": "pnpm --filter releaser list-published", "script:pack": "pnpm --filter scripts pack-all-to-dest", "pretest": "pnpm build", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 830c730465..f95f70fc37 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,7 +45,7 @@ importers: version: 1.50.0 '@sentry/nextjs': specifier: ^8.33.1 - version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15))) + version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15))) '@sentry/node': specifier: ^8.33.1 version: 8.37.1 @@ -135,7 +135,7 @@ importers: version: 10.1.3(@aws-sdk/credential-providers@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)))(socks@2.8.3) next: specifier: 15.2.3 - version: 15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + version: 15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) open: specifier: ^10.1.0 version: 10.1.0 @@ -1076,7 +1076,7 @@ importers: dependencies: next: specifier: ^15.2.3 - version: 15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + version: 15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) devDependencies: '@payloadcms/eslint-config': specifier: workspace:* @@ -1141,7 +1141,7 @@ importers: dependencies: '@sentry/nextjs': specifier: ^8.33.1 - version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15))) + version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15))) '@sentry/types': specifier: ^8.33.1 version: 8.37.1 @@ -1500,7 +1500,7 @@ importers: version: link:../plugin-cloud-storage uploadthing: specifier: 7.3.0 - version: 7.3.0(next@15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4)) + version: 7.3.0(next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4)) devDependencies: payload: specifier: workspace:* @@ -1786,7 +1786,7 @@ importers: version: link:../packages/ui '@sentry/nextjs': specifier: ^8.33.1 - version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15))) + version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15))) '@sentry/react': specifier: ^7.77.0 version: 7.119.2(react@19.0.0) @@ -1843,7 +1843,7 @@ importers: version: 8.9.5(@aws-sdk/credential-providers@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)))(socks@2.8.3) next: specifier: 15.2.3 - version: 15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + version: 15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) nodemailer: specifier: 6.9.16 version: 6.9.16 @@ -1946,6 +1946,12 @@ importers: create-payload-app: specifier: workspace:* version: link:../../packages/create-payload-app + csv-stringify: + specifier: ^6.5.2 + version: 6.5.2 + license-checker: + specifier: 25.0.1 + version: 25.0.1 open: specifier: ^10.1.0 version: 10.1.0 @@ -5568,6 +5574,9 @@ packages: '@xtuc/long@4.2.2': resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + abbrev@1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} @@ -5638,6 +5647,10 @@ packages: resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} engines: {node: '>=12'} + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -5674,6 +5687,10 @@ packages: resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} engines: {node: '>= 0.4'} + array-find-index@1.0.2: + resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==} + engines: {node: '>=0.10.0'} + array-includes@3.1.8: resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} engines: {node: '>= 0.4'} @@ -5701,6 +5718,9 @@ packages: resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==} engines: {node: '>=8'} + asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} @@ -5941,6 +5961,10 @@ packages: ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + chalk@3.0.0: resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} engines: {node: '>=8'} @@ -6057,10 +6081,16 @@ packages: collect-v8-coverage@1.0.2: resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} @@ -6254,6 +6284,10 @@ packages: supports-color: optional: true + debuglog@1.0.1: + resolution: {integrity: sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + decode-named-character-reference@1.0.2: resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==} @@ -6356,6 +6390,9 @@ packages: devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + dezalgo@1.0.4: + resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} + diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -6596,6 +6633,10 @@ packages: escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + escape-string-regexp@2.0.0: resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} engines: {node: '>=8'} @@ -7247,6 +7288,10 @@ packages: has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -7290,6 +7335,9 @@ packages: resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} engines: {node: '>=0.10.0'} + hosted-git-info@2.8.9: + resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + html-entities@2.5.2: resolution: {integrity: sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==} @@ -7902,9 +7950,12 @@ packages: libsql@0.4.7: resolution: {integrity: sha512-T9eIRCs6b0J1SHKYIvD8+KCJMcWZ900iZyxdnSCdqxN12Z1ijzT+jY5nrk72Jw4B0HGzms2NgpryArlJqvc3Lw==} - cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] + license-checker@25.0.1: + resolution: {integrity: sha512-mET5AIwl7MR2IAKYYoVBBpV0OnkKQ1xGj2IMMeEFIs42QAkEVjRtFZGWmQ28WeU7MP779iAgOaOy93Mn44mn6g==} + hasBin: true + lie@3.1.1: resolution: {integrity: sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==} @@ -8198,6 +8249,10 @@ packages: mkdirp-classic@0.5.3: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} @@ -8371,6 +8426,13 @@ packages: noms@0.0.0: resolution: {integrity: sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==} + nopt@4.0.3: + resolution: {integrity: sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==} + hasBin: true + + normalize-package-data@2.5.0: + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -8379,6 +8441,9 @@ packages: resolution: {integrity: sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==} engines: {node: '>=14.16'} + npm-normalize-package-bin@1.0.1: + resolution: {integrity: sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==} + npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} @@ -8463,6 +8528,18 @@ packages: resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} engines: {node: '>=10'} + os-homedir@1.0.2: + resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==} + engines: {node: '>=0.10.0'} + + os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + + osenv@0.1.5: + resolution: {integrity: sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==} + deprecated: This package is no longer supported. + oxc-resolver@1.12.0: resolution: {integrity: sha512-YlaCIArvWNKCWZFRrMjhh2l5jK80eXnpYP+bhRc1J/7cW3TiyEY0ngJo73o/5n8hA3+4yLdTmXLNTQ3Ncz50LQ==} @@ -8871,6 +8948,14 @@ packages: resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} engines: {node: '>=0.10.0'} + read-installed@4.0.3: + resolution: {integrity: sha512-O03wg/IYuV/VtnK2h/KXEt9VIbMUFbk3ERG0Iu4FhLZw0EP0T9znqrYDGn6ncbEsXUFaUjiVAWXHzxwt3lhRPQ==} + deprecated: This package is no longer supported. + + read-package-json@2.1.2: + resolution: {integrity: sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==} + deprecated: This package is no longer supported. Please use @npmcli/package-json instead. + readable-stream@1.0.34: resolution: {integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==} @@ -8881,6 +8966,10 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} + readdir-scoped-modules@1.1.0: + resolution: {integrity: sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==} + deprecated: This functionality has been moved to @npmcli/fs + readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -9352,6 +9441,9 @@ packages: resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==} engines: {node: '>=18'} + slide@1.1.6: + resolution: {integrity: sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==} + smart-buffer@4.2.0: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} @@ -9409,6 +9501,27 @@ packages: sparse-bitfield@3.0.3: resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==} + spdx-compare@1.0.0: + resolution: {integrity: sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==} + + spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + + spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + + spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + + spdx-license-ids@3.0.21: + resolution: {integrity: sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==} + + spdx-ranges@2.1.1: + resolution: {integrity: sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==} + + spdx-satisfies@4.0.1: + resolution: {integrity: sha512-WVzZ/cXAzoNmjCWiEluEA3BjHp5tiUmmhn9MK+X0tBbR9sOqtC6UQwmgCNrAIZvNlMuBUYAaHYfb2oqlF9SwKA==} + split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} @@ -9566,6 +9679,10 @@ packages: stylis@4.2.0: resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -9711,6 +9828,10 @@ packages: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true + treeify@1.1.0: + resolution: {integrity: sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==} + engines: {node: '>=0.6'} + truncate-utf8-bytes@1.0.2: resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} @@ -9975,6 +10096,9 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + util-extend@1.0.3: + resolution: {integrity: sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==} + uuid@10.0.0: resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} hasBin: true @@ -9995,6 +10119,9 @@ packages: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} + validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + varint@6.0.0: resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} @@ -13592,7 +13719,7 @@ snapshots: '@sentry/utils': 7.119.2 localforage: 1.10.0 - '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15)))': + '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15)))': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation-http': 0.53.0(@opentelemetry/api@1.9.0) @@ -13608,7 +13735,7 @@ snapshots: '@sentry/vercel-edge': 8.37.1 '@sentry/webpack-plugin': 2.22.6(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15))) chalk: 3.0.0 - next: 15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + next: 15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) resolve: 1.22.8 rollup: 3.29.5 stacktrace-parser: 0.1.10 @@ -14947,6 +15074,8 @@ snapshots: '@xtuc/long@4.2.2': {} + abbrev@1.1.1: {} + abort-controller@3.0.0: dependencies: event-target-shim: 5.0.1 @@ -15024,6 +15153,10 @@ snapshots: ansi-regex@6.1.0: {} + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 @@ -15054,6 +15187,8 @@ snapshots: call-bind: 1.0.7 is-array-buffer: 3.0.4 + array-find-index@1.0.2: {} + array-includes@3.1.8: dependencies: call-bind: 1.0.7 @@ -15094,6 +15229,8 @@ snapshots: arrify@2.0.1: {} + asap@2.0.6: {} + ast-types-flow@0.0.8: {} async-mutex@0.5.0: @@ -15380,6 +15517,12 @@ snapshots: ccount@2.0.1: {} + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + chalk@3.0.0: dependencies: ansi-styles: 4.3.0 @@ -15494,10 +15637,16 @@ snapshots: collect-v8-coverage@1.0.2: {} + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + color-convert@2.0.1: dependencies: color-name: 1.1.4 + color-name@1.1.3: {} + color-name@1.1.4: {} color-string@1.9.1: @@ -15683,6 +15832,8 @@ snapshots: dependencies: ms: 2.1.3 + debuglog@1.0.1: {} + decode-named-character-reference@1.0.2: dependencies: character-entities: 2.0.2 @@ -15765,6 +15916,11 @@ snapshots: dependencies: dequal: 2.0.3 + dezalgo@1.0.4: + dependencies: + asap: 2.0.6 + wrappy: 1.0.2 + diff-sequences@29.6.3: {} diff@5.2.0: {} @@ -16065,6 +16221,8 @@ snapshots: escape-html@1.0.3: {} + escape-string-regexp@1.0.5: {} + escape-string-regexp@2.0.0: {} escape-string-regexp@4.0.0: {} @@ -16888,6 +17046,8 @@ snapshots: has-bigints@1.0.2: {} + has-flag@3.0.0: {} + has-flag@4.0.0: {} has-own-prop@2.0.0: {} @@ -16924,6 +17084,8 @@ snapshots: dependencies: parse-passwd: 1.0.0 + hosted-git-info@2.8.9: {} + html-entities@2.5.2: {} html-escaper@2.0.2: {} @@ -17686,6 +17848,21 @@ snapshots: '@libsql/linux-x64-musl': 0.4.7 '@libsql/win32-x64-msvc': 0.4.7 + license-checker@25.0.1: + dependencies: + chalk: 2.4.2 + debug: 3.2.7 + mkdirp: 0.5.6 + nopt: 4.0.3 + read-installed: 4.0.3 + semver: 5.7.2 + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + spdx-satisfies: 4.0.1 + treeify: 1.1.0 + transitivePeerDependencies: + - supports-color + lie@3.1.1: dependencies: immediate: 3.0.6 @@ -18102,6 +18279,10 @@ snapshots: mkdirp-classic@0.5.3: {} + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + mkdirp@1.0.4: {} mkdirp@3.0.1: {} @@ -18251,6 +18432,35 @@ snapshots: - '@babel/core' - babel-plugin-macros + next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4): + dependencies: + '@next/env': 15.2.3 + '@swc/counter': 0.1.3 + '@swc/helpers': 0.5.15 + busboy: 1.6.0 + caniuse-lite: 1.0.30001678 + postcss: 8.4.31 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + styled-jsx: 5.1.6(@babel/core@7.26.7)(babel-plugin-macros@3.1.0)(react@19.0.0) + optionalDependencies: + '@next/swc-darwin-arm64': 15.2.3 + '@next/swc-darwin-x64': 15.2.3 + '@next/swc-linux-arm64-gnu': 15.2.3 + '@next/swc-linux-arm64-musl': 15.2.3 + '@next/swc-linux-x64-gnu': 15.2.3 + '@next/swc-linux-x64-musl': 15.2.3 + '@next/swc-win32-arm64-msvc': 15.2.3 + '@next/swc-win32-x64-msvc': 15.2.3 + '@opentelemetry/api': 1.9.0 + '@playwright/test': 1.50.0 + babel-plugin-react-compiler: 19.0.0-beta-714736e-20250131 + sass: 1.77.4 + sharp: 0.33.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + node-abi@3.71.0: dependencies: semver: 7.6.3 @@ -18284,10 +18494,24 @@ snapshots: inherits: 2.0.4 readable-stream: 1.0.34 + nopt@4.0.3: + dependencies: + abbrev: 1.1.1 + osenv: 0.1.5 + + normalize-package-data@2.5.0: + dependencies: + hosted-git-info: 2.8.9 + resolve: 1.22.8 + semver: 5.7.2 + validate-npm-package-license: 3.0.4 + normalize-path@3.0.0: {} normalize-url@8.0.1: {} + npm-normalize-package-bin@1.0.1: {} + npm-run-path@4.0.1: dependencies: path-key: 3.1.1 @@ -18391,6 +18615,15 @@ snapshots: strip-ansi: 6.0.1 wcwidth: 1.0.1 + os-homedir@1.0.2: {} + + os-tmpdir@1.0.2: {} + + osenv@0.1.5: + dependencies: + os-homedir: 1.0.2 + os-tmpdir: 1.0.2 + oxc-resolver@1.12.0: optionalDependencies: '@oxc-resolver/binding-darwin-arm64': 1.12.0 @@ -18817,6 +19050,24 @@ snapshots: react@19.0.0: {} + read-installed@4.0.3: + dependencies: + debuglog: 1.0.1 + read-package-json: 2.1.2 + readdir-scoped-modules: 1.1.0 + semver: 5.7.2 + slide: 1.1.6 + util-extend: 1.0.3 + optionalDependencies: + graceful-fs: 4.2.11 + + read-package-json@2.1.2: + dependencies: + glob: 7.2.3 + json-parse-even-better-errors: 2.3.1 + normalize-package-data: 2.5.0 + npm-normalize-package-bin: 1.0.1 + readable-stream@1.0.34: dependencies: core-util-is: 1.0.3 @@ -18840,6 +19091,13 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 + readdir-scoped-modules@1.1.0: + dependencies: + debuglog: 1.0.1 + dezalgo: 1.0.4 + graceful-fs: 4.2.11 + once: 1.4.0 + readdirp@3.6.0: dependencies: picomatch: 2.3.1 @@ -19310,6 +19568,8 @@ snapshots: ansi-styles: 6.2.1 is-fullwidth-code-point: 5.0.0 + slide@1.1.6: {} + smart-buffer@4.2.0: optional: true @@ -19371,6 +19631,34 @@ snapshots: dependencies: memory-pager: 1.5.0 + spdx-compare@1.0.0: + dependencies: + array-find-index: 1.0.2 + spdx-expression-parse: 3.0.1 + spdx-ranges: 2.1.1 + + spdx-correct@3.2.0: + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.21 + + spdx-exceptions@2.5.0: {} + + spdx-expression-parse@3.0.1: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.21 + + spdx-license-ids@3.0.21: {} + + spdx-ranges@2.1.1: {} + + spdx-satisfies@4.0.1: + dependencies: + spdx-compare: 1.0.0 + spdx-expression-parse: 3.0.1 + spdx-ranges: 2.1.1 + split2@4.2.0: {} sprintf-js@1.0.3: {} @@ -19529,6 +19817,10 @@ snapshots: stylis@4.2.0: {} + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -19700,6 +19992,8 @@ snapshots: tree-kill@1.2.2: {} + treeify@1.1.0: {} + truncate-utf8-bytes@1.0.2: dependencies: utf8-byte-length: 1.0.5 @@ -19909,14 +20203,14 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - uploadthing@7.3.0(next@15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4)): + uploadthing@7.3.0(next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4)): dependencies: '@effect/platform': 0.69.8(effect@3.10.3) '@uploadthing/mime-types': 0.3.2 '@uploadthing/shared': 7.1.1 effect: 3.10.3 optionalDependencies: - next: 15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + next: 15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) uri-js@4.4.1: dependencies: @@ -19941,6 +20235,8 @@ snapshots: util-deprecate@1.0.2: {} + util-extend@1.0.3: {} + uuid@10.0.0: {} uuid@8.3.2: {} @@ -19955,6 +20251,11 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 + validate-npm-package-license@3.0.4: + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + varint@6.0.0: {} vfile-message@4.0.2: diff --git a/tools/releaser/src/lib/getPackageDetails.ts b/tools/releaser/src/lib/getPackageDetails.ts index 244e1886f7..3599d5dea6 100644 --- a/tools/releaser/src/lib/getPackageDetails.ts +++ b/tools/releaser/src/lib/getPackageDetails.ts @@ -8,7 +8,11 @@ export type PackageDetails = { name: string /** Full path to package relative to project root */ packagePath: `packages/${string}` - /** Short name is the directory name */ + /** + * Short name is the directory name of the package + * + * @example payload, db-mongodb, ui, etc + * */ shortName: string /** Version in package.json */ version: string @@ -42,7 +46,7 @@ export const getPackageDetails = async (packages?: null | string[]): Promise { + console.error(error) + process.exit(1) +}) + +async function main() { + const packageDetails = await getPackageDetails() + const packages = packageDetails.map((p) => p.shortName) + + header(`\n🔨 Getting all package.json licenses...`) + const results: { component: string; package: string; license: string; repository: string }[] = [] + + for (const pack of packages) { + info(`Checking ${pack}...`) + const prodResults = await runLicenseCheck(pack, 'production') + const devResults = await runLicenseCheck(pack, 'development') + results.push(...prodResults, ...devResults) + } + + const outputPath = path.join(PROJECT_ROOT, 'licenses.csv') + + header(`\n💾 Writing to ${outputPath}...`) + const csvString = stringify(results, { header: true }) + const buffer = Buffer.from(csvString) + await fs.writeFile(outputPath, buffer) + + header(`🎉 Done!`) +} + +function header(message: string) { + console.log(chalk.bold.green(`${message}\n`)) +} + +function info(message: string) { + console.log(chalk.dim(message)) +} + +async function runLicenseCheck( + pkg: string, + type: 'development' | 'production', +): Promise<{ component: string; package: string; license: string; repository: string }[]> { + const result = await exec( + `node ${path.resolve(dirname, '../node_modules/license-checker/bin/license-checker')} --summary --direct --start --json`, + { + ...execOpts, + cwd: path.join(PROJECT_ROOT, 'packages', pkg), + }, + ) + const a: Record = JSON.parse(result.stdout) + const results: { + component: string + package: string + license: string + repository: string + distributed: 'No' | 'Yes' + }[] = [] + Object.entries(a).forEach(([key, value]) => { + if (key.startsWith('@payloadcms/')) { + return + } + results.push({ + component: pkg, + package: key, + license: value.licenses, + repository: value.repository, + distributed: type === 'production' ? 'Yes' : 'No', + }) + }) + + return results +} From 73fc3c607a2c91bf43cb194156379c3991ee47ae Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Tue, 25 Mar 2025 10:11:20 -0600 Subject: [PATCH 17/77] perf(drizzle): remove unnecessary db.select call in updateOne operation (#11847) This will improve performance when updating a single document in postgres/drizzle, if the ID is known. Previously, this resulted in 2 sequential operations: - `db.select `to fetch the document by the ID - `upsertRow` to update the document (multiple db operations) This PR removes the unnecessary `db.select` call, as the document ID is already known --- packages/drizzle/src/updateOne.ts | 67 ++++++++++++++++--------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/packages/drizzle/src/updateOne.ts b/packages/drizzle/src/updateOne.ts index 4ebb3abafc..9119e7f8c3 100644 --- a/packages/drizzle/src/updateOne.ts +++ b/packages/drizzle/src/updateOne.ts @@ -19,50 +19,51 @@ export const updateOne: UpdateOne = async function updateOne( joins: joinQuery, locale, req, + returning, select, where: whereArg, - returning, }, ) { const db = await getTransaction(this, req) const collection = this.payload.collections[collectionSlug].config const tableName = this.tableNameMap.get(toSnakeCase(collection.slug)) - const whereToUse = whereArg || { id: { equals: id } } let idToUpdate = id - const { joins, selectFields, where } = buildQuery({ - adapter: this, - fields: collection.flattenedFields, - locale, - tableName, - where: whereToUse, - }) + if (!idToUpdate) { + const { joins, selectFields, where } = buildQuery({ + adapter: this, + fields: collection.flattenedFields, + locale, + tableName, + where: whereArg, + }) - // selectDistinct will only return if there are joins - const selectDistinctResult = await selectDistinct({ - adapter: this, - chainedMethods: [{ args: [1], method: 'limit' }], - db, - joins, - selectFields, - tableName, - where, - }) + // selectDistinct will only return if there are joins + const selectDistinctResult = await selectDistinct({ + adapter: this, + chainedMethods: [{ args: [1], method: 'limit' }], + db, + joins, + selectFields, + tableName, + where, + }) - if (selectDistinctResult?.[0]?.id) { - idToUpdate = selectDistinctResult?.[0]?.id - // If id wasn't passed but `where` without any joins, retrieve it with findFirst - } else if (whereArg && !joins.length) { - const table = this.tables[tableName] + if (selectDistinctResult?.[0]?.id) { + idToUpdate = selectDistinctResult?.[0]?.id + // If id wasn't passed but `where` without any joins, retrieve it with findFirst + } else if (whereArg && !joins.length) { + const table = this.tables[tableName] - const docsToUpdate = await (db as LibSQLDatabase) - .select({ - id: table.id, - }) - .from(table) - .where(where) - .limit(1) - idToUpdate = docsToUpdate?.[0]?.id + const docsToUpdate = await (db as LibSQLDatabase) + .select({ + id: table.id, + }) + .from(table) + .where(where) + .limit(1) + idToUpdate = docsToUpdate?.[0]?.id + } } const result = await upsertRow({ @@ -71,12 +72,12 @@ export const updateOne: UpdateOne = async function updateOne( data, db, fields: collection.flattenedFields, + ignoreResult: returning === false, joinQuery, operation: 'update', req, select, tableName, - ignoreResult: returning === false, }) if (returning === false) { From 74f935bfb9a17a1daf75fbc33e10160c2a8f18c1 Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Tue, 25 Mar 2025 12:19:29 -0400 Subject: [PATCH 18/77] fix: auth fields distrupt field paths within the field schema map (#11861) Within auth-enabled collections, we inject the `password` and `confirmPassword` fields into the field schema map. While this is fine within the edit view where these fields are used, this breaks field paths within the version diff view where unnamed fields are no longer able to lookup their corresponding config. This is because the presence of these injected fields increments the field indices by two. A temporary fix for this is to simply inject these fields _last_ into the schema map. This way their presence does not disrupt field path generation. A long term fix should be implemented, however, where these fields actually exist on the collection config itself. This way no config mutation would be required as the sanitized config would the single source of truth. To do this, we'd need to ensure that these fields do not appear in any APIs, and that they do not generate types, etc. --- .../views/Version/RenderFieldsToDiff/buildVersionFields.tsx | 2 ++ packages/next/src/views/Version/index.tsx | 5 +++-- packages/ui/src/utilities/buildClientFieldSchemaMap/index.ts | 3 ++- packages/ui/src/utilities/buildFieldSchemaMap/index.ts | 3 ++- tsconfig.base.json | 2 +- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/next/src/views/Version/RenderFieldsToDiff/buildVersionFields.tsx b/packages/next/src/views/Version/RenderFieldsToDiff/buildVersionFields.tsx index 9d448bf261..5e14d48485 100644 --- a/packages/next/src/views/Version/RenderFieldsToDiff/buildVersionFields.tsx +++ b/packages/next/src/views/Version/RenderFieldsToDiff/buildVersionFields.tsx @@ -75,8 +75,10 @@ export const buildVersionFields = ({ } => { const versionFields: VersionField[] = [] let fieldIndex = -1 + for (const field of fields) { fieldIndex++ + if (fieldIsID(field)) { continue } diff --git a/packages/next/src/views/Version/index.tsx b/packages/next/src/views/Version/index.tsx index e2563f658f..30a53a84d7 100644 --- a/packages/next/src/views/Version/index.tsx +++ b/packages/next/src/views/Version/index.tsx @@ -37,6 +37,7 @@ export async function VersionView(props: DocumentViewServerProps) { const localeCodesFromParams = searchParams.localeCodes ? JSON.parse(searchParams.localeCodes as string) : null + const comparisonVersionIDFromParams: string = searchParams.compareValue as string const modifiedOnly: boolean = searchParams.modifiedOnly === 'true' @@ -88,7 +89,7 @@ export async function VersionView(props: DocumentViewServerProps) { status: 'published', }) } - } catch (error) { + } catch (_err) { return notFound() } } @@ -129,7 +130,7 @@ export async function VersionView(props: DocumentViewServerProps) { status: 'published', }) } - } catch (error) { + } catch (_err) { return notFound() } } diff --git a/packages/ui/src/utilities/buildClientFieldSchemaMap/index.ts b/packages/ui/src/utilities/buildClientFieldSchemaMap/index.ts index 31762d1784..68dce36128 100644 --- a/packages/ui/src/utilities/buildClientFieldSchemaMap/index.ts +++ b/packages/ui/src/utilities/buildClientFieldSchemaMap/index.ts @@ -49,7 +49,8 @@ export const buildClientFieldSchemaMap = (args: { if (matchedCollection.auth && !matchedCollection.auth.disableLocalStrategy) { ;(baseAuthFields[0] as TextFieldClient).label = i18n.t('general:password') ;(baseAuthFields[1] as TextFieldClient).label = i18n.t('authentication:confirmPassword') - fieldsToSet = baseAuthFields.concat(fieldsToSet) + // Place these fields _last_ to ensure they do not disrupt field paths in the field schema map + fieldsToSet = fieldsToSet.concat(baseAuthFields) } clientSchemaMap.set(collectionSlug, { diff --git a/packages/ui/src/utilities/buildFieldSchemaMap/index.ts b/packages/ui/src/utilities/buildFieldSchemaMap/index.ts index 342ea59274..404460ad7d 100644 --- a/packages/ui/src/utilities/buildFieldSchemaMap/index.ts +++ b/packages/ui/src/utilities/buildFieldSchemaMap/index.ts @@ -44,7 +44,8 @@ export const buildFieldSchemaMap = (args: { if (matchedCollection.auth && !matchedCollection.auth.disableLocalStrategy) { ;(baseAuthFields[0] as TextField).label = i18n.t('general:password') ;(baseAuthFields[1] as TextField).label = i18n.t('authentication:confirmPassword') - fieldsToSet = baseAuthFields.concat(fieldsToSet) + // Place these fields _last_ to ensure they do not disrupt field paths in the field schema map + fieldsToSet = fieldsToSet.concat(baseAuthFields) } schemaMap.set(collectionSlug, { diff --git a/tsconfig.base.json b/tsconfig.base.json index daa36c7211..c9793d25c6 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -31,7 +31,7 @@ } ], "paths": { - "@payload-config": ["./test/query-presets/config.ts"], + "@payload-config": ["./test/_community/config.ts"], "@payloadcms/admin-bar": ["./packages/admin-bar/src"], "@payloadcms/live-preview": ["./packages/live-preview/src"], "@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"], From a5c3aa0e4f1282071ae455b33d2d55ad9aba47da Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Tue, 25 Mar 2025 12:09:52 -0600 Subject: [PATCH 19/77] perf: reduce job queue db calls (#11846) Continuation of #11489. This adds a new, optional `updateJobs` db adapter method that reduces the amount of database calls for the jobs queue. ## MongoDB ### Previous: running a set of 50 queued jobs - 1x db.find (= 1x `Model.paginate`) - 50x db.updateOne (= 50x `Model.findOneAndUpdate`) ### Now: running a set of 50 queued jobs - 1x db.updateJobs (= 1x `Model.find` and 1x `Model.updateMany`) **=> 51 db round trips before, 2 db round trips after** ### Previous: upon task completion - 1x db.find (= 1x `Model.paginate`) - 1x db.updateOne (= 1x `Model.findOneAndUpdate`) ### Now: upon task completion - 1x db.updateJobs (= 1x `Model.findOneAndUpdate`) **=> 2 db round trips before, 1 db round trip after** ## Drizzle (e.g. Postgres) ### running a set of 50 queued jobs - 1x db.query[tablename].findMany - 50x db.select - 50x upsertRow This is unaffected by this PR and will be addressed in a future PR --- packages/db-mongodb/src/index.ts | 3 +- packages/db-mongodb/src/updateJobs.ts | 83 +++++++++++++++++++ packages/db-postgres/src/index.ts | 2 + packages/db-sqlite/src/index.ts | 2 + packages/db-vercel-postgres/src/index.ts | 2 + packages/drizzle/src/index.ts | 1 + packages/drizzle/src/updateJobs.ts | 66 +++++++++++++++ .../src/database/createDatabaseAdapter.ts | 3 + .../payload/src/database/defaultUpdateJobs.ts | 53 ++++++++++++ packages/payload/src/database/types.ts | 30 ++++++- packages/payload/src/index.ts | 2 + .../payload/src/queues/utilities/updateJob.ts | 79 ++++++++---------- 12 files changed, 279 insertions(+), 47 deletions(-) create mode 100644 packages/db-mongodb/src/updateJobs.ts create mode 100644 packages/drizzle/src/updateJobs.ts create mode 100644 packages/payload/src/database/defaultUpdateJobs.ts diff --git a/packages/db-mongodb/src/index.ts b/packages/db-mongodb/src/index.ts index b828e7dac0..d69359b73f 100644 --- a/packages/db-mongodb/src/index.ts +++ b/packages/db-mongodb/src/index.ts @@ -17,7 +17,6 @@ import type { TypeWithVersion, UpdateGlobalArgs, UpdateGlobalVersionArgs, - UpdateManyArgs, UpdateOneArgs, UpdateVersionArgs, } from 'payload' @@ -55,6 +54,7 @@ import { commitTransaction } from './transactions/commitTransaction.js' import { rollbackTransaction } from './transactions/rollbackTransaction.js' import { updateGlobal } from './updateGlobal.js' import { updateGlobalVersion } from './updateGlobalVersion.js' +import { updateJobs } from './updateJobs.js' import { updateMany } from './updateMany.js' import { updateOne } from './updateOne.js' import { updateVersion } from './updateVersion.js' @@ -227,6 +227,7 @@ export function mongooseAdapter({ mongoMemoryServer, sessions: {}, transactionOptions: transactionOptions === false ? undefined : transactionOptions, + updateJobs, updateMany, url, versions: {}, diff --git a/packages/db-mongodb/src/updateJobs.ts b/packages/db-mongodb/src/updateJobs.ts new file mode 100644 index 0000000000..51dd7c0277 --- /dev/null +++ b/packages/db-mongodb/src/updateJobs.ts @@ -0,0 +1,83 @@ +import type { MongooseUpdateQueryOptions } from 'mongoose' +import type { BaseJob, UpdateJobs, Where } from 'payload' + +import type { MongooseAdapter } from './index.js' + +import { buildQuery } from './queries/buildQuery.js' +import { getCollection } from './utilities/getEntity.js' +import { getSession } from './utilities/getSession.js' +import { handleError } from './utilities/handleError.js' +import { transform } from './utilities/transform.js' + +export const updateJobs: UpdateJobs = async function updateMany( + this: MongooseAdapter, + { id, data, limit, req, returning, where: whereArg }, +) { + const where = id ? { id: { equals: id } } : (whereArg as Where) + + const { collectionConfig, Model } = getCollection({ + adapter: this, + collectionSlug: 'payload-jobs', + }) + + const options: MongooseUpdateQueryOptions = { + lean: true, + new: true, + session: await getSession(this, req), + } + + let query = await buildQuery({ + adapter: this, + collectionSlug: collectionConfig.slug, + fields: collectionConfig.flattenedFields, + where, + }) + + transform({ adapter: this, data, fields: collectionConfig.fields, operation: 'write' }) + + let result: BaseJob[] = [] + + try { + if (id) { + if (returning === false) { + await Model.updateOne(query, data, options) + return null + } else { + const doc = await Model.findOneAndUpdate(query, data, options) + result = doc ? [doc] : [] + } + } else { + if (typeof limit === 'number' && limit > 0) { + const documentsToUpdate = await Model.find( + query, + {}, + { ...options, limit, projection: { _id: 1 } }, + ) + if (documentsToUpdate.length === 0) { + return null + } + + query = { _id: { $in: documentsToUpdate.map((doc) => doc._id) } } + } + + await Model.updateMany(query, data, options) + + if (returning === false) { + return null + } + + result = await Model.find(query, {}, options) + } + } catch (error) { + handleError({ collection: collectionConfig.slug, error, req }) + } + + transform({ + adapter: this, + data: result, + fields: collectionConfig.fields, + operation: 'read', + }) + + return result +} diff --git a/packages/db-postgres/src/index.ts b/packages/db-postgres/src/index.ts index 26ec09a11b..4df6026215 100644 --- a/packages/db-postgres/src/index.ts +++ b/packages/db-postgres/src/index.ts @@ -33,6 +33,7 @@ import { rollbackTransaction, updateGlobal, updateGlobalVersion, + updateJobs, updateMany, updateOne, updateVersion, @@ -172,6 +173,7 @@ export function postgresAdapter(args: Args): DatabaseAdapterObj find, findGlobal, findGlobalVersions, + updateJobs, // @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve findOne, findVersions, diff --git a/packages/db-sqlite/src/index.ts b/packages/db-sqlite/src/index.ts index f4ab2d6330..86b15302d6 100644 --- a/packages/db-sqlite/src/index.ts +++ b/packages/db-sqlite/src/index.ts @@ -34,6 +34,7 @@ import { rollbackTransaction, updateGlobal, updateGlobalVersion, + updateJobs, updateMany, updateOne, updateVersion, @@ -127,6 +128,7 @@ export function sqliteAdapter(args: Args): DatabaseAdapterObj { tables: {}, // @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve transactionOptions: args.transactionOptions || undefined, + updateJobs, updateMany, versionsSuffix: args.versionsSuffix || '_v', diff --git a/packages/db-vercel-postgres/src/index.ts b/packages/db-vercel-postgres/src/index.ts index a96892560a..410c7ca9a5 100644 --- a/packages/db-vercel-postgres/src/index.ts +++ b/packages/db-vercel-postgres/src/index.ts @@ -34,6 +34,7 @@ import { rollbackTransaction, updateGlobal, updateGlobalVersion, + updateJobs, updateMany, updateOne, updateVersion, @@ -138,6 +139,7 @@ export function vercelPostgresAdapter(args: Args = {}): DatabaseAdapterObj( | 'migrateReset' | 'migrateStatus' | 'migrationDir' + | 'updateJobs' >, ): T { return { @@ -45,6 +47,7 @@ export function createDatabaseAdapter( migrateReset, migrateStatus, rollbackTransaction, + updateJobs: defaultUpdateJobs, ...args, // Ensure migrationDir is set diff --git a/packages/payload/src/database/defaultUpdateJobs.ts b/packages/payload/src/database/defaultUpdateJobs.ts new file mode 100644 index 0000000000..cc66f6a2fc --- /dev/null +++ b/packages/payload/src/database/defaultUpdateJobs.ts @@ -0,0 +1,53 @@ +import type { BaseJob, DatabaseAdapter } from '../index.js' +import type { UpdateJobs } from './types.js' + +import { jobsCollectionSlug } from '../queues/config/index.js' +import { sanitizeUpdateData } from '../queues/utilities/sanitizeUpdateData.js' + +export const defaultUpdateJobs: UpdateJobs = async function updateMany( + this: DatabaseAdapter, + { id, data, limit, req, returning, where }, +) { + const updatedJobs: BaseJob[] | null = [] + + const jobsToUpdate: BaseJob[] = ( + id + ? [ + await this.findOne({ + collection: jobsCollectionSlug, + req, + where: { id: { equals: id } }, + }), + ] + : ( + await this.find({ + collection: jobsCollectionSlug, + limit, + pagination: false, + req, + where, + }) + ).docs + ).filter(Boolean) as BaseJob[] + + if (!jobsToUpdate) { + return null + } + + for (const job of jobsToUpdate) { + const updateData = { + ...job, + ...data, + } + const updatedJob = await this.updateOne({ + id: job.id, + collection: jobsCollectionSlug, + data: sanitizeUpdateData({ data: updateData }), + req, + returning, + }) + updatedJobs.push(updatedJob) + } + + return updatedJobs +} diff --git a/packages/payload/src/database/types.ts b/packages/payload/src/database/types.ts index d978e9d1f2..55c907b94e 100644 --- a/packages/payload/src/database/types.ts +++ b/packages/payload/src/database/types.ts @@ -1,5 +1,5 @@ import type { TypeWithID } from '../collections/config/types.js' -import type { CollectionSlug, GlobalSlug } from '../index.js' +import type { BaseJob, CollectionSlug, GlobalSlug } from '../index.js' import type { Document, JoinQuery, @@ -147,6 +147,8 @@ export interface BaseDatabaseAdapter { updateGlobalVersion: UpdateGlobalVersion + updateJobs: UpdateJobs + updateMany: UpdateMany updateOne: UpdateOne @@ -540,6 +542,32 @@ export type UpdateManyArgs = { export type UpdateMany = (args: UpdateManyArgs) => Promise +export type UpdateJobsArgs = { + data: Record + req?: Partial + /** + * If true, returns the updated documents + * + * @default true + */ + returning?: boolean +} & ( + | { + id: number | string + limit?: never + sort?: never + where?: never + } + | { + id?: never + limit?: number + sort?: Sort + where: Where + } +) + +export type UpdateJobs = (args: UpdateJobsArgs) => Promise + export type UpsertArgs = { collection: CollectionSlug data: Record diff --git a/packages/payload/src/index.ts b/packages/payload/src/index.ts index 61c24caa9e..ad401c8cbb 100644 --- a/packages/payload/src/index.ts +++ b/packages/payload/src/index.ts @@ -1160,6 +1160,8 @@ export type { UpdateGlobalArgs, UpdateGlobalVersion, UpdateGlobalVersionArgs, + UpdateJobs, + UpdateJobsArgs, UpdateMany, UpdateManyArgs, UpdateOne, diff --git a/packages/payload/src/queues/utilities/updateJob.ts b/packages/payload/src/queues/utilities/updateJob.ts index 90867620c6..113f4d8a34 100644 --- a/packages/payload/src/queues/utilities/updateJob.ts +++ b/packages/payload/src/queues/utilities/updateJob.ts @@ -1,5 +1,6 @@ import type { ManyOptions } from '../../collections/operations/local/update.js' -import type { PayloadRequest, Where } from '../../types/index.js' +import type { UpdateJobsArgs } from '../../database/types.js' +import type { PayloadRequest, Sort, Where } from '../../types/index.js' import type { BaseJob } from '../config/types/workflowTypes.js' import { jobAfterRead, jobsCollectionSlug } from '../config/index.js' @@ -17,32 +18,29 @@ type BaseArgs = { type ArgsByID = { id: number | string limit?: never + sort?: never where?: never } +type ArgsWhere = { + id?: never + limit?: number + sort?: Sort + where: Where +} + +type RunJobsArgs = (ArgsByID | ArgsWhere) & BaseArgs + /** * Convenience method for updateJobs by id */ export async function updateJob(args: ArgsByID & BaseArgs) { - const result = await updateJobs({ - ...args, - id: undefined, - limit: 1, - where: { id: { equals: args.id } }, - }) + const result = await updateJobs(args) if (result) { return result[0] } } -type ArgsWhere = { - id?: never | undefined - limit?: number - where: Where -} - -type RunJobsArgs = (ArgsByID | ArgsWhere) & BaseArgs - export async function updateJobs({ id, data, @@ -51,9 +49,12 @@ export async function updateJobs({ limit: limitArg, req, returning, - where, + sort, + where: whereArg, }: RunJobsArgs): Promise { const limit = id ? 1 : limitArg + const where = id ? { id: { equals: id } } : whereArg + if (depth || req.payload.config?.jobs?.runHooks) { const result = await req.payload.update({ id, @@ -71,36 +72,24 @@ export async function updateJobs({ return result.docs as BaseJob[] } - const updatedJobs = [] + const args: UpdateJobsArgs = id + ? { + id, + data: sanitizeUpdateData({ data }), + req: disableTransaction === true ? undefined : req, + returning, + } + : { + data: sanitizeUpdateData({ data }), + limit, + req: disableTransaction === true ? undefined : req, + returning, + sort, + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + where: where as Where, + } - // TODO: this can be optimized in the future - partial updates are supported in mongodb. In postgres, - // we can support this by manually constructing the sql query. We should use req.payload.db.updateMany instead - // of req.payload.db.updateOne once this is supported - const jobsToUpdate = await req.payload.db.find({ - collection: jobsCollectionSlug, - limit, - pagination: false, - req: disableTransaction === true ? undefined : req, - where, - }) - if (!jobsToUpdate?.docs) { - return null - } - - for (const job of jobsToUpdate.docs) { - const updateData = { - ...job, - ...data, - } - const updatedJob = await req.payload.db.updateOne({ - id: job.id, - collection: jobsCollectionSlug, - data: sanitizeUpdateData({ data: updateData }), - req: disableTransaction === true ? undefined : req, - returning, - }) - updatedJobs.push(updatedJob) - } + const updatedJobs: BaseJob[] | null = await req.payload.db.updateJobs(args) if (returning === false || !updatedJobs?.length) { return null From 35e6cfbdfc24aedcfc2e53692226d91843cac91b Mon Sep 17 00:00:00 2001 From: Elliot DeNolf Date: Tue, 25 Mar 2025 14:28:01 -0400 Subject: [PATCH 20/77] chore(release): v3.31.0 [skip ci] --- package.json | 2 +- packages/admin-bar/package.json | 2 +- packages/create-payload-app/package.json | 2 +- packages/db-mongodb/package.json | 2 +- packages/db-postgres/package.json | 2 +- packages/db-sqlite/package.json | 2 +- packages/db-vercel-postgres/package.json | 2 +- packages/drizzle/package.json | 2 +- packages/email-nodemailer/package.json | 2 +- packages/email-resend/package.json | 2 +- packages/graphql/package.json | 2 +- packages/live-preview-react/package.json | 2 +- packages/live-preview-vue/package.json | 2 +- packages/live-preview/package.json | 2 +- packages/next/package.json | 2 +- packages/payload-cloud/package.json | 2 +- packages/payload/package.json | 2 +- packages/plugin-cloud-storage/package.json | 2 +- packages/plugin-form-builder/package.json | 2 +- packages/plugin-import-export/package.json | 2 +- packages/plugin-multi-tenant/package.json | 2 +- packages/plugin-nested-docs/package.json | 2 +- packages/plugin-redirects/package.json | 2 +- packages/plugin-search/package.json | 2 +- packages/plugin-sentry/package.json | 2 +- packages/plugin-seo/package.json | 2 +- packages/plugin-stripe/package.json | 2 +- packages/richtext-lexical/package.json | 2 +- packages/richtext-slate/package.json | 2 +- packages/storage-azure/package.json | 2 +- packages/storage-gcs/package.json | 2 +- packages/storage-s3/package.json | 2 +- packages/storage-uploadthing/package.json | 2 +- packages/storage-vercel-blob/package.json | 2 +- packages/translations/package.json | 2 +- packages/ui/package.json | 2 +- 36 files changed, 36 insertions(+), 36 deletions(-) diff --git a/package.json b/package.json index def7bbf3cb..934cf39f07 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "payload-monorepo", - "version": "3.30.0", + "version": "3.31.0", "private": true, "type": "module", "scripts": { diff --git a/packages/admin-bar/package.json b/packages/admin-bar/package.json index 269216696f..8597542928 100644 --- a/packages/admin-bar/package.json +++ b/packages/admin-bar/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/admin-bar", - "version": "3.30.0", + "version": "3.31.0", "description": "An admin bar for React apps using Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/create-payload-app/package.json b/packages/create-payload-app/package.json index bdf535b0f1..12257895d0 100644 --- a/packages/create-payload-app/package.json +++ b/packages/create-payload-app/package.json @@ -1,6 +1,6 @@ { "name": "create-payload-app", - "version": "3.30.0", + "version": "3.31.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/db-mongodb/package.json b/packages/db-mongodb/package.json index 7e14dbc80d..a0da521a0f 100644 --- a/packages/db-mongodb/package.json +++ b/packages/db-mongodb/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-mongodb", - "version": "3.30.0", + "version": "3.31.0", "description": "The officially supported MongoDB database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-postgres/package.json b/packages/db-postgres/package.json index f5c3c9f3fa..4099ac633a 100644 --- a/packages/db-postgres/package.json +++ b/packages/db-postgres/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-postgres", - "version": "3.30.0", + "version": "3.31.0", "description": "The officially supported Postgres database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-sqlite/package.json b/packages/db-sqlite/package.json index d7c0b0c003..717e5df070 100644 --- a/packages/db-sqlite/package.json +++ b/packages/db-sqlite/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-sqlite", - "version": "3.30.0", + "version": "3.31.0", "description": "The officially supported SQLite database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-vercel-postgres/package.json b/packages/db-vercel-postgres/package.json index 5d0274ecc0..0a4f42d701 100644 --- a/packages/db-vercel-postgres/package.json +++ b/packages/db-vercel-postgres/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-vercel-postgres", - "version": "3.30.0", + "version": "3.31.0", "description": "Vercel Postgres adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/drizzle/package.json b/packages/drizzle/package.json index 4ef539d60d..8e4d725b8f 100644 --- a/packages/drizzle/package.json +++ b/packages/drizzle/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/drizzle", - "version": "3.30.0", + "version": "3.31.0", "description": "A library of shared functions used by different payload database adapters", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/email-nodemailer/package.json b/packages/email-nodemailer/package.json index 89070b2c7b..3bf9344c12 100644 --- a/packages/email-nodemailer/package.json +++ b/packages/email-nodemailer/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/email-nodemailer", - "version": "3.30.0", + "version": "3.31.0", "description": "Payload Nodemailer Email Adapter", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/email-resend/package.json b/packages/email-resend/package.json index 8dc9de3fdb..a09853c396 100644 --- a/packages/email-resend/package.json +++ b/packages/email-resend/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/email-resend", - "version": "3.30.0", + "version": "3.31.0", "description": "Payload Resend Email Adapter", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/graphql/package.json b/packages/graphql/package.json index 551132c0e8..b5a84e745d 100644 --- a/packages/graphql/package.json +++ b/packages/graphql/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/graphql", - "version": "3.30.0", + "version": "3.31.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/live-preview-react/package.json b/packages/live-preview-react/package.json index a93e9916c8..82015534f0 100644 --- a/packages/live-preview-react/package.json +++ b/packages/live-preview-react/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview-react", - "version": "3.30.0", + "version": "3.31.0", "description": "The official React SDK for Payload Live Preview", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/live-preview-vue/package.json b/packages/live-preview-vue/package.json index fcc5e9113c..8351a3e2b3 100644 --- a/packages/live-preview-vue/package.json +++ b/packages/live-preview-vue/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview-vue", - "version": "3.30.0", + "version": "3.31.0", "description": "The official Vue SDK for Payload Live Preview", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/live-preview/package.json b/packages/live-preview/package.json index 4623397374..3d34a4af24 100644 --- a/packages/live-preview/package.json +++ b/packages/live-preview/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview", - "version": "3.30.0", + "version": "3.31.0", "description": "The official live preview JavaScript SDK for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/next/package.json b/packages/next/package.json index 3ca142c1db..bb9dfeafab 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/next", - "version": "3.30.0", + "version": "3.31.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/payload-cloud/package.json b/packages/payload-cloud/package.json index fd6f5682bb..488e4b7a39 100644 --- a/packages/payload-cloud/package.json +++ b/packages/payload-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/payload-cloud", - "version": "3.30.0", + "version": "3.31.0", "description": "The official Payload Cloud plugin", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/payload/package.json b/packages/payload/package.json index 11afab175e..984f95888a 100644 --- a/packages/payload/package.json +++ b/packages/payload/package.json @@ -1,6 +1,6 @@ { "name": "payload", - "version": "3.30.0", + "version": "3.31.0", "description": "Node, React, Headless CMS and Application Framework built on Next.js", "keywords": [ "admin panel", diff --git a/packages/plugin-cloud-storage/package.json b/packages/plugin-cloud-storage/package.json index 0436572d5d..c1870c9609 100644 --- a/packages/plugin-cloud-storage/package.json +++ b/packages/plugin-cloud-storage/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-cloud-storage", - "version": "3.30.0", + "version": "3.31.0", "description": "The official cloud storage plugin for Payload CMS", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/plugin-form-builder/package.json b/packages/plugin-form-builder/package.json index 35be02fe17..da1a4b8a96 100644 --- a/packages/plugin-form-builder/package.json +++ b/packages/plugin-form-builder/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-form-builder", - "version": "3.30.0", + "version": "3.31.0", "description": "Form builder plugin for Payload CMS", "keywords": [ "payload", diff --git a/packages/plugin-import-export/package.json b/packages/plugin-import-export/package.json index d6de0219f0..4950e31012 100644 --- a/packages/plugin-import-export/package.json +++ b/packages/plugin-import-export/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-import-export", - "version": "3.30.0", + "version": "3.31.0", "description": "Import-Export plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-multi-tenant/package.json b/packages/plugin-multi-tenant/package.json index c839810da4..0abb6159d6 100644 --- a/packages/plugin-multi-tenant/package.json +++ b/packages/plugin-multi-tenant/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-multi-tenant", - "version": "3.30.0", + "version": "3.31.0", "description": "Multi Tenant plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-nested-docs/package.json b/packages/plugin-nested-docs/package.json index 80e2ed2d78..6e7cb75ac4 100644 --- a/packages/plugin-nested-docs/package.json +++ b/packages/plugin-nested-docs/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-nested-docs", - "version": "3.30.0", + "version": "3.31.0", "description": "The official Nested Docs plugin for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/plugin-redirects/package.json b/packages/plugin-redirects/package.json index 1f75f99691..fed8c2fefb 100644 --- a/packages/plugin-redirects/package.json +++ b/packages/plugin-redirects/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-redirects", - "version": "3.30.0", + "version": "3.31.0", "description": "Redirects plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-search/package.json b/packages/plugin-search/package.json index 8b5cea8bd5..b49292920b 100644 --- a/packages/plugin-search/package.json +++ b/packages/plugin-search/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-search", - "version": "3.30.0", + "version": "3.31.0", "description": "Search plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-sentry/package.json b/packages/plugin-sentry/package.json index cf12065234..4844bc3ce4 100644 --- a/packages/plugin-sentry/package.json +++ b/packages/plugin-sentry/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-sentry", - "version": "3.30.0", + "version": "3.31.0", "description": "Sentry plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-seo/package.json b/packages/plugin-seo/package.json index 574ab5ed8a..6b7fc9da91 100644 --- a/packages/plugin-seo/package.json +++ b/packages/plugin-seo/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-seo", - "version": "3.30.0", + "version": "3.31.0", "description": "SEO plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-stripe/package.json b/packages/plugin-stripe/package.json index 7b311a8bf9..a143986af6 100644 --- a/packages/plugin-stripe/package.json +++ b/packages/plugin-stripe/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-stripe", - "version": "3.30.0", + "version": "3.31.0", "description": "Stripe plugin for Payload", "keywords": [ "payload", diff --git a/packages/richtext-lexical/package.json b/packages/richtext-lexical/package.json index f420feb9ea..92f430dfbc 100644 --- a/packages/richtext-lexical/package.json +++ b/packages/richtext-lexical/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/richtext-lexical", - "version": "3.30.0", + "version": "3.31.0", "description": "The officially supported Lexical richtext adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/richtext-slate/package.json b/packages/richtext-slate/package.json index 12a804a064..9297b7096a 100644 --- a/packages/richtext-slate/package.json +++ b/packages/richtext-slate/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/richtext-slate", - "version": "3.30.0", + "version": "3.31.0", "description": "The officially supported Slate richtext adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-azure/package.json b/packages/storage-azure/package.json index 28604d70c9..f6c46ad88d 100644 --- a/packages/storage-azure/package.json +++ b/packages/storage-azure/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-azure", - "version": "3.30.0", + "version": "3.31.0", "description": "Payload storage adapter for Azure Blob Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-gcs/package.json b/packages/storage-gcs/package.json index af5069e2ff..3df704839b 100644 --- a/packages/storage-gcs/package.json +++ b/packages/storage-gcs/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-gcs", - "version": "3.30.0", + "version": "3.31.0", "description": "Payload storage adapter for Google Cloud Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-s3/package.json b/packages/storage-s3/package.json index fa5897455a..6ce49ca71f 100644 --- a/packages/storage-s3/package.json +++ b/packages/storage-s3/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-s3", - "version": "3.30.0", + "version": "3.31.0", "description": "Payload storage adapter for Amazon S3", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-uploadthing/package.json b/packages/storage-uploadthing/package.json index 74e8265dd8..c67a5319eb 100644 --- a/packages/storage-uploadthing/package.json +++ b/packages/storage-uploadthing/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-uploadthing", - "version": "3.30.0", + "version": "3.31.0", "description": "Payload storage adapter for uploadthing", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-vercel-blob/package.json b/packages/storage-vercel-blob/package.json index cbc5a44ff0..f6ba6eac69 100644 --- a/packages/storage-vercel-blob/package.json +++ b/packages/storage-vercel-blob/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-vercel-blob", - "version": "3.30.0", + "version": "3.31.0", "description": "Payload storage adapter for Vercel Blob Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/translations/package.json b/packages/translations/package.json index f363d2a7e3..44f988e557 100644 --- a/packages/translations/package.json +++ b/packages/translations/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/translations", - "version": "3.30.0", + "version": "3.31.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/ui/package.json b/packages/ui/package.json index e09842c2f4..f0fed6e6bd 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/ui", - "version": "3.30.0", + "version": "3.31.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", From 10ac9893ad3ea65c78c77b97394b175386900077 Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Tue, 25 Mar 2025 20:40:16 -0400 Subject: [PATCH 21/77] fix(ui): nested custom components sometimes disappear when queued in form state (#11867) When rendering custom fields nested within arrays or blocks, such as the Lexical rich text editor which is treated as a custom field, these fields will sometimes disappear when form state requests are invoked sequentially. This is especially reproducible on slow networks. This is because form state invocations are placed into a [task queue](https://github.com/payloadcms/payload/pull/11579) which aborts the currently running tasks when a new one arrives. By doing this, local form state is never dispatched, and the second task in the queue becomes stale. The fix is to _not_ abort the currently running task. This will trigger a complete rendering cycle, and when the second task is invoked, local state will be up to date. Fixes #11340, #11425, and #11824. --- packages/ui/src/elements/Autosave/index.tsx | 1 + packages/ui/src/forms/Form/index.tsx | 60 ++++++++++----------- test/form-state/collections/Posts/index.ts | 13 +++++ test/form-state/e2e.spec.ts | 46 +++++++++++++++- test/form-state/payload-types.ts | 27 ++++++++++ 5 files changed, 115 insertions(+), 32 deletions(-) diff --git a/packages/ui/src/elements/Autosave/index.tsx b/packages/ui/src/elements/Autosave/index.tsx index ab1d02b087..73f42f4a86 100644 --- a/packages/ui/src/elements/Autosave/index.tsx +++ b/packages/ui/src/elements/Autosave/index.tsx @@ -130,6 +130,7 @@ export const Autosave: React.FC = ({ id, collection, global: globalDoc }) queueRef.current = [] setBackgroundProcessing(true) + try { await latestAction() } finally { diff --git a/packages/ui/src/forms/Form/index.tsx b/packages/ui/src/forms/Form/index.tsx index 309d256f72..5470ea5a44 100644 --- a/packages/ui/src/forms/Form/index.tsx +++ b/packages/ui/src/forms/Form/index.tsx @@ -720,53 +720,51 @@ export const Form: React.FC = (props) => { const classes = [className, baseClass].filter(Boolean).join(' ') - const executeOnChange = useEffectEvent(async (submitted: boolean, signal: AbortSignal) => { - if (Array.isArray(onChange)) { - let revalidatedFormState: FormState = contextRef.current.fields + const executeOnChange = useEffectEvent((submitted: boolean) => { + queueTask(async () => { + if (Array.isArray(onChange)) { + let revalidatedFormState: FormState = contextRef.current.fields - for (const onChangeFn of onChange) { - if (signal.aborted) { + for (const onChangeFn of onChange) { + // Edit view default onChange is in packages/ui/src/views/Edit/index.tsx. This onChange usually sends a form state request + revalidatedFormState = await onChangeFn({ + formState: deepCopyObjectSimpleWithoutReactComponents(contextRef.current.fields), + submitted, + }) + } + + if (!revalidatedFormState) { return } - // Edit view default onChange is in packages/ui/src/views/Edit/index.tsx. This onChange usually sends a form state request - revalidatedFormState = await onChangeFn({ - formState: deepCopyObjectSimpleWithoutReactComponents(contextRef.current.fields), - submitted, + const { changed, newState } = mergeServerFormState({ + existingState: contextRef.current.fields || {}, + incomingState: revalidatedFormState, }) + + if (changed) { + prevFields.current = newState + + dispatchFields({ + type: 'REPLACE_STATE', + optimize: false, + state: newState, + }) + } } - - if (!revalidatedFormState) { - return - } - - const { changed, newState } = mergeServerFormState({ - existingState: contextRef.current.fields || {}, - incomingState: revalidatedFormState, - }) - - if (changed && !signal.aborted) { - prevFields.current = newState - - dispatchFields({ - type: 'REPLACE_STATE', - optimize: false, - state: newState, - }) - } - } + }) }) useDebouncedEffect( () => { if ((isFirstRenderRef.current || !dequal(fields, prevFields.current)) && modified) { - queueTask(async (signal) => executeOnChange(submitted, signal)) + executeOnChange(submitted) } prevFields.current = fields isFirstRenderRef.current = false }, - [modified, submitted, fields, queueTask], + [modified, submitted, fields], 250, ) diff --git a/test/form-state/collections/Posts/index.ts b/test/form-state/collections/Posts/index.ts index af136f6a57..c82c47b41e 100644 --- a/test/form-state/collections/Posts/index.ts +++ b/test/form-state/collections/Posts/index.ts @@ -1,5 +1,7 @@ import type { CollectionConfig } from 'payload' +import { lexicalEditor } from '@payloadcms/richtext-lexical' + export const postsSlug = 'posts' export const PostsCollection: CollectionConfig = { @@ -64,5 +66,16 @@ export const PostsCollection: CollectionConfig = { }, ], }, + { + name: 'array', + type: 'array', + fields: [ + { + name: 'richText', + type: 'richText', + editor: lexicalEditor(), + }, + ], + }, ], } diff --git a/test/form-state/e2e.spec.ts b/test/form-state/e2e.spec.ts index 1c0b541851..72b9ea243f 100644 --- a/test/form-state/e2e.spec.ts +++ b/test/form-state/e2e.spec.ts @@ -17,7 +17,7 @@ import { } from '../helpers.js' import { AdminUrlUtil } from '../helpers/adminUrlUtil.js' import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' -import { TEST_TIMEOUT_LONG } from '../playwright.config.js' +import { TEST_TIMEOUT, TEST_TIMEOUT_LONG } from '../playwright.config.js' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) @@ -179,6 +179,50 @@ test.describe('Form State', () => { await cdpSession.detach() }) + + test('sequentially queued tasks not cause nested custom components to disappear', async () => { + await page.goto(postsUrl.create) + const field = page.locator('#field-title') + await field.fill('Test') + + const cdpSession = await throttleTest({ + page, + context, + delay: 'Slow 3G', + }) + + await assertNetworkRequests( + page, + postsUrl.create, + async () => { + await page.locator('#field-array .array-field__add-row').click() + + await page.locator('#field-title').fill('Title 2') + + // eslint-disable-next-line playwright/no-wait-for-selector + await page.waitForSelector('#field-array #array-row-0 .field-type.rich-text-lexical', { + timeout: TEST_TIMEOUT, + }) + + await expect( + page.locator('#field-array #array-row-0 .field-type.rich-text-lexical'), + ).toBeVisible() + }, + { + allowedNumberOfRequests: 2, + timeout: 10000, + }, + ) + + await cdpSession.send('Network.emulateNetworkConditions', { + offline: false, + latency: 0, + downloadThroughput: -1, + uploadThroughput: -1, + }) + + await cdpSession.detach() + }) }) async function createPost(overrides?: Partial): Promise { diff --git a/test/form-state/payload-types.ts b/test/form-state/payload-types.ts index eb31820ce3..2197621369 100644 --- a/test/form-state/payload-types.ts +++ b/test/form-state/payload-types.ts @@ -54,6 +54,7 @@ export type SupportedTimezones = | 'Asia/Singapore' | 'Asia/Tokyo' | 'Asia/Seoul' + | 'Australia/Brisbane' | 'Australia/Sydney' | 'Pacific/Guam' | 'Pacific/Noumea' @@ -140,6 +141,26 @@ export interface Post { } )[] | null; + array?: + | { + richText?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + id?: string | null; + }[] + | null; updatedAt: string; createdAt: string; } @@ -243,6 +264,12 @@ export interface PostsSelect { blockName?: T; }; }; + array?: + | T + | { + richText?: T; + id?: T; + }; updatedAt?: T; createdAt?: T; } From 4fc2eec301c10661938ba3b6c952aa62116441ec Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Tue, 25 Mar 2025 23:45:03 -0400 Subject: [PATCH 22/77] fix(ui): query presets are available for unrelated collections (#11872) When selecting query presets from the list drawer, all query presets are available for selection, even if unrelated to the underlying collection. When selecting one of these presets, the list view will crash with client-side exceptions because the columns and filters that are applied are incompatible. The fix is to the thread `filterOptions` through the query presets drawer. This will ensure that only related collections are shown. --- .../elements/ListControls/useQueryPresets.tsx | 13 +++++ test/query-presets/collections/Posts/index.ts | 21 +++++++ test/query-presets/config.ts | 3 +- test/query-presets/e2e.spec.ts | 15 +++++ .../helpers/openQueryPresetDrawer.ts | 10 +++- test/query-presets/payload-types.ts | 57 ++++++++++++++----- test/query-presets/slugs.ts | 4 +- tsconfig.base.json | 2 +- 8 files changed, 105 insertions(+), 20 deletions(-) create mode 100644 test/query-presets/collections/Posts/index.ts diff --git a/packages/ui/src/elements/ListControls/useQueryPresets.tsx b/packages/ui/src/elements/ListControls/useQueryPresets.tsx index cafc1d041d..c6ec9ca53d 100644 --- a/packages/ui/src/elements/ListControls/useQueryPresets.tsx +++ b/packages/ui/src/elements/ListControls/useQueryPresets.tsx @@ -65,9 +65,22 @@ export const useQueryPresets = ({ collectionSlug: queryPresetsSlug, }) + const filterOptions = useMemo( + () => ({ + 'payload-query-presets': { + relatedCollection: { + equals: collectionSlug, + }, + }, + }), + [collectionSlug], + ) + const [ListDrawer, , { closeDrawer: closeListDrawer, openDrawer: openListDrawer }] = useListDrawer({ collectionSlugs: [queryPresetsSlug], + filterOptions, + selectedCollection: queryPresetsSlug, }) const handlePresetChange = useCallback( diff --git a/test/query-presets/collections/Posts/index.ts b/test/query-presets/collections/Posts/index.ts new file mode 100644 index 0000000000..84aec17300 --- /dev/null +++ b/test/query-presets/collections/Posts/index.ts @@ -0,0 +1,21 @@ +import type { CollectionConfig } from 'payload' + +import { postsSlug } from '../../slugs.js' + +export const Posts: CollectionConfig = { + slug: postsSlug, + admin: { + useAsTitle: 'text', + }, + enableQueryPresets: true, + lockDocuments: false, + fields: [ + { + name: 'text', + type: 'text', + }, + ], + versions: { + drafts: true, + }, +} diff --git a/test/query-presets/config.ts b/test/query-presets/config.ts index bf0e4d4e05..2a786ef4af 100644 --- a/test/query-presets/config.ts +++ b/test/query-presets/config.ts @@ -3,6 +3,7 @@ import path from 'path' import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' import { Pages } from './collections/Pages/index.js' +import { Posts } from './collections/Posts/index.js' import { Users } from './collections/Users/index.js' import { roles } from './fields/roles.js' import { seed } from './seed.js' @@ -54,7 +55,7 @@ export default buildConfigWithDefaults({ ], }, }, - collections: [Pages, Users], + collections: [Pages, Users, Posts], onInit: async (payload) => { if (process.env.SEED_IN_CONFIG_ONINIT !== 'false') { await seed(payload) diff --git a/test/query-presets/e2e.spec.ts b/test/query-presets/e2e.spec.ts index 30c19de3d4..6f2cc43805 100644 --- a/test/query-presets/e2e.spec.ts +++ b/test/query-presets/e2e.spec.ts @@ -389,4 +389,19 @@ describe('Query Presets', () => { }), ).toBeVisible() }) + + test('only shows query presets related to the underlying collection', async () => { + // no results on `users` collection + const postsUrl = new AdminUrlUtil(serverURL, 'posts') + await page.goto(postsUrl.list) + const drawer = await openQueryPresetDrawer({ page }) + await expect(drawer.locator('.table table > tbody > tr')).toHaveCount(0) + await expect(drawer.locator('.collection-list__no-results')).toBeVisible() + + // results on `pages` collection + await page.goto(pagesUrl.list) + await openQueryPresetDrawer({ page }) + await expect(drawer.locator('.table table > tbody > tr')).toHaveCount(3) + await drawer.locator('.collection-list__no-results').isHidden() + }) }) diff --git a/test/query-presets/helpers/openQueryPresetDrawer.ts b/test/query-presets/helpers/openQueryPresetDrawer.ts index e9c5db1f1a..fa3747ff11 100644 --- a/test/query-presets/helpers/openQueryPresetDrawer.ts +++ b/test/query-presets/helpers/openQueryPresetDrawer.ts @@ -1,5 +1,11 @@ -import type { Page } from '@playwright/test' +import type { Locator, Page } from '@playwright/test' -export async function openQueryPresetDrawer({ page }: { page: Page }) { +import { expect } from '@playwright/test' + +export async function openQueryPresetDrawer({ page }: { page: Page }): Promise { await page.click('button#select-preset') + const drawer = page.locator('dialog[id^="list-drawer_0_"]') + await expect(drawer).toBeVisible() + await expect(drawer.locator('.collection-list--payload-query-presets')).toBeVisible() + return drawer } diff --git a/test/query-presets/payload-types.ts b/test/query-presets/payload-types.ts index 20fbd0a7b8..2f6ee94ee9 100644 --- a/test/query-presets/payload-types.ts +++ b/test/query-presets/payload-types.ts @@ -69,6 +69,7 @@ export interface Config { collections: { pages: Page; users: User; + posts: Post; 'payload-locked-documents': PayloadLockedDocument; 'payload-preferences': PayloadPreference; 'payload-migrations': PayloadMigration; @@ -78,13 +79,14 @@ export interface Config { collectionsSelect: { pages: PagesSelect | PagesSelect; users: UsersSelect | UsersSelect; + posts: PostsSelect | PostsSelect; 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; 'payload-migrations': PayloadMigrationsSelect | PayloadMigrationsSelect; 'payload-query-presets': PayloadQueryPresetsSelect | PayloadQueryPresetsSelect; }; db: { - defaultIDType: number; + defaultIDType: string; }; globals: {}; globalsSelect: {}; @@ -120,7 +122,7 @@ export interface UserAuthOperations { * via the `definition` "pages". */ export interface Page { - id: number; + id: string; text?: string | null; updatedAt: string; createdAt: string; @@ -131,7 +133,7 @@ export interface Page { * via the `definition` "users". */ export interface User { - id: number; + id: string; name?: string | null; roles?: ('admin' | 'user' | 'anonymous')[] | null; updatedAt: string; @@ -145,25 +147,40 @@ export interface User { lockUntil?: string | null; password?: string | null; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "posts". + */ +export interface Post { + id: string; + text?: string | null; + updatedAt: string; + createdAt: string; + _status?: ('draft' | 'published') | null; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "payload-locked-documents". */ export interface PayloadLockedDocument { - id: number; + id: string; document?: | ({ relationTo: 'pages'; - value: number | Page; + value: string | Page; } | null) | ({ relationTo: 'users'; - value: number | User; + value: string | User; + } | null) + | ({ + relationTo: 'posts'; + value: string | Post; } | null); globalSlug?: string | null; user: { relationTo: 'users'; - value: number | User; + value: string | User; }; updatedAt: string; createdAt: string; @@ -173,10 +190,10 @@ export interface PayloadLockedDocument { * via the `definition` "payload-preferences". */ export interface PayloadPreference { - id: number; + id: string; user: { relationTo: 'users'; - value: number | User; + value: string | User; }; key?: string | null; value?: @@ -196,7 +213,7 @@ export interface PayloadPreference { * via the `definition` "payload-migrations". */ export interface PayloadMigration { - id: number; + id: string; name?: string | null; batch?: number | null; updatedAt: string; @@ -207,23 +224,23 @@ export interface PayloadMigration { * via the `definition` "payload-query-presets". */ export interface PayloadQueryPreset { - id: number; + id: string; title: string; isShared?: boolean | null; access?: { read?: { constraint?: ('everyone' | 'onlyMe' | 'specificUsers' | 'specificRoles') | null; - users?: (number | User)[] | null; + users?: (string | User)[] | null; roles?: ('admin' | 'user' | 'anonymous')[] | null; }; update?: { constraint?: ('everyone' | 'onlyMe' | 'specificUsers' | 'specificRoles') | null; - users?: (number | User)[] | null; + users?: (string | User)[] | null; roles?: ('admin' | 'user' | 'anonymous')[] | null; }; delete?: { constraint?: ('everyone' | 'onlyMe' | 'specificUsers') | null; - users?: (number | User)[] | null; + users?: (string | User)[] | null; }; }; where?: @@ -244,7 +261,7 @@ export interface PayloadQueryPreset { | number | boolean | null; - relatedCollection: 'pages'; + relatedCollection: 'pages' | 'posts'; updatedAt: string; createdAt: string; } @@ -275,6 +292,16 @@ export interface UsersSelect { loginAttempts?: T; lockUntil?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "posts_select". + */ +export interface PostsSelect { + text?: T; + updatedAt?: T; + createdAt?: T; + _status?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "payload-locked-documents_select". diff --git a/test/query-presets/slugs.ts b/test/query-presets/slugs.ts index 85c6ec36fd..b7fb1e104c 100644 --- a/test/query-presets/slugs.ts +++ b/test/query-presets/slugs.ts @@ -2,4 +2,6 @@ export const usersSlug = 'users' export const pagesSlug = 'pages' -export const collectionSlugs = [usersSlug, pagesSlug] +export const postsSlug = 'posts' + +export const collectionSlugs = [usersSlug, pagesSlug, postsSlug] diff --git a/tsconfig.base.json b/tsconfig.base.json index c9793d25c6..daa36c7211 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -31,7 +31,7 @@ } ], "paths": { - "@payload-config": ["./test/_community/config.ts"], + "@payload-config": ["./test/query-presets/config.ts"], "@payloadcms/admin-bar": ["./packages/admin-bar/src"], "@payloadcms/live-preview": ["./packages/live-preview/src"], "@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"], From 6b56343b97c2e8aa8818b53a77d7d4dc8eac4986 Mon Sep 17 00:00:00 2001 From: Said Akhrarov <36972061+akhrarovsaid@users.noreply.github.com> Date: Wed, 26 Mar 2025 14:12:01 -0400 Subject: [PATCH 23/77] docs: fix links in custom components and custom features (#11881) ### What? Fixes a few broken links in `docs/custom-components` and `docs/rich-text`. Also made some custom component links lowercase. ### Why? To direct end users to the correct location in the docs. ### How? Changes to `docs/custom-components/custom-views.mdx`, `docs/custom-components/list-view.mdx`, and `docs/rich-text/custom-features.mdx`. --- docs/custom-components/custom-views.mdx | 2 +- docs/custom-components/list-view.mdx | 16 ++++++++-------- docs/rich-text/custom-features.mdx | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/custom-components/custom-views.mdx b/docs/custom-components/custom-views.mdx index a976c48e1e..59e18ddcfe 100644 --- a/docs/custom-components/custom-views.mdx +++ b/docs/custom-components/custom-views.mdx @@ -55,7 +55,7 @@ For more granular control, pass a configuration object instead. Payload exposes | `exact` | Boolean. When true, will only match if the path matches the `usePathname()` exactly. | | `strict` | When true, a path that has a trailing slash will only match a `location.pathname` with a trailing slash. This has no effect when there are additional URL segments in the pathname. | | `sensitive` | When true, will match if the path is case sensitive. | -| `meta` | Page metadata overrides to apply to this view within the Admin Panel. [More details](./metadata). | +| `meta` | Page metadata overrides to apply to this view within the Admin Panel. [More details](../admin/metadata). | _\* An asterisk denotes that a property is required._ diff --git a/docs/custom-components/list-view.mdx b/docs/custom-components/list-view.mdx index d2ce84d6e3..0f4754ad8a 100644 --- a/docs/custom-components/list-view.mdx +++ b/docs/custom-components/list-view.mdx @@ -6,13 +6,13 @@ desc: keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs --- -The List View is where users interact with a list of [Collection](../collections/overview) Documents within the [Admin Panel](../admin/overview). This is where they can view, sort, filter, and paginate their documents to find exactly what they're looking for. This is also where users can perform bulk operations on multiple documents at once, such as deleting, editing, or publishing many. +The List View is where users interact with a list of [Collection](../configuration/collections) Documents within the [Admin Panel](../admin/overview). This is where they can view, sort, filter, and paginate their documents to find exactly what they're looking for. This is also where users can perform bulk operations on multiple documents at once, such as deleting, editing, or publishing many. The List View can be swapped out in its entirety for a Custom View, or it can be injected with a number of Custom Components to add additional functionality or presentational elements without replacing the entire view. - **Note:** Only [Collections](../collections/overview) have a List View. - [Globals](../globals/overview) do not have a List View as they are single + **Note:** Only [Collections](../configuration/collections) have a List View. + [Globals](../configuration/globals) do not have a List View as they are single documents. @@ -90,11 +90,11 @@ The following options are available: | Path | Description | | ----------------- | ------------------------------------------------------------------------------------------------------------------------- | -| `beforeList` | An array of custom components to inject before the list of documents in the List View. [More details](#beforeList). | -| `beforeListTable` | An array of custom components to inject before the table of documents in the List View. [More details](#beforeListTable). | -| `afterList` | An array of custom components to inject after the list of documents in the List View. [More details](#afterList). | -| `afterListTable` | An array of custom components to inject after the table of documents in the List View. [More details](#afterListTable). | -| `Description` | A component to render a description of the Collection. [More details](#Description). | +| `beforeList` | An array of custom components to inject before the list of documents in the List View. [More details](#beforelist). | +| `beforeListTable` | An array of custom components to inject before the table of documents in the List View. [More details](#beforelisttable). | +| `afterList` | An array of custom components to inject after the list of documents in the List View. [More details](#afterlist). | +| `afterListTable` | An array of custom components to inject after the table of documents in the List View. [More details](#afterlisttable). | +| `Description` | A component to render a description of the Collection. [More details](#description). | ### beforeList diff --git a/docs/rich-text/custom-features.mdx b/docs/rich-text/custom-features.mdx index 8f31ae0fe2..4ad06a2877 100644 --- a/docs/rich-text/custom-features.mdx +++ b/docs/rich-text/custom-features.mdx @@ -409,7 +409,7 @@ Explore the APIs available through ClientFeature to add the specific functionali ### Adding a client feature to the server feature -Inside of your server feature, you can provide an [import path](/docs/admin/custom-components/overview#component-paths) to the client feature like this: +Inside of your server feature, you can provide an [import path](/docs/custom-components/overview#component-paths) to the client feature like this: ```ts import { createServerFeature } from '@payloadcms/richtext-lexical' From 98e4db07c3063a7dca87c151980faf0661cb2717 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Wed, 26 Mar 2025 12:13:32 -0600 Subject: [PATCH 24/77] fix(plugin-cloud-storage): ensure client handlers are added to import map regardless of enabled state (#11880) There are cases when a storage plugin is disabled during development and enabled in production. This will result in import maps that differ depending on if they're generated during development or production. In a lot of cases, those import maps are generated during development-only. During production, we just re-use what was generated locally. This will cause missing import map entries for those plugins that are disabled during development. This PR ensures the import map entries are added regardless of the enabled state of those plugins. This is necessary for our generate-templates script to not omit the vercel blob storage import map entry. --- .../payload/src/bin/generateImportMap/iterateConfig.ts | 3 +-- packages/payload/src/config/types.ts | 4 +--- .../src/utilities/initClientUploads.ts | 10 ++++++++++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/payload/src/bin/generateImportMap/iterateConfig.ts b/packages/payload/src/bin/generateImportMap/iterateConfig.ts index bf001bc045..cb0da57418 100644 --- a/packages/payload/src/bin/generateImportMap/iterateConfig.ts +++ b/packages/payload/src/bin/generateImportMap/iterateConfig.ts @@ -95,8 +95,7 @@ export function iterateConfig({ } if (config?.admin?.dependencies) { - for (const key in config.admin.dependencies) { - const dependency = config.admin.dependencies[key] + for (const dependency of Object.values(config.admin.dependencies)) { addToImportMap(dependency.path) } } diff --git a/packages/payload/src/config/types.ts b/packages/payload/src/config/types.ts index 96f3773537..8e96323818 100644 --- a/packages/payload/src/config/types.ts +++ b/packages/payload/src/config/types.ts @@ -793,9 +793,7 @@ export type Config = { /** Global date format that will be used for all dates in the Admin panel. Any valid date-fns format pattern can be used. */ dateFormat?: string /** - * Each entry in this map generates an entry in the importMap, - * as well as an entry in the componentMap if the type of the - * dependency is 'component' + * Each entry in this map generates an entry in the importMap. */ dependencies?: AdminDependencies /** diff --git a/packages/plugin-cloud-storage/src/utilities/initClientUploads.ts b/packages/plugin-cloud-storage/src/utilities/initClientUploads.ts index b1ac748511..0fb0acec67 100644 --- a/packages/plugin-cloud-storage/src/utilities/initClientUploads.ts +++ b/packages/plugin-cloud-storage/src/utilities/initClientUploads.ts @@ -53,6 +53,16 @@ export const initClientUploads = , T> config.admin = {} } + if (!config.admin.dependencies) { + config.admin.dependencies = {} + } + // Ensure client handler is always part of the import map, to avoid + // import map discrepancies between dev and prod + config.admin.dependencies[clientHandler] = { + type: 'function', + path: clientHandler, + } + if (!config.admin.components) { config.admin.components = {} } From 5ae5255ba33917440ca4ca262ef622cb80c6ac5c Mon Sep 17 00:00:00 2001 From: Said Akhrarov <36972061+akhrarovsaid@users.noreply.github.com> Date: Wed, 26 Mar 2025 16:13:52 -0400 Subject: [PATCH 25/77] perf(ui): download only images and optimize image selection for document edit view, prioritize best-fit size (#11844) ### What? In the same vein as #11696, this PR optimizes how images are selected for display in the document edit view. It ensures that only image files are processed and selects the most appropriate size to minimize unnecessary downloads and improve performance. #### Previously: - Non-image files were being processed unnecessarily, despite not generating thumbnails. - Images without a `thumbnailURL` defaulted to their original full size, even when smaller, optimized versions were available. #### Now: - **Only images** are processed for thumbnails, avoiding redundant requests for non-images. - **The smallest available image within a target range** (`40px - 180px`) is prioritized for display. - **If no images fit within this range**, the logic selects: - The next smallest larger image (if available). - The **original** image if it is smaller than the next available larger size. - The largest **smaller** image if no better fit exists. ### Why? Prevents unnecessary downloads of non-image files, reduces bandwidth usage by selecting more efficient image sizes and improves load times and performance in the edit view. ### How? - **Filters out non-image files** when determining which assets to display. - Uses the same algorithm as in #11696 but turns it into a reusable function to be used in various areas around the codebase. Namely the upload field hasOne and hasMany components. Before (4.5mb transfer): ![edit-view-before](https://github.com/user-attachments/assets/ff3513b7-b874-48c3-bce7-8a9425243e00) After (15.9kb transfer): ![edit-view-after](https://github.com/user-attachments/assets/fce8c463-65ae-4f1d-81b5-8781e89f06f1) --- .../Table/DefaultCell/fields/File/index.tsx | 54 +++----------- .../ui/src/fields/Upload/HasMany/index.tsx | 17 ++++- .../ui/src/fields/Upload/HasOne/index.tsx | 15 +++- .../Upload/RelationshipContent/index.tsx | 4 +- .../ui/src/utilities/getBestFitFromSizes.ts | 70 +++++++++++++++++++ test/uploads/config.ts | 25 +++++++ test/uploads/e2e.spec.ts | 51 ++++++++++++++ test/uploads/payload-types.ts | 31 ++++++++ 8 files changed, 217 insertions(+), 50 deletions(-) create mode 100644 packages/ui/src/utilities/getBestFitFromSizes.ts diff --git a/packages/ui/src/elements/Table/DefaultCell/fields/File/index.tsx b/packages/ui/src/elements/Table/DefaultCell/fields/File/index.tsx index ae03844a78..cb7f3658e8 100644 --- a/packages/ui/src/elements/Table/DefaultCell/fields/File/index.tsx +++ b/packages/ui/src/elements/Table/DefaultCell/fields/File/index.tsx @@ -6,16 +6,15 @@ import type { UploadFieldClient, } from 'payload' +import { isImage } from 'payload/shared' import React from 'react' -import { Thumbnail } from '../../../../Thumbnail/index.js' import './index.scss' +import { getBestFitFromSizes } from '../../../../../utilities/getBestFitFromSizes.js' +import { Thumbnail } from '../../../../Thumbnail/index.js' const baseClass = 'file' -const targetThumbnailSizeMin = 40 -const targetThumbnailSizeMax = 180 - export interface FileCellProps extends DefaultCellComponentProps { readonly collectionConfig: ClientCollectionConfig @@ -33,46 +32,13 @@ export const FileCell: React.FC = ({ if (previewAllowed) { let fileSrc: string | undefined = rowData?.thumbnailURL ?? rowData?.url - if ( - rowData?.url && - !rowData?.thumbnailURL && - typeof rowData?.mimeType === 'string' && - rowData?.mimeType.startsWith('image') && - rowData?.sizes - ) { - const sizes = Object.values<{ url?: string; width?: number }>(rowData.sizes) - - const bestFit = sizes.reduce( - (closest, current) => { - if (!current.width || current.width < targetThumbnailSizeMin) { - return closest - } - - if (current.width >= targetThumbnailSizeMin && current.width <= targetThumbnailSizeMax) { - return !closest.width || - current.width < closest.width || - closest.width < targetThumbnailSizeMin || - closest.width > targetThumbnailSizeMax - ? current - : closest - } - - if ( - !closest.width || - (!closest.original && - closest.width < targetThumbnailSizeMin && - current.width > closest.width) || - (closest.width > targetThumbnailSizeMax && current.width < closest.width) - ) { - return current - } - - return closest - }, - { original: true, url: rowData?.url, width: rowData?.width }, - ) - - fileSrc = bestFit.url || fileSrc + if (isImage(rowData?.mimeType)) { + fileSrc = getBestFitFromSizes({ + sizes: rowData?.sizes, + thumbnailURL: rowData?.thumbnailURL, + url: rowData?.url, + width: rowData?.width, + }) } return ( diff --git a/packages/ui/src/fields/Upload/HasMany/index.tsx b/packages/ui/src/fields/Upload/HasMany/index.tsx index 7f3972b5de..30c68b780c 100644 --- a/packages/ui/src/fields/Upload/HasMany/index.tsx +++ b/packages/ui/src/fields/Upload/HasMany/index.tsx @@ -11,10 +11,14 @@ import { UploadCard } from '../UploadCard/index.js' const baseClass = 'upload upload--has-many' -import type { ReloadDoc } from '../types.js' +import { isImage } from 'payload/shared' import './index.scss' +import type { ReloadDoc } from '../types.js' + +import { getBestFitFromSizes } from '../../../utilities/getBestFitFromSizes.js' + type Props = { readonly className?: string readonly displayPreview?: boolean @@ -96,6 +100,15 @@ export function UploadComponentHasMany(props: Props) { } } + if (isImage(value.mimeType)) { + thumbnailSrc = getBestFitFromSizes({ + sizes: value.sizes, + thumbnailURL: thumbnailSrc, + url: src, + width: value.width, + }) + } + return ( {(draggableSortableItemProps) => ( @@ -137,7 +150,7 @@ export function UploadComponentHasMany(props: Props) { onRemove={() => removeItem(index)} reloadDoc={reloadDoc} src={src} - thumbnailSrc={thumbnailSrc || src} + thumbnailSrc={thumbnailSrc} withMeta={false} x={value?.width as number} y={value?.height as number} diff --git a/packages/ui/src/fields/Upload/HasOne/index.tsx b/packages/ui/src/fields/Upload/HasOne/index.tsx index b2e34c7e8a..b8bec14b11 100644 --- a/packages/ui/src/fields/Upload/HasOne/index.tsx +++ b/packages/ui/src/fields/Upload/HasOne/index.tsx @@ -2,13 +2,15 @@ import type { JsonObject } from 'payload' +import { isImage } from 'payload/shared' import React from 'react' import type { ReloadDoc } from '../types.js' +import { getBestFitFromSizes } from '../../../utilities/getBestFitFromSizes.js' +import './index.scss' import { RelationshipContent } from '../RelationshipContent/index.js' import { UploadCard } from '../UploadCard/index.js' -import './index.scss' const baseClass = 'upload upload--has-one' @@ -49,6 +51,15 @@ export function UploadComponentHasOne(props: Props) { } } + if (isImage(value.mimeType)) { + thumbnailSrc = getBestFitFromSizes({ + sizes: value.sizes, + thumbnailURL: thumbnailSrc, + url: src, + width: value.width, + }) + } + return ( diff --git a/packages/ui/src/fields/Upload/RelationshipContent/index.tsx b/packages/ui/src/fields/Upload/RelationshipContent/index.tsx index 875acbc236..5ee765b45b 100644 --- a/packages/ui/src/fields/Upload/RelationshipContent/index.tsx +++ b/packages/ui/src/fields/Upload/RelationshipContent/index.tsx @@ -2,7 +2,7 @@ import type { TypeWithID } from 'payload' -import { formatFilesize } from 'payload/shared' +import { formatFilesize, isImage } from 'payload/shared' import React from 'react' import type { ReloadDoc } from '../types.js' @@ -99,7 +99,7 @@ export function RelationshipContent(props: Props) { alt={alt} className={`${baseClass}__thumbnail`} filename={filename} - fileSrc={thumbnailSrc} + fileSrc={isImage(mimeType) && thumbnailSrc} size="small" /> )} diff --git a/packages/ui/src/utilities/getBestFitFromSizes.ts b/packages/ui/src/utilities/getBestFitFromSizes.ts new file mode 100644 index 0000000000..5a2c7633c3 --- /dev/null +++ b/packages/ui/src/utilities/getBestFitFromSizes.ts @@ -0,0 +1,70 @@ +/** + * Takes image sizes and a target range and returns the url of the image within that range. + * If no images fit within the range, it selects the next smallest adequate image, the original, + * or the largest smaller image if no better fit exists. + * + * @param sizes The given FileSizes. + * @param targetSizeMax The ideal image maximum width. Defaults to 180. + * @param targetSizeMin The ideal image minimum width. Defaults to 40. + * @param thumbnailURL The thumbnail url set in config. If passed a url, will return early with it. + * @param url The url of the original file. + * @param width The width of the original file. + * @returns A url of the best fit file. + */ +export const getBestFitFromSizes = ({ + sizes, + targetSizeMax = 180, + targetSizeMin = 40, + thumbnailURL, + url, + width, +}: { + sizes?: Record + targetSizeMax?: number + targetSizeMin?: number + thumbnailURL?: string + url: string + width?: number +}) => { + if (thumbnailURL) { + return thumbnailURL + } + + if (!sizes) { + return url + } + + const bestFit = Object.values(sizes).reduce<{ + original?: boolean + url?: string + width?: number + }>( + (closest, current) => { + if (!current.width || current.width < targetSizeMin) { + return closest + } + + if (current.width >= targetSizeMin && current.width <= targetSizeMax) { + return !closest.width || + current.width < closest.width || + closest.width < targetSizeMin || + closest.width > targetSizeMax + ? current + : closest + } + + if ( + !closest.width || + (!closest.original && closest.width < targetSizeMin && current.width > closest.width) || + (closest.width > targetSizeMax && current.width < closest.width) + ) { + return current + } + + return closest + }, + { original: true, url, width }, + ) + + return bestFit.url || url +} diff --git a/test/uploads/config.ts b/test/uploads/config.ts index 183591a7a7..ab0199c695 100644 --- a/test/uploads/config.ts +++ b/test/uploads/config.ts @@ -735,6 +735,31 @@ export default buildConfigWithDefaults({ }, ], }, + { + slug: 'best-fit', + fields: [ + { + name: 'withAdminThumbnail', + type: 'upload', + relationTo: 'admin-thumbnail-function', + }, + { + name: 'withinRange', + type: 'upload', + relationTo: enlargeSlug, + }, + { + name: 'nextSmallestOutOfRange', + type: 'upload', + relationTo: 'focal-only', + }, + { + name: 'original', + type: 'upload', + relationTo: 'focal-only', + }, + ], + }, ], onInit: async (payload) => { const uploadsDir = path.resolve(dirname, './media') diff --git a/test/uploads/e2e.spec.ts b/test/uploads/e2e.spec.ts index 9d02038879..6b9a2e5157 100644 --- a/test/uploads/e2e.spec.ts +++ b/test/uploads/e2e.spec.ts @@ -66,6 +66,7 @@ let uploadsOne: AdminUrlUtil let uploadsTwo: AdminUrlUtil let customUploadFieldURL: AdminUrlUtil let hideFileInputOnCreateURL: AdminUrlUtil +let bestFitURL: AdminUrlUtil let consoleErrorsFromPage: string[] = [] let collectErrorsFromPage: () => boolean let stopCollectingErrorsFromPage: () => boolean @@ -99,6 +100,7 @@ describe('Uploads', () => { uploadsTwo = new AdminUrlUtil(serverURL, 'uploads-2') customUploadFieldURL = new AdminUrlUtil(serverURL, customUploadFieldSlug) hideFileInputOnCreateURL = new AdminUrlUtil(serverURL, hideFileInputOnCreateSlug) + bestFitURL = new AdminUrlUtil(serverURL, 'best-fit') const context = await browser.newContext() page = await context.newPage() @@ -1349,4 +1351,53 @@ describe('Uploads', () => { await expect(page.locator('.file-field .file-details__remove')).toBeHidden() }) + + describe('imageSizes best fit', () => { + test('should select adminThumbnail if one exists', async () => { + await page.goto(bestFitURL.create) + await page.locator('#field-withAdminThumbnail button.upload__listToggler').click() + await page.locator('tr.row-1 td.cell-filename button.default-cell__first-cell').click() + const thumbnail = page.locator('#field-withAdminThumbnail div.thumbnail > img') + await expect(thumbnail).toHaveAttribute( + 'src', + 'https://payloadcms.com/images/universal-truth.jpg', + ) + }) + + test('should select an image within target range', async () => { + await page.goto(bestFitURL.create) + await page.locator('#field-withinRange button.upload__createNewToggler').click() + const fileChooserPromise = page.waitForEvent('filechooser') + await page.getByText('Select a file').click() + const fileChooser = await fileChooserPromise + await fileChooser.setFiles(path.join(dirname, 'test-image.jpg')) + await page.locator('dialog button#action-save').click() + const thumbnail = page.locator('#field-withinRange div.thumbnail > img') + await expect(thumbnail).toHaveAttribute('src', '/api/enlarge/file/test-image-180x50.jpg') + }) + + test('should select next smallest image outside of range but smaller than original', async () => { + await page.goto(bestFitURL.create) + await page.locator('#field-nextSmallestOutOfRange button.upload__createNewToggler').click() + const fileChooserPromise = page.waitForEvent('filechooser') + await page.getByText('Select a file').click() + const fileChooser = await fileChooserPromise + await fileChooser.setFiles(path.join(dirname, 'test-image.jpg')) + await page.locator('dialog button#action-save').click() + const thumbnail = page.locator('#field-nextSmallestOutOfRange div.thumbnail > img') + await expect(thumbnail).toHaveAttribute('src', '/api/focal-only/file/test-image-400x300.jpg') + }) + + test('should select original if smaller than next available size', async () => { + await page.goto(bestFitURL.create) + await page.locator('#field-original button.upload__createNewToggler').click() + const fileChooserPromise = page.waitForEvent('filechooser') + await page.getByText('Select a file').click() + const fileChooser = await fileChooserPromise + await fileChooser.setFiles(path.join(dirname, 'small.png')) + await page.locator('dialog button#action-save').click() + const thumbnail = page.locator('#field-original div.thumbnail > img') + await expect(thumbnail).toHaveAttribute('src', '/api/focal-only/file/small.png') + }) + }) }) diff --git a/test/uploads/payload-types.ts b/test/uploads/payload-types.ts index bd0bc2592e..2dc7d55528 100644 --- a/test/uploads/payload-types.ts +++ b/test/uploads/payload-types.ts @@ -101,6 +101,7 @@ export interface Config { 'media-without-relation-preview': MediaWithoutRelationPreview; 'relation-preview': RelationPreview; 'hide-file-input-on-create': HideFileInputOnCreate; + 'best-fit': BestFit; users: User; 'payload-locked-documents': PayloadLockedDocument; 'payload-preferences': PayloadPreference; @@ -142,6 +143,7 @@ export interface Config { 'media-without-relation-preview': MediaWithoutRelationPreviewSelect | MediaWithoutRelationPreviewSelect; 'relation-preview': RelationPreviewSelect | RelationPreviewSelect; 'hide-file-input-on-create': HideFileInputOnCreateSelect | HideFileInputOnCreateSelect; + 'best-fit': BestFitSelect | BestFitSelect; users: UsersSelect | UsersSelect; 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; @@ -1260,6 +1262,19 @@ export interface RelationPreview { updatedAt: string; createdAt: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "best-fit". + */ +export interface BestFit { + id: string; + withAdminThumbnail?: (string | null) | AdminThumbnailFunction; + withinRange?: (string | null) | Enlarge; + nextSmallestOutOfRange?: (string | null) | FocalOnly; + original?: (string | null) | FocalOnly; + updatedAt: string; + createdAt: string; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users". @@ -1420,6 +1435,10 @@ export interface PayloadLockedDocument { relationTo: 'hide-file-input-on-create'; value: string | HideFileInputOnCreate; } | null) + | ({ + relationTo: 'best-fit'; + value: string | BestFit; + } | null) | ({ relationTo: 'users'; value: string | User; @@ -2632,6 +2651,18 @@ export interface HideFileInputOnCreateSelect { focalX?: T; focalY?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "best-fit_select". + */ +export interface BestFitSelect { + withAdminThumbnail?: T; + withinRange?: T; + nextSmallestOutOfRange?: T; + original?: T; + updatedAt?: T; + createdAt?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users_select". From 1578cd2425f0a9f3d400e18a912ba57edec5f989 Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 26 Mar 2025 20:32:42 +0000 Subject: [PATCH 26/77] chore(ui): added selected option as a class to list table cell (#11750) In the Cell component for a select field such as our `_status` fields it will now add a class eg. `selected--published` for the selected option so it can be easily targeted with CSS. --------- Co-authored-by: Dan Ribbens --- .../src/elements/Table/DefaultCell/index.tsx | 14 +++++++++ test/admin/collections/Posts.ts | 31 +++++++++++++++++++ test/admin/e2e/list-view/e2e.spec.ts | 26 ++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/packages/ui/src/elements/Table/DefaultCell/index.tsx b/packages/ui/src/elements/Table/DefaultCell/index.tsx index 57847eba1b..51f6769502 100644 --- a/packages/ui/src/elements/Table/DefaultCell/index.tsx +++ b/packages/ui/src/elements/Table/DefaultCell/index.tsx @@ -148,5 +148,19 @@ export const DefaultCell: React.FC = (props) => { } } + if ((field.type === 'select' || field.type === 'radio') && field.options.length && cellData) { + const classes = Array.isArray(cellData) + ? cellData.map((value) => `selected--${value}`).join(' ') + : `selected--${cellData}` + + const className = [wrapElementProps.className, classes].filter(Boolean).join(' ') + + return ( + + {CellComponent} + + ) + } + return {CellComponent} } diff --git a/test/admin/collections/Posts.ts b/test/admin/collections/Posts.ts index 257cbb9692..eeac32a803 100644 --- a/test/admin/collections/Posts.ts +++ b/test/admin/collections/Posts.ts @@ -205,6 +205,37 @@ export const Posts: CollectionConfig = { position: 'sidebar', }, }, + { + type: 'radio', + name: 'wavelengths', + defaultValue: 'fm', + options: [ + { + label: 'FM', + value: 'fm', + }, + { + label: 'AM', + value: 'am', + }, + ], + }, + { + type: 'select', + name: 'selectField', + hasMany: true, + defaultValue: ['option1', 'option2'], + options: [ + { + label: 'Option 1', + value: 'option1', + }, + { + label: 'Option 2', + value: 'option2', + }, + ], + }, ], labels: { plural: slugPluralLabel, diff --git a/test/admin/e2e/list-view/e2e.spec.ts b/test/admin/e2e/list-view/e2e.spec.ts index 796a21b3c8..567a7fdfd7 100644 --- a/test/admin/e2e/list-view/e2e.spec.ts +++ b/test/admin/e2e/list-view/e2e.spec.ts @@ -413,6 +413,7 @@ describe('List View', () => { await expect(whereBuilder.locator('.condition__value input')).toHaveValue('') }) + // eslint-disable-next-line playwright/expect-expect test('should remove condition from URL when value is cleared', async () => { await page.goto(postsUrl.list) @@ -1285,6 +1286,31 @@ describe('List View', () => { await expect(page.locator('#heading-_status')).toBeVisible() await expect(page.locator('.cell-_status').first()).toBeVisible() + await toggleColumn(page, { + columnLabel: 'Wavelengths', + targetState: 'on', + columnName: 'wavelengths', + }) + + await toggleColumn(page, { + columnLabel: 'Select Field', + targetState: 'on', + columnName: 'selectField', + }) + + // check that the cells have the classes added per value selected + await expect( + page.locator('.cell-_status').first().locator("[class*='selected--']"), + ).toBeVisible() + + await expect( + page.locator('.cell-wavelengths').first().locator("[class*='selected--']"), + ).toBeVisible() + + await expect( + page.locator('.cell-selectField').first().locator("[class*='selected--']"), + ).toBeVisible() + // sort by title again in descending order await page.locator('#heading-title button.sort-column__desc').click() await page.waitForURL(/sort=-title/) From 59c9feeb456cd4d06ebc8706a64e75c0ddf72782 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Wed, 26 Mar 2025 14:52:53 -0600 Subject: [PATCH 27/77] templates: pin all payload packages, improve gen-templates script (#11841) This PR comes with a bunch of improvements to our template generation script that makes it safer and more reliable - bumps all our templates - Using `latest` as payload version in our templates has proven to be unreliable. This updates the gen-templates script to pin all payload packages to the latest version - adds the missing `website` entry for our template variations, thus ensuring its lockfile gets updated - adds importmap generation to the gen-templates script - adds new `script:gen-templates:build` script to verify that all templates still build correctly --- package.json | 1 + templates/blank/package.json | 10 +- templates/blank/pnpm-lock.yaml | 5071 ++++++++++---- templates/website/package.json | 26 +- templates/website/pnpm-lock.yaml | 5991 ++++++++++++----- templates/with-postgres/package.json | 10 +- ...tial.json => 20250326_181533_initial.json} | 2 +- ..._initial.ts => 20250326_181533_initial.ts} | 0 .../with-postgres/src/migrations/index.ts | 8 +- templates/with-postgres/src/payload-types.ts | 1 + templates/with-vercel-mongodb/package.json | 12 +- .../src/app/(payload)/admin/importMap.js | 7 +- templates/with-vercel-postgres/package.json | 12 +- .../src/app/(payload)/admin/importMap.js | 7 +- ...tial.json => 20250326_181520_initial.json} | 2 +- ..._initial.ts => 20250326_181520_initial.ts} | 0 .../src/migrations/index.ts | 8 +- .../with-vercel-postgres/src/payload-types.ts | 1 + templates/with-vercel-website/package.json | 28 +- .../src/components/Media/ImageMedia/index.tsx | 3 +- .../src/components/Media/types.ts | 1 + ...tial.json => 20250326_181527_initial.json} | 8 +- ..._initial.ts => 20250326_181527_initial.ts} | 1 + .../src/migrations/index.ts | 8 +- .../with-vercel-website/src/payload-types.ts | 3 + .../src/generate-template-variations.ts | 144 +- 26 files changed, 8383 insertions(+), 2982 deletions(-) rename templates/with-postgres/src/migrations/{20250311_214602_initial.json => 20250326_181533_initial.json} (99%) rename templates/with-postgres/src/migrations/{20250311_214602_initial.ts => 20250326_181533_initial.ts} (100%) rename templates/with-vercel-postgres/src/migrations/{20250311_214549_initial.json => 20250326_181520_initial.json} (99%) rename templates/with-vercel-postgres/src/migrations/{20250311_214549_initial.ts => 20250326_181520_initial.ts} (100%) rename templates/with-vercel-website/src/migrations/{20250311_214555_initial.json => 20250326_181527_initial.json} (99%) rename templates/with-vercel-website/src/migrations/{20250311_214555_initial.ts => 20250326_181527_initial.ts} (99%) diff --git a/package.json b/package.json index 934cf39f07..9e53ddbf75 100644 --- a/package.json +++ b/package.json @@ -87,6 +87,7 @@ "runts": "cross-env NODE_OPTIONS=--no-deprecation node --no-deprecation --import @swc-node/register/esm-register", "script:build-template-with-local-pkgs": "pnpm --filter scripts build-template-with-local-pkgs", "script:gen-templates": "pnpm --filter scripts gen-templates", + "script:gen-templates:build": "pnpm --filter scripts gen-templates --build", "script:license-check": "pnpm --filter scripts license-check", "script:list-published": "pnpm --filter releaser list-published", "script:pack": "pnpm --filter scripts pack-all-to-dest", diff --git a/templates/blank/package.json b/templates/blank/package.json index 8e58189ad8..e64e871add 100644 --- a/templates/blank/package.json +++ b/templates/blank/package.json @@ -15,14 +15,14 @@ "start": "cross-env NODE_OPTIONS=--no-deprecation next start" }, "dependencies": { - "@payloadcms/db-mongodb": "latest", - "@payloadcms/next": "latest", - "@payloadcms/payload-cloud": "latest", - "@payloadcms/richtext-lexical": "latest", + "@payloadcms/db-mongodb": "3.31.0", + "@payloadcms/next": "3.31.0", + "@payloadcms/payload-cloud": "3.31.0", + "@payloadcms/richtext-lexical": "3.31.0", "cross-env": "^7.0.3", "graphql": "^16.8.1", "next": "15.2.3", - "payload": "latest", + "payload": "3.31.0", "react": "19.0.0", "react-dom": "19.0.0", "sharp": "0.32.6" diff --git a/templates/blank/pnpm-lock.yaml b/templates/blank/pnpm-lock.yaml index 2ac66eb723..df59a7a2f9 100644 --- a/templates/blank/pnpm-lock.yaml +++ b/templates/blank/pnpm-lock.yaml @@ -5,21 +5,20 @@ settings: excludeLinksFromLockfile: false importers: - .: dependencies: '@payloadcms/db-mongodb': - specifier: latest - version: 3.29.0(@aws-sdk/credential-providers@3.772.0)(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3)) + specifier: 3.31.0 + version: 3.31.0(@aws-sdk/credential-providers@3.772.0)(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3)) '@payloadcms/next': - specifier: latest - version: 3.29.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + specifier: 3.31.0 + version: 3.31.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) '@payloadcms/payload-cloud': - specifier: latest - version: 3.29.0(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3)) + specifier: 3.31.0 + version: 3.31.0(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3)) '@payloadcms/richtext-lexical': - specifier: latest - version: 3.29.0(@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@faceless-ui/scroll-info@2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@payloadcms/next@3.29.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3))(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)(yjs@13.6.24) + specifier: 3.31.0 + version: 3.31.0(@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@faceless-ui/scroll-info@2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@payloadcms/next@3.31.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3))(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)(yjs@13.6.24) cross-env: specifier: ^7.0.3 version: 7.0.3 @@ -30,8 +29,8 @@ importers: specifier: 15.2.3 version: 15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) payload: - specifier: latest - version: 3.29.0(graphql@16.10.0)(typescript@5.7.3) + specifier: 3.31.0 + version: 3.31.0(graphql@16.10.0)(typescript@5.7.3) react: specifier: 19.0.0 version: 19.0.0 @@ -68,176 +67,307 @@ importers: version: 5.7.3 packages: - '@apidevtools/json-schema-ref-parser@11.9.3': - resolution: {integrity: sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==} - engines: {node: '>= 16'} + resolution: + { + integrity: sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==, + } + engines: { node: '>= 16' } '@aws-crypto/crc32@5.2.0': - resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} - engines: {node: '>=16.0.0'} + resolution: + { + integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==, + } + engines: { node: '>=16.0.0' } '@aws-crypto/crc32c@5.2.0': - resolution: {integrity: sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==} + resolution: + { + integrity: sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==, + } '@aws-crypto/sha1-browser@5.2.0': - resolution: {integrity: sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==} + resolution: + { + integrity: sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==, + } '@aws-crypto/sha256-browser@5.2.0': - resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + resolution: + { + integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==, + } '@aws-crypto/sha256-js@1.2.2': - resolution: {integrity: sha512-Nr1QJIbW/afYYGzYvrF70LtaHrIRtd4TNAglX8BvlfxJLZ45SAmueIKYl5tWoNBPzp65ymXGFK0Bb1vZUpuc9g==} + resolution: + { + integrity: sha512-Nr1QJIbW/afYYGzYvrF70LtaHrIRtd4TNAglX8BvlfxJLZ45SAmueIKYl5tWoNBPzp65ymXGFK0Bb1vZUpuc9g==, + } '@aws-crypto/sha256-js@5.2.0': - resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} - engines: {node: '>=16.0.0'} + resolution: + { + integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==, + } + engines: { node: '>=16.0.0' } '@aws-crypto/supports-web-crypto@5.2.0': - resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + resolution: + { + integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==, + } '@aws-crypto/util@1.2.2': - resolution: {integrity: sha512-H8PjG5WJ4wz0UXAFXeJjWCW1vkvIJ3qUUD+rGRwJ2/hj+xT58Qle2MTql/2MGzkU+1JLAFuR6aJpLAjHwhmwwg==} + resolution: + { + integrity: sha512-H8PjG5WJ4wz0UXAFXeJjWCW1vkvIJ3qUUD+rGRwJ2/hj+xT58Qle2MTql/2MGzkU+1JLAFuR6aJpLAjHwhmwwg==, + } '@aws-crypto/util@5.2.0': - resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + resolution: + { + integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==, + } '@aws-sdk/client-cognito-identity@3.772.0': - resolution: {integrity: sha512-R11dYd2NGAH9TDRUJHd3Ab3HZzSoyqwQu+ZR9MZdcA2l3k99mqsrvcLp60YBPGq1dOEQDB1A85xgrAwtWLj81Q==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-R11dYd2NGAH9TDRUJHd3Ab3HZzSoyqwQu+ZR9MZdcA2l3k99mqsrvcLp60YBPGq1dOEQDB1A85xgrAwtWLj81Q==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/client-s3@3.772.0': - resolution: {integrity: sha512-HQXlQIyyLp47h1/Hdjr36yK8/gsAAFX2vRzgDJhSRaz0vWZlWX07AJdYfrxapLUXfVU6DbBu3rwi2UGqM7ixqQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-HQXlQIyyLp47h1/Hdjr36yK8/gsAAFX2vRzgDJhSRaz0vWZlWX07AJdYfrxapLUXfVU6DbBu3rwi2UGqM7ixqQ==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/client-sso@3.772.0': - resolution: {integrity: sha512-sDdxepi74+cL6gXJJ2yw3UNSI7GBvoGTwZqFyPoNAzcURvaYwo8dBr7G4jS9GDanjTlO3CGVAf2VMcpqEvmoEw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-sDdxepi74+cL6gXJJ2yw3UNSI7GBvoGTwZqFyPoNAzcURvaYwo8dBr7G4jS9GDanjTlO3CGVAf2VMcpqEvmoEw==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/core@3.758.0': - resolution: {integrity: sha512-0RswbdR9jt/XKemaLNuxi2gGr4xGlHyGxkTdhSQzCyUe9A9OPCoLl3rIESRguQEech+oJnbHk/wuiwHqTuP9sg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-0RswbdR9jt/XKemaLNuxi2gGr4xGlHyGxkTdhSQzCyUe9A9OPCoLl3rIESRguQEech+oJnbHk/wuiwHqTuP9sg==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/credential-provider-cognito-identity@3.772.0': - resolution: {integrity: sha512-rgGCB7+ttlOvuFjz016WVF0m1zDQNakreXVGmlqxKUHTgAkbXulbzcCnZt44S7QGP6V1ElbRB4jI7piRFirdwg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-rgGCB7+ttlOvuFjz016WVF0m1zDQNakreXVGmlqxKUHTgAkbXulbzcCnZt44S7QGP6V1ElbRB4jI7piRFirdwg==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/credential-provider-env@3.758.0': - resolution: {integrity: sha512-N27eFoRrO6MeUNumtNHDW9WOiwfd59LPXPqDrIa3kWL/s+fOKFHb9xIcF++bAwtcZnAxKkgpDCUP+INNZskE+w==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-N27eFoRrO6MeUNumtNHDW9WOiwfd59LPXPqDrIa3kWL/s+fOKFHb9xIcF++bAwtcZnAxKkgpDCUP+INNZskE+w==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/credential-provider-http@3.758.0': - resolution: {integrity: sha512-Xt9/U8qUCiw1hihztWkNeIR+arg6P+yda10OuCHX6kFVx3auTlU7+hCqs3UxqniGU4dguHuftf3mRpi5/GJ33Q==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-Xt9/U8qUCiw1hihztWkNeIR+arg6P+yda10OuCHX6kFVx3auTlU7+hCqs3UxqniGU4dguHuftf3mRpi5/GJ33Q==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/credential-provider-ini@3.772.0': - resolution: {integrity: sha512-T1Ec9Q25zl5c/eZUPHZsiq8vgBeWBjHM7WM5xtZszZRPqqhQGnmFlomz1r9rwhW8RFB5k8HRaD/SLKo6jtYl/A==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-T1Ec9Q25zl5c/eZUPHZsiq8vgBeWBjHM7WM5xtZszZRPqqhQGnmFlomz1r9rwhW8RFB5k8HRaD/SLKo6jtYl/A==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/credential-provider-node@3.772.0': - resolution: {integrity: sha512-0IdVfjBO88Mtekq/KaScYSIEPIeR+ABRvBOWyj/c/qQ2KJyI0GRlSAzpANfxDLHVPn3yEHuZd9nRL6sOmOMI0A==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-0IdVfjBO88Mtekq/KaScYSIEPIeR+ABRvBOWyj/c/qQ2KJyI0GRlSAzpANfxDLHVPn3yEHuZd9nRL6sOmOMI0A==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/credential-provider-process@3.758.0': - resolution: {integrity: sha512-AzcY74QTPqcbXWVgjpPZ3HOmxQZYPROIBz2YINF0OQk0MhezDWV/O7Xec+K1+MPGQO3qS6EDrUUlnPLjsqieHA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-AzcY74QTPqcbXWVgjpPZ3HOmxQZYPROIBz2YINF0OQk0MhezDWV/O7Xec+K1+MPGQO3qS6EDrUUlnPLjsqieHA==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/credential-provider-sso@3.772.0': - resolution: {integrity: sha512-yR3Y5RAVPa4ogojcBOpZUx6XyRVAkynIJCjd0avdlxW1hhnzSr5/pzoiJ6u21UCbkxlJJTDZE3jfFe7tt+HA4w==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-yR3Y5RAVPa4ogojcBOpZUx6XyRVAkynIJCjd0avdlxW1hhnzSr5/pzoiJ6u21UCbkxlJJTDZE3jfFe7tt+HA4w==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/credential-provider-web-identity@3.772.0': - resolution: {integrity: sha512-yHAT5Y2y0fnecSuWRUn8NMunKfDqFYhnOpGq8UyCEcwz9aXzibU0hqRIEm51qpR81hqo0GMFDH0EOmegZ/iW5w==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-yHAT5Y2y0fnecSuWRUn8NMunKfDqFYhnOpGq8UyCEcwz9aXzibU0hqRIEm51qpR81hqo0GMFDH0EOmegZ/iW5w==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/credential-providers@3.772.0': - resolution: {integrity: sha512-+gOrzw05jNVSHFBTZ+LOaGQZ0IXT95aQjNUeWqYXzdgjxKXptrhuMnFLwBBliLbHPp8ziauRnnwG8aK58LOUlg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-+gOrzw05jNVSHFBTZ+LOaGQZ0IXT95aQjNUeWqYXzdgjxKXptrhuMnFLwBBliLbHPp8ziauRnnwG8aK58LOUlg==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/lib-storage@3.772.0': - resolution: {integrity: sha512-d59NJAHDa7mGf82ApOdIp1FsN1i7/VlNTk2t3NIepH/8FsMTzKPZQvbMzqE33ba4oik7y6QrDliYXoRXB/nZPg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-d59NJAHDa7mGf82ApOdIp1FsN1i7/VlNTk2t3NIepH/8FsMTzKPZQvbMzqE33ba4oik7y6QrDliYXoRXB/nZPg==, + } + engines: { node: '>=18.0.0' } peerDependencies: '@aws-sdk/client-s3': ^3.772.0 '@aws-sdk/middleware-bucket-endpoint@3.734.0': - resolution: {integrity: sha512-etC7G18aF7KdZguW27GE/wpbrNmYLVT755EsFc8kXpZj8D6AFKxc7OuveinJmiy0bYXAMspJUWsF6CrGpOw6CQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-etC7G18aF7KdZguW27GE/wpbrNmYLVT755EsFc8kXpZj8D6AFKxc7OuveinJmiy0bYXAMspJUWsF6CrGpOw6CQ==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/middleware-expect-continue@3.734.0': - resolution: {integrity: sha512-P38/v1l6HjuB2aFUewt7ueAW5IvKkFcv5dalPtbMGRhLeyivBOHwbCyuRKgVs7z7ClTpu9EaViEGki2jEQqEsQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-P38/v1l6HjuB2aFUewt7ueAW5IvKkFcv5dalPtbMGRhLeyivBOHwbCyuRKgVs7z7ClTpu9EaViEGki2jEQqEsQ==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/middleware-flexible-checksums@3.758.0': - resolution: {integrity: sha512-o8Rk71S08YTKLoSobucjnbj97OCGaXgpEDNKXpXaavUM5xLNoHCLSUPRCiEN86Ivqxg1n17Y2nSRhfbsveOXXA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-o8Rk71S08YTKLoSobucjnbj97OCGaXgpEDNKXpXaavUM5xLNoHCLSUPRCiEN86Ivqxg1n17Y2nSRhfbsveOXXA==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/middleware-host-header@3.734.0': - resolution: {integrity: sha512-LW7RRgSOHHBzWZnigNsDIzu3AiwtjeI2X66v+Wn1P1u+eXssy1+up4ZY/h+t2sU4LU36UvEf+jrZti9c6vRnFw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-LW7RRgSOHHBzWZnigNsDIzu3AiwtjeI2X66v+Wn1P1u+eXssy1+up4ZY/h+t2sU4LU36UvEf+jrZti9c6vRnFw==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/middleware-location-constraint@3.734.0': - resolution: {integrity: sha512-EJEIXwCQhto/cBfHdm3ZOeLxd2NlJD+X2F+ZTOxzokuhBtY0IONfC/91hOo5tWQweerojwshSMHRCKzRv1tlwg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-EJEIXwCQhto/cBfHdm3ZOeLxd2NlJD+X2F+ZTOxzokuhBtY0IONfC/91hOo5tWQweerojwshSMHRCKzRv1tlwg==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/middleware-logger@3.734.0': - resolution: {integrity: sha512-mUMFITpJUW3LcKvFok176eI5zXAUomVtahb9IQBwLzkqFYOrMJvWAvoV4yuxrJ8TlQBG8gyEnkb9SnhZvjg67w==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-mUMFITpJUW3LcKvFok176eI5zXAUomVtahb9IQBwLzkqFYOrMJvWAvoV4yuxrJ8TlQBG8gyEnkb9SnhZvjg67w==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/middleware-recursion-detection@3.772.0': - resolution: {integrity: sha512-zg0LjJa4v7fcLzn5QzZvtVS+qyvmsnu7oQnb86l6ckduZpWDCDC9+A0ZzcXTrxblPCJd3JqkoG1+Gzi4S4Ny/Q==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-zg0LjJa4v7fcLzn5QzZvtVS+qyvmsnu7oQnb86l6ckduZpWDCDC9+A0ZzcXTrxblPCJd3JqkoG1+Gzi4S4Ny/Q==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/middleware-sdk-s3@3.758.0': - resolution: {integrity: sha512-6mJ2zyyHPYSV6bAcaFpsdoXZJeQlR1QgBnZZ6juY/+dcYiuyWCdyLUbGzSZSE7GTfx6i+9+QWFeoIMlWKgU63A==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-6mJ2zyyHPYSV6bAcaFpsdoXZJeQlR1QgBnZZ6juY/+dcYiuyWCdyLUbGzSZSE7GTfx6i+9+QWFeoIMlWKgU63A==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/middleware-ssec@3.734.0': - resolution: {integrity: sha512-d4yd1RrPW/sspEXizq2NSOUivnheac6LPeLSLnaeTbBG9g1KqIqvCzP1TfXEqv2CrWfHEsWtJpX7oyjySSPvDQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-d4yd1RrPW/sspEXizq2NSOUivnheac6LPeLSLnaeTbBG9g1KqIqvCzP1TfXEqv2CrWfHEsWtJpX7oyjySSPvDQ==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/middleware-user-agent@3.758.0': - resolution: {integrity: sha512-iNyehQXtQlj69JCgfaOssgZD4HeYGOwxcaKeG6F+40cwBjTAi0+Ph1yfDwqk2qiBPIRWJ/9l2LodZbxiBqgrwg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-iNyehQXtQlj69JCgfaOssgZD4HeYGOwxcaKeG6F+40cwBjTAi0+Ph1yfDwqk2qiBPIRWJ/9l2LodZbxiBqgrwg==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/nested-clients@3.772.0': - resolution: {integrity: sha512-gNJbBxR5YlEumsCS9EWWEASXEnysL0aDnr9MNPX1ip/g1xOqRHmytgV/+t8RFZFTKg0OprbWTq5Ich3MqsEuCQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-gNJbBxR5YlEumsCS9EWWEASXEnysL0aDnr9MNPX1ip/g1xOqRHmytgV/+t8RFZFTKg0OprbWTq5Ich3MqsEuCQ==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/region-config-resolver@3.734.0': - resolution: {integrity: sha512-Lvj1kPRC5IuJBr9DyJ9T9/plkh+EfKLy+12s/mykOy1JaKHDpvj+XGy2YO6YgYVOb8JFtaqloid+5COtje4JTQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-Lvj1kPRC5IuJBr9DyJ9T9/plkh+EfKLy+12s/mykOy1JaKHDpvj+XGy2YO6YgYVOb8JFtaqloid+5COtje4JTQ==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/signature-v4-multi-region@3.758.0': - resolution: {integrity: sha512-0RPCo8fYJcrenJ6bRtiUbFOSgQ1CX/GpvwtLU2Fam1tS9h2klKK8d74caeV6A1mIUvBU7bhyQ0wMGlwMtn3EYw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-0RPCo8fYJcrenJ6bRtiUbFOSgQ1CX/GpvwtLU2Fam1tS9h2klKK8d74caeV6A1mIUvBU7bhyQ0wMGlwMtn3EYw==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/token-providers@3.772.0': - resolution: {integrity: sha512-d1Waa1vyebuokcAWYlkZdtFlciIgob7B39vPRmtxMObbGumJKiOy/qCe2/FB/72h1Ej9Ih32lwvbxUjORQWN4g==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-d1Waa1vyebuokcAWYlkZdtFlciIgob7B39vPRmtxMObbGumJKiOy/qCe2/FB/72h1Ej9Ih32lwvbxUjORQWN4g==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/types@3.734.0': - resolution: {integrity: sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/util-arn-parser@3.723.0': - resolution: {integrity: sha512-ZhEfvUwNliOQROcAk34WJWVYTlTa4694kSVhDSjW6lE1bMataPnIN8A0ycukEzBXmd8ZSoBcQLn6lKGl7XIJ5w==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-ZhEfvUwNliOQROcAk34WJWVYTlTa4694kSVhDSjW6lE1bMataPnIN8A0ycukEzBXmd8ZSoBcQLn6lKGl7XIJ5w==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/util-endpoints@3.743.0': - resolution: {integrity: sha512-sN1l559zrixeh5x+pttrnd0A3+r34r0tmPkJ/eaaMaAzXqsmKU/xYre9K3FNnsSS1J1k4PEfk/nHDTVUgFYjnw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-sN1l559zrixeh5x+pttrnd0A3+r34r0tmPkJ/eaaMaAzXqsmKU/xYre9K3FNnsSS1J1k4PEfk/nHDTVUgFYjnw==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/util-locate-window@3.723.0': - resolution: {integrity: sha512-Yf2CS10BqK688DRsrKI/EO6B8ff5J86NXe4C+VCysK7UOgN0l1zOTeTukZ3H8Q9tYYX3oaF1961o8vRkFm7Nmw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-Yf2CS10BqK688DRsrKI/EO6B8ff5J86NXe4C+VCysK7UOgN0l1zOTeTukZ3H8Q9tYYX3oaF1961o8vRkFm7Nmw==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/util-user-agent-browser@3.734.0': - resolution: {integrity: sha512-xQTCus6Q9LwUuALW+S76OL0jcWtMOVu14q+GoLnWPUM7QeUw963oQcLhF7oq0CtaLLKyl4GOUfcwc773Zmwwng==} + resolution: + { + integrity: sha512-xQTCus6Q9LwUuALW+S76OL0jcWtMOVu14q+GoLnWPUM7QeUw963oQcLhF7oq0CtaLLKyl4GOUfcwc773Zmwwng==, + } '@aws-sdk/util-user-agent-node@3.758.0': - resolution: {integrity: sha512-A5EZw85V6WhoKMV2hbuFRvb9NPlxEErb4HPO6/SPXYY4QrjprIzScHxikqcWv1w4J3apB1wto9LPU3IMsYtfrw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-A5EZw85V6WhoKMV2hbuFRvb9NPlxEErb4HPO6/SPXYY4QrjprIzScHxikqcWv1w4J3apB1wto9LPU3IMsYtfrw==, + } + engines: { node: '>=18.0.0' } peerDependencies: aws-crt: '>=1.0.0' peerDependenciesMeta: @@ -245,104 +375,182 @@ packages: optional: true '@aws-sdk/util-utf8-browser@3.259.0': - resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} + resolution: + { + integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==, + } '@aws-sdk/xml-builder@3.734.0': - resolution: {integrity: sha512-Zrjxi5qwGEcUsJ0ru7fRtW74WcTS0rbLcehoFB+rN1GRi2hbLcFaYs4PwVA5diLeAJH0gszv3x4Hr/S87MfbKQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-Zrjxi5qwGEcUsJ0ru7fRtW74WcTS0rbLcehoFB+rN1GRi2hbLcFaYs4PwVA5diLeAJH0gszv3x4Hr/S87MfbKQ==, + } + engines: { node: '>=18.0.0' } '@babel/code-frame@7.26.2': - resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} - engines: {node: '>=6.9.0'} + resolution: + { + integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==, + } + engines: { node: '>=6.9.0' } '@babel/generator@7.26.10': - resolution: {integrity: sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==} - engines: {node: '>=6.9.0'} + resolution: + { + integrity: sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==, + } + engines: { node: '>=6.9.0' } '@babel/helper-module-imports@7.25.9': - resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} - engines: {node: '>=6.9.0'} + resolution: + { + integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==, + } + engines: { node: '>=6.9.0' } '@babel/helper-string-parser@7.25.9': - resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} - engines: {node: '>=6.9.0'} + resolution: + { + integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==, + } + engines: { node: '>=6.9.0' } '@babel/helper-validator-identifier@7.25.9': - resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} - engines: {node: '>=6.9.0'} + resolution: + { + integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==, + } + engines: { node: '>=6.9.0' } '@babel/parser@7.26.10': - resolution: {integrity: sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==} - engines: {node: '>=6.0.0'} + resolution: + { + integrity: sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==, + } + engines: { node: '>=6.0.0' } hasBin: true '@babel/runtime@7.26.10': - resolution: {integrity: sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==} - engines: {node: '>=6.9.0'} + resolution: + { + integrity: sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==, + } + engines: { node: '>=6.9.0' } '@babel/template@7.26.9': - resolution: {integrity: sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==} - engines: {node: '>=6.9.0'} + resolution: + { + integrity: sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==, + } + engines: { node: '>=6.9.0' } '@babel/traverse@7.26.10': - resolution: {integrity: sha512-k8NuDrxr0WrPH5Aupqb2LCVURP/S0vBEn5mK6iH+GIYob66U5EtoZvcdudR2jQ4cmTwhEwW1DLB+Yyas9zjF6A==} - engines: {node: '>=6.9.0'} + resolution: + { + integrity: sha512-k8NuDrxr0WrPH5Aupqb2LCVURP/S0vBEn5mK6iH+GIYob66U5EtoZvcdudR2jQ4cmTwhEwW1DLB+Yyas9zjF6A==, + } + engines: { node: '>=6.9.0' } '@babel/types@7.26.10': - resolution: {integrity: sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==} - engines: {node: '>=6.9.0'} + resolution: + { + integrity: sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==, + } + engines: { node: '>=6.9.0' } '@date-fns/tz@1.2.0': - resolution: {integrity: sha512-LBrd7MiJZ9McsOgxqWX7AaxrDjcFVjWH/tIKJd7pnR7McaslGYOP1QmmiBXdJH/H/yLCT+rcQ7FaPBUxRGUtrg==} + resolution: + { + integrity: sha512-LBrd7MiJZ9McsOgxqWX7AaxrDjcFVjWH/tIKJd7pnR7McaslGYOP1QmmiBXdJH/H/yLCT+rcQ7FaPBUxRGUtrg==, + } '@dnd-kit/accessibility@3.1.1': - resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==} + resolution: + { + integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==, + } peerDependencies: react: '>=16.8.0' '@dnd-kit/core@6.0.8': - resolution: {integrity: sha512-lYaoP8yHTQSLlZe6Rr9qogouGUz9oRUj4AHhDQGQzq/hqaJRpFo65X+JKsdHf8oUFBzx5A+SJPUvxAwTF2OabA==} + resolution: + { + integrity: sha512-lYaoP8yHTQSLlZe6Rr9qogouGUz9oRUj4AHhDQGQzq/hqaJRpFo65X+JKsdHf8oUFBzx5A+SJPUvxAwTF2OabA==, + } peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' '@dnd-kit/sortable@7.0.2': - resolution: {integrity: sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==} + resolution: + { + integrity: sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==, + } peerDependencies: '@dnd-kit/core': ^6.0.7 react: '>=16.8.0' '@dnd-kit/utilities@3.2.2': - resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==} + resolution: + { + integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==, + } peerDependencies: react: '>=16.8.0' '@emnapi/core@1.3.1': - resolution: {integrity: sha512-pVGjBIt1Y6gg3EJN8jTcfpP/+uuRksIo055oE/OBkDNcjZqVbfkWCksG1Jp4yZnj3iKWyWX8fdG/j6UDYPbFog==} + resolution: + { + integrity: sha512-pVGjBIt1Y6gg3EJN8jTcfpP/+uuRksIo055oE/OBkDNcjZqVbfkWCksG1Jp4yZnj3iKWyWX8fdG/j6UDYPbFog==, + } '@emnapi/runtime@1.3.1': - resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} + resolution: + { + integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==, + } '@emnapi/wasi-threads@1.0.1': - resolution: {integrity: sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==} + resolution: + { + integrity: sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==, + } '@emotion/babel-plugin@11.13.5': - resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} + resolution: + { + integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==, + } '@emotion/cache@11.14.0': - resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==} + resolution: + { + integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==, + } '@emotion/css@11.13.5': - resolution: {integrity: sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w==} + resolution: + { + integrity: sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w==, + } '@emotion/hash@0.9.2': - resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + resolution: + { + integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==, + } '@emotion/memoize@0.9.0': - resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} + resolution: + { + integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==, + } '@emotion/react@11.14.0': - resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==} + resolution: + { + integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==, + } peerDependencies: '@types/react': '*' react: '>=16.8.0' @@ -351,1125 +559,1893 @@ packages: optional: true '@emotion/serialize@1.3.3': - resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==} + resolution: + { + integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==, + } '@emotion/sheet@1.4.0': - resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==} + resolution: + { + integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==, + } '@emotion/unitless@0.10.0': - resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} + resolution: + { + integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==, + } '@emotion/use-insertion-effect-with-fallbacks@1.2.0': - resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==} + resolution: + { + integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==, + } peerDependencies: react: '>=16.8.0' '@emotion/utils@1.4.2': - resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==} + resolution: + { + integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==, + } '@emotion/weak-memoize@0.4.0': - resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} + resolution: + { + integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==, + } '@esbuild/aix-ppc64@0.23.1': - resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==, + } + engines: { node: '>=18' } cpu: [ppc64] os: [aix] '@esbuild/android-arm64@0.23.1': - resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==, + } + engines: { node: '>=18' } cpu: [arm64] os: [android] '@esbuild/android-arm@0.23.1': - resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==, + } + engines: { node: '>=18' } cpu: [arm] os: [android] '@esbuild/android-x64@0.23.1': - resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==, + } + engines: { node: '>=18' } cpu: [x64] os: [android] '@esbuild/darwin-arm64@0.23.1': - resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==, + } + engines: { node: '>=18' } cpu: [arm64] os: [darwin] '@esbuild/darwin-x64@0.23.1': - resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==, + } + engines: { node: '>=18' } cpu: [x64] os: [darwin] '@esbuild/freebsd-arm64@0.23.1': - resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==, + } + engines: { node: '>=18' } cpu: [arm64] os: [freebsd] '@esbuild/freebsd-x64@0.23.1': - resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==, + } + engines: { node: '>=18' } cpu: [x64] os: [freebsd] '@esbuild/linux-arm64@0.23.1': - resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==, + } + engines: { node: '>=18' } cpu: [arm64] os: [linux] '@esbuild/linux-arm@0.23.1': - resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==, + } + engines: { node: '>=18' } cpu: [arm] os: [linux] '@esbuild/linux-ia32@0.23.1': - resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==, + } + engines: { node: '>=18' } cpu: [ia32] os: [linux] '@esbuild/linux-loong64@0.23.1': - resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==, + } + engines: { node: '>=18' } cpu: [loong64] os: [linux] '@esbuild/linux-mips64el@0.23.1': - resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==, + } + engines: { node: '>=18' } cpu: [mips64el] os: [linux] '@esbuild/linux-ppc64@0.23.1': - resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==, + } + engines: { node: '>=18' } cpu: [ppc64] os: [linux] '@esbuild/linux-riscv64@0.23.1': - resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==, + } + engines: { node: '>=18' } cpu: [riscv64] os: [linux] '@esbuild/linux-s390x@0.23.1': - resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==, + } + engines: { node: '>=18' } cpu: [s390x] os: [linux] '@esbuild/linux-x64@0.23.1': - resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==, + } + engines: { node: '>=18' } cpu: [x64] os: [linux] '@esbuild/netbsd-x64@0.23.1': - resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==, + } + engines: { node: '>=18' } cpu: [x64] os: [netbsd] '@esbuild/openbsd-arm64@0.23.1': - resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==, + } + engines: { node: '>=18' } cpu: [arm64] os: [openbsd] '@esbuild/openbsd-x64@0.23.1': - resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==, + } + engines: { node: '>=18' } cpu: [x64] os: [openbsd] '@esbuild/sunos-x64@0.23.1': - resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==, + } + engines: { node: '>=18' } cpu: [x64] os: [sunos] '@esbuild/win32-arm64@0.23.1': - resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==, + } + engines: { node: '>=18' } cpu: [arm64] os: [win32] '@esbuild/win32-ia32@0.23.1': - resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==, + } + engines: { node: '>=18' } cpu: [ia32] os: [win32] '@esbuild/win32-x64@0.23.1': - resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==, + } + engines: { node: '>=18' } cpu: [x64] os: [win32] '@eslint-community/eslint-utils@4.5.1': - resolution: {integrity: sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + resolution: + { + integrity: sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 '@eslint-community/regexpp@4.12.1': - resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + resolution: + { + integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==, + } + engines: { node: ^12.0.0 || ^14.0.0 || >=16.0.0 } '@eslint/config-array@0.19.2': - resolution: {integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } '@eslint/config-helpers@0.2.0': - resolution: {integrity: sha512-yJLLmLexii32mGrhW29qvU3QBVTu0GUmEf/J4XsBtVhp4JkIUFN/BjWqTF63yRvGApIDpZm5fa97LtYtINmfeQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-yJLLmLexii32mGrhW29qvU3QBVTu0GUmEf/J4XsBtVhp4JkIUFN/BjWqTF63yRvGApIDpZm5fa97LtYtINmfeQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } '@eslint/core@0.12.0': - resolution: {integrity: sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } '@eslint/eslintrc@3.3.1': - resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } '@eslint/js@9.23.0': - resolution: {integrity: sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } '@eslint/object-schema@2.1.6': - resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } '@eslint/plugin-kit@0.2.7': - resolution: {integrity: sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } '@faceless-ui/modal@3.0.0-beta.2': - resolution: {integrity: sha512-UmXvz7Iw3KMO4Pm3llZczU4uc5pPQDb6rdqwoBvYDFgWvkraOAHKx0HxSZgwqQvqOhn8joEFBfFp6/Do2562ow==} + resolution: + { + integrity: sha512-UmXvz7Iw3KMO4Pm3llZczU4uc5pPQDb6rdqwoBvYDFgWvkraOAHKx0HxSZgwqQvqOhn8joEFBfFp6/Do2562ow==, + } peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 '@faceless-ui/scroll-info@2.0.0': - resolution: {integrity: sha512-BkyJ9OQ4bzpKjE3UhI8BhcG36ZgfB4run8TmlaR4oMFUbl59dfyarNfjveyimrxIso9RhFEja/AJ5nQmbcR9hw==} + resolution: + { + integrity: sha512-BkyJ9OQ4bzpKjE3UhI8BhcG36ZgfB4run8TmlaR4oMFUbl59dfyarNfjveyimrxIso9RhFEja/AJ5nQmbcR9hw==, + } peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 '@faceless-ui/window-info@3.0.1': - resolution: {integrity: sha512-uPjdJYE/j7hqVNelE9CRUNOeXuXDdPxR4DMe+oz3xwyZi2Y4CxsfpfdPTqqwmNAZa1P33O+ZiCyIkBEeNed0kw==} + resolution: + { + integrity: sha512-uPjdJYE/j7hqVNelE9CRUNOeXuXDdPxR4DMe+oz3xwyZi2Y4CxsfpfdPTqqwmNAZa1P33O+ZiCyIkBEeNed0kw==, + } peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 '@floating-ui/core@1.6.9': - resolution: {integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==} + resolution: + { + integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==, + } '@floating-ui/dom@1.6.13': - resolution: {integrity: sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==} + resolution: + { + integrity: sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==, + } '@floating-ui/react-dom@2.1.2': - resolution: {integrity: sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==} + resolution: + { + integrity: sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==, + } peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' '@floating-ui/react@0.27.5': - resolution: {integrity: sha512-BX3jKxo39Ba05pflcQmqPPwc0qdNsdNi/eweAFtoIdrJWNen2sVEWMEac3i6jU55Qfx+lOcdMNKYn2CtWmlnOQ==} + resolution: + { + integrity: sha512-BX3jKxo39Ba05pflcQmqPPwc0qdNsdNi/eweAFtoIdrJWNen2sVEWMEac3i6jU55Qfx+lOcdMNKYn2CtWmlnOQ==, + } peerDependencies: react: '>=17.0.0' react-dom: '>=17.0.0' '@floating-ui/utils@0.2.9': - resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} + resolution: + { + integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==, + } '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} - engines: {node: '>=18.18.0'} + resolution: + { + integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==, + } + engines: { node: '>=18.18.0' } '@humanfs/node@0.16.6': - resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} - engines: {node: '>=18.18.0'} + resolution: + { + integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==, + } + engines: { node: '>=18.18.0' } '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} + resolution: + { + integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==, + } + engines: { node: '>=12.22' } '@humanwhocodes/retry@0.3.1': - resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} - engines: {node: '>=18.18'} + resolution: + { + integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==, + } + engines: { node: '>=18.18' } '@humanwhocodes/retry@0.4.2': - resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==} - engines: {node: '>=18.18'} + resolution: + { + integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==, + } + engines: { node: '>=18.18' } '@img/sharp-darwin-arm64@0.33.5': - resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [arm64] os: [darwin] '@img/sharp-darwin-x64@0.33.5': - resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [x64] os: [darwin] '@img/sharp-libvips-darwin-arm64@1.0.4': - resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} + resolution: + { + integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==, + } cpu: [arm64] os: [darwin] '@img/sharp-libvips-darwin-x64@1.0.4': - resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + resolution: + { + integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==, + } cpu: [x64] os: [darwin] '@img/sharp-libvips-linux-arm64@1.0.4': - resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} + resolution: + { + integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==, + } cpu: [arm64] os: [linux] '@img/sharp-libvips-linux-arm@1.0.5': - resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} + resolution: + { + integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==, + } cpu: [arm] os: [linux] '@img/sharp-libvips-linux-s390x@1.0.4': - resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + resolution: + { + integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==, + } cpu: [s390x] os: [linux] '@img/sharp-libvips-linux-x64@1.0.4': - resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} + resolution: + { + integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==, + } cpu: [x64] os: [linux] '@img/sharp-libvips-linuxmusl-arm64@1.0.4': - resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + resolution: + { + integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==, + } cpu: [arm64] os: [linux] '@img/sharp-libvips-linuxmusl-x64@1.0.4': - resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} + resolution: + { + integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==, + } cpu: [x64] os: [linux] '@img/sharp-linux-arm64@0.33.5': - resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [arm64] os: [linux] '@img/sharp-linux-arm@0.33.5': - resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [arm] os: [linux] '@img/sharp-linux-s390x@0.33.5': - resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [s390x] os: [linux] '@img/sharp-linux-x64@0.33.5': - resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [x64] os: [linux] '@img/sharp-linuxmusl-arm64@0.33.5': - resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [arm64] os: [linux] '@img/sharp-linuxmusl-x64@0.33.5': - resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [x64] os: [linux] '@img/sharp-wasm32@0.33.5': - resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [wasm32] '@img/sharp-win32-ia32@0.33.5': - resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [ia32] os: [win32] '@img/sharp-win32-x64@0.33.5': - resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [x64] os: [win32] '@jridgewell/gen-mapping@0.3.8': - resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} - engines: {node: '>=6.0.0'} + resolution: + { + integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==, + } + engines: { node: '>=6.0.0' } '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} + resolution: + { + integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==, + } + engines: { node: '>=6.0.0' } '@jridgewell/set-array@1.2.1': - resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} - engines: {node: '>=6.0.0'} + resolution: + { + integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==, + } + engines: { node: '>=6.0.0' } '@jridgewell/sourcemap-codec@1.5.0': - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + resolution: + { + integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==, + } '@jridgewell/trace-mapping@0.3.25': - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + resolution: + { + integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==, + } '@jsdevtools/ono@7.1.3': - resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + resolution: + { + integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==, + } '@lexical/clipboard@0.28.0': - resolution: {integrity: sha512-LYqion+kAwFQJStA37JAEMxTL/m1WlZbotDfM/2WuONmlO0yWxiyRDI18oeCwhBD6LQQd9c3Ccxp9HFwUG1AVw==} + resolution: + { + integrity: sha512-LYqion+kAwFQJStA37JAEMxTL/m1WlZbotDfM/2WuONmlO0yWxiyRDI18oeCwhBD6LQQd9c3Ccxp9HFwUG1AVw==, + } '@lexical/code@0.28.0': - resolution: {integrity: sha512-9LOKSWdRhxqAKRq5yveNC21XKtW4h2rmFNTucwMWZ9vLu9xteOHEwZdO1Qv82PFUmgCpAhg6EntmnZu9xD3K7Q==} + resolution: + { + integrity: sha512-9LOKSWdRhxqAKRq5yveNC21XKtW4h2rmFNTucwMWZ9vLu9xteOHEwZdO1Qv82PFUmgCpAhg6EntmnZu9xD3K7Q==, + } '@lexical/devtools-core@0.28.0': - resolution: {integrity: sha512-Fk4itAjZ+MqTYXN84aE5RDf+wQX67N5nyo3JVxQTFZGAghx7Ux1xLWHB25zzD0YfjMtJ0NQROAbE3xdecZzxcQ==} + resolution: + { + integrity: sha512-Fk4itAjZ+MqTYXN84aE5RDf+wQX67N5nyo3JVxQTFZGAghx7Ux1xLWHB25zzD0YfjMtJ0NQROAbE3xdecZzxcQ==, + } peerDependencies: react: '>=17.x' react-dom: '>=17.x' '@lexical/dragon@0.28.0': - resolution: {integrity: sha512-T6T8YaHnhU863ruuqmRHTLUYa8sfg/ArYcrnNGZGfpvvFTfFjpWb/ELOvOWo8N6Y/4fnSLjQ20aXexVW1KcTBQ==} + resolution: + { + integrity: sha512-T6T8YaHnhU863ruuqmRHTLUYa8sfg/ArYcrnNGZGfpvvFTfFjpWb/ELOvOWo8N6Y/4fnSLjQ20aXexVW1KcTBQ==, + } '@lexical/hashtag@0.28.0': - resolution: {integrity: sha512-zcqX9Qna4lj96bAUfwSQSVEhYQ0O5erSjrIhOVqEgeQ5ubz0EvqnnMbbwNHIb2n6jzSwAvpD/3UZJZtolh+zVg==} + resolution: + { + integrity: sha512-zcqX9Qna4lj96bAUfwSQSVEhYQ0O5erSjrIhOVqEgeQ5ubz0EvqnnMbbwNHIb2n6jzSwAvpD/3UZJZtolh+zVg==, + } '@lexical/headless@0.28.0': - resolution: {integrity: sha512-btcaTfw9I/xQ/XYom6iKWgsPecmRawGd/5jOhP7QDtLUp7gxgM7/kiCZFYa8jDJO6j20rXuWTkc81ynVpKvjow==} + resolution: + { + integrity: sha512-btcaTfw9I/xQ/XYom6iKWgsPecmRawGd/5jOhP7QDtLUp7gxgM7/kiCZFYa8jDJO6j20rXuWTkc81ynVpKvjow==, + } '@lexical/history@0.28.0': - resolution: {integrity: sha512-CHzDxaGDn6qCFFhU0YKP1B8sgEb++0Ksqsj6BfDL/6TMxoLNQwRQhP3BUNNXl1kvUhxTQZgk3b9MjJZRaFKG9Q==} + resolution: + { + integrity: sha512-CHzDxaGDn6qCFFhU0YKP1B8sgEb++0Ksqsj6BfDL/6TMxoLNQwRQhP3BUNNXl1kvUhxTQZgk3b9MjJZRaFKG9Q==, + } '@lexical/html@0.28.0': - resolution: {integrity: sha512-ayb0FPxr55Ko99/d9ewbfrApul4L0z+KpU2ZG03im7EvUPVLyIGLx4S0QguMDvQh0Vu+eJ7/EESuonDs5BCe3A==} + resolution: + { + integrity: sha512-ayb0FPxr55Ko99/d9ewbfrApul4L0z+KpU2ZG03im7EvUPVLyIGLx4S0QguMDvQh0Vu+eJ7/EESuonDs5BCe3A==, + } '@lexical/link@0.28.0': - resolution: {integrity: sha512-T5VKxpOnML5DcXv2lW3Le0vjNlcbdohZjS9f6PAvm6eX8EzBKDpLQCopr1/0KGdlLd1QrzQsykQrdU7ieC4LRg==} + resolution: + { + integrity: sha512-T5VKxpOnML5DcXv2lW3Le0vjNlcbdohZjS9f6PAvm6eX8EzBKDpLQCopr1/0KGdlLd1QrzQsykQrdU7ieC4LRg==, + } '@lexical/list@0.28.0': - resolution: {integrity: sha512-3a8QcZ75n2TLxP+xkSPJ2V15jsysMLMe0YoObG+ew/sioVelIU8GciYsWBo5GgQmwSzJNQJeK5cJ9p1b71z2cg==} + resolution: + { + integrity: sha512-3a8QcZ75n2TLxP+xkSPJ2V15jsysMLMe0YoObG+ew/sioVelIU8GciYsWBo5GgQmwSzJNQJeK5cJ9p1b71z2cg==, + } '@lexical/mark@0.28.0': - resolution: {integrity: sha512-v5PzmTACsJrw3GvNZy2rgPxrNn9InLvLFoKqrSlNhhyvYNIAcuC4KVy00LKLja43Gw/fuB3QwKohYfAtM3yR3g==} + resolution: + { + integrity: sha512-v5PzmTACsJrw3GvNZy2rgPxrNn9InLvLFoKqrSlNhhyvYNIAcuC4KVy00LKLja43Gw/fuB3QwKohYfAtM3yR3g==, + } '@lexical/markdown@0.28.0': - resolution: {integrity: sha512-F3JXClqN4cjmXYLDK0IztxkbZuqkqS/AVbxnhGvnDYHQ9Gp8l7BonczhOiPwmJCDubJrAACP0L9LCqyt0jDRFw==} + resolution: + { + integrity: sha512-F3JXClqN4cjmXYLDK0IztxkbZuqkqS/AVbxnhGvnDYHQ9Gp8l7BonczhOiPwmJCDubJrAACP0L9LCqyt0jDRFw==, + } '@lexical/offset@0.28.0': - resolution: {integrity: sha512-/SMDQgBPeWM936t04mtH6UAn3xAjP/meu9q136bcT3S7p7V8ew9JfNp9aznTPTx+2W3brJORAvUow7Xn1fSHmw==} + resolution: + { + integrity: sha512-/SMDQgBPeWM936t04mtH6UAn3xAjP/meu9q136bcT3S7p7V8ew9JfNp9aznTPTx+2W3brJORAvUow7Xn1fSHmw==, + } '@lexical/overflow@0.28.0': - resolution: {integrity: sha512-ppmhHXEZVicBm05w9EVflzwFavTVNAe4q0bkabWUeW0IoCT3Vg2A3JT7PC9ypmp+mboUD195foFEr1BBSv1Y8Q==} + resolution: + { + integrity: sha512-ppmhHXEZVicBm05w9EVflzwFavTVNAe4q0bkabWUeW0IoCT3Vg2A3JT7PC9ypmp+mboUD195foFEr1BBSv1Y8Q==, + } '@lexical/plain-text@0.28.0': - resolution: {integrity: sha512-Jj2dCMDEfRuVetfDKcUes8J5jvAfZrLnILFlHxnu7y+lC+7R/NR403DYb3NJ8H7+lNiH1K15+U2K7ewbjxS6KQ==} + resolution: + { + integrity: sha512-Jj2dCMDEfRuVetfDKcUes8J5jvAfZrLnILFlHxnu7y+lC+7R/NR403DYb3NJ8H7+lNiH1K15+U2K7ewbjxS6KQ==, + } '@lexical/react@0.28.0': - resolution: {integrity: sha512-dWPnxrKrbQFjNqExqnaAsV0UEUgw/5M1ZYRWd5FGBGjHqVTCaX2jNHlKLMA68Od0VPIoOX2Zy1TYZ8ZKtsj5Dg==} + resolution: + { + integrity: sha512-dWPnxrKrbQFjNqExqnaAsV0UEUgw/5M1ZYRWd5FGBGjHqVTCaX2jNHlKLMA68Od0VPIoOX2Zy1TYZ8ZKtsj5Dg==, + } peerDependencies: react: '>=17.x' react-dom: '>=17.x' '@lexical/rich-text@0.28.0': - resolution: {integrity: sha512-y+vUWI+9uFupIb9UvssKU/DKcT9dFUZuQBu7utFkLadxCNyXQHeRjxzjzmvFiM3DBV0guPUDGu5VS5TPnIA+OA==} + resolution: + { + integrity: sha512-y+vUWI+9uFupIb9UvssKU/DKcT9dFUZuQBu7utFkLadxCNyXQHeRjxzjzmvFiM3DBV0guPUDGu5VS5TPnIA+OA==, + } '@lexical/selection@0.28.0': - resolution: {integrity: sha512-AJDi67Nsexyejzp4dEQSVoPov4P+FJ0t1v6DxUU+YmcvV56QyJQi6ue0i/xd8unr75ZufzLsAC0cDJJCEI7QDA==} + resolution: + { + integrity: sha512-AJDi67Nsexyejzp4dEQSVoPov4P+FJ0t1v6DxUU+YmcvV56QyJQi6ue0i/xd8unr75ZufzLsAC0cDJJCEI7QDA==, + } '@lexical/table@0.28.0': - resolution: {integrity: sha512-HMPCwXdj0sRWdlDzsHcNWRgbeKbEhn3L8LPhFnTq7q61gZ4YW2umdmuvQFKnIBcKq49drTH8cUwZoIwI8+AEEw==} + resolution: + { + integrity: sha512-HMPCwXdj0sRWdlDzsHcNWRgbeKbEhn3L8LPhFnTq7q61gZ4YW2umdmuvQFKnIBcKq49drTH8cUwZoIwI8+AEEw==, + } '@lexical/text@0.28.0': - resolution: {integrity: sha512-PT/A2RZv+ktn7SG/tJkOpGlYE6zjOND59VtRHnV/xciZ+jEJVaqAHtWjhbWibAIZQAkv/O7UouuDqzDaNTSGAA==} + resolution: + { + integrity: sha512-PT/A2RZv+ktn7SG/tJkOpGlYE6zjOND59VtRHnV/xciZ+jEJVaqAHtWjhbWibAIZQAkv/O7UouuDqzDaNTSGAA==, + } '@lexical/utils@0.28.0': - resolution: {integrity: sha512-Qw00DjkS1nRK7DLSgqJpJ77Ti2AuiOQ6m5eM38YojoWXkVmoxqKAUMaIbVNVKqjFgrQvKFF46sXxIJPbUQkB0w==} + resolution: + { + integrity: sha512-Qw00DjkS1nRK7DLSgqJpJ77Ti2AuiOQ6m5eM38YojoWXkVmoxqKAUMaIbVNVKqjFgrQvKFF46sXxIJPbUQkB0w==, + } '@lexical/yjs@0.28.0': - resolution: {integrity: sha512-rKHpUEd3nrvMY7ghmOC0AeGSYT7YIviba+JViaOzrCX4/Wtv5C/3Sl7Io12Z9k+s1BKmy7C28bOdQHvRWaD7vQ==} + resolution: + { + integrity: sha512-rKHpUEd3nrvMY7ghmOC0AeGSYT7YIviba+JViaOzrCX4/Wtv5C/3Sl7Io12Z9k+s1BKmy7C28bOdQHvRWaD7vQ==, + } peerDependencies: yjs: '>=13.5.22' '@monaco-editor/loader@1.5.0': - resolution: {integrity: sha512-hKoGSM+7aAc7eRTRjpqAZucPmoNOC4UUbknb/VNoTkEIkCPhqV8LfbsgM1webRM7S/z21eHEx9Fkwx8Z/C/+Xw==} + resolution: + { + integrity: sha512-hKoGSM+7aAc7eRTRjpqAZucPmoNOC4UUbknb/VNoTkEIkCPhqV8LfbsgM1webRM7S/z21eHEx9Fkwx8Z/C/+Xw==, + } '@monaco-editor/react@4.7.0': - resolution: {integrity: sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==} + resolution: + { + integrity: sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==, + } peerDependencies: monaco-editor: '>= 0.25.0 < 1' react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 '@mongodb-js/saslprep@1.2.0': - resolution: {integrity: sha512-+ywrb0AqkfaYuhHs6LxKWgqbh3I72EpEgESCw37o+9qPx9WTCkgDm2B+eMrwehGtHBWHFU4GXvnSCNiFhhausg==} + resolution: + { + integrity: sha512-+ywrb0AqkfaYuhHs6LxKWgqbh3I72EpEgESCw37o+9qPx9WTCkgDm2B+eMrwehGtHBWHFU4GXvnSCNiFhhausg==, + } '@napi-rs/wasm-runtime@0.2.7': - resolution: {integrity: sha512-5yximcFK5FNompXfJFoWanu5l8v1hNGqNHh9du1xETp9HWk/B/PzvchX55WYOPaIeNglG8++68AAiauBAtbnzw==} + resolution: + { + integrity: sha512-5yximcFK5FNompXfJFoWanu5l8v1hNGqNHh9du1xETp9HWk/B/PzvchX55WYOPaIeNglG8++68AAiauBAtbnzw==, + } '@next/env@15.2.3': - resolution: {integrity: sha512-a26KnbW9DFEUsSxAxKBORR/uD9THoYoKbkpFywMN/AFvboTt94b8+g/07T8J6ACsdLag8/PDU60ov4rPxRAixw==} + resolution: + { + integrity: sha512-a26KnbW9DFEUsSxAxKBORR/uD9THoYoKbkpFywMN/AFvboTt94b8+g/07T8J6ACsdLag8/PDU60ov4rPxRAixw==, + } '@next/eslint-plugin-next@15.2.3': - resolution: {integrity: sha512-eNSOIMJtjs+dp4Ms1tB1PPPJUQHP3uZK+OQ7iFY9qXpGO6ojT6imCL+KcUOqE/GXGidWbBZJzYdgAdPHqeCEPA==} + resolution: + { + integrity: sha512-eNSOIMJtjs+dp4Ms1tB1PPPJUQHP3uZK+OQ7iFY9qXpGO6ojT6imCL+KcUOqE/GXGidWbBZJzYdgAdPHqeCEPA==, + } '@next/swc-darwin-arm64@15.2.3': - resolution: {integrity: sha512-uaBhA8aLbXLqwjnsHSkxs353WrRgQgiFjduDpc7YXEU0B54IKx3vU+cxQlYwPCyC8uYEEX7THhtQQsfHnvv8dw==} - engines: {node: '>= 10'} + resolution: + { + integrity: sha512-uaBhA8aLbXLqwjnsHSkxs353WrRgQgiFjduDpc7YXEU0B54IKx3vU+cxQlYwPCyC8uYEEX7THhtQQsfHnvv8dw==, + } + engines: { node: '>= 10' } cpu: [arm64] os: [darwin] '@next/swc-darwin-x64@15.2.3': - resolution: {integrity: sha512-pVwKvJ4Zk7h+4hwhqOUuMx7Ib02u3gDX3HXPKIShBi9JlYllI0nU6TWLbPT94dt7FSi6mSBhfc2JrHViwqbOdw==} - engines: {node: '>= 10'} + resolution: + { + integrity: sha512-pVwKvJ4Zk7h+4hwhqOUuMx7Ib02u3gDX3HXPKIShBi9JlYllI0nU6TWLbPT94dt7FSi6mSBhfc2JrHViwqbOdw==, + } + engines: { node: '>= 10' } cpu: [x64] os: [darwin] '@next/swc-linux-arm64-gnu@15.2.3': - resolution: {integrity: sha512-50ibWdn2RuFFkOEUmo9NCcQbbV9ViQOrUfG48zHBCONciHjaUKtHcYFiCwBVuzD08fzvzkWuuZkd4AqbvKO7UQ==} - engines: {node: '>= 10'} + resolution: + { + integrity: sha512-50ibWdn2RuFFkOEUmo9NCcQbbV9ViQOrUfG48zHBCONciHjaUKtHcYFiCwBVuzD08fzvzkWuuZkd4AqbvKO7UQ==, + } + engines: { node: '>= 10' } cpu: [arm64] os: [linux] '@next/swc-linux-arm64-musl@15.2.3': - resolution: {integrity: sha512-2gAPA7P652D3HzR4cLyAuVYwYqjG0mt/3pHSWTCyKZq/N/dJcUAEoNQMyUmwTZWCJRKofB+JPuDVP2aD8w2J6Q==} - engines: {node: '>= 10'} + resolution: + { + integrity: sha512-2gAPA7P652D3HzR4cLyAuVYwYqjG0mt/3pHSWTCyKZq/N/dJcUAEoNQMyUmwTZWCJRKofB+JPuDVP2aD8w2J6Q==, + } + engines: { node: '>= 10' } cpu: [arm64] os: [linux] '@next/swc-linux-x64-gnu@15.2.3': - resolution: {integrity: sha512-ODSKvrdMgAJOVU4qElflYy1KSZRM3M45JVbeZu42TINCMG3anp7YCBn80RkISV6bhzKwcUqLBAmOiWkaGtBA9w==} - engines: {node: '>= 10'} + resolution: + { + integrity: sha512-ODSKvrdMgAJOVU4qElflYy1KSZRM3M45JVbeZu42TINCMG3anp7YCBn80RkISV6bhzKwcUqLBAmOiWkaGtBA9w==, + } + engines: { node: '>= 10' } cpu: [x64] os: [linux] '@next/swc-linux-x64-musl@15.2.3': - resolution: {integrity: sha512-ZR9kLwCWrlYxwEoytqPi1jhPd1TlsSJWAc+H/CJHmHkf2nD92MQpSRIURR1iNgA/kuFSdxB8xIPt4p/T78kwsg==} - engines: {node: '>= 10'} + resolution: + { + integrity: sha512-ZR9kLwCWrlYxwEoytqPi1jhPd1TlsSJWAc+H/CJHmHkf2nD92MQpSRIURR1iNgA/kuFSdxB8xIPt4p/T78kwsg==, + } + engines: { node: '>= 10' } cpu: [x64] os: [linux] '@next/swc-win32-arm64-msvc@15.2.3': - resolution: {integrity: sha512-+G2FrDcfm2YDbhDiObDU/qPriWeiz/9cRR0yMWJeTLGGX6/x8oryO3tt7HhodA1vZ8r2ddJPCjtLcpaVl7TE2Q==} - engines: {node: '>= 10'} + resolution: + { + integrity: sha512-+G2FrDcfm2YDbhDiObDU/qPriWeiz/9cRR0yMWJeTLGGX6/x8oryO3tt7HhodA1vZ8r2ddJPCjtLcpaVl7TE2Q==, + } + engines: { node: '>= 10' } cpu: [arm64] os: [win32] '@next/swc-win32-x64-msvc@15.2.3': - resolution: {integrity: sha512-gHYS9tc+G2W0ZC8rBL+H6RdtXIyk40uLiaos0yj5US85FNhbFEndMA2nW3z47nzOWiSvXTZ5kBClc3rD0zJg0w==} - engines: {node: '>= 10'} + resolution: + { + integrity: sha512-gHYS9tc+G2W0ZC8rBL+H6RdtXIyk40uLiaos0yj5US85FNhbFEndMA2nW3z47nzOWiSvXTZ5kBClc3rD0zJg0w==, + } + engines: { node: '>= 10' } cpu: [x64] os: [win32] '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==, + } + engines: { node: '>= 8' } '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==, + } + engines: { node: '>= 8' } '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==, + } + engines: { node: '>= 8' } '@nolyfill/is-core-module@1.0.39': - resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} - engines: {node: '>=12.4.0'} + resolution: + { + integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==, + } + engines: { node: '>=12.4.0' } - '@payloadcms/db-mongodb@3.29.0': - resolution: {integrity: sha512-n9y5njLbc3Q3FrtuCCxsTEN/HJsEIkLrEKLw/2bOIn356gZJGTLi0bazcnFSKEmwsZfyrzzrNsle7gWlrOUOSQ==} + '@payloadcms/db-mongodb@3.31.0': + resolution: + { + integrity: sha512-Eoh/CrT2AXhKtWMr6Gn2pG7TmmR5O4hIXq7zb+kZmiQAZcbwHC4KiTEEnVuqVXg2RXKz9KQDDYsYz9P4FeBk3g==, + } peerDependencies: - payload: 3.29.0 + payload: 3.31.0 - '@payloadcms/email-nodemailer@3.29.0': - resolution: {integrity: sha512-5xIWmTadlpMvdBd96vUUWhvDdFepCBE35vKhdDvObkvqr0g33lJmm7n7V2HHKPCG1C9EmJa4m0c+B7hj8UqH5Q==} - engines: {node: ^18.20.2 || >=20.9.0} + '@payloadcms/email-nodemailer@3.31.0': + resolution: + { + integrity: sha512-F9oqqdVvorbDPMLTumOvupTY4Tpp6ajJzTPQJpvDJyrTRUl2mH3wYkBTtCnm7oCzv8mcurvM9aRfKTSOmySK0g==, + } + engines: { node: ^18.20.2 || >=20.9.0 } peerDependencies: - payload: 3.29.0 + payload: 3.31.0 - '@payloadcms/graphql@3.29.0': - resolution: {integrity: sha512-3xeRzs8D8Oxty2xXRSQIDeJCkfXJDL+7+oTb9lP3vYGMaf5uiYnXvEmpJcciOTg5aigLFA6XY08ghkg0eU7uqw==} + '@payloadcms/graphql@3.31.0': + resolution: + { + integrity: sha512-IJWP+eBzZm7GpQvsvx/+2kfPK6RLhshCXPebtsmLDrjXlySmx1kZOm5F185Zd1yHwMfXfQw4pc6+ipukG1l6sA==, + } hasBin: true peerDependencies: graphql: ^16.8.1 - payload: 3.29.0 + payload: 3.31.0 - '@payloadcms/next@3.29.0': - resolution: {integrity: sha512-uq9abb6DB/n0UimKhq0ShXeiD9pC+l4Z1mKd2pyPUYwQa1d0dMW+YjAeW3q3WVUvt2ZQV3JtPO68hjboXlaNUg==} - engines: {node: ^18.20.2 || >=20.9.0} + '@payloadcms/next@3.31.0': + resolution: + { + integrity: sha512-O+1E9bgQPR2bigIjxw6wFz8KVY048ZUgZ+eONjf5eLGlIPU8yHorMyruj5hJRzoXqXhehWNYtk5ru5XbouCQnA==, + } + engines: { node: ^18.20.2 || >=20.9.0 } peerDependencies: graphql: ^16.8.1 - next: ^15.0.0 - payload: 3.29.0 + next: ^15.2.3 + payload: 3.31.0 - '@payloadcms/payload-cloud@3.29.0': - resolution: {integrity: sha512-g8PgPAm2rHbParD9P5w9qZ7AldwU0IRjqlmkJiS21SbR89+hlDJebpIBM0vlnCUU+XQ9M4pnf5XZ0/vt3J1xsA==} + '@payloadcms/payload-cloud@3.31.0': + resolution: + { + integrity: sha512-+JNxgTykSJXNmrVA2Xkn+42d5iwZXc468nLRjiM29LrY6s/75yCaq55iSr0aw2UFy1hsxkHl0MjSEVLREk/LOw==, + } peerDependencies: - payload: 3.29.0 + payload: 3.31.0 - '@payloadcms/richtext-lexical@3.29.0': - resolution: {integrity: sha512-OlCgr4/7hUIg4OZwSw3qoI7OUml2glsDPRI0AV6v+dZWQTQrrysCGGGM9KnO2qvAEK2TP1nfQ774v5Tz4yxSYQ==} - engines: {node: ^18.20.2 || >=20.9.0} + '@payloadcms/richtext-lexical@3.31.0': + resolution: + { + integrity: sha512-xSMO3Pd7k3mFF+PbvWEozCT4m2nFGqxdTmxKHHFKjcH2wswQwmNkuddXRXcpRm2aSzpUXPYak+8TfC+vPBC7bA==, + } + engines: { node: ^18.20.2 || >=20.9.0 } peerDependencies: '@faceless-ui/modal': 3.0.0-beta.2 '@faceless-ui/scroll-info': 2.0.0 - '@payloadcms/next': 3.29.0 - payload: 3.29.0 + '@payloadcms/next': 3.31.0 + payload: 3.31.0 react: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 react-dom: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 - '@payloadcms/translations@3.29.0': - resolution: {integrity: sha512-leM0AYBAsXFfmqM7OkQ546f7tAYAXOClDDiFi1D2SL1dcgKzbsWf3jPeCEZmZiUArolrXgWbfuHSnH7Ah78e/g==} + '@payloadcms/translations@3.31.0': + resolution: + { + integrity: sha512-vjbBuHJUZ04R7wkOR1+QhZRO1xG7bvkLgx6zoiKZZmvItqiPA5ZWsyrq3NFhviOH26dH2tOdnO+RLPuaElkWFg==, + } - '@payloadcms/ui@3.29.0': - resolution: {integrity: sha512-uTGB+T71fdlEhCtQAWzW1wDd15EUnc7hqNsM50ImuwPBqq7kMgtySrji0weG5atitXReZXJUEgHNvmhUtO+eWA==} - engines: {node: ^18.20.2 || >=20.9.0} + '@payloadcms/ui@3.31.0': + resolution: + { + integrity: sha512-SvRFqCmCo0PCOrwqFeNmL5EoJjGx7712l7pcvyMxpF0RmziZVAzqttnBizO3ha+7z65dJZFmyVHsawhO+iZk1Q==, + } + engines: { node: ^18.20.2 || >=20.9.0 } peerDependencies: - next: ^15.0.0 - payload: 3.29.0 + next: ^15.2.3 + payload: 3.31.0 react: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 react-dom: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 '@rtsao/scc@1.1.0': - resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + resolution: + { + integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==, + } '@rushstack/eslint-patch@1.11.0': - resolution: {integrity: sha512-zxnHvoMQVqewTJr/W4pKjF0bMGiKJv1WX7bSrkl46Hg0QjESbzBROWK0Wg4RphzSOS5Jiy7eFimmM3UgMrMZbQ==} + resolution: + { + integrity: sha512-zxnHvoMQVqewTJr/W4pKjF0bMGiKJv1WX7bSrkl46Hg0QjESbzBROWK0Wg4RphzSOS5Jiy7eFimmM3UgMrMZbQ==, + } '@smithy/abort-controller@4.0.1': - resolution: {integrity: sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==, + } + engines: { node: '>=18.0.0' } '@smithy/chunked-blob-reader-native@4.0.0': - resolution: {integrity: sha512-R9wM2yPmfEMsUmlMlIgSzOyICs0x9uu7UTHoccMyt7BWw8shcGM8HqB355+BZCPBcySvbTYMs62EgEQkNxz2ig==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-R9wM2yPmfEMsUmlMlIgSzOyICs0x9uu7UTHoccMyt7BWw8shcGM8HqB355+BZCPBcySvbTYMs62EgEQkNxz2ig==, + } + engines: { node: '>=18.0.0' } '@smithy/chunked-blob-reader@5.0.0': - resolution: {integrity: sha512-+sKqDBQqb036hh4NPaUiEkYFkTUGYzRsn3EuFhyfQfMy6oGHEUJDurLP9Ufb5dasr/XiAmPNMr6wa9afjQB+Gw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-+sKqDBQqb036hh4NPaUiEkYFkTUGYzRsn3EuFhyfQfMy6oGHEUJDurLP9Ufb5dasr/XiAmPNMr6wa9afjQB+Gw==, + } + engines: { node: '>=18.0.0' } '@smithy/config-resolver@4.0.1': - resolution: {integrity: sha512-Igfg8lKu3dRVkTSEm98QpZUvKEOa71jDX4vKRcvJVyRc3UgN3j7vFMf0s7xLQhYmKa8kyJGQgUJDOV5V3neVlQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-Igfg8lKu3dRVkTSEm98QpZUvKEOa71jDX4vKRcvJVyRc3UgN3j7vFMf0s7xLQhYmKa8kyJGQgUJDOV5V3neVlQ==, + } + engines: { node: '>=18.0.0' } '@smithy/core@3.1.5': - resolution: {integrity: sha512-HLclGWPkCsekQgsyzxLhCQLa8THWXtB5PxyYN+2O6nkyLt550KQKTlbV2D1/j5dNIQapAZM1+qFnpBFxZQkgCA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-HLclGWPkCsekQgsyzxLhCQLa8THWXtB5PxyYN+2O6nkyLt550KQKTlbV2D1/j5dNIQapAZM1+qFnpBFxZQkgCA==, + } + engines: { node: '>=18.0.0' } '@smithy/credential-provider-imds@4.0.1': - resolution: {integrity: sha512-l/qdInaDq1Zpznpmev/+52QomsJNZ3JkTl5yrTl02V6NBgJOQ4LY0SFw/8zsMwj3tLe8vqiIuwF6nxaEwgf6mg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-l/qdInaDq1Zpznpmev/+52QomsJNZ3JkTl5yrTl02V6NBgJOQ4LY0SFw/8zsMwj3tLe8vqiIuwF6nxaEwgf6mg==, + } + engines: { node: '>=18.0.0' } '@smithy/eventstream-codec@4.0.1': - resolution: {integrity: sha512-Q2bCAAR6zXNVtJgifsU16ZjKGqdw/DyecKNgIgi7dlqw04fqDu0mnq+JmGphqheypVc64CYq3azSuCpAdFk2+A==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-Q2bCAAR6zXNVtJgifsU16ZjKGqdw/DyecKNgIgi7dlqw04fqDu0mnq+JmGphqheypVc64CYq3azSuCpAdFk2+A==, + } + engines: { node: '>=18.0.0' } '@smithy/eventstream-serde-browser@4.0.1': - resolution: {integrity: sha512-HbIybmz5rhNg+zxKiyVAnvdM3vkzjE6ccrJ620iPL8IXcJEntd3hnBl+ktMwIy12Te/kyrSbUb8UCdnUT4QEdA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-HbIybmz5rhNg+zxKiyVAnvdM3vkzjE6ccrJ620iPL8IXcJEntd3hnBl+ktMwIy12Te/kyrSbUb8UCdnUT4QEdA==, + } + engines: { node: '>=18.0.0' } '@smithy/eventstream-serde-config-resolver@4.0.1': - resolution: {integrity: sha512-lSipaiq3rmHguHa3QFF4YcCM3VJOrY9oq2sow3qlhFY+nBSTF/nrO82MUQRPrxHQXA58J5G1UnU2WuJfi465BA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-lSipaiq3rmHguHa3QFF4YcCM3VJOrY9oq2sow3qlhFY+nBSTF/nrO82MUQRPrxHQXA58J5G1UnU2WuJfi465BA==, + } + engines: { node: '>=18.0.0' } '@smithy/eventstream-serde-node@4.0.1': - resolution: {integrity: sha512-o4CoOI6oYGYJ4zXo34U8X9szDe3oGjmHgsMGiZM0j4vtNoT+h80TLnkUcrLZR3+E6HIxqW+G+9WHAVfl0GXK0Q==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-o4CoOI6oYGYJ4zXo34U8X9szDe3oGjmHgsMGiZM0j4vtNoT+h80TLnkUcrLZR3+E6HIxqW+G+9WHAVfl0GXK0Q==, + } + engines: { node: '>=18.0.0' } '@smithy/eventstream-serde-universal@4.0.1': - resolution: {integrity: sha512-Z94uZp0tGJuxds3iEAZBqGU2QiaBHP4YytLUjwZWx+oUeohCsLyUm33yp4MMBmhkuPqSbQCXq5hDet6JGUgHWA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-Z94uZp0tGJuxds3iEAZBqGU2QiaBHP4YytLUjwZWx+oUeohCsLyUm33yp4MMBmhkuPqSbQCXq5hDet6JGUgHWA==, + } + engines: { node: '>=18.0.0' } '@smithy/fetch-http-handler@5.0.1': - resolution: {integrity: sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==, + } + engines: { node: '>=18.0.0' } '@smithy/hash-blob-browser@4.0.1': - resolution: {integrity: sha512-rkFIrQOKZGS6i1D3gKJ8skJ0RlXqDvb1IyAphksaFOMzkn3v3I1eJ8m7OkLj0jf1McP63rcCEoLlkAn/HjcTRw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-rkFIrQOKZGS6i1D3gKJ8skJ0RlXqDvb1IyAphksaFOMzkn3v3I1eJ8m7OkLj0jf1McP63rcCEoLlkAn/HjcTRw==, + } + engines: { node: '>=18.0.0' } '@smithy/hash-node@4.0.1': - resolution: {integrity: sha512-TJ6oZS+3r2Xu4emVse1YPB3Dq3d8RkZDKcPr71Nj/lJsdAP1c7oFzYqEn1IBc915TsgLl2xIJNuxCz+gLbLE0w==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-TJ6oZS+3r2Xu4emVse1YPB3Dq3d8RkZDKcPr71Nj/lJsdAP1c7oFzYqEn1IBc915TsgLl2xIJNuxCz+gLbLE0w==, + } + engines: { node: '>=18.0.0' } '@smithy/hash-stream-node@4.0.1': - resolution: {integrity: sha512-U1rAE1fxmReCIr6D2o/4ROqAQX+GffZpyMt3d7njtGDr2pUNmAKRWa49gsNVhCh2vVAuf3wXzWwNr2YN8PAXIw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-U1rAE1fxmReCIr6D2o/4ROqAQX+GffZpyMt3d7njtGDr2pUNmAKRWa49gsNVhCh2vVAuf3wXzWwNr2YN8PAXIw==, + } + engines: { node: '>=18.0.0' } '@smithy/invalid-dependency@4.0.1': - resolution: {integrity: sha512-gdudFPf4QRQ5pzj7HEnu6FhKRi61BfH/Gk5Yf6O0KiSbr1LlVhgjThcvjdu658VE6Nve8vaIWB8/fodmS1rBPQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-gdudFPf4QRQ5pzj7HEnu6FhKRi61BfH/Gk5Yf6O0KiSbr1LlVhgjThcvjdu658VE6Nve8vaIWB8/fodmS1rBPQ==, + } + engines: { node: '>=18.0.0' } '@smithy/is-array-buffer@2.2.0': - resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} - engines: {node: '>=14.0.0'} + resolution: + { + integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==, + } + engines: { node: '>=14.0.0' } '@smithy/is-array-buffer@4.0.0': - resolution: {integrity: sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==, + } + engines: { node: '>=18.0.0' } '@smithy/md5-js@4.0.1': - resolution: {integrity: sha512-HLZ647L27APi6zXkZlzSFZIjpo8po45YiyjMGJZM3gyDY8n7dPGdmxIIljLm4gPt/7rRvutLTTkYJpZVfG5r+A==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-HLZ647L27APi6zXkZlzSFZIjpo8po45YiyjMGJZM3gyDY8n7dPGdmxIIljLm4gPt/7rRvutLTTkYJpZVfG5r+A==, + } + engines: { node: '>=18.0.0' } '@smithy/middleware-content-length@4.0.1': - resolution: {integrity: sha512-OGXo7w5EkB5pPiac7KNzVtfCW2vKBTZNuCctn++TTSOMpe6RZO/n6WEC1AxJINn3+vWLKW49uad3lo/u0WJ9oQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-OGXo7w5EkB5pPiac7KNzVtfCW2vKBTZNuCctn++TTSOMpe6RZO/n6WEC1AxJINn3+vWLKW49uad3lo/u0WJ9oQ==, + } + engines: { node: '>=18.0.0' } '@smithy/middleware-endpoint@4.0.6': - resolution: {integrity: sha512-ftpmkTHIFqgaFugcjzLZv3kzPEFsBFSnq1JsIkr2mwFzCraZVhQk2gqN51OOeRxqhbPTkRFj39Qd2V91E/mQxg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-ftpmkTHIFqgaFugcjzLZv3kzPEFsBFSnq1JsIkr2mwFzCraZVhQk2gqN51OOeRxqhbPTkRFj39Qd2V91E/mQxg==, + } + engines: { node: '>=18.0.0' } '@smithy/middleware-retry@4.0.7': - resolution: {integrity: sha512-58j9XbUPLkqAcV1kHzVX/kAR16GT+j7DUZJqwzsxh1jtz7G82caZiGyyFgUvogVfNTg3TeAOIJepGc8TXF4AVQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-58j9XbUPLkqAcV1kHzVX/kAR16GT+j7DUZJqwzsxh1jtz7G82caZiGyyFgUvogVfNTg3TeAOIJepGc8TXF4AVQ==, + } + engines: { node: '>=18.0.0' } '@smithy/middleware-serde@4.0.2': - resolution: {integrity: sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==, + } + engines: { node: '>=18.0.0' } '@smithy/middleware-stack@4.0.1': - resolution: {integrity: sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==, + } + engines: { node: '>=18.0.0' } '@smithy/node-config-provider@4.0.1': - resolution: {integrity: sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==, + } + engines: { node: '>=18.0.0' } '@smithy/node-http-handler@4.0.3': - resolution: {integrity: sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA==, + } + engines: { node: '>=18.0.0' } '@smithy/property-provider@4.0.1': - resolution: {integrity: sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==, + } + engines: { node: '>=18.0.0' } '@smithy/protocol-http@5.0.1': - resolution: {integrity: sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==, + } + engines: { node: '>=18.0.0' } '@smithy/querystring-builder@4.0.1': - resolution: {integrity: sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==, + } + engines: { node: '>=18.0.0' } '@smithy/querystring-parser@4.0.1': - resolution: {integrity: sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==, + } + engines: { node: '>=18.0.0' } '@smithy/service-error-classification@4.0.1': - resolution: {integrity: sha512-3JNjBfOWpj/mYfjXJHB4Txc/7E4LVq32bwzE7m28GN79+M1f76XHflUaSUkhOriprPDzev9cX/M+dEB80DNDKA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-3JNjBfOWpj/mYfjXJHB4Txc/7E4LVq32bwzE7m28GN79+M1f76XHflUaSUkhOriprPDzev9cX/M+dEB80DNDKA==, + } + engines: { node: '>=18.0.0' } '@smithy/shared-ini-file-loader@4.0.1': - resolution: {integrity: sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==, + } + engines: { node: '>=18.0.0' } '@smithy/signature-v4@5.0.1': - resolution: {integrity: sha512-nCe6fQ+ppm1bQuw5iKoeJ0MJfz2os7Ic3GBjOkLOPtavbD1ONoyE3ygjBfz2ythFWm4YnRm6OxW+8p/m9uCoIA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-nCe6fQ+ppm1bQuw5iKoeJ0MJfz2os7Ic3GBjOkLOPtavbD1ONoyE3ygjBfz2ythFWm4YnRm6OxW+8p/m9uCoIA==, + } + engines: { node: '>=18.0.0' } '@smithy/smithy-client@4.1.6': - resolution: {integrity: sha512-UYDolNg6h2O0L+cJjtgSyKKvEKCOa/8FHYJnBobyeoeWDmNpXjwOAtw16ezyeu1ETuuLEOZbrynK0ZY1Lx9Jbw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-UYDolNg6h2O0L+cJjtgSyKKvEKCOa/8FHYJnBobyeoeWDmNpXjwOAtw16ezyeu1ETuuLEOZbrynK0ZY1Lx9Jbw==, + } + engines: { node: '>=18.0.0' } '@smithy/types@4.1.0': - resolution: {integrity: sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==, + } + engines: { node: '>=18.0.0' } '@smithy/url-parser@4.0.1': - resolution: {integrity: sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==, + } + engines: { node: '>=18.0.0' } '@smithy/util-base64@4.0.0': - resolution: {integrity: sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==, + } + engines: { node: '>=18.0.0' } '@smithy/util-body-length-browser@4.0.0': - resolution: {integrity: sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==, + } + engines: { node: '>=18.0.0' } '@smithy/util-body-length-node@4.0.0': - resolution: {integrity: sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==, + } + engines: { node: '>=18.0.0' } '@smithy/util-buffer-from@2.2.0': - resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} - engines: {node: '>=14.0.0'} + resolution: + { + integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==, + } + engines: { node: '>=14.0.0' } '@smithy/util-buffer-from@4.0.0': - resolution: {integrity: sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==, + } + engines: { node: '>=18.0.0' } '@smithy/util-config-provider@4.0.0': - resolution: {integrity: sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==, + } + engines: { node: '>=18.0.0' } '@smithy/util-defaults-mode-browser@4.0.7': - resolution: {integrity: sha512-CZgDDrYHLv0RUElOsmZtAnp1pIjwDVCSuZWOPhIOBvG36RDfX1Q9+6lS61xBf+qqvHoqRjHxgINeQz47cYFC2Q==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-CZgDDrYHLv0RUElOsmZtAnp1pIjwDVCSuZWOPhIOBvG36RDfX1Q9+6lS61xBf+qqvHoqRjHxgINeQz47cYFC2Q==, + } + engines: { node: '>=18.0.0' } '@smithy/util-defaults-mode-node@4.0.7': - resolution: {integrity: sha512-79fQW3hnfCdrfIi1soPbK3zmooRFnLpSx3Vxi6nUlqaaQeC5dm8plt4OTNDNqEEEDkvKghZSaoti684dQFVrGQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-79fQW3hnfCdrfIi1soPbK3zmooRFnLpSx3Vxi6nUlqaaQeC5dm8plt4OTNDNqEEEDkvKghZSaoti684dQFVrGQ==, + } + engines: { node: '>=18.0.0' } '@smithy/util-endpoints@3.0.1': - resolution: {integrity: sha512-zVdUENQpdtn9jbpD9SCFK4+aSiavRb9BxEtw9ZGUR1TYo6bBHbIoi7VkrFQ0/RwZlzx0wRBaRmPclj8iAoJCLA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-zVdUENQpdtn9jbpD9SCFK4+aSiavRb9BxEtw9ZGUR1TYo6bBHbIoi7VkrFQ0/RwZlzx0wRBaRmPclj8iAoJCLA==, + } + engines: { node: '>=18.0.0' } '@smithy/util-hex-encoding@4.0.0': - resolution: {integrity: sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==, + } + engines: { node: '>=18.0.0' } '@smithy/util-middleware@4.0.1': - resolution: {integrity: sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==, + } + engines: { node: '>=18.0.0' } '@smithy/util-retry@4.0.1': - resolution: {integrity: sha512-WmRHqNVwn3kI3rKk1LsKcVgPBG6iLTBGC1iYOV3GQegwJ3E8yjzHytPt26VNzOWr1qu0xE03nK0Ug8S7T7oufw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-WmRHqNVwn3kI3rKk1LsKcVgPBG6iLTBGC1iYOV3GQegwJ3E8yjzHytPt26VNzOWr1qu0xE03nK0Ug8S7T7oufw==, + } + engines: { node: '>=18.0.0' } '@smithy/util-stream@4.1.2': - resolution: {integrity: sha512-44PKEqQ303d3rlQuiDpcCcu//hV8sn+u2JBo84dWCE0rvgeiVl0IlLMagbU++o0jCWhYCsHaAt9wZuZqNe05Hw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-44PKEqQ303d3rlQuiDpcCcu//hV8sn+u2JBo84dWCE0rvgeiVl0IlLMagbU++o0jCWhYCsHaAt9wZuZqNe05Hw==, + } + engines: { node: '>=18.0.0' } '@smithy/util-uri-escape@4.0.0': - resolution: {integrity: sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==, + } + engines: { node: '>=18.0.0' } '@smithy/util-utf8@2.3.0': - resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} - engines: {node: '>=14.0.0'} + resolution: + { + integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==, + } + engines: { node: '>=14.0.0' } '@smithy/util-utf8@4.0.0': - resolution: {integrity: sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==, + } + engines: { node: '>=18.0.0' } '@smithy/util-waiter@4.0.2': - resolution: {integrity: sha512-piUTHyp2Axx3p/kc2CIJkYSv0BAaheBQmbACZgQSSfWUumWNW+R1lL+H9PDBxKJkvOeEX+hKYEFiwO8xagL8AQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-piUTHyp2Axx3p/kc2CIJkYSv0BAaheBQmbACZgQSSfWUumWNW+R1lL+H9PDBxKJkvOeEX+hKYEFiwO8xagL8AQ==, + } + engines: { node: '>=18.0.0' } '@swc/counter@0.1.3': - resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + resolution: + { + integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==, + } '@swc/helpers@0.5.15': - resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + resolution: + { + integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==, + } '@tokenizer/token@0.3.0': - resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + resolution: + { + integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==, + } '@tybys/wasm-util@0.9.0': - resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} + resolution: + { + integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==, + } '@types/acorn@4.0.6': - resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==} + resolution: + { + integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==, + } '@types/busboy@1.5.4': - resolution: {integrity: sha512-kG7WrUuAKK0NoyxfQHsVE6j1m01s6kMma64E+OZenQABMQyTJop1DumUWcLwAQ2JzpefU7PDYoRDKl8uZosFjw==} + resolution: + { + integrity: sha512-kG7WrUuAKK0NoyxfQHsVE6j1m01s6kMma64E+OZenQABMQyTJop1DumUWcLwAQ2JzpefU7PDYoRDKl8uZosFjw==, + } '@types/debug@4.1.12': - resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + resolution: + { + integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==, + } '@types/estree-jsx@1.0.5': - resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + resolution: + { + integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==, + } '@types/estree@1.0.6': - resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + resolution: + { + integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==, + } '@types/hast@3.0.4': - resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + resolution: + { + integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==, + } '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + resolution: + { + integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==, + } '@types/json5@0.0.29': - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + resolution: + { + integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==, + } '@types/lodash@4.17.16': - resolution: {integrity: sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==} + resolution: + { + integrity: sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==, + } '@types/mdast@4.0.4': - resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + resolution: + { + integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==, + } '@types/ms@2.1.0': - resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + resolution: + { + integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==, + } '@types/node@22.13.11': - resolution: {integrity: sha512-iEUCUJoU0i3VnrCmgoWCXttklWcvoCIx4jzcP22fioIVSdTmjgoEvmAO/QPw6TcS9k5FrNgn4w7q5lGOd1CT5g==} + resolution: + { + integrity: sha512-iEUCUJoU0i3VnrCmgoWCXttklWcvoCIx4jzcP22fioIVSdTmjgoEvmAO/QPw6TcS9k5FrNgn4w7q5lGOd1CT5g==, + } '@types/parse-json@4.0.2': - resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + resolution: + { + integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==, + } '@types/react-dom@19.0.4': - resolution: {integrity: sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==} + resolution: + { + integrity: sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==, + } peerDependencies: '@types/react': ^19.0.0 '@types/react-transition-group@4.4.12': - resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==} + resolution: + { + integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==, + } peerDependencies: '@types/react': '*' '@types/react@19.0.12': - resolution: {integrity: sha512-V6Ar115dBDrjbtXSrS+/Oruobc+qVbbUxDFC1RSbRqLt5SYvxxyIDrSC85RWml54g+jfNeEMZhEj7wW07ONQhA==} + resolution: + { + integrity: sha512-V6Ar115dBDrjbtXSrS+/Oruobc+qVbbUxDFC1RSbRqLt5SYvxxyIDrSC85RWml54g+jfNeEMZhEj7wW07ONQhA==, + } '@types/unist@2.0.11': - resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + resolution: + { + integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==, + } '@types/unist@3.0.3': - resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + resolution: + { + integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==, + } '@types/uuid@10.0.0': - resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + resolution: + { + integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==, + } '@types/webidl-conversions@7.0.3': - resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==} + resolution: + { + integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==, + } '@types/whatwg-url@11.0.5': - resolution: {integrity: sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==} + resolution: + { + integrity: sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==, + } '@typescript-eslint/eslint-plugin@8.27.0': - resolution: {integrity: sha512-4henw4zkePi5p252c8ncBLzLce52SEUz2Ebj8faDnuUXz2UuHEONYcJ+G0oaCF+bYCWVZtrGzq3FD7YXetmnSA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-4henw4zkePi5p252c8ncBLzLce52SEUz2Ebj8faDnuUXz2UuHEONYcJ+G0oaCF+bYCWVZtrGzq3FD7YXetmnSA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } peerDependencies: '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' '@typescript-eslint/parser@8.27.0': - resolution: {integrity: sha512-XGwIabPallYipmcOk45DpsBSgLC64A0yvdAkrwEzwZ2viqGqRUJ8eEYoPz0CWnutgAFbNMPdsGGvzjSmcWVlEA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-XGwIabPallYipmcOk45DpsBSgLC64A0yvdAkrwEzwZ2viqGqRUJ8eEYoPz0CWnutgAFbNMPdsGGvzjSmcWVlEA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' '@typescript-eslint/scope-manager@8.27.0': - resolution: {integrity: sha512-8oI9GwPMQmBryaaxG1tOZdxXVeMDte6NyJA4i7/TWa4fBwgnAXYlIQP+uYOeqAaLJ2JRxlG9CAyL+C+YE9Xknw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-8oI9GwPMQmBryaaxG1tOZdxXVeMDte6NyJA4i7/TWa4fBwgnAXYlIQP+uYOeqAaLJ2JRxlG9CAyL+C+YE9Xknw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } '@typescript-eslint/type-utils@8.27.0': - resolution: {integrity: sha512-wVArTVcz1oJOIEJxui/nRhV0TXzD/zMSOYi/ggCfNq78EIszddXcJb7r4RCp/oBrjt8n9A0BSxRMKxHftpDxDA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-wVArTVcz1oJOIEJxui/nRhV0TXzD/zMSOYi/ggCfNq78EIszddXcJb7r4RCp/oBrjt8n9A0BSxRMKxHftpDxDA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' '@typescript-eslint/types@8.27.0': - resolution: {integrity: sha512-/6cp9yL72yUHAYq9g6DsAU+vVfvQmd1a8KyA81uvfDE21O2DwQ/qxlM4AR8TSdAu+kJLBDrEHKC5/W2/nxsY0A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-/6cp9yL72yUHAYq9g6DsAU+vVfvQmd1a8KyA81uvfDE21O2DwQ/qxlM4AR8TSdAu+kJLBDrEHKC5/W2/nxsY0A==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } '@typescript-eslint/typescript-estree@8.27.0': - resolution: {integrity: sha512-BnKq8cqPVoMw71O38a1tEb6iebEgGA80icSxW7g+kndx0o6ot6696HjG7NdgfuAVmVEtwXUr3L8R9ZuVjoQL6A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-BnKq8cqPVoMw71O38a1tEb6iebEgGA80icSxW7g+kndx0o6ot6696HjG7NdgfuAVmVEtwXUr3L8R9ZuVjoQL6A==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } peerDependencies: typescript: '>=4.8.4 <5.9.0' '@typescript-eslint/utils@8.27.0': - resolution: {integrity: sha512-njkodcwH1yvmo31YWgRHNb/x1Xhhq4/m81PhtvmRngD8iHPehxffz1SNCO+kwaePhATC+kOa/ggmvPoPza5i0Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-njkodcwH1yvmo31YWgRHNb/x1Xhhq4/m81PhtvmRngD8iHPehxffz1SNCO+kwaePhATC+kOa/ggmvPoPza5i0Q==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' '@typescript-eslint/visitor-keys@8.27.0': - resolution: {integrity: sha512-WsXQwMkILJvffP6z4U3FYJPlbf/j07HIxmDjZpbNvBJkMfvwXj5ACRkkHwBDvLBbDbtX5TdU64/rcvKJ/vuInQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-WsXQwMkILJvffP6z4U3FYJPlbf/j07HIxmDjZpbNvBJkMfvwXj5ACRkkHwBDvLBbDbtX5TdU64/rcvKJ/vuInQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } '@unrs/rspack-resolver-binding-darwin-arm64@1.2.2': - resolution: {integrity: sha512-i7z0B+C0P8Q63O/5PXJAzeFtA1ttY3OR2VSJgGv18S+PFNwD98xHgAgPOT1H5HIV6jlQP8Avzbp09qxJUdpPNw==} + resolution: + { + integrity: sha512-i7z0B+C0P8Q63O/5PXJAzeFtA1ttY3OR2VSJgGv18S+PFNwD98xHgAgPOT1H5HIV6jlQP8Avzbp09qxJUdpPNw==, + } cpu: [arm64] os: [darwin] '@unrs/rspack-resolver-binding-darwin-x64@1.2.2': - resolution: {integrity: sha512-YEdFzPjIbDUCfmehC6eS+AdJYtFWY35YYgWUnqqTM2oe/N58GhNy5yRllxYhxwJ9GcfHoNc6Ubze1yjkNv+9Qg==} + resolution: + { + integrity: sha512-YEdFzPjIbDUCfmehC6eS+AdJYtFWY35YYgWUnqqTM2oe/N58GhNy5yRllxYhxwJ9GcfHoNc6Ubze1yjkNv+9Qg==, + } cpu: [x64] os: [darwin] '@unrs/rspack-resolver-binding-freebsd-x64@1.2.2': - resolution: {integrity: sha512-TU4ntNXDgPN2giQyyzSnGWf/dVCem5lvwxg0XYvsvz35h5H19WrhTmHgbrULMuypCB3aHe1enYUC9rPLDw45mA==} + resolution: + { + integrity: sha512-TU4ntNXDgPN2giQyyzSnGWf/dVCem5lvwxg0XYvsvz35h5H19WrhTmHgbrULMuypCB3aHe1enYUC9rPLDw45mA==, + } cpu: [x64] os: [freebsd] '@unrs/rspack-resolver-binding-linux-arm-gnueabihf@1.2.2': - resolution: {integrity: sha512-ik3w4/rU6RujBvNWiDnKdXi1smBhqxEDhccNi/j2rHaMjm0Fk49KkJ6XKsoUnD2kZ5xaMJf9JjailW/okfUPIw==} + resolution: + { + integrity: sha512-ik3w4/rU6RujBvNWiDnKdXi1smBhqxEDhccNi/j2rHaMjm0Fk49KkJ6XKsoUnD2kZ5xaMJf9JjailW/okfUPIw==, + } cpu: [arm] os: [linux] '@unrs/rspack-resolver-binding-linux-arm64-gnu@1.2.2': - resolution: {integrity: sha512-fp4Azi8kHz6TX8SFmKfyScZrMLfp++uRm2srpqRjsRZIIBzH74NtSkdEUHImR4G7f7XJ+sVZjCc6KDDK04YEpQ==} + resolution: + { + integrity: sha512-fp4Azi8kHz6TX8SFmKfyScZrMLfp++uRm2srpqRjsRZIIBzH74NtSkdEUHImR4G7f7XJ+sVZjCc6KDDK04YEpQ==, + } cpu: [arm64] os: [linux] '@unrs/rspack-resolver-binding-linux-arm64-musl@1.2.2': - resolution: {integrity: sha512-gMiG3DCFioJxdGBzhlL86KcFgt9HGz0iDhw0YVYPsShItpN5pqIkNrI+L/Q/0gfDiGrfcE0X3VANSYIPmqEAlQ==} + resolution: + { + integrity: sha512-gMiG3DCFioJxdGBzhlL86KcFgt9HGz0iDhw0YVYPsShItpN5pqIkNrI+L/Q/0gfDiGrfcE0X3VANSYIPmqEAlQ==, + } cpu: [arm64] os: [linux] '@unrs/rspack-resolver-binding-linux-x64-gnu@1.2.2': - resolution: {integrity: sha512-n/4n2CxaUF9tcaJxEaZm+lqvaw2gflfWQ1R9I7WQgYkKEKbRKbpG/R3hopYdUmLSRI4xaW1Cy0Bz40eS2Yi4Sw==} + resolution: + { + integrity: sha512-n/4n2CxaUF9tcaJxEaZm+lqvaw2gflfWQ1R9I7WQgYkKEKbRKbpG/R3hopYdUmLSRI4xaW1Cy0Bz40eS2Yi4Sw==, + } cpu: [x64] os: [linux] '@unrs/rspack-resolver-binding-linux-x64-musl@1.2.2': - resolution: {integrity: sha512-cHyhAr6rlYYbon1L2Ag449YCj3p6XMfcYTP0AQX+KkQo025d1y/VFtPWvjMhuEsE2lLvtHm7GdJozj6BOMtzVg==} + resolution: + { + integrity: sha512-cHyhAr6rlYYbon1L2Ag449YCj3p6XMfcYTP0AQX+KkQo025d1y/VFtPWvjMhuEsE2lLvtHm7GdJozj6BOMtzVg==, + } cpu: [x64] os: [linux] '@unrs/rspack-resolver-binding-wasm32-wasi@1.2.2': - resolution: {integrity: sha512-eogDKuICghDLGc32FtP+WniG38IB1RcGOGz0G3z8406dUdjJvxfHGuGs/dSlM9YEp/v0lEqhJ4mBu6X2nL9pog==} - engines: {node: '>=14.0.0'} + resolution: + { + integrity: sha512-eogDKuICghDLGc32FtP+WniG38IB1RcGOGz0G3z8406dUdjJvxfHGuGs/dSlM9YEp/v0lEqhJ4mBu6X2nL9pog==, + } + engines: { node: '>=14.0.0' } cpu: [wasm32] '@unrs/rspack-resolver-binding-win32-arm64-msvc@1.2.2': - resolution: {integrity: sha512-7sWRJumhpXSi2lccX8aQpfFXHsSVASdWndLv8AmD8nDRA/5PBi8IplQVZNx2mYRx6+Bp91Z00kuVqpXO9NfCTg==} + resolution: + { + integrity: sha512-7sWRJumhpXSi2lccX8aQpfFXHsSVASdWndLv8AmD8nDRA/5PBi8IplQVZNx2mYRx6+Bp91Z00kuVqpXO9NfCTg==, + } cpu: [arm64] os: [win32] '@unrs/rspack-resolver-binding-win32-x64-msvc@1.2.2': - resolution: {integrity: sha512-hewo/UMGP1a7O6FG/ThcPzSJdm/WwrYDNkdGgWl6M18H6K6MSitklomWpT9MUtT5KGj++QJb06va/14QBC4pvw==} + resolution: + { + integrity: sha512-hewo/UMGP1a7O6FG/ThcPzSJdm/WwrYDNkdGgWl6M18H6K6MSitklomWpT9MUtT5KGj++QJb06va/14QBC4pvw==, + } cpu: [x64] os: [win32] acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + resolution: + { + integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==, + } peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 acorn@8.12.1: - resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} - engines: {node: '>=0.4.0'} + resolution: + { + integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==, + } + engines: { node: '>=0.4.0' } hasBin: true acorn@8.14.1: - resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} - engines: {node: '>=0.4.0'} + resolution: + { + integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==, + } + engines: { node: '>=0.4.0' } hasBin: true ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + resolution: + { + integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==, + } ajv@8.17.1: - resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + resolution: + { + integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==, + } amazon-cognito-identity-js@6.3.12: - resolution: {integrity: sha512-s7NKDZgx336cp+oDeUtB2ZzT8jWJp/v2LWuYl+LQtMEODe22RF1IJ4nRiDATp+rp1pTffCZcm44Quw4jx2bqNg==} + resolution: + { + integrity: sha512-s7NKDZgx336cp+oDeUtB2ZzT8jWJp/v2LWuYl+LQtMEODe22RF1IJ4nRiDATp+rp1pTffCZcm44Quw4jx2bqNg==, + } ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==, + } + engines: { node: '>=8' } anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==, + } + engines: { node: '>= 8' } argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + resolution: + { + integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, + } aria-query@5.3.2: - resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==, + } + engines: { node: '>= 0.4' } array-buffer-byte-length@1.0.2: - resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==, + } + engines: { node: '>= 0.4' } array-includes@3.1.8: - resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==, + } + engines: { node: '>= 0.4' } array.prototype.findlast@1.2.5: - resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==, + } + engines: { node: '>= 0.4' } array.prototype.findlastindex@1.2.6: - resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==, + } + engines: { node: '>= 0.4' } array.prototype.flat@1.3.3: - resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==, + } + engines: { node: '>= 0.4' } array.prototype.flatmap@1.3.3: - resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==, + } + engines: { node: '>= 0.4' } array.prototype.tosorted@1.1.4: - resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==, + } + engines: { node: '>= 0.4' } arraybuffer.prototype.slice@1.0.4: - resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==, + } + engines: { node: '>= 0.4' } ast-types-flow@0.0.8: - resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + resolution: + { + integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==, + } async-function@1.0.0: - resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==, + } + engines: { node: '>= 0.4' } atomic-sleep@1.0.0: - resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} - engines: {node: '>=8.0.0'} + resolution: + { + integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==, + } + engines: { node: '>=8.0.0' } available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==, + } + engines: { node: '>= 0.4' } axe-core@4.10.3: - resolution: {integrity: sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==, + } + engines: { node: '>=4' } axobject-query@4.1.0: - resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==, + } + engines: { node: '>= 0.4' } b4a@1.6.7: - resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==} + resolution: + { + integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==, + } babel-plugin-macros@3.1.0: - resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} - engines: {node: '>=10', npm: '>=6'} + resolution: + { + integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==, + } + engines: { node: '>=10', npm: '>=6' } balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + resolution: + { + integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, + } bare-events@2.5.4: - resolution: {integrity: sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==} + resolution: + { + integrity: sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==, + } bare-fs@4.0.1: - resolution: {integrity: sha512-ilQs4fm/l9eMfWY2dY0WCIUplSUp7U0CT1vrqMg1MUdeZl4fypu5UP0XcDBK5WBQPJAKP1b7XEodISmekH/CEg==} - engines: {bare: '>=1.7.0'} + resolution: + { + integrity: sha512-ilQs4fm/l9eMfWY2dY0WCIUplSUp7U0CT1vrqMg1MUdeZl4fypu5UP0XcDBK5WBQPJAKP1b7XEodISmekH/CEg==, + } + engines: { bare: '>=1.7.0' } bare-os@3.6.0: - resolution: {integrity: sha512-BUrFS5TqSBdA0LwHop4OjPJwisqxGy6JsWVqV6qaFoe965qqtaKfDzHY5T2YA1gUL0ZeeQeA+4BBc1FJTcHiPw==} - engines: {bare: '>=1.14.0'} + resolution: + { + integrity: sha512-BUrFS5TqSBdA0LwHop4OjPJwisqxGy6JsWVqV6qaFoe965qqtaKfDzHY5T2YA1gUL0ZeeQeA+4BBc1FJTcHiPw==, + } + engines: { bare: '>=1.14.0' } bare-path@3.0.0: - resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==} + resolution: + { + integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==, + } bare-stream@2.6.5: - resolution: {integrity: sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==} + resolution: + { + integrity: sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==, + } peerDependencies: bare-buffer: '*' bare-events: '*' @@ -1480,197 +2456,368 @@ packages: optional: true base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + resolution: + { + integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==, + } binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==, + } + engines: { node: '>=8' } bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + resolution: + { + integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==, + } body-scroll-lock@4.0.0-beta.0: - resolution: {integrity: sha512-a7tP5+0Mw3YlUJcGAKUqIBkYYGlYxk2fnCasq/FUph1hadxlTRjF+gAcZksxANnaMnALjxEddmSi/H3OR8ugcQ==} + resolution: + { + integrity: sha512-a7tP5+0Mw3YlUJcGAKUqIBkYYGlYxk2fnCasq/FUph1hadxlTRjF+gAcZksxANnaMnALjxEddmSi/H3OR8ugcQ==, + } bowser@2.11.0: - resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} + resolution: + { + integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==, + } brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + resolution: + { + integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==, + } brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + resolution: + { + integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==, + } braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==, + } + engines: { node: '>=8' } bson-objectid@2.0.4: - resolution: {integrity: sha512-vgnKAUzcDoa+AeyYwXCoHyF2q6u/8H46dxu5JN+4/TZeq/Dlinn0K6GvxsCLb3LHUJl0m/TLiEK31kUwtgocMQ==} + resolution: + { + integrity: sha512-vgnKAUzcDoa+AeyYwXCoHyF2q6u/8H46dxu5JN+4/TZeq/Dlinn0K6GvxsCLb3LHUJl0m/TLiEK31kUwtgocMQ==, + } bson@6.10.3: - resolution: {integrity: sha512-MTxGsqgYTwfshYWTRdmZRC+M7FnG1b4y7RO7p2k3X24Wq0yv1m77Wsj0BzlPzd/IowgESfsruQCUToa7vbOpPQ==} - engines: {node: '>=16.20.1'} + resolution: + { + integrity: sha512-MTxGsqgYTwfshYWTRdmZRC+M7FnG1b4y7RO7p2k3X24Wq0yv1m77Wsj0BzlPzd/IowgESfsruQCUToa7vbOpPQ==, + } + engines: { node: '>=16.20.1' } buffer@4.9.2: - resolution: {integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==} + resolution: + { + integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==, + } buffer@5.6.0: - resolution: {integrity: sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==} + resolution: + { + integrity: sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==, + } buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + resolution: + { + integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==, + } busboy@1.6.0: - resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} - engines: {node: '>=10.16.0'} + resolution: + { + integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==, + } + engines: { node: '>=10.16.0' } call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==, + } + engines: { node: '>= 0.4' } call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==, + } + engines: { node: '>= 0.4' } call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==, + } + engines: { node: '>= 0.4' } callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==, + } + engines: { node: '>=6' } caniuse-lite@1.0.30001706: - resolution: {integrity: sha512-3ZczoTApMAZwPKYWmwVbQMFpXBDds3/0VciVoUwPUbldlYyVLmRVuRs/PcUZtHpbLRpzzDvrvnFuREsGt6lUug==} + resolution: + { + integrity: sha512-3ZczoTApMAZwPKYWmwVbQMFpXBDds3/0VciVoUwPUbldlYyVLmRVuRs/PcUZtHpbLRpzzDvrvnFuREsGt6lUug==, + } ccount@2.0.1: - resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + resolution: + { + integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==, + } chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==, + } + engines: { node: '>=10' } character-entities-html4@2.1.0: - resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + resolution: + { + integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==, + } character-entities-legacy@3.0.0: - resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + resolution: + { + integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==, + } character-entities@2.0.2: - resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + resolution: + { + integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==, + } character-reference-invalid@2.0.1: - resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + resolution: + { + integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==, + } charenc@0.0.2: - resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} + resolution: + { + integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==, + } chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} + resolution: + { + integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==, + } + engines: { node: '>= 8.10.0' } chownr@1.1.4: - resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + resolution: + { + integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==, + } ci-info@4.2.0: - resolution: {integrity: sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==, + } + engines: { node: '>=8' } classnames@2.5.1: - resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + resolution: + { + integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==, + } client-only@0.0.1: - resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + resolution: + { + integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==, + } clsx@2.1.1: - resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==, + } + engines: { node: '>=6' } color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} + resolution: + { + integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==, + } + engines: { node: '>=7.0.0' } color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + resolution: + { + integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, + } color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + resolution: + { + integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==, + } color@4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: '>=12.5.0'} + resolution: + { + integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==, + } + engines: { node: '>=12.5.0' } colorette@2.0.20: - resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + resolution: + { + integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==, + } commander@2.20.3: - resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + resolution: + { + integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==, + } concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + resolution: + { + integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==, + } console-table-printer@2.12.1: - resolution: {integrity: sha512-wKGOQRRvdnd89pCeH96e2Fn4wkbenSP6LMHfjfyNLMbGuHEFbMqQNuxXqd0oXG9caIOQ1FTvc5Uijp9/4jujnQ==} + resolution: + { + integrity: sha512-wKGOQRRvdnd89pCeH96e2Fn4wkbenSP6LMHfjfyNLMbGuHEFbMqQNuxXqd0oXG9caIOQ1FTvc5Uijp9/4jujnQ==, + } convert-source-map@1.9.0: - resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + resolution: + { + integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==, + } cosmiconfig@7.1.0: - resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==, + } + engines: { node: '>=10' } croner@9.0.0: - resolution: {integrity: sha512-onMB0OkDjkXunhdW9htFjEhqrD54+M94i6ackoUkjHKbRnXdyEyKRelp4nJ1kAz32+s27jP1FsebpJCVl0BsvA==} - engines: {node: '>=18.0'} + resolution: + { + integrity: sha512-onMB0OkDjkXunhdW9htFjEhqrD54+M94i6ackoUkjHKbRnXdyEyKRelp4nJ1kAz32+s27jP1FsebpJCVl0BsvA==, + } + engines: { node: '>=18.0' } cross-env@7.0.3: - resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} - engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} + resolution: + { + integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==, + } + engines: { node: '>=10.14', npm: '>=6', yarn: '>=1' } hasBin: true cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==, + } + engines: { node: '>= 8' } crypt@0.0.2: - resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} + resolution: + { + integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==, + } cssfilter@0.0.10: - resolution: {integrity: sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==} + resolution: + { + integrity: sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==, + } csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + resolution: + { + integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==, + } damerau-levenshtein@1.0.8: - resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + resolution: + { + integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==, + } data-view-buffer@1.0.2: - resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==, + } + engines: { node: '>= 0.4' } data-view-byte-length@1.0.2: - resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==, + } + engines: { node: '>= 0.4' } data-view-byte-offset@1.0.1: - resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==, + } + engines: { node: '>= 0.4' } dataloader@2.2.3: - resolution: {integrity: sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==} + resolution: + { + integrity: sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==, + } date-fns@3.6.0: - resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==} + resolution: + { + integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==, + } date-fns@4.1.0: - resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + resolution: + { + integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==, + } dateformat@4.6.3: - resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} + resolution: + { + integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==, + } debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + resolution: + { + integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==, + } peerDependencies: supports-color: '*' peerDependenciesMeta: @@ -1678,8 +2825,11 @@ packages: optional: true debug@4.4.0: - resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} - engines: {node: '>=6.0'} + resolution: + { + integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==, + } + engines: { node: '>=6.0' } peerDependencies: supports-color: '*' peerDependenciesMeta: @@ -1687,112 +2837,199 @@ packages: optional: true decode-named-character-reference@1.1.0: - resolution: {integrity: sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==} + resolution: + { + integrity: sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==, + } decompress-response@6.0.0: - resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==, + } + engines: { node: '>=10' } deep-extend@0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.0'} + resolution: + { + integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==, + } + engines: { node: '>=4.0.0' } deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + resolution: + { + integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==, + } deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==, + } + engines: { node: '>=0.10.0' } define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==, + } + engines: { node: '>= 0.4' } define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==, + } + engines: { node: '>= 0.4' } dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==, + } + engines: { node: '>=6' } detect-libc@2.0.3: - resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==, + } + engines: { node: '>=8' } devlop@1.1.0: - resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + resolution: + { + integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==, + } diff@5.2.0: - resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} - engines: {node: '>=0.3.1'} + resolution: + { + integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==, + } + engines: { node: '>=0.3.1' } doctrine@2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==, + } + engines: { node: '>=0.10.0' } dom-helpers@5.2.1: - resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + resolution: + { + integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==, + } dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==, + } + engines: { node: '>= 0.4' } emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + resolution: + { + integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==, + } end-of-stream@1.4.4: - resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + resolution: + { + integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==, + } error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + resolution: + { + integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==, + } es-abstract@1.23.9: - resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==, + } + engines: { node: '>= 0.4' } es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==, + } + engines: { node: '>= 0.4' } es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==, + } + engines: { node: '>= 0.4' } es-iterator-helpers@1.2.1: - resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==, + } + engines: { node: '>= 0.4' } es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==, + } + engines: { node: '>= 0.4' } es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==, + } + engines: { node: '>= 0.4' } es-shim-unscopables@1.1.0: - resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==, + } + engines: { node: '>= 0.4' } es-to-primitive@1.3.0: - resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==, + } + engines: { node: '>= 0.4' } esbuild@0.23.1: - resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==, + } + engines: { node: '>=18' } hasBin: true escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + resolution: + { + integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==, + } escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==, + } + engines: { node: '>=10' } eslint-config-next@15.2.3: - resolution: {integrity: sha512-VDQwbajhNMFmrhLWVyUXCqsGPN+zz5G8Ys/QwFubfsxTIrkqdx3N3x3QPW+pERz8bzGPP0IgEm8cNbZcd8PFRQ==} + resolution: + { + integrity: sha512-VDQwbajhNMFmrhLWVyUXCqsGPN+zz5G8Ys/QwFubfsxTIrkqdx3N3x3QPW+pERz8bzGPP0IgEm8cNbZcd8PFRQ==, + } peerDependencies: eslint: ^7.23.0 || ^8.0.0 || ^9.0.0 typescript: '>=3.3.1' @@ -1801,11 +3038,17 @@ packages: optional: true eslint-import-resolver-node@0.3.9: - resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + resolution: + { + integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==, + } eslint-import-resolver-typescript@3.9.1: - resolution: {integrity: sha512-euxa5rTGqHeqVxmOHT25hpk58PxkQ4mNoX6Yun4ooGaCHAxOCojJYNvjmyeOQxj/LyW+3fulH0+xtk+p2kPPTw==} - engines: {node: ^14.18.0 || >=16.0.0} + resolution: + { + integrity: sha512-euxa5rTGqHeqVxmOHT25hpk58PxkQ4mNoX6Yun4ooGaCHAxOCojJYNvjmyeOQxj/LyW+3fulH0+xtk+p2kPPTw==, + } + engines: { node: ^14.18.0 || >=16.0.0 } peerDependencies: eslint: '*' eslint-plugin-import: '*' @@ -1817,8 +3060,11 @@ packages: optional: true eslint-module-utils@2.12.0: - resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==, + } + engines: { node: '>=4' } peerDependencies: '@typescript-eslint/parser': '*' eslint: '*' @@ -1838,8 +3084,11 @@ packages: optional: true eslint-plugin-import@2.31.0: - resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==, + } + engines: { node: '>=4' } peerDependencies: '@typescript-eslint/parser': '*' eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 @@ -1848,38 +3097,59 @@ packages: optional: true eslint-plugin-jsx-a11y@6.10.2: - resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} - engines: {node: '>=4.0'} + resolution: + { + integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==, + } + engines: { node: '>=4.0' } peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 eslint-plugin-react-hooks@5.2.0: - resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==, + } + engines: { node: '>=10' } peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 eslint-plugin-react@7.37.4: - resolution: {integrity: sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ==, + } + engines: { node: '>=4' } peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 eslint-scope@8.3.0: - resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + resolution: + { + integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } eslint-visitor-keys@4.2.0: - resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } eslint@9.23.0: - resolution: {integrity: sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } hasBin: true peerDependencies: jiti: '*' @@ -1888,84 +3158,153 @@ packages: optional: true espree@10.3.0: - resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} - engines: {node: '>=0.10'} + resolution: + { + integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==, + } + engines: { node: '>=0.10' } esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} + resolution: + { + integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==, + } + engines: { node: '>=4.0' } estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} + resolution: + { + integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==, + } + engines: { node: '>=4.0' } estree-util-is-identifier-name@3.0.0: - resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + resolution: + { + integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==, + } estree-util-visit@2.0.0: - resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} + resolution: + { + integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==, + } esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==, + } + engines: { node: '>=0.10.0' } events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} + resolution: + { + integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==, + } + engines: { node: '>=0.8.x' } expand-template@2.0.3: - resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==, + } + engines: { node: '>=6' } fast-base64-decode@1.0.0: - resolution: {integrity: sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==} + resolution: + { + integrity: sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==, + } fast-copy@3.0.2: - resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==} + resolution: + { + integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==, + } fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + resolution: + { + integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, + } fast-fifo@1.3.2: - resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + resolution: + { + integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==, + } fast-glob@3.3.1: - resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} - engines: {node: '>=8.6.0'} + resolution: + { + integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==, + } + engines: { node: '>=8.6.0' } fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} + resolution: + { + integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==, + } + engines: { node: '>=8.6.0' } fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + resolution: + { + integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==, + } fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + resolution: + { + integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==, + } fast-redact@3.5.0: - resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==, + } + engines: { node: '>=6' } fast-safe-stringify@2.1.1: - resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + resolution: + { + integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==, + } fast-uri@3.0.6: - resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} + resolution: + { + integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==, + } fast-xml-parser@4.4.1: - resolution: {integrity: sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==} + resolution: + { + integrity: sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==, + } hasBin: true fastq@1.19.1: - resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + resolution: + { + integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==, + } fdir@6.4.3: - resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==} + resolution: + { + integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==, + } peerDependencies: picomatch: ^3 || ^4 peerDependenciesMeta: @@ -1973,574 +3312,1057 @@ packages: optional: true file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} + resolution: + { + integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==, + } + engines: { node: '>=16.0.0' } file-type@19.3.0: - resolution: {integrity: sha512-mROwiKLZf/Kwa/2Rol+OOZQn1eyTkPB3ZTwC0ExY6OLFCbgxHYZvBm7xI77NvfZFMKBsmuXfmLJnD4eEftEhrA==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-mROwiKLZf/Kwa/2Rol+OOZQn1eyTkPB3ZTwC0ExY6OLFCbgxHYZvBm7xI77NvfZFMKBsmuXfmLJnD4eEftEhrA==, + } + engines: { node: '>=18' } fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==, + } + engines: { node: '>=8' } find-root@1.1.0: - resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} + resolution: + { + integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==, + } find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==, + } + engines: { node: '>=10' } flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} + resolution: + { + integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==, + } + engines: { node: '>=16' } flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + resolution: + { + integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==, + } focus-trap@7.5.4: - resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==} + resolution: + { + integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==, + } for-each@0.3.5: - resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==, + } + engines: { node: '>= 0.4' } fs-constants@1.0.0: - resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + resolution: + { + integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==, + } fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + resolution: + { + integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, + } + engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } os: [darwin] function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + resolution: + { + integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==, + } function.prototype.name@1.1.8: - resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==, + } + engines: { node: '>= 0.4' } functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + resolution: + { + integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==, + } get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==, + } + engines: { node: '>= 0.4' } get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==, + } + engines: { node: '>= 0.4' } get-symbol-description@1.1.0: - resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==, + } + engines: { node: '>= 0.4' } get-tsconfig@4.10.0: - resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==} + resolution: + { + integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==, + } get-tsconfig@4.8.1: - resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} + resolution: + { + integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==, + } github-from-package@0.0.0: - resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + resolution: + { + integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==, + } glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} + resolution: + { + integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==, + } + engines: { node: '>= 6' } glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} + resolution: + { + integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==, + } + engines: { node: '>=10.13.0' } globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==, + } + engines: { node: '>=4' } globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==, + } + engines: { node: '>=18' } globalthis@1.0.4: - resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==, + } + engines: { node: '>= 0.4' } gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==, + } + engines: { node: '>= 0.4' } graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + resolution: + { + integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==, + } graphql-http@1.22.4: - resolution: {integrity: sha512-OC3ucK988teMf+Ak/O+ZJ0N2ukcgrEurypp8ePyJFWq83VzwRAmHxxr+XxrMpxO/FIwI4a7m/Fzv3tWGJv0wPA==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-OC3ucK988teMf+Ak/O+ZJ0N2ukcgrEurypp8ePyJFWq83VzwRAmHxxr+XxrMpxO/FIwI4a7m/Fzv3tWGJv0wPA==, + } + engines: { node: '>=12' } peerDependencies: graphql: '>=0.11 <=16' graphql-playground-html@1.6.30: - resolution: {integrity: sha512-tpCujhsJMva4aqE8ULnF7/l3xw4sNRZcSHu+R00VV+W0mfp+Q20Plvcrp+5UXD+2yS6oyCXncA+zoQJQqhGCEw==} + resolution: + { + integrity: sha512-tpCujhsJMva4aqE8ULnF7/l3xw4sNRZcSHu+R00VV+W0mfp+Q20Plvcrp+5UXD+2yS6oyCXncA+zoQJQqhGCEw==, + } graphql-scalars@1.22.2: - resolution: {integrity: sha512-my9FB4GtghqXqi/lWSVAOPiTzTnnEzdOXCsAC2bb5V7EFNQjVjwy3cSSbUvgYOtDuDibd+ZsCDhz+4eykYOlhQ==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-my9FB4GtghqXqi/lWSVAOPiTzTnnEzdOXCsAC2bb5V7EFNQjVjwy3cSSbUvgYOtDuDibd+ZsCDhz+4eykYOlhQ==, + } + engines: { node: '>=10' } peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 graphql@16.10.0: - resolution: {integrity: sha512-AjqGKbDGUFRKIRCP9tCKiIGHyriz2oHEbPIbEtcSLSs4YjReZOIPQQWek4+6hjw62H9QShXHyaGivGiYVLeYFQ==} - engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + resolution: + { + integrity: sha512-AjqGKbDGUFRKIRCP9tCKiIGHyriz2oHEbPIbEtcSLSs4YjReZOIPQQWek4+6hjw62H9QShXHyaGivGiYVLeYFQ==, + } + engines: { node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0 } has-bigints@1.1.0: - resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==, + } + engines: { node: '>= 0.4' } has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==, + } + engines: { node: '>=8' } has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + resolution: + { + integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==, + } has-proto@1.2.0: - resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==, + } + engines: { node: '>= 0.4' } has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==, + } + engines: { node: '>= 0.4' } has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==, + } + engines: { node: '>= 0.4' } hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==, + } + engines: { node: '>= 0.4' } help-me@5.0.0: - resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} + resolution: + { + integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==, + } hoist-non-react-statics@3.3.2: - resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + resolution: + { + integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==, + } http-status@2.1.0: - resolution: {integrity: sha512-O5kPr7AW7wYd/BBiOezTwnVAnmSNFY+J7hlZD2X5IOxVBetjcHAiTXhzj0gMrnojQlwy+UT1/Y3H3vJ3UlmvLA==} - engines: {node: '>= 0.4.0'} + resolution: + { + integrity: sha512-O5kPr7AW7wYd/BBiOezTwnVAnmSNFY+J7hlZD2X5IOxVBetjcHAiTXhzj0gMrnojQlwy+UT1/Y3H3vJ3UlmvLA==, + } + engines: { node: '>= 0.4.0' } ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + resolution: + { + integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==, + } ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} + resolution: + { + integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==, + } + engines: { node: '>= 4' } image-size@1.2.0: - resolution: {integrity: sha512-4S8fwbO6w3GeCVN6OPtA9I5IGKkcDMPcKndtUlpJuCwu7JLjtj7JZpwqLuyY2nrmQT3AWsCJLSKPsc2mPBSl3w==} - engines: {node: '>=16.x'} + resolution: + { + integrity: sha512-4S8fwbO6w3GeCVN6OPtA9I5IGKkcDMPcKndtUlpJuCwu7JLjtj7JZpwqLuyY2nrmQT3AWsCJLSKPsc2mPBSl3w==, + } + engines: { node: '>=16.x' } hasBin: true immutable@4.3.7: - resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} + resolution: + { + integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==, + } import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==, + } + engines: { node: '>=6' } imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} + resolution: + { + integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==, + } + engines: { node: '>=0.8.19' } inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + resolution: + { + integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==, + } ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + resolution: + { + integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==, + } internal-slot@1.1.0: - resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==, + } + engines: { node: '>= 0.4' } is-alphabetical@2.0.1: - resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + resolution: + { + integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==, + } is-alphanumerical@2.0.1: - resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + resolution: + { + integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==, + } is-array-buffer@3.0.5: - resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==, + } + engines: { node: '>= 0.4' } is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + resolution: + { + integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==, + } is-arrayish@0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} + resolution: + { + integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==, + } is-async-function@2.1.1: - resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==, + } + engines: { node: '>= 0.4' } is-bigint@1.1.0: - resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==, + } + engines: { node: '>= 0.4' } is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==, + } + engines: { node: '>=8' } is-boolean-object@1.2.2: - resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==, + } + engines: { node: '>= 0.4' } is-buffer@1.1.6: - resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + resolution: + { + integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==, + } is-bun-module@1.3.0: - resolution: {integrity: sha512-DgXeu5UWI0IsMQundYb5UAOzm6G2eVnarJ0byP6Tm55iZNKceD59LNPA2L4VvsScTtHcw0yEkVwSf7PC+QoLSA==} + resolution: + { + integrity: sha512-DgXeu5UWI0IsMQundYb5UAOzm6G2eVnarJ0byP6Tm55iZNKceD59LNPA2L4VvsScTtHcw0yEkVwSf7PC+QoLSA==, + } is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==, + } + engines: { node: '>= 0.4' } is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==, + } + engines: { node: '>= 0.4' } is-data-view@1.0.2: - resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==, + } + engines: { node: '>= 0.4' } is-date-object@1.1.0: - resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==, + } + engines: { node: '>= 0.4' } is-decimal@2.0.1: - resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + resolution: + { + integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==, + } is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, + } + engines: { node: '>=0.10.0' } is-finalizationregistry@1.1.1: - resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==, + } + engines: { node: '>= 0.4' } is-generator-function@1.1.0: - resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==, + } + engines: { node: '>= 0.4' } is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==, + } + engines: { node: '>=0.10.0' } is-hexadecimal@2.0.1: - resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + resolution: + { + integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==, + } is-map@2.0.3: - resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==, + } + engines: { node: '>= 0.4' } is-number-object@1.1.1: - resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==, + } + engines: { node: '>= 0.4' } is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} + resolution: + { + integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==, + } + engines: { node: '>=0.12.0' } is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==, + } + engines: { node: '>= 0.4' } is-set@2.0.3: - resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==, + } + engines: { node: '>= 0.4' } is-shared-array-buffer@1.0.4: - resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==, + } + engines: { node: '>= 0.4' } is-string@1.1.1: - resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==, + } + engines: { node: '>= 0.4' } is-symbol@1.1.1: - resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==, + } + engines: { node: '>= 0.4' } is-typed-array@1.1.15: - resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==, + } + engines: { node: '>= 0.4' } is-weakmap@2.0.2: - resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==, + } + engines: { node: '>= 0.4' } is-weakref@1.1.1: - resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==, + } + engines: { node: '>= 0.4' } is-weakset@2.0.4: - resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==, + } + engines: { node: '>= 0.4' } isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + resolution: + { + integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==, + } isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + resolution: + { + integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==, + } isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + resolution: + { + integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, + } isomorphic-unfetch@3.1.0: - resolution: {integrity: sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==} + resolution: + { + integrity: sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==, + } isomorphic.js@0.2.5: - resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} + resolution: + { + integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==, + } iterator.prototype@1.1.5: - resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==, + } + engines: { node: '>= 0.4' } jose@5.9.6: - resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==} + resolution: + { + integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==, + } joycon@3.1.1: - resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==, + } + engines: { node: '>=10' } js-cookie@2.2.1: - resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==} + resolution: + { + integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==, + } js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + resolution: + { + integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, + } js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + resolution: + { + integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==, + } hasBin: true jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==, + } + engines: { node: '>=6' } hasBin: true json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + resolution: + { + integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==, + } json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + resolution: + { + integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==, + } json-schema-to-typescript@15.0.3: - resolution: {integrity: sha512-iOKdzTUWEVM4nlxpFudFsWyUiu/Jakkga4OZPEt7CGoSEsAsUgdOZqR6pcgx2STBek9Gm4hcarJpXSzIvZ/hKA==} - engines: {node: '>=16.0.0'} + resolution: + { + integrity: sha512-iOKdzTUWEVM4nlxpFudFsWyUiu/Jakkga4OZPEt7CGoSEsAsUgdOZqR6pcgx2STBek9Gm4hcarJpXSzIvZ/hKA==, + } + engines: { node: '>=16.0.0' } hasBin: true json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + resolution: + { + integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==, + } json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + resolution: + { + integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==, + } json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + resolution: + { + integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==, + } json5@1.0.2: - resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + resolution: + { + integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==, + } hasBin: true jsox@1.2.121: - resolution: {integrity: sha512-9Ag50tKhpTwS6r5wh3MJSAvpSof0UBr39Pto8OnzFT32Z/pAbxAsKHzyvsyMEHVslELvHyO/4/jaQELHk8wDcw==} + resolution: + { + integrity: sha512-9Ag50tKhpTwS6r5wh3MJSAvpSof0UBr39Pto8OnzFT32Z/pAbxAsKHzyvsyMEHVslELvHyO/4/jaQELHk8wDcw==, + } hasBin: true jsx-ast-utils@3.3.5: - resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} - engines: {node: '>=4.0'} + resolution: + { + integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==, + } + engines: { node: '>=4.0' } kareem@2.6.3: - resolution: {integrity: sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==} - engines: {node: '>=12.0.0'} + resolution: + { + integrity: sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==, + } + engines: { node: '>=12.0.0' } keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + resolution: + { + integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==, + } kleur@3.0.3: - resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==, + } + engines: { node: '>=6' } language-subtag-registry@0.3.23: - resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} + resolution: + { + integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==, + } language-tags@1.0.9: - resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} - engines: {node: '>=0.10'} + resolution: + { + integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==, + } + engines: { node: '>=0.10' } levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} + resolution: + { + integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==, + } + engines: { node: '>= 0.8.0' } lexical@0.28.0: - resolution: {integrity: sha512-dLE3O1PZg0TlZxRQo9YDpjCjDUj8zluGyBO9MHdjo21qZmMUNrxQPeCRt8fn2s5l4HKYFQ1YNgl7k1pOJB/vZQ==} + resolution: + { + integrity: sha512-dLE3O1PZg0TlZxRQo9YDpjCjDUj8zluGyBO9MHdjo21qZmMUNrxQPeCRt8fn2s5l4HKYFQ1YNgl7k1pOJB/vZQ==, + } lib0@0.2.100: - resolution: {integrity: sha512-ACQmtZ8cRD7/SpBEzBP88KrgrjOnhfcOANhhk8ASv+HFEvBSHOprxur3vuhmNw4YLq29y4Yen4jU0jHpIqVYWw==} - engines: {node: '>=16'} + resolution: + { + integrity: sha512-ACQmtZ8cRD7/SpBEzBP88KrgrjOnhfcOANhhk8ASv+HFEvBSHOprxur3vuhmNw4YLq29y4Yen4jU0jHpIqVYWw==, + } + engines: { node: '>=16' } hasBin: true lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + resolution: + { + integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==, + } locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==, + } + engines: { node: '>=10' } lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + resolution: + { + integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==, + } lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + resolution: + { + integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==, + } longest-streak@3.1.0: - resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + resolution: + { + integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==, + } loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + resolution: + { + integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==, + } hasBin: true math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==, + } + engines: { node: '>= 0.4' } md5@2.3.0: - resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} + resolution: + { + integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==, + } mdast-util-from-markdown@2.0.2: - resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + resolution: + { + integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==, + } mdast-util-mdx-jsx@3.1.3: - resolution: {integrity: sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==} + resolution: + { + integrity: sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==, + } mdast-util-phrasing@4.1.0: - resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + resolution: + { + integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==, + } mdast-util-to-markdown@2.1.2: - resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + resolution: + { + integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==, + } mdast-util-to-string@4.0.0: - resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + resolution: + { + integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==, + } memoize-one@6.0.0: - resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} + resolution: + { + integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==, + } memory-pager@1.5.0: - resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==} + resolution: + { + integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==, + } merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==, + } + engines: { node: '>= 8' } micromark-core-commonmark@2.0.3: - resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + resolution: + { + integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==, + } micromark-extension-mdx-jsx@3.0.1: - resolution: {integrity: sha512-vNuFb9czP8QCtAQcEJn0UJQJZA8Dk6DXKBqx+bg/w0WGuSxDxNr7hErW89tHUY31dUW4NqEOWwmEUNhjTFmHkg==} + resolution: + { + integrity: sha512-vNuFb9czP8QCtAQcEJn0UJQJZA8Dk6DXKBqx+bg/w0WGuSxDxNr7hErW89tHUY31dUW4NqEOWwmEUNhjTFmHkg==, + } micromark-factory-destination@2.0.1: - resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + resolution: + { + integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==, + } micromark-factory-label@2.0.1: - resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + resolution: + { + integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==, + } micromark-factory-mdx-expression@2.0.2: - resolution: {integrity: sha512-5E5I2pFzJyg2CtemqAbcyCktpHXuJbABnsb32wX2U8IQKhhVFBqkcZR5LRm1WVoFqa4kTueZK4abep7wdo9nrw==} + resolution: + { + integrity: sha512-5E5I2pFzJyg2CtemqAbcyCktpHXuJbABnsb32wX2U8IQKhhVFBqkcZR5LRm1WVoFqa4kTueZK4abep7wdo9nrw==, + } micromark-factory-space@2.0.1: - resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + resolution: + { + integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==, + } micromark-factory-title@2.0.1: - resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + resolution: + { + integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==, + } micromark-factory-whitespace@2.0.1: - resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + resolution: + { + integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==, + } micromark-util-character@2.1.1: - resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + resolution: + { + integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==, + } micromark-util-chunked@2.0.1: - resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + resolution: + { + integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==, + } micromark-util-classify-character@2.0.1: - resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + resolution: + { + integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==, + } micromark-util-combine-extensions@2.0.1: - resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + resolution: + { + integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==, + } micromark-util-decode-numeric-character-reference@2.0.2: - resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + resolution: + { + integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==, + } micromark-util-decode-string@2.0.1: - resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + resolution: + { + integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==, + } micromark-util-encode@2.0.1: - resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + resolution: + { + integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==, + } micromark-util-events-to-acorn@2.0.2: - resolution: {integrity: sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==} + resolution: + { + integrity: sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==, + } micromark-util-html-tag-name@2.0.1: - resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + resolution: + { + integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==, + } micromark-util-normalize-identifier@2.0.1: - resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + resolution: + { + integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==, + } micromark-util-resolve-all@2.0.1: - resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + resolution: + { + integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==, + } micromark-util-sanitize-uri@2.0.1: - resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + resolution: + { + integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==, + } micromark-util-subtokenize@2.1.0: - resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + resolution: + { + integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==, + } micromark-util-symbol@2.0.1: - resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + resolution: + { + integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==, + } micromark-util-types@2.0.2: - resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + resolution: + { + integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==, + } micromark@4.0.2: - resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + resolution: + { + integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==, + } micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} + resolution: + { + integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==, + } + engines: { node: '>=8.6' } mimic-response@3.1.0: - resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==, + } + engines: { node: '>=10' } minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + resolution: + { + integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==, + } minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} + resolution: + { + integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==, + } + engines: { node: '>=16 || 14 >=14.17' } minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + resolution: + { + integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==, + } mkdirp-classic@0.5.3: - resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + resolution: + { + integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==, + } monaco-editor@0.52.2: - resolution: {integrity: sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==} + resolution: + { + integrity: sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==, + } mongodb-connection-string-url@3.0.2: - resolution: {integrity: sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==} + resolution: + { + integrity: sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==, + } mongodb@6.12.0: - resolution: {integrity: sha512-RM7AHlvYfS7jv7+BXund/kR64DryVI+cHbVAy9P61fnb1RcWZqOW1/Wj2YhqMCx+MuYhqTRGv7AwHBzmsCKBfA==} - engines: {node: '>=16.20.1'} + resolution: + { + integrity: sha512-RM7AHlvYfS7jv7+BXund/kR64DryVI+cHbVAy9P61fnb1RcWZqOW1/Wj2YhqMCx+MuYhqTRGv7AwHBzmsCKBfA==, + } + engines: { node: '>=16.20.1' } peerDependencies: '@aws-sdk/credential-providers': ^3.188.0 '@mongodb-js/zstd': ^1.1.0 || ^2.0.0 @@ -2566,38 +4388,65 @@ packages: optional: true mongoose-paginate-v2@1.8.5: - resolution: {integrity: sha512-kFxhot+yw9KmpAGSSrF/o+f00aC2uawgNUbhyaM0USS9L7dln1NA77/pLg4lgOaRgXMtfgCENamjqZwIM1Zrig==} - engines: {node: '>=4.0.0'} + resolution: + { + integrity: sha512-kFxhot+yw9KmpAGSSrF/o+f00aC2uawgNUbhyaM0USS9L7dln1NA77/pLg4lgOaRgXMtfgCENamjqZwIM1Zrig==, + } + engines: { node: '>=4.0.0' } mongoose@8.9.5: - resolution: {integrity: sha512-SPhOrgBm0nKV3b+IIHGqpUTOmgVL5Z3OO9AwkFEmvOZznXTvplbomstCnPOGAyungtRXE5pJTgKpKcZTdjeESg==} - engines: {node: '>=16.20.1'} + resolution: + { + integrity: sha512-SPhOrgBm0nKV3b+IIHGqpUTOmgVL5Z3OO9AwkFEmvOZznXTvplbomstCnPOGAyungtRXE5pJTgKpKcZTdjeESg==, + } + engines: { node: '>=16.20.1' } mpath@0.9.0: - resolution: {integrity: sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==} - engines: {node: '>=4.0.0'} + resolution: + { + integrity: sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==, + } + engines: { node: '>=4.0.0' } mquery@5.0.0: - resolution: {integrity: sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==} - engines: {node: '>=14.0.0'} + resolution: + { + integrity: sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==, + } + engines: { node: '>=14.0.0' } ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + resolution: + { + integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, + } nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + resolution: + { + integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==, + } + engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 } hasBin: true napi-build-utils@2.0.0: - resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + resolution: + { + integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==, + } natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + resolution: + { + integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==, + } next@15.2.3: - resolution: {integrity: sha512-x6eDkZxk2rPpu46E1ZVUWIBhYCLszmUY6fvHBFcbzJ9dD+qRX6vcHusaqqDlnY+VngKzKbAiG2iRCkPbmi8f7w==} - engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + resolution: + { + integrity: sha512-x6eDkZxk2rPpu46E1ZVUWIBhYCLszmUY6fvHBFcbzJ9dD+qRX6vcHusaqqDlnY+VngKzKbAiG2iRCkPbmi8f7w==, + } + engines: { node: ^18.18.0 || ^19.8.0 || >= 20.0.0 } hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -2617,15 +4466,24 @@ packages: optional: true node-abi@3.74.0: - resolution: {integrity: sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==, + } + engines: { node: '>=10' } node-addon-api@6.1.0: - resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} + resolution: + { + integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==, + } node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} + resolution: + { + integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==, + } + engines: { node: 4.x || >=6.0.0 } peerDependencies: encoding: ^0.1.0 peerDependenciesMeta: @@ -2633,504 +4491,891 @@ packages: optional: true nodemailer@6.9.16: - resolution: {integrity: sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==} - engines: {node: '>=6.0.0'} + resolution: + { + integrity: sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==, + } + engines: { node: '>=6.0.0' } normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==, + } + engines: { node: '>=0.10.0' } object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==, + } + engines: { node: '>=0.10.0' } object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==, + } + engines: { node: '>= 0.4' } object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==, + } + engines: { node: '>= 0.4' } object-to-formdata@4.5.1: - resolution: {integrity: sha512-QiM9D0NiU5jV6J6tjE1g7b4Z2tcUnKs1OPUi4iMb2zH+7jwlcUrASghgkFk9GtzqNNq8rTQJtT8AzjBAvLoNMw==} + resolution: + { + integrity: sha512-QiM9D0NiU5jV6J6tjE1g7b4Z2tcUnKs1OPUi4iMb2zH+7jwlcUrASghgkFk9GtzqNNq8rTQJtT8AzjBAvLoNMw==, + } object.assign@4.1.7: - resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==, + } + engines: { node: '>= 0.4' } object.entries@1.1.9: - resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==, + } + engines: { node: '>= 0.4' } object.fromentries@2.0.8: - resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==, + } + engines: { node: '>= 0.4' } object.groupby@1.0.3: - resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==, + } + engines: { node: '>= 0.4' } object.values@1.2.1: - resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==, + } + engines: { node: '>= 0.4' } on-exit-leak-free@2.1.2: - resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} - engines: {node: '>=14.0.0'} + resolution: + { + integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==, + } + engines: { node: '>=14.0.0' } once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + resolution: + { + integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==, + } optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} + resolution: + { + integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==, + } + engines: { node: '>= 0.8.0' } own-keys@1.0.1: - resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==, + } + engines: { node: '>= 0.4' } p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==, + } + engines: { node: '>=10' } p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==, + } + engines: { node: '>=10' } parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==, + } + engines: { node: '>=6' } parse-entities@4.0.2: - resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + resolution: + { + integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==, + } parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==, + } + engines: { node: '>=8' } path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==, + } + engines: { node: '>=8' } path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==, + } + engines: { node: '>=8' } path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + resolution: + { + integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==, + } path-to-regexp@6.3.0: - resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + resolution: + { + integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==, + } path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==, + } + engines: { node: '>=8' } - payload@3.29.0: - resolution: {integrity: sha512-Y/QPIMEagxo2tbfZs8Z7Nn4Uq2m+JziGMtwYpGr0ACzj625xdOy6FE4tR5lJ1ekTfEo+k1gzTHmCiMJ22sZgUQ==} - engines: {node: ^18.20.2 || >=20.9.0} + payload@3.31.0: + resolution: + { + integrity: sha512-rPP4n8yHa7FGh1uCcdx0nng1i71cPUetsiyVK0ntt/IIx0+iwfk9qcEreDboNe5CxZuIozjAt42R70kGYlVStw==, + } + engines: { node: ^18.20.2 || >=20.9.0 } hasBin: true peerDependencies: graphql: ^16.8.1 peek-readable@5.4.2: - resolution: {integrity: sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg==} - engines: {node: '>=14.16'} + resolution: + { + integrity: sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg==, + } + engines: { node: '>=14.16' } picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + resolution: + { + integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==, + } picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} + resolution: + { + integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==, + } + engines: { node: '>=8.6' } picomatch@4.0.2: - resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==, + } + engines: { node: '>=12' } pino-abstract-transport@2.0.0: - resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} + resolution: + { + integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==, + } pino-pretty@13.0.0: - resolution: {integrity: sha512-cQBBIVG3YajgoUjo1FdKVRX6t9XPxwB9lcNJVD5GCnNM4Y6T12YYx8c6zEejxQsU0wrg9TwmDulcE9LR7qcJqA==} + resolution: + { + integrity: sha512-cQBBIVG3YajgoUjo1FdKVRX6t9XPxwB9lcNJVD5GCnNM4Y6T12YYx8c6zEejxQsU0wrg9TwmDulcE9LR7qcJqA==, + } hasBin: true pino-std-serializers@7.0.0: - resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==} + resolution: + { + integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==, + } pino@9.5.0: - resolution: {integrity: sha512-xSEmD4pLnV54t0NOUN16yCl7RIB1c5UUOse5HSyEXtBp+FgFQyPeDutc+Q2ZO7/22vImV7VfEjH/1zV2QuqvYw==} + resolution: + { + integrity: sha512-xSEmD4pLnV54t0NOUN16yCl7RIB1c5UUOse5HSyEXtBp+FgFQyPeDutc+Q2ZO7/22vImV7VfEjH/1zV2QuqvYw==, + } hasBin: true pluralize@8.0.0: - resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==, + } + engines: { node: '>=4' } possible-typed-array-names@1.1.0: - resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==, + } + engines: { node: '>= 0.4' } postcss@8.4.31: - resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} - engines: {node: ^10 || ^12 || >=14} + resolution: + { + integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==, + } + engines: { node: ^10 || ^12 || >=14 } prebuild-install@7.1.3: - resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==, + } + engines: { node: '>=10' } hasBin: true prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} + resolution: + { + integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==, + } + engines: { node: '>= 0.8.0' } prettier@3.5.3: - resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==} - engines: {node: '>=14'} + resolution: + { + integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==, + } + engines: { node: '>=14' } hasBin: true prismjs@1.30.0: - resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==, + } + engines: { node: '>=6' } process-warning@4.0.1: - resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==} + resolution: + { + integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==, + } prompts@2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} + resolution: + { + integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==, + } + engines: { node: '>= 6' } prop-types@15.8.1: - resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + resolution: + { + integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==, + } pump@3.0.2: - resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} + resolution: + { + integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==, + } punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==, + } + engines: { node: '>=6' } qs-esm@7.0.2: - resolution: {integrity: sha512-D8NAthKSD7SGn748v+GLaaO6k08Mvpoqroa35PqIQC4gtUa8/Pb/k+r0m0NnGBVbHDP1gKZ2nVywqfMisRhV5A==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-D8NAthKSD7SGn748v+GLaaO6k08Mvpoqroa35PqIQC4gtUa8/Pb/k+r0m0NnGBVbHDP1gKZ2nVywqfMisRhV5A==, + } + engines: { node: '>=18' } queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + resolution: + { + integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, + } queue@6.0.2: - resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} + resolution: + { + integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==, + } quick-format-unescaped@4.0.4: - resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + resolution: + { + integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==, + } rc@1.2.8: - resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + resolution: + { + integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==, + } hasBin: true react-datepicker@7.6.0: - resolution: {integrity: sha512-9cQH6Z/qa4LrGhzdc3XoHbhrxNcMi9MKjZmYgF/1MNNaJwvdSjv3Xd+jjvrEEbKEf71ZgCA3n7fQbdwd70qCRw==} + resolution: + { + integrity: sha512-9cQH6Z/qa4LrGhzdc3XoHbhrxNcMi9MKjZmYgF/1MNNaJwvdSjv3Xd+jjvrEEbKEf71ZgCA3n7fQbdwd70qCRw==, + } peerDependencies: react: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc react-dom: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc react-diff-viewer-continued@4.0.5: - resolution: {integrity: sha512-L43gIPdhHgu1MYdip4vNqAt5s2JLICKe2/RyGUr2ohAxfhYaH1+QZ6vBO0qgo4xGBhE3jmvbOA/swq4/gdS/0g==} - engines: {node: '>= 16'} + resolution: + { + integrity: sha512-L43gIPdhHgu1MYdip4vNqAt5s2JLICKe2/RyGUr2ohAxfhYaH1+QZ6vBO0qgo4xGBhE3jmvbOA/swq4/gdS/0g==, + } + engines: { node: '>= 16' } peerDependencies: react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom@19.0.0: - resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==} + resolution: + { + integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==, + } peerDependencies: react: ^19.0.0 react-error-boundary@3.1.4: - resolution: {integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==} - engines: {node: '>=10', npm: '>=6'} + resolution: + { + integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==, + } + engines: { node: '>=10', npm: '>=6' } peerDependencies: react: '>=16.13.1' react-error-boundary@4.1.2: - resolution: {integrity: sha512-GQDxZ5Jd+Aq/qUxbCm1UtzmL/s++V7zKgE8yMktJiCQXCCFZnMZh9ng+6/Ne6PjNSXH0L9CjeOEREfRnq6Duag==} + resolution: + { + integrity: sha512-GQDxZ5Jd+Aq/qUxbCm1UtzmL/s++V7zKgE8yMktJiCQXCCFZnMZh9ng+6/Ne6PjNSXH0L9CjeOEREfRnq6Duag==, + } peerDependencies: react: '>=16.13.1' react-image-crop@10.1.8: - resolution: {integrity: sha512-4rb8XtXNx7ZaOZarKKnckgz4xLMvds/YrU6mpJfGhGAsy2Mg4mIw1x+DCCGngVGq2soTBVVOxx2s/C6mTX9+pA==} + resolution: + { + integrity: sha512-4rb8XtXNx7ZaOZarKKnckgz4xLMvds/YrU6mpJfGhGAsy2Mg4mIw1x+DCCGngVGq2soTBVVOxx2s/C6mTX9+pA==, + } peerDependencies: react: '>=16.13.1' react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + resolution: + { + integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==, + } react-select@5.9.0: - resolution: {integrity: sha512-nwRKGanVHGjdccsnzhFte/PULziueZxGD8LL2WojON78Mvnq7LdAMEtu2frrwld1fr3geixg3iiMBIc/LLAZpw==} + resolution: + { + integrity: sha512-nwRKGanVHGjdccsnzhFte/PULziueZxGD8LL2WojON78Mvnq7LdAMEtu2frrwld1fr3geixg3iiMBIc/LLAZpw==, + } peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-transition-group@4.4.5: - resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} + resolution: + { + integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==, + } peerDependencies: react: '>=16.6.0' react-dom: '>=16.6.0' react@19.0.0: - resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==, + } + engines: { node: '>=0.10.0' } readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} + resolution: + { + integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==, + } + engines: { node: '>= 6' } readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} + resolution: + { + integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==, + } + engines: { node: '>=8.10.0' } real-require@0.2.0: - resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} - engines: {node: '>= 12.13.0'} + resolution: + { + integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==, + } + engines: { node: '>= 12.13.0' } reflect.getprototypeof@1.0.10: - resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==, + } + engines: { node: '>= 0.4' } regenerator-runtime@0.14.1: - resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + resolution: + { + integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==, + } regexp.prototype.flags@1.5.4: - resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==, + } + engines: { node: '>= 0.4' } require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==, + } + engines: { node: '>=0.10.0' } resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==, + } + engines: { node: '>=4' } resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolution: + { + integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==, + } resolve@1.22.10: - resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==, + } + engines: { node: '>= 0.4' } hasBin: true resolve@2.0.0-next.5: - resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + resolution: + { + integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==, + } hasBin: true reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + resolution: + { + integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==, + } + engines: { iojs: '>=1.0.0', node: '>=0.10.0' } rspack-resolver@1.2.2: - resolution: {integrity: sha512-Fwc19jMBA3g+fxDJH2B4WxwZjE0VaaOL7OX/A4Wn5Zv7bOD/vyPZhzXfaO73Xc2GAlfi96g5fGUa378WbIGfFw==} + resolution: + { + integrity: sha512-Fwc19jMBA3g+fxDJH2B4WxwZjE0VaaOL7OX/A4Wn5Zv7bOD/vyPZhzXfaO73Xc2GAlfi96g5fGUa378WbIGfFw==, + } run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + resolution: + { + integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==, + } safe-array-concat@1.1.3: - resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} - engines: {node: '>=0.4'} + resolution: + { + integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==, + } + engines: { node: '>=0.4' } safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + resolution: + { + integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==, + } safe-push-apply@1.0.0: - resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==, + } + engines: { node: '>= 0.4' } safe-regex-test@1.1.0: - resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==, + } + engines: { node: '>= 0.4' } safe-stable-stringify@2.5.0: - resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==, + } + engines: { node: '>=10' } sanitize-filename@1.6.3: - resolution: {integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==} + resolution: + { + integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==, + } sass@1.77.4: - resolution: {integrity: sha512-vcF3Ckow6g939GMA4PeU7b2K/9FALXk2KF9J87txdHzXbUF9XRQRwSxcAs/fGaTnJeBFd7UoV22j3lzMLdM0Pw==} - engines: {node: '>=14.0.0'} + resolution: + { + integrity: sha512-vcF3Ckow6g939GMA4PeU7b2K/9FALXk2KF9J87txdHzXbUF9XRQRwSxcAs/fGaTnJeBFd7UoV22j3lzMLdM0Pw==, + } + engines: { node: '>=14.0.0' } hasBin: true scheduler@0.25.0: - resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} + resolution: + { + integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==, + } scmp@2.1.0: - resolution: {integrity: sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==} + resolution: + { + integrity: sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==, + } secure-json-parse@2.7.0: - resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + resolution: + { + integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==, + } semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + resolution: + { + integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==, + } hasBin: true semver@7.7.1: - resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==, + } + engines: { node: '>=10' } hasBin: true set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==, + } + engines: { node: '>= 0.4' } set-function-name@2.0.2: - resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==, + } + engines: { node: '>= 0.4' } set-proto@1.0.0: - resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==, + } + engines: { node: '>= 0.4' } sharp@0.32.6: - resolution: {integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==} - engines: {node: '>=14.15.0'} + resolution: + { + integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==, + } + engines: { node: '>=14.15.0' } sharp@0.33.5: - resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==, + } + engines: { node: '>=8' } shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==, + } + engines: { node: '>=8' } side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==, + } + engines: { node: '>= 0.4' } side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==, + } + engines: { node: '>= 0.4' } side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==, + } + engines: { node: '>= 0.4' } side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==, + } + engines: { node: '>= 0.4' } sift@17.1.3: - resolution: {integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==} + resolution: + { + integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==, + } simple-concat@1.0.1: - resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + resolution: + { + integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==, + } simple-get@4.0.1: - resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + resolution: + { + integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==, + } simple-swizzle@0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + resolution: + { + integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==, + } simple-wcswidth@1.0.1: - resolution: {integrity: sha512-xMO/8eNREtaROt7tJvWJqHBDTMFN4eiQ5I4JRMuilwfnFcV5W9u7RUkueNkdw0jPqGMX36iCywelS5yilTuOxg==} + resolution: + { + integrity: sha512-xMO/8eNREtaROt7tJvWJqHBDTMFN4eiQ5I4JRMuilwfnFcV5W9u7RUkueNkdw0jPqGMX36iCywelS5yilTuOxg==, + } sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + resolution: + { + integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==, + } sonic-boom@4.2.0: - resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} + resolution: + { + integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==, + } sonner@1.7.4: - resolution: {integrity: sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==} + resolution: + { + integrity: sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==, + } peerDependencies: react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==, + } + engines: { node: '>=0.10.0' } source-map@0.5.7: - resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==, + } + engines: { node: '>=0.10.0' } sparse-bitfield@3.0.3: - resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==} + resolution: + { + integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==, + } split2@4.2.0: - resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} - engines: {node: '>= 10.x'} + resolution: + { + integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==, + } + engines: { node: '>= 10.x' } stable-hash@0.0.5: - resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} + resolution: + { + integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==, + } state-local@1.0.7: - resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} + resolution: + { + integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==, + } stream-browserify@3.0.0: - resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==} + resolution: + { + integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==, + } streamsearch@1.1.0: - resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} - engines: {node: '>=10.0.0'} + resolution: + { + integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==, + } + engines: { node: '>=10.0.0' } streamx@2.22.0: - resolution: {integrity: sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==} + resolution: + { + integrity: sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==, + } string.prototype.includes@2.0.1: - resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==, + } + engines: { node: '>= 0.4' } string.prototype.matchall@4.0.12: - resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==, + } + engines: { node: '>= 0.4' } string.prototype.repeat@1.0.0: - resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + resolution: + { + integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==, + } string.prototype.trim@1.2.10: - resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==, + } + engines: { node: '>= 0.4' } string.prototype.trimend@1.0.9: - resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==, + } + engines: { node: '>= 0.4' } string.prototype.trimstart@1.0.8: - resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==, + } + engines: { node: '>= 0.4' } string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + resolution: + { + integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==, + } stringify-entities@4.0.4: - resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + resolution: + { + integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==, + } strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==, + } + engines: { node: '>=4' } strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==, + } + engines: { node: '>=0.10.0' } strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==, + } + engines: { node: '>=8' } strnum@1.1.2: - resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==} + resolution: + { + integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==, + } strtok3@8.1.0: - resolution: {integrity: sha512-ExzDvHYPj6F6QkSNe/JxSlBxTh3OrI6wrAIz53ulxo1c4hBJ1bT9C/JrAthEKHWG9riVH3Xzg7B03Oxty6S2Lw==} - engines: {node: '>=16'} + resolution: + { + integrity: sha512-ExzDvHYPj6F6QkSNe/JxSlBxTh3OrI6wrAIz53ulxo1c4hBJ1bT9C/JrAthEKHWG9riVH3Xzg7B03Oxty6S2Lw==, + } + engines: { node: '>=16' } styled-jsx@5.1.6: - resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} - engines: {node: '>= 12.0.0'} + resolution: + { + integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==, + } + engines: { node: '>= 12.0.0' } peerDependencies: '@babel/core': '*' babel-plugin-macros: '*' @@ -3142,68 +5387,122 @@ packages: optional: true stylis@4.2.0: - resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} + resolution: + { + integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==, + } supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==, + } + engines: { node: '>=8' } supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==, + } + engines: { node: '>= 0.4' } tabbable@6.2.0: - resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + resolution: + { + integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==, + } tar-fs@2.1.2: - resolution: {integrity: sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==} + resolution: + { + integrity: sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==, + } tar-fs@3.0.8: - resolution: {integrity: sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg==} + resolution: + { + integrity: sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg==, + } tar-stream@2.2.0: - resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==, + } + engines: { node: '>=6' } tar-stream@3.1.7: - resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + resolution: + { + integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==, + } text-decoder@1.2.3: - resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} + resolution: + { + integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==, + } thread-stream@3.1.0: - resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + resolution: + { + integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==, + } tinyglobby@0.2.12: - resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==} - engines: {node: '>=12.0.0'} + resolution: + { + integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==, + } + engines: { node: '>=12.0.0' } to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} + resolution: + { + integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==, + } + engines: { node: '>=8.0' } token-types@6.0.0: - resolution: {integrity: sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA==} - engines: {node: '>=14.16'} + resolution: + { + integrity: sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA==, + } + engines: { node: '>=14.16' } tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + resolution: + { + integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==, + } tr46@5.1.0: - resolution: {integrity: sha512-IUWnUK7ADYR5Sl1fZlO1INDUhVhatWl7BtJWsIhwJ0UAK7ilzzIa8uIqOO/aYVWHZPJkKbEL+362wrzoeRF7bw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-IUWnUK7ADYR5Sl1fZlO1INDUhVhatWl7BtJWsIhwJ0UAK7ilzzIa8uIqOO/aYVWHZPJkKbEL+362wrzoeRF7bw==, + } + engines: { node: '>=18' } truncate-utf8-bytes@1.0.2: - resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} + resolution: + { + integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==, + } ts-api-utils@2.1.0: - resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} - engines: {node: '>=18.12'} + resolution: + { + integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==, + } + engines: { node: '>=18.12' } peerDependencies: typescript: '>=4.8.4' ts-essentials@10.0.3: - resolution: {integrity: sha512-/FrVAZ76JLTWxJOERk04fm8hYENDo0PWSP3YLQKxevLwWtxemGcl5JJEzN4iqfDlRve0ckyfFaOBu4xbNH/wZw==} + resolution: + { + integrity: sha512-/FrVAZ76JLTWxJOERk04fm8hYENDo0PWSP3YLQKxevLwWtxemGcl5JJEzN4iqfDlRve0ckyfFaOBu4xbNH/wZw==, + } peerDependencies: typescript: '>=4.5.0' peerDependenciesMeta: @@ -3211,87 +5510,156 @@ packages: optional: true tsconfig-paths@3.15.0: - resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + resolution: + { + integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==, + } tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + resolution: + { + integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==, + } tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + resolution: + { + integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==, + } tsx@4.19.2: - resolution: {integrity: sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==, + } + engines: { node: '>=18.0.0' } hasBin: true tunnel-agent@0.6.0: - resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + resolution: + { + integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==, + } type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} + resolution: + { + integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==, + } + engines: { node: '>= 0.8.0' } typed-array-buffer@1.0.3: - resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==, + } + engines: { node: '>= 0.4' } typed-array-byte-length@1.0.3: - resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==, + } + engines: { node: '>= 0.4' } typed-array-byte-offset@1.0.4: - resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==, + } + engines: { node: '>= 0.4' } typed-array-length@1.0.7: - resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==, + } + engines: { node: '>= 0.4' } typescript@5.7.3: - resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} - engines: {node: '>=14.17'} + resolution: + { + integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==, + } + engines: { node: '>=14.17' } hasBin: true uint8array-extras@1.4.0: - resolution: {integrity: sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==, + } + engines: { node: '>=18' } unbox-primitive@1.1.0: - resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==, + } + engines: { node: '>= 0.4' } undici-types@6.20.0: - resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + resolution: + { + integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==, + } unfetch@4.2.0: - resolution: {integrity: sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==} + resolution: + { + integrity: sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==, + } unist-util-is@6.0.0: - resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} + resolution: + { + integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==, + } unist-util-position-from-estree@2.0.0: - resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} + resolution: + { + integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==, + } unist-util-stringify-position@4.0.0: - resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + resolution: + { + integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==, + } unist-util-visit-parents@6.0.1: - resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} + resolution: + { + integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==, + } unist-util-visit@5.0.0: - resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + resolution: + { + integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==, + } uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + resolution: + { + integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==, + } use-context-selector@2.0.0: - resolution: {integrity: sha512-owfuSmUNd3eNp3J9CdDl0kMgfidV+MkDvHPpvthN5ThqM+ibMccNE0k+Iq7TWC6JPFvGZqanqiGCuQx6DyV24g==} + resolution: + { + integrity: sha512-owfuSmUNd3eNp3J9CdDl0kMgfidV+MkDvHPpvthN5ThqM+ibMccNE0k+Iq7TWC6JPFvGZqanqiGCuQx6DyV24g==, + } peerDependencies: react: '>=18.0.0' scheduler: '>=0.19.0' use-isomorphic-layout-effect@1.2.0: - resolution: {integrity: sha512-q6ayo8DWoPZT0VdG4u3D3uxcgONP3Mevx2i2b0434cwWBoL+aelL1DzkXI6w3PhTZzUeR2kaVlZn70iCiseP6w==} + resolution: + { + integrity: sha512-q6ayo8DWoPZT0VdG4u3D3uxcgONP3Mevx2i2b0434cwWBoL+aelL1DzkXI6w3PhTZzUeR2kaVlZn70iCiseP6w==, + } peerDependencies: '@types/react': '*' react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -3300,67 +5668,118 @@ packages: optional: true utf8-byte-length@1.0.5: - resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==} + resolution: + { + integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==, + } util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + resolution: + { + integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==, + } uuid@10.0.0: - resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + resolution: + { + integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==, + } hasBin: true uuid@9.0.1: - resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + resolution: + { + integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==, + } hasBin: true vfile-message@4.0.2: - resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} + resolution: + { + integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==, + } webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + resolution: + { + integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==, + } webidl-conversions@7.0.0: - resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==, + } + engines: { node: '>=12' } whatwg-url@14.2.0: - resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==, + } + engines: { node: '>=18' } whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + resolution: + { + integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==, + } which-boxed-primitive@1.1.1: - resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==, + } + engines: { node: '>= 0.4' } which-builtin-type@1.2.1: - resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==, + } + engines: { node: '>= 0.4' } which-collection@1.0.2: - resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==, + } + engines: { node: '>= 0.4' } which-typed-array@1.1.19: - resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==, + } + engines: { node: '>= 0.4' } which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==, + } + engines: { node: '>= 8' } hasBin: true word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==, + } + engines: { node: '>=0.10.0' } wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + resolution: + { + integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, + } ws@8.18.1: - resolution: {integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==} - engines: {node: '>=10.0.0'} + resolution: + { + integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==, + } + engines: { node: '>=10.0.0' } peerDependencies: bufferutil: ^4.0.1 utf-8-validate: '>=5.0.2' @@ -3371,27 +5790,41 @@ packages: optional: true xss@1.0.15: - resolution: {integrity: sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==} - engines: {node: '>= 0.10.0'} + resolution: + { + integrity: sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==, + } + engines: { node: '>= 0.10.0' } hasBin: true yaml@1.10.2: - resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} - engines: {node: '>= 6'} + resolution: + { + integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==, + } + engines: { node: '>= 6' } yjs@13.6.24: - resolution: {integrity: sha512-xn/pYLTZa3uD1uDG8lpxfLRo5SR/rp0frdASOl2a71aYNvUXdWcLtVL91s2y7j+Q8ppmjZ9H3jsGVgoFMbT2VA==} - engines: {node: '>=16.0.0', npm: '>=8.0.0'} + resolution: + { + integrity: sha512-xn/pYLTZa3uD1uDG8lpxfLRo5SR/rp0frdASOl2a71aYNvUXdWcLtVL91s2y7j+Q8ppmjZ9H3jsGVgoFMbT2VA==, + } + engines: { node: '>=16.0.0', npm: '>=8.0.0' } yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==, + } + engines: { node: '>=10' } zwitch@2.0.4: - resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + resolution: + { + integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==, + } snapshots: - '@apidevtools/json-schema-ref-parser@11.9.3': dependencies: '@jsdevtools/ono': 7.1.3 @@ -4613,11 +7046,11 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} - '@payloadcms/db-mongodb@3.29.0(@aws-sdk/credential-providers@3.772.0)(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))': + '@payloadcms/db-mongodb@3.31.0(@aws-sdk/credential-providers@3.772.0)(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))': dependencies: mongoose: 8.9.5(@aws-sdk/credential-providers@3.772.0) mongoose-paginate-v2: 1.8.5 - payload: 3.29.0(graphql@16.10.0)(typescript@5.7.3) + payload: 3.31.0(graphql@16.10.0)(typescript@5.7.3) prompts: 2.4.2 uuid: 10.0.0 transitivePeerDependencies: @@ -4630,28 +7063,28 @@ snapshots: - socks - supports-color - '@payloadcms/email-nodemailer@3.29.0(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))': + '@payloadcms/email-nodemailer@3.31.0(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))': dependencies: nodemailer: 6.9.16 - payload: 3.29.0(graphql@16.10.0)(typescript@5.7.3) + payload: 3.31.0(graphql@16.10.0)(typescript@5.7.3) - '@payloadcms/graphql@3.29.0(graphql@16.10.0)(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(typescript@5.7.3)': + '@payloadcms/graphql@3.31.0(graphql@16.10.0)(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(typescript@5.7.3)': dependencies: graphql: 16.10.0 graphql-scalars: 1.22.2(graphql@16.10.0) - payload: 3.29.0(graphql@16.10.0)(typescript@5.7.3) + payload: 3.31.0(graphql@16.10.0)(typescript@5.7.3) pluralize: 8.0.0 ts-essentials: 10.0.3(typescript@5.7.3) tsx: 4.19.2 transitivePeerDependencies: - typescript - '@payloadcms/next@3.29.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)': + '@payloadcms/next@3.31.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)': dependencies: '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@payloadcms/graphql': 3.29.0(graphql@16.10.0)(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(typescript@5.7.3) - '@payloadcms/translations': 3.29.0 - '@payloadcms/ui': 3.29.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + '@payloadcms/graphql': 3.31.0(graphql@16.10.0)(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(typescript@5.7.3) + '@payloadcms/translations': 3.31.0 + '@payloadcms/ui': 3.31.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) busboy: 1.6.0 dequal: 2.0.3 file-type: 19.3.0 @@ -4661,7 +7094,7 @@ snapshots: http-status: 2.1.0 next: 15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) path-to-regexp: 6.3.0 - payload: 3.29.0(graphql@16.10.0)(typescript@5.7.3) + payload: 3.31.0(graphql@16.10.0)(typescript@5.7.3) qs-esm: 7.0.2 react-diff-viewer-continued: 4.0.5(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) sass: 1.77.4 @@ -4674,21 +7107,21 @@ snapshots: - supports-color - typescript - '@payloadcms/payload-cloud@3.29.0(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))': + '@payloadcms/payload-cloud@3.31.0(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))': dependencies: '@aws-sdk/client-cognito-identity': 3.772.0 '@aws-sdk/client-s3': 3.772.0 '@aws-sdk/credential-providers': 3.772.0 '@aws-sdk/lib-storage': 3.772.0(@aws-sdk/client-s3@3.772.0) - '@payloadcms/email-nodemailer': 3.29.0(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3)) + '@payloadcms/email-nodemailer': 3.31.0(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3)) amazon-cognito-identity-js: 6.3.12 nodemailer: 6.9.16 - payload: 3.29.0(graphql@16.10.0)(typescript@5.7.3) + payload: 3.31.0(graphql@16.10.0)(typescript@5.7.3) transitivePeerDependencies: - aws-crt - encoding - '@payloadcms/richtext-lexical@3.29.0(@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@faceless-ui/scroll-info@2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@payloadcms/next@3.29.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3))(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)(yjs@13.6.24)': + '@payloadcms/richtext-lexical@3.31.0(@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@faceless-ui/scroll-info@2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@payloadcms/next@3.31.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3))(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)(yjs@13.6.24)': dependencies: '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@faceless-ui/scroll-info': 2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -4702,9 +7135,9 @@ snapshots: '@lexical/selection': 0.28.0 '@lexical/table': 0.28.0 '@lexical/utils': 0.28.0 - '@payloadcms/next': 3.29.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) - '@payloadcms/translations': 3.29.0 - '@payloadcms/ui': 3.29.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + '@payloadcms/next': 3.31.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + '@payloadcms/translations': 3.31.0 + '@payloadcms/ui': 3.31.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) '@types/uuid': 10.0.0 acorn: 8.12.1 bson-objectid: 2.0.4 @@ -4715,7 +7148,7 @@ snapshots: mdast-util-from-markdown: 2.0.2 mdast-util-mdx-jsx: 3.1.3 micromark-extension-mdx-jsx: 3.0.1 - payload: 3.29.0(graphql@16.10.0)(typescript@5.7.3) + payload: 3.31.0(graphql@16.10.0)(typescript@5.7.3) qs-esm: 7.0.2 react: 19.0.0 react-dom: 19.0.0(react@19.0.0) @@ -4730,11 +7163,11 @@ snapshots: - typescript - yjs - '@payloadcms/translations@3.29.0': + '@payloadcms/translations@3.31.0': dependencies: date-fns: 4.1.0 - '@payloadcms/ui@3.29.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)': + '@payloadcms/ui@3.31.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)': dependencies: '@date-fns/tz': 1.2.0 '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -4743,14 +7176,14 @@ snapshots: '@faceless-ui/scroll-info': 2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@faceless-ui/window-info': 3.0.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@monaco-editor/react': 4.7.0(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@payloadcms/translations': 3.29.0 + '@payloadcms/translations': 3.31.0 bson-objectid: 2.0.4 date-fns: 4.1.0 dequal: 2.0.3 md5: 2.3.0 next: 15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) object-to-formdata: 4.5.1 - payload: 3.29.0(graphql@16.10.0)(typescript@5.7.3) + payload: 3.31.0(graphql@16.10.0)(typescript@5.7.3) qs-esm: 7.0.2 react: 19.0.0 react-datepicker: 7.6.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -6975,10 +9408,10 @@ snapshots: path-type@4.0.0: {} - payload@3.29.0(graphql@16.10.0)(typescript@5.7.3): + payload@3.31.0(graphql@16.10.0)(typescript@5.7.3): dependencies: '@next/env': 15.2.3 - '@payloadcms/translations': 3.29.0 + '@payloadcms/translations': 3.31.0 '@types/busboy': 1.5.4 ajv: 8.17.1 bson-objectid: 2.0.4 @@ -7632,7 +10065,7 @@ snapshots: tsx@4.19.2: dependencies: esbuild: 0.23.1 - get-tsconfig: 4.8.1 + get-tsconfig: 4.10.0 optionalDependencies: fsevents: 2.3.3 diff --git a/templates/website/package.json b/templates/website/package.json index a2e4d207ae..93decef549 100644 --- a/templates/website/package.json +++ b/templates/website/package.json @@ -19,18 +19,18 @@ "start": "cross-env NODE_OPTIONS=--no-deprecation next start" }, "dependencies": { - "@payloadcms/admin-bar": "latest", - "@payloadcms/db-mongodb": "latest", - "@payloadcms/live-preview-react": "latest", - "@payloadcms/next": "latest", - "@payloadcms/payload-cloud": "latest", - "@payloadcms/plugin-form-builder": "latest", - "@payloadcms/plugin-nested-docs": "latest", - "@payloadcms/plugin-redirects": "latest", - "@payloadcms/plugin-search": "latest", - "@payloadcms/plugin-seo": "latest", - "@payloadcms/richtext-lexical": "latest", - "@payloadcms/ui": "latest", + "@payloadcms/admin-bar": "3.31.0", + "@payloadcms/db-mongodb": "3.31.0", + "@payloadcms/live-preview-react": "3.31.0", + "@payloadcms/next": "3.31.0", + "@payloadcms/payload-cloud": "3.31.0", + "@payloadcms/plugin-form-builder": "3.31.0", + "@payloadcms/plugin-nested-docs": "3.31.0", + "@payloadcms/plugin-redirects": "3.31.0", + "@payloadcms/plugin-search": "3.31.0", + "@payloadcms/plugin-seo": "3.31.0", + "@payloadcms/richtext-lexical": "3.31.0", + "@payloadcms/ui": "3.31.0", "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-select": "^2.0.0", @@ -43,7 +43,7 @@ "lucide-react": "^0.378.0", "next": "15.2.3", "next-sitemap": "^4.2.3", - "payload": "latest", + "payload": "3.31.0", "prism-react-renderer": "^2.3.1", "react": "19.0.0", "react-dom": "19.0.0", diff --git a/templates/website/pnpm-lock.yaml b/templates/website/pnpm-lock.yaml index d116159365..5c9b74bad0 100644 --- a/templates/website/pnpm-lock.yaml +++ b/templates/website/pnpm-lock.yaml @@ -5,45 +5,44 @@ settings: excludeLinksFromLockfile: false importers: - .: dependencies: '@payloadcms/admin-bar': - specifier: latest - version: 3.29.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: 3.31.0 + version: 3.31.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@payloadcms/db-mongodb': - specifier: latest - version: 3.29.0(@aws-sdk/credential-providers@3.772.0)(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3)) + specifier: 3.31.0 + version: 3.31.0(@aws-sdk/credential-providers@3.772.0)(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3)) '@payloadcms/live-preview-react': - specifier: latest - version: 3.29.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: 3.31.0 + version: 3.31.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@payloadcms/next': - specifier: latest - version: 3.29.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + specifier: 3.31.0 + version: 3.31.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) '@payloadcms/payload-cloud': - specifier: latest - version: 3.29.0(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3)) + specifier: 3.31.0 + version: 3.31.0(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3)) '@payloadcms/plugin-form-builder': - specifier: latest - version: 3.29.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + specifier: 3.31.0 + version: 3.31.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) '@payloadcms/plugin-nested-docs': - specifier: latest - version: 3.29.0(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3)) + specifier: 3.31.0 + version: 3.31.0(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3)) '@payloadcms/plugin-redirects': - specifier: latest - version: 3.29.0(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3)) + specifier: 3.31.0 + version: 3.31.0(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3)) '@payloadcms/plugin-search': - specifier: latest - version: 3.29.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + specifier: 3.31.0 + version: 3.31.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) '@payloadcms/plugin-seo': - specifier: latest - version: 3.29.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + specifier: 3.31.0 + version: 3.31.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) '@payloadcms/richtext-lexical': - specifier: latest - version: 3.29.0(@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@faceless-ui/scroll-info@2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@payloadcms/next@3.29.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3))(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)(yjs@13.6.24) + specifier: 3.31.0 + version: 3.31.0(@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@faceless-ui/scroll-info@2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@payloadcms/next@3.31.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3))(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)(yjs@13.6.24) '@payloadcms/ui': - specifier: latest - version: 3.29.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + specifier: 3.31.0 + version: 3.31.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) '@radix-ui/react-checkbox': specifier: ^1.0.4 version: 1.1.4(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -81,8 +80,8 @@ importers: specifier: ^4.2.3 version: 4.2.3(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4)) payload: - specifier: latest - version: 3.29.0(graphql@16.10.0)(typescript@5.7.3) + specifier: 3.31.0 + version: 3.31.0(graphql@16.10.0)(typescript@5.7.3) prism-react-renderer: specifier: ^2.3.1 version: 2.4.1(react@19.0.0) @@ -149,180 +148,314 @@ importers: version: 5.7.3 packages: - '@alloc/quick-lru@5.2.0': - resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==, + } + engines: { node: '>=10' } '@apidevtools/json-schema-ref-parser@11.9.3': - resolution: {integrity: sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==} - engines: {node: '>= 16'} + resolution: + { + integrity: sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==, + } + engines: { node: '>= 16' } '@aws-crypto/crc32@5.2.0': - resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} - engines: {node: '>=16.0.0'} + resolution: + { + integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==, + } + engines: { node: '>=16.0.0' } '@aws-crypto/crc32c@5.2.0': - resolution: {integrity: sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==} + resolution: + { + integrity: sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==, + } '@aws-crypto/sha1-browser@5.2.0': - resolution: {integrity: sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==} + resolution: + { + integrity: sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==, + } '@aws-crypto/sha256-browser@5.2.0': - resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + resolution: + { + integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==, + } '@aws-crypto/sha256-js@1.2.2': - resolution: {integrity: sha512-Nr1QJIbW/afYYGzYvrF70LtaHrIRtd4TNAglX8BvlfxJLZ45SAmueIKYl5tWoNBPzp65ymXGFK0Bb1vZUpuc9g==} + resolution: + { + integrity: sha512-Nr1QJIbW/afYYGzYvrF70LtaHrIRtd4TNAglX8BvlfxJLZ45SAmueIKYl5tWoNBPzp65ymXGFK0Bb1vZUpuc9g==, + } '@aws-crypto/sha256-js@5.2.0': - resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} - engines: {node: '>=16.0.0'} + resolution: + { + integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==, + } + engines: { node: '>=16.0.0' } '@aws-crypto/supports-web-crypto@5.2.0': - resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + resolution: + { + integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==, + } '@aws-crypto/util@1.2.2': - resolution: {integrity: sha512-H8PjG5WJ4wz0UXAFXeJjWCW1vkvIJ3qUUD+rGRwJ2/hj+xT58Qle2MTql/2MGzkU+1JLAFuR6aJpLAjHwhmwwg==} + resolution: + { + integrity: sha512-H8PjG5WJ4wz0UXAFXeJjWCW1vkvIJ3qUUD+rGRwJ2/hj+xT58Qle2MTql/2MGzkU+1JLAFuR6aJpLAjHwhmwwg==, + } '@aws-crypto/util@5.2.0': - resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + resolution: + { + integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==, + } '@aws-sdk/client-cognito-identity@3.772.0': - resolution: {integrity: sha512-R11dYd2NGAH9TDRUJHd3Ab3HZzSoyqwQu+ZR9MZdcA2l3k99mqsrvcLp60YBPGq1dOEQDB1A85xgrAwtWLj81Q==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-R11dYd2NGAH9TDRUJHd3Ab3HZzSoyqwQu+ZR9MZdcA2l3k99mqsrvcLp60YBPGq1dOEQDB1A85xgrAwtWLj81Q==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/client-s3@3.772.0': - resolution: {integrity: sha512-HQXlQIyyLp47h1/Hdjr36yK8/gsAAFX2vRzgDJhSRaz0vWZlWX07AJdYfrxapLUXfVU6DbBu3rwi2UGqM7ixqQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-HQXlQIyyLp47h1/Hdjr36yK8/gsAAFX2vRzgDJhSRaz0vWZlWX07AJdYfrxapLUXfVU6DbBu3rwi2UGqM7ixqQ==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/client-sso@3.772.0': - resolution: {integrity: sha512-sDdxepi74+cL6gXJJ2yw3UNSI7GBvoGTwZqFyPoNAzcURvaYwo8dBr7G4jS9GDanjTlO3CGVAf2VMcpqEvmoEw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-sDdxepi74+cL6gXJJ2yw3UNSI7GBvoGTwZqFyPoNAzcURvaYwo8dBr7G4jS9GDanjTlO3CGVAf2VMcpqEvmoEw==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/core@3.758.0': - resolution: {integrity: sha512-0RswbdR9jt/XKemaLNuxi2gGr4xGlHyGxkTdhSQzCyUe9A9OPCoLl3rIESRguQEech+oJnbHk/wuiwHqTuP9sg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-0RswbdR9jt/XKemaLNuxi2gGr4xGlHyGxkTdhSQzCyUe9A9OPCoLl3rIESRguQEech+oJnbHk/wuiwHqTuP9sg==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/credential-provider-cognito-identity@3.772.0': - resolution: {integrity: sha512-rgGCB7+ttlOvuFjz016WVF0m1zDQNakreXVGmlqxKUHTgAkbXulbzcCnZt44S7QGP6V1ElbRB4jI7piRFirdwg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-rgGCB7+ttlOvuFjz016WVF0m1zDQNakreXVGmlqxKUHTgAkbXulbzcCnZt44S7QGP6V1ElbRB4jI7piRFirdwg==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/credential-provider-env@3.758.0': - resolution: {integrity: sha512-N27eFoRrO6MeUNumtNHDW9WOiwfd59LPXPqDrIa3kWL/s+fOKFHb9xIcF++bAwtcZnAxKkgpDCUP+INNZskE+w==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-N27eFoRrO6MeUNumtNHDW9WOiwfd59LPXPqDrIa3kWL/s+fOKFHb9xIcF++bAwtcZnAxKkgpDCUP+INNZskE+w==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/credential-provider-http@3.758.0': - resolution: {integrity: sha512-Xt9/U8qUCiw1hihztWkNeIR+arg6P+yda10OuCHX6kFVx3auTlU7+hCqs3UxqniGU4dguHuftf3mRpi5/GJ33Q==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-Xt9/U8qUCiw1hihztWkNeIR+arg6P+yda10OuCHX6kFVx3auTlU7+hCqs3UxqniGU4dguHuftf3mRpi5/GJ33Q==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/credential-provider-ini@3.772.0': - resolution: {integrity: sha512-T1Ec9Q25zl5c/eZUPHZsiq8vgBeWBjHM7WM5xtZszZRPqqhQGnmFlomz1r9rwhW8RFB5k8HRaD/SLKo6jtYl/A==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-T1Ec9Q25zl5c/eZUPHZsiq8vgBeWBjHM7WM5xtZszZRPqqhQGnmFlomz1r9rwhW8RFB5k8HRaD/SLKo6jtYl/A==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/credential-provider-node@3.772.0': - resolution: {integrity: sha512-0IdVfjBO88Mtekq/KaScYSIEPIeR+ABRvBOWyj/c/qQ2KJyI0GRlSAzpANfxDLHVPn3yEHuZd9nRL6sOmOMI0A==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-0IdVfjBO88Mtekq/KaScYSIEPIeR+ABRvBOWyj/c/qQ2KJyI0GRlSAzpANfxDLHVPn3yEHuZd9nRL6sOmOMI0A==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/credential-provider-process@3.758.0': - resolution: {integrity: sha512-AzcY74QTPqcbXWVgjpPZ3HOmxQZYPROIBz2YINF0OQk0MhezDWV/O7Xec+K1+MPGQO3qS6EDrUUlnPLjsqieHA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-AzcY74QTPqcbXWVgjpPZ3HOmxQZYPROIBz2YINF0OQk0MhezDWV/O7Xec+K1+MPGQO3qS6EDrUUlnPLjsqieHA==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/credential-provider-sso@3.772.0': - resolution: {integrity: sha512-yR3Y5RAVPa4ogojcBOpZUx6XyRVAkynIJCjd0avdlxW1hhnzSr5/pzoiJ6u21UCbkxlJJTDZE3jfFe7tt+HA4w==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-yR3Y5RAVPa4ogojcBOpZUx6XyRVAkynIJCjd0avdlxW1hhnzSr5/pzoiJ6u21UCbkxlJJTDZE3jfFe7tt+HA4w==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/credential-provider-web-identity@3.772.0': - resolution: {integrity: sha512-yHAT5Y2y0fnecSuWRUn8NMunKfDqFYhnOpGq8UyCEcwz9aXzibU0hqRIEm51qpR81hqo0GMFDH0EOmegZ/iW5w==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-yHAT5Y2y0fnecSuWRUn8NMunKfDqFYhnOpGq8UyCEcwz9aXzibU0hqRIEm51qpR81hqo0GMFDH0EOmegZ/iW5w==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/credential-providers@3.772.0': - resolution: {integrity: sha512-+gOrzw05jNVSHFBTZ+LOaGQZ0IXT95aQjNUeWqYXzdgjxKXptrhuMnFLwBBliLbHPp8ziauRnnwG8aK58LOUlg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-+gOrzw05jNVSHFBTZ+LOaGQZ0IXT95aQjNUeWqYXzdgjxKXptrhuMnFLwBBliLbHPp8ziauRnnwG8aK58LOUlg==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/lib-storage@3.772.0': - resolution: {integrity: sha512-d59NJAHDa7mGf82ApOdIp1FsN1i7/VlNTk2t3NIepH/8FsMTzKPZQvbMzqE33ba4oik7y6QrDliYXoRXB/nZPg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-d59NJAHDa7mGf82ApOdIp1FsN1i7/VlNTk2t3NIepH/8FsMTzKPZQvbMzqE33ba4oik7y6QrDliYXoRXB/nZPg==, + } + engines: { node: '>=18.0.0' } peerDependencies: '@aws-sdk/client-s3': ^3.772.0 '@aws-sdk/middleware-bucket-endpoint@3.734.0': - resolution: {integrity: sha512-etC7G18aF7KdZguW27GE/wpbrNmYLVT755EsFc8kXpZj8D6AFKxc7OuveinJmiy0bYXAMspJUWsF6CrGpOw6CQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-etC7G18aF7KdZguW27GE/wpbrNmYLVT755EsFc8kXpZj8D6AFKxc7OuveinJmiy0bYXAMspJUWsF6CrGpOw6CQ==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/middleware-expect-continue@3.734.0': - resolution: {integrity: sha512-P38/v1l6HjuB2aFUewt7ueAW5IvKkFcv5dalPtbMGRhLeyivBOHwbCyuRKgVs7z7ClTpu9EaViEGki2jEQqEsQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-P38/v1l6HjuB2aFUewt7ueAW5IvKkFcv5dalPtbMGRhLeyivBOHwbCyuRKgVs7z7ClTpu9EaViEGki2jEQqEsQ==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/middleware-flexible-checksums@3.758.0': - resolution: {integrity: sha512-o8Rk71S08YTKLoSobucjnbj97OCGaXgpEDNKXpXaavUM5xLNoHCLSUPRCiEN86Ivqxg1n17Y2nSRhfbsveOXXA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-o8Rk71S08YTKLoSobucjnbj97OCGaXgpEDNKXpXaavUM5xLNoHCLSUPRCiEN86Ivqxg1n17Y2nSRhfbsveOXXA==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/middleware-host-header@3.734.0': - resolution: {integrity: sha512-LW7RRgSOHHBzWZnigNsDIzu3AiwtjeI2X66v+Wn1P1u+eXssy1+up4ZY/h+t2sU4LU36UvEf+jrZti9c6vRnFw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-LW7RRgSOHHBzWZnigNsDIzu3AiwtjeI2X66v+Wn1P1u+eXssy1+up4ZY/h+t2sU4LU36UvEf+jrZti9c6vRnFw==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/middleware-location-constraint@3.734.0': - resolution: {integrity: sha512-EJEIXwCQhto/cBfHdm3ZOeLxd2NlJD+X2F+ZTOxzokuhBtY0IONfC/91hOo5tWQweerojwshSMHRCKzRv1tlwg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-EJEIXwCQhto/cBfHdm3ZOeLxd2NlJD+X2F+ZTOxzokuhBtY0IONfC/91hOo5tWQweerojwshSMHRCKzRv1tlwg==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/middleware-logger@3.734.0': - resolution: {integrity: sha512-mUMFITpJUW3LcKvFok176eI5zXAUomVtahb9IQBwLzkqFYOrMJvWAvoV4yuxrJ8TlQBG8gyEnkb9SnhZvjg67w==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-mUMFITpJUW3LcKvFok176eI5zXAUomVtahb9IQBwLzkqFYOrMJvWAvoV4yuxrJ8TlQBG8gyEnkb9SnhZvjg67w==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/middleware-recursion-detection@3.772.0': - resolution: {integrity: sha512-zg0LjJa4v7fcLzn5QzZvtVS+qyvmsnu7oQnb86l6ckduZpWDCDC9+A0ZzcXTrxblPCJd3JqkoG1+Gzi4S4Ny/Q==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-zg0LjJa4v7fcLzn5QzZvtVS+qyvmsnu7oQnb86l6ckduZpWDCDC9+A0ZzcXTrxblPCJd3JqkoG1+Gzi4S4Ny/Q==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/middleware-sdk-s3@3.758.0': - resolution: {integrity: sha512-6mJ2zyyHPYSV6bAcaFpsdoXZJeQlR1QgBnZZ6juY/+dcYiuyWCdyLUbGzSZSE7GTfx6i+9+QWFeoIMlWKgU63A==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-6mJ2zyyHPYSV6bAcaFpsdoXZJeQlR1QgBnZZ6juY/+dcYiuyWCdyLUbGzSZSE7GTfx6i+9+QWFeoIMlWKgU63A==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/middleware-ssec@3.734.0': - resolution: {integrity: sha512-d4yd1RrPW/sspEXizq2NSOUivnheac6LPeLSLnaeTbBG9g1KqIqvCzP1TfXEqv2CrWfHEsWtJpX7oyjySSPvDQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-d4yd1RrPW/sspEXizq2NSOUivnheac6LPeLSLnaeTbBG9g1KqIqvCzP1TfXEqv2CrWfHEsWtJpX7oyjySSPvDQ==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/middleware-user-agent@3.758.0': - resolution: {integrity: sha512-iNyehQXtQlj69JCgfaOssgZD4HeYGOwxcaKeG6F+40cwBjTAi0+Ph1yfDwqk2qiBPIRWJ/9l2LodZbxiBqgrwg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-iNyehQXtQlj69JCgfaOssgZD4HeYGOwxcaKeG6F+40cwBjTAi0+Ph1yfDwqk2qiBPIRWJ/9l2LodZbxiBqgrwg==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/nested-clients@3.772.0': - resolution: {integrity: sha512-gNJbBxR5YlEumsCS9EWWEASXEnysL0aDnr9MNPX1ip/g1xOqRHmytgV/+t8RFZFTKg0OprbWTq5Ich3MqsEuCQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-gNJbBxR5YlEumsCS9EWWEASXEnysL0aDnr9MNPX1ip/g1xOqRHmytgV/+t8RFZFTKg0OprbWTq5Ich3MqsEuCQ==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/region-config-resolver@3.734.0': - resolution: {integrity: sha512-Lvj1kPRC5IuJBr9DyJ9T9/plkh+EfKLy+12s/mykOy1JaKHDpvj+XGy2YO6YgYVOb8JFtaqloid+5COtje4JTQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-Lvj1kPRC5IuJBr9DyJ9T9/plkh+EfKLy+12s/mykOy1JaKHDpvj+XGy2YO6YgYVOb8JFtaqloid+5COtje4JTQ==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/signature-v4-multi-region@3.758.0': - resolution: {integrity: sha512-0RPCo8fYJcrenJ6bRtiUbFOSgQ1CX/GpvwtLU2Fam1tS9h2klKK8d74caeV6A1mIUvBU7bhyQ0wMGlwMtn3EYw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-0RPCo8fYJcrenJ6bRtiUbFOSgQ1CX/GpvwtLU2Fam1tS9h2klKK8d74caeV6A1mIUvBU7bhyQ0wMGlwMtn3EYw==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/token-providers@3.772.0': - resolution: {integrity: sha512-d1Waa1vyebuokcAWYlkZdtFlciIgob7B39vPRmtxMObbGumJKiOy/qCe2/FB/72h1Ej9Ih32lwvbxUjORQWN4g==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-d1Waa1vyebuokcAWYlkZdtFlciIgob7B39vPRmtxMObbGumJKiOy/qCe2/FB/72h1Ej9Ih32lwvbxUjORQWN4g==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/types@3.734.0': - resolution: {integrity: sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/util-arn-parser@3.723.0': - resolution: {integrity: sha512-ZhEfvUwNliOQROcAk34WJWVYTlTa4694kSVhDSjW6lE1bMataPnIN8A0ycukEzBXmd8ZSoBcQLn6lKGl7XIJ5w==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-ZhEfvUwNliOQROcAk34WJWVYTlTa4694kSVhDSjW6lE1bMataPnIN8A0ycukEzBXmd8ZSoBcQLn6lKGl7XIJ5w==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/util-endpoints@3.743.0': - resolution: {integrity: sha512-sN1l559zrixeh5x+pttrnd0A3+r34r0tmPkJ/eaaMaAzXqsmKU/xYre9K3FNnsSS1J1k4PEfk/nHDTVUgFYjnw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-sN1l559zrixeh5x+pttrnd0A3+r34r0tmPkJ/eaaMaAzXqsmKU/xYre9K3FNnsSS1J1k4PEfk/nHDTVUgFYjnw==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/util-locate-window@3.723.0': - resolution: {integrity: sha512-Yf2CS10BqK688DRsrKI/EO6B8ff5J86NXe4C+VCysK7UOgN0l1zOTeTukZ3H8Q9tYYX3oaF1961o8vRkFm7Nmw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-Yf2CS10BqK688DRsrKI/EO6B8ff5J86NXe4C+VCysK7UOgN0l1zOTeTukZ3H8Q9tYYX3oaF1961o8vRkFm7Nmw==, + } + engines: { node: '>=18.0.0' } '@aws-sdk/util-user-agent-browser@3.734.0': - resolution: {integrity: sha512-xQTCus6Q9LwUuALW+S76OL0jcWtMOVu14q+GoLnWPUM7QeUw963oQcLhF7oq0CtaLLKyl4GOUfcwc773Zmwwng==} + resolution: + { + integrity: sha512-xQTCus6Q9LwUuALW+S76OL0jcWtMOVu14q+GoLnWPUM7QeUw963oQcLhF7oq0CtaLLKyl4GOUfcwc773Zmwwng==, + } '@aws-sdk/util-user-agent-node@3.758.0': - resolution: {integrity: sha512-A5EZw85V6WhoKMV2hbuFRvb9NPlxEErb4HPO6/SPXYY4QrjprIzScHxikqcWv1w4J3apB1wto9LPU3IMsYtfrw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-A5EZw85V6WhoKMV2hbuFRvb9NPlxEErb4HPO6/SPXYY4QrjprIzScHxikqcWv1w4J3apB1wto9LPU3IMsYtfrw==, + } + engines: { node: '>=18.0.0' } peerDependencies: aws-crt: '>=1.0.0' peerDependenciesMeta: @@ -330,107 +463,188 @@ packages: optional: true '@aws-sdk/util-utf8-browser@3.259.0': - resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} + resolution: + { + integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==, + } '@aws-sdk/xml-builder@3.734.0': - resolution: {integrity: sha512-Zrjxi5qwGEcUsJ0ru7fRtW74WcTS0rbLcehoFB+rN1GRi2hbLcFaYs4PwVA5diLeAJH0gszv3x4Hr/S87MfbKQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-Zrjxi5qwGEcUsJ0ru7fRtW74WcTS0rbLcehoFB+rN1GRi2hbLcFaYs4PwVA5diLeAJH0gszv3x4Hr/S87MfbKQ==, + } + engines: { node: '>=18.0.0' } '@babel/code-frame@7.26.2': - resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} - engines: {node: '>=6.9.0'} + resolution: + { + integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==, + } + engines: { node: '>=6.9.0' } '@babel/generator@7.26.10': - resolution: {integrity: sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==} - engines: {node: '>=6.9.0'} + resolution: + { + integrity: sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==, + } + engines: { node: '>=6.9.0' } '@babel/helper-module-imports@7.25.9': - resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} - engines: {node: '>=6.9.0'} + resolution: + { + integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==, + } + engines: { node: '>=6.9.0' } '@babel/helper-string-parser@7.25.9': - resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} - engines: {node: '>=6.9.0'} + resolution: + { + integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==, + } + engines: { node: '>=6.9.0' } '@babel/helper-validator-identifier@7.25.9': - resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} - engines: {node: '>=6.9.0'} + resolution: + { + integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==, + } + engines: { node: '>=6.9.0' } '@babel/parser@7.26.10': - resolution: {integrity: sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==} - engines: {node: '>=6.0.0'} + resolution: + { + integrity: sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==, + } + engines: { node: '>=6.0.0' } hasBin: true '@babel/runtime@7.26.10': - resolution: {integrity: sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==} - engines: {node: '>=6.9.0'} + resolution: + { + integrity: sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==, + } + engines: { node: '>=6.9.0' } '@babel/template@7.26.9': - resolution: {integrity: sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==} - engines: {node: '>=6.9.0'} + resolution: + { + integrity: sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==, + } + engines: { node: '>=6.9.0' } '@babel/traverse@7.26.10': - resolution: {integrity: sha512-k8NuDrxr0WrPH5Aupqb2LCVURP/S0vBEn5mK6iH+GIYob66U5EtoZvcdudR2jQ4cmTwhEwW1DLB+Yyas9zjF6A==} - engines: {node: '>=6.9.0'} + resolution: + { + integrity: sha512-k8NuDrxr0WrPH5Aupqb2LCVURP/S0vBEn5mK6iH+GIYob66U5EtoZvcdudR2jQ4cmTwhEwW1DLB+Yyas9zjF6A==, + } + engines: { node: '>=6.9.0' } '@babel/types@7.26.10': - resolution: {integrity: sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==} - engines: {node: '>=6.9.0'} + resolution: + { + integrity: sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==, + } + engines: { node: '>=6.9.0' } '@corex/deepmerge@4.0.43': - resolution: {integrity: sha512-N8uEMrMPL0cu/bdboEWpQYb/0i2K5Qn8eCsxzOmxSggJbbQte7ljMRoXm917AbntqTGOzdTu+vP3KOOzoC70HQ==} + resolution: + { + integrity: sha512-N8uEMrMPL0cu/bdboEWpQYb/0i2K5Qn8eCsxzOmxSggJbbQte7ljMRoXm917AbntqTGOzdTu+vP3KOOzoC70HQ==, + } '@date-fns/tz@1.2.0': - resolution: {integrity: sha512-LBrd7MiJZ9McsOgxqWX7AaxrDjcFVjWH/tIKJd7pnR7McaslGYOP1QmmiBXdJH/H/yLCT+rcQ7FaPBUxRGUtrg==} + resolution: + { + integrity: sha512-LBrd7MiJZ9McsOgxqWX7AaxrDjcFVjWH/tIKJd7pnR7McaslGYOP1QmmiBXdJH/H/yLCT+rcQ7FaPBUxRGUtrg==, + } '@dnd-kit/accessibility@3.1.1': - resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==} + resolution: + { + integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==, + } peerDependencies: react: '>=16.8.0' '@dnd-kit/core@6.0.8': - resolution: {integrity: sha512-lYaoP8yHTQSLlZe6Rr9qogouGUz9oRUj4AHhDQGQzq/hqaJRpFo65X+JKsdHf8oUFBzx5A+SJPUvxAwTF2OabA==} + resolution: + { + integrity: sha512-lYaoP8yHTQSLlZe6Rr9qogouGUz9oRUj4AHhDQGQzq/hqaJRpFo65X+JKsdHf8oUFBzx5A+SJPUvxAwTF2OabA==, + } peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' '@dnd-kit/sortable@7.0.2': - resolution: {integrity: sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==} + resolution: + { + integrity: sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==, + } peerDependencies: '@dnd-kit/core': ^6.0.7 react: '>=16.8.0' '@dnd-kit/utilities@3.2.2': - resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==} + resolution: + { + integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==, + } peerDependencies: react: '>=16.8.0' '@emnapi/core@1.3.1': - resolution: {integrity: sha512-pVGjBIt1Y6gg3EJN8jTcfpP/+uuRksIo055oE/OBkDNcjZqVbfkWCksG1Jp4yZnj3iKWyWX8fdG/j6UDYPbFog==} + resolution: + { + integrity: sha512-pVGjBIt1Y6gg3EJN8jTcfpP/+uuRksIo055oE/OBkDNcjZqVbfkWCksG1Jp4yZnj3iKWyWX8fdG/j6UDYPbFog==, + } '@emnapi/runtime@1.3.1': - resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} + resolution: + { + integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==, + } '@emnapi/wasi-threads@1.0.1': - resolution: {integrity: sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==} + resolution: + { + integrity: sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==, + } '@emotion/babel-plugin@11.13.5': - resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} + resolution: + { + integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==, + } '@emotion/cache@11.14.0': - resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==} + resolution: + { + integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==, + } '@emotion/css@11.13.5': - resolution: {integrity: sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w==} + resolution: + { + integrity: sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w==, + } '@emotion/hash@0.9.2': - resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + resolution: + { + integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==, + } '@emotion/memoize@0.9.0': - resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} + resolution: + { + integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==, + } '@emotion/react@11.14.0': - resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==} + resolution: + { + integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==, + } peerDependencies: '@types/react': '*' react: '>=16.8.0' @@ -439,671 +653,1088 @@ packages: optional: true '@emotion/serialize@1.3.3': - resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==} + resolution: + { + integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==, + } '@emotion/sheet@1.4.0': - resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==} + resolution: + { + integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==, + } '@emotion/unitless@0.10.0': - resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} + resolution: + { + integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==, + } '@emotion/use-insertion-effect-with-fallbacks@1.2.0': - resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==} + resolution: + { + integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==, + } peerDependencies: react: '>=16.8.0' '@emotion/utils@1.4.2': - resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==} + resolution: + { + integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==, + } '@emotion/weak-memoize@0.4.0': - resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} + resolution: + { + integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==, + } '@esbuild/aix-ppc64@0.23.1': - resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==, + } + engines: { node: '>=18' } cpu: [ppc64] os: [aix] '@esbuild/android-arm64@0.23.1': - resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==, + } + engines: { node: '>=18' } cpu: [arm64] os: [android] '@esbuild/android-arm@0.23.1': - resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==, + } + engines: { node: '>=18' } cpu: [arm] os: [android] '@esbuild/android-x64@0.23.1': - resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==, + } + engines: { node: '>=18' } cpu: [x64] os: [android] '@esbuild/darwin-arm64@0.23.1': - resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==, + } + engines: { node: '>=18' } cpu: [arm64] os: [darwin] '@esbuild/darwin-x64@0.23.1': - resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==, + } + engines: { node: '>=18' } cpu: [x64] os: [darwin] '@esbuild/freebsd-arm64@0.23.1': - resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==, + } + engines: { node: '>=18' } cpu: [arm64] os: [freebsd] '@esbuild/freebsd-x64@0.23.1': - resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==, + } + engines: { node: '>=18' } cpu: [x64] os: [freebsd] '@esbuild/linux-arm64@0.23.1': - resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==, + } + engines: { node: '>=18' } cpu: [arm64] os: [linux] '@esbuild/linux-arm@0.23.1': - resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==, + } + engines: { node: '>=18' } cpu: [arm] os: [linux] '@esbuild/linux-ia32@0.23.1': - resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==, + } + engines: { node: '>=18' } cpu: [ia32] os: [linux] '@esbuild/linux-loong64@0.23.1': - resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==, + } + engines: { node: '>=18' } cpu: [loong64] os: [linux] '@esbuild/linux-mips64el@0.23.1': - resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==, + } + engines: { node: '>=18' } cpu: [mips64el] os: [linux] '@esbuild/linux-ppc64@0.23.1': - resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==, + } + engines: { node: '>=18' } cpu: [ppc64] os: [linux] '@esbuild/linux-riscv64@0.23.1': - resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==, + } + engines: { node: '>=18' } cpu: [riscv64] os: [linux] '@esbuild/linux-s390x@0.23.1': - resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==, + } + engines: { node: '>=18' } cpu: [s390x] os: [linux] '@esbuild/linux-x64@0.23.1': - resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==, + } + engines: { node: '>=18' } cpu: [x64] os: [linux] '@esbuild/netbsd-x64@0.23.1': - resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==, + } + engines: { node: '>=18' } cpu: [x64] os: [netbsd] '@esbuild/openbsd-arm64@0.23.1': - resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==, + } + engines: { node: '>=18' } cpu: [arm64] os: [openbsd] '@esbuild/openbsd-x64@0.23.1': - resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==, + } + engines: { node: '>=18' } cpu: [x64] os: [openbsd] '@esbuild/sunos-x64@0.23.1': - resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==, + } + engines: { node: '>=18' } cpu: [x64] os: [sunos] '@esbuild/win32-arm64@0.23.1': - resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==, + } + engines: { node: '>=18' } cpu: [arm64] os: [win32] '@esbuild/win32-ia32@0.23.1': - resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==, + } + engines: { node: '>=18' } cpu: [ia32] os: [win32] '@esbuild/win32-x64@0.23.1': - resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==, + } + engines: { node: '>=18' } cpu: [x64] os: [win32] '@eslint-community/eslint-utils@4.5.1': - resolution: {integrity: sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + resolution: + { + integrity: sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 '@eslint-community/regexpp@4.12.1': - resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + resolution: + { + integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==, + } + engines: { node: ^12.0.0 || ^14.0.0 || >=16.0.0 } '@eslint/config-array@0.19.2': - resolution: {integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } '@eslint/config-helpers@0.2.0': - resolution: {integrity: sha512-yJLLmLexii32mGrhW29qvU3QBVTu0GUmEf/J4XsBtVhp4JkIUFN/BjWqTF63yRvGApIDpZm5fa97LtYtINmfeQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-yJLLmLexii32mGrhW29qvU3QBVTu0GUmEf/J4XsBtVhp4JkIUFN/BjWqTF63yRvGApIDpZm5fa97LtYtINmfeQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } '@eslint/core@0.12.0': - resolution: {integrity: sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } '@eslint/eslintrc@3.3.1': - resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } '@eslint/js@9.23.0': - resolution: {integrity: sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } '@eslint/object-schema@2.1.6': - resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } '@eslint/plugin-kit@0.2.7': - resolution: {integrity: sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } '@faceless-ui/modal@3.0.0-beta.2': - resolution: {integrity: sha512-UmXvz7Iw3KMO4Pm3llZczU4uc5pPQDb6rdqwoBvYDFgWvkraOAHKx0HxSZgwqQvqOhn8joEFBfFp6/Do2562ow==} + resolution: + { + integrity: sha512-UmXvz7Iw3KMO4Pm3llZczU4uc5pPQDb6rdqwoBvYDFgWvkraOAHKx0HxSZgwqQvqOhn8joEFBfFp6/Do2562ow==, + } peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 '@faceless-ui/scroll-info@2.0.0': - resolution: {integrity: sha512-BkyJ9OQ4bzpKjE3UhI8BhcG36ZgfB4run8TmlaR4oMFUbl59dfyarNfjveyimrxIso9RhFEja/AJ5nQmbcR9hw==} + resolution: + { + integrity: sha512-BkyJ9OQ4bzpKjE3UhI8BhcG36ZgfB4run8TmlaR4oMFUbl59dfyarNfjveyimrxIso9RhFEja/AJ5nQmbcR9hw==, + } peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 '@faceless-ui/window-info@3.0.1': - resolution: {integrity: sha512-uPjdJYE/j7hqVNelE9CRUNOeXuXDdPxR4DMe+oz3xwyZi2Y4CxsfpfdPTqqwmNAZa1P33O+ZiCyIkBEeNed0kw==} + resolution: + { + integrity: sha512-uPjdJYE/j7hqVNelE9CRUNOeXuXDdPxR4DMe+oz3xwyZi2Y4CxsfpfdPTqqwmNAZa1P33O+ZiCyIkBEeNed0kw==, + } peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 '@floating-ui/core@1.6.9': - resolution: {integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==} + resolution: + { + integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==, + } '@floating-ui/dom@1.6.13': - resolution: {integrity: sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==} + resolution: + { + integrity: sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==, + } '@floating-ui/react-dom@2.1.2': - resolution: {integrity: sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==} + resolution: + { + integrity: sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==, + } peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' '@floating-ui/react@0.27.5': - resolution: {integrity: sha512-BX3jKxo39Ba05pflcQmqPPwc0qdNsdNi/eweAFtoIdrJWNen2sVEWMEac3i6jU55Qfx+lOcdMNKYn2CtWmlnOQ==} + resolution: + { + integrity: sha512-BX3jKxo39Ba05pflcQmqPPwc0qdNsdNi/eweAFtoIdrJWNen2sVEWMEac3i6jU55Qfx+lOcdMNKYn2CtWmlnOQ==, + } peerDependencies: react: '>=17.0.0' react-dom: '>=17.0.0' '@floating-ui/utils@0.2.9': - resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} + resolution: + { + integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==, + } '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} - engines: {node: '>=18.18.0'} + resolution: + { + integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==, + } + engines: { node: '>=18.18.0' } '@humanfs/node@0.16.6': - resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} - engines: {node: '>=18.18.0'} + resolution: + { + integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==, + } + engines: { node: '>=18.18.0' } '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} + resolution: + { + integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==, + } + engines: { node: '>=12.22' } '@humanwhocodes/retry@0.3.1': - resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} - engines: {node: '>=18.18'} + resolution: + { + integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==, + } + engines: { node: '>=18.18' } '@humanwhocodes/retry@0.4.2': - resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==} - engines: {node: '>=18.18'} + resolution: + { + integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==, + } + engines: { node: '>=18.18' } '@img/sharp-darwin-arm64@0.33.5': - resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [arm64] os: [darwin] '@img/sharp-darwin-x64@0.33.5': - resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [x64] os: [darwin] '@img/sharp-libvips-darwin-arm64@1.0.4': - resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} + resolution: + { + integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==, + } cpu: [arm64] os: [darwin] '@img/sharp-libvips-darwin-x64@1.0.4': - resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + resolution: + { + integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==, + } cpu: [x64] os: [darwin] '@img/sharp-libvips-linux-arm64@1.0.4': - resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} + resolution: + { + integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==, + } cpu: [arm64] os: [linux] '@img/sharp-libvips-linux-arm@1.0.5': - resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} + resolution: + { + integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==, + } cpu: [arm] os: [linux] '@img/sharp-libvips-linux-s390x@1.0.4': - resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + resolution: + { + integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==, + } cpu: [s390x] os: [linux] '@img/sharp-libvips-linux-x64@1.0.4': - resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} + resolution: + { + integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==, + } cpu: [x64] os: [linux] '@img/sharp-libvips-linuxmusl-arm64@1.0.4': - resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + resolution: + { + integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==, + } cpu: [arm64] os: [linux] '@img/sharp-libvips-linuxmusl-x64@1.0.4': - resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} + resolution: + { + integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==, + } cpu: [x64] os: [linux] '@img/sharp-linux-arm64@0.33.5': - resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [arm64] os: [linux] '@img/sharp-linux-arm@0.33.5': - resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [arm] os: [linux] '@img/sharp-linux-s390x@0.33.5': - resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [s390x] os: [linux] '@img/sharp-linux-x64@0.33.5': - resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [x64] os: [linux] '@img/sharp-linuxmusl-arm64@0.33.5': - resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [arm64] os: [linux] '@img/sharp-linuxmusl-x64@0.33.5': - resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [x64] os: [linux] '@img/sharp-wasm32@0.33.5': - resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [wasm32] '@img/sharp-win32-ia32@0.33.5': - resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [ia32] os: [win32] '@img/sharp-win32-x64@0.33.5': - resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [x64] os: [win32] '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==, + } + engines: { node: '>=12' } '@jridgewell/gen-mapping@0.3.8': - resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} - engines: {node: '>=6.0.0'} + resolution: + { + integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==, + } + engines: { node: '>=6.0.0' } '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} + resolution: + { + integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==, + } + engines: { node: '>=6.0.0' } '@jridgewell/set-array@1.2.1': - resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} - engines: {node: '>=6.0.0'} + resolution: + { + integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==, + } + engines: { node: '>=6.0.0' } '@jridgewell/sourcemap-codec@1.5.0': - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + resolution: + { + integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==, + } '@jridgewell/trace-mapping@0.3.25': - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + resolution: + { + integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==, + } '@jsdevtools/ono@7.1.3': - resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + resolution: + { + integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==, + } '@lexical/clipboard@0.28.0': - resolution: {integrity: sha512-LYqion+kAwFQJStA37JAEMxTL/m1WlZbotDfM/2WuONmlO0yWxiyRDI18oeCwhBD6LQQd9c3Ccxp9HFwUG1AVw==} + resolution: + { + integrity: sha512-LYqion+kAwFQJStA37JAEMxTL/m1WlZbotDfM/2WuONmlO0yWxiyRDI18oeCwhBD6LQQd9c3Ccxp9HFwUG1AVw==, + } '@lexical/code@0.28.0': - resolution: {integrity: sha512-9LOKSWdRhxqAKRq5yveNC21XKtW4h2rmFNTucwMWZ9vLu9xteOHEwZdO1Qv82PFUmgCpAhg6EntmnZu9xD3K7Q==} + resolution: + { + integrity: sha512-9LOKSWdRhxqAKRq5yveNC21XKtW4h2rmFNTucwMWZ9vLu9xteOHEwZdO1Qv82PFUmgCpAhg6EntmnZu9xD3K7Q==, + } '@lexical/devtools-core@0.28.0': - resolution: {integrity: sha512-Fk4itAjZ+MqTYXN84aE5RDf+wQX67N5nyo3JVxQTFZGAghx7Ux1xLWHB25zzD0YfjMtJ0NQROAbE3xdecZzxcQ==} + resolution: + { + integrity: sha512-Fk4itAjZ+MqTYXN84aE5RDf+wQX67N5nyo3JVxQTFZGAghx7Ux1xLWHB25zzD0YfjMtJ0NQROAbE3xdecZzxcQ==, + } peerDependencies: react: '>=17.x' react-dom: '>=17.x' '@lexical/dragon@0.28.0': - resolution: {integrity: sha512-T6T8YaHnhU863ruuqmRHTLUYa8sfg/ArYcrnNGZGfpvvFTfFjpWb/ELOvOWo8N6Y/4fnSLjQ20aXexVW1KcTBQ==} + resolution: + { + integrity: sha512-T6T8YaHnhU863ruuqmRHTLUYa8sfg/ArYcrnNGZGfpvvFTfFjpWb/ELOvOWo8N6Y/4fnSLjQ20aXexVW1KcTBQ==, + } '@lexical/hashtag@0.28.0': - resolution: {integrity: sha512-zcqX9Qna4lj96bAUfwSQSVEhYQ0O5erSjrIhOVqEgeQ5ubz0EvqnnMbbwNHIb2n6jzSwAvpD/3UZJZtolh+zVg==} + resolution: + { + integrity: sha512-zcqX9Qna4lj96bAUfwSQSVEhYQ0O5erSjrIhOVqEgeQ5ubz0EvqnnMbbwNHIb2n6jzSwAvpD/3UZJZtolh+zVg==, + } '@lexical/headless@0.28.0': - resolution: {integrity: sha512-btcaTfw9I/xQ/XYom6iKWgsPecmRawGd/5jOhP7QDtLUp7gxgM7/kiCZFYa8jDJO6j20rXuWTkc81ynVpKvjow==} + resolution: + { + integrity: sha512-btcaTfw9I/xQ/XYom6iKWgsPecmRawGd/5jOhP7QDtLUp7gxgM7/kiCZFYa8jDJO6j20rXuWTkc81ynVpKvjow==, + } '@lexical/history@0.28.0': - resolution: {integrity: sha512-CHzDxaGDn6qCFFhU0YKP1B8sgEb++0Ksqsj6BfDL/6TMxoLNQwRQhP3BUNNXl1kvUhxTQZgk3b9MjJZRaFKG9Q==} + resolution: + { + integrity: sha512-CHzDxaGDn6qCFFhU0YKP1B8sgEb++0Ksqsj6BfDL/6TMxoLNQwRQhP3BUNNXl1kvUhxTQZgk3b9MjJZRaFKG9Q==, + } '@lexical/html@0.28.0': - resolution: {integrity: sha512-ayb0FPxr55Ko99/d9ewbfrApul4L0z+KpU2ZG03im7EvUPVLyIGLx4S0QguMDvQh0Vu+eJ7/EESuonDs5BCe3A==} + resolution: + { + integrity: sha512-ayb0FPxr55Ko99/d9ewbfrApul4L0z+KpU2ZG03im7EvUPVLyIGLx4S0QguMDvQh0Vu+eJ7/EESuonDs5BCe3A==, + } '@lexical/link@0.28.0': - resolution: {integrity: sha512-T5VKxpOnML5DcXv2lW3Le0vjNlcbdohZjS9f6PAvm6eX8EzBKDpLQCopr1/0KGdlLd1QrzQsykQrdU7ieC4LRg==} + resolution: + { + integrity: sha512-T5VKxpOnML5DcXv2lW3Le0vjNlcbdohZjS9f6PAvm6eX8EzBKDpLQCopr1/0KGdlLd1QrzQsykQrdU7ieC4LRg==, + } '@lexical/list@0.28.0': - resolution: {integrity: sha512-3a8QcZ75n2TLxP+xkSPJ2V15jsysMLMe0YoObG+ew/sioVelIU8GciYsWBo5GgQmwSzJNQJeK5cJ9p1b71z2cg==} + resolution: + { + integrity: sha512-3a8QcZ75n2TLxP+xkSPJ2V15jsysMLMe0YoObG+ew/sioVelIU8GciYsWBo5GgQmwSzJNQJeK5cJ9p1b71z2cg==, + } '@lexical/mark@0.28.0': - resolution: {integrity: sha512-v5PzmTACsJrw3GvNZy2rgPxrNn9InLvLFoKqrSlNhhyvYNIAcuC4KVy00LKLja43Gw/fuB3QwKohYfAtM3yR3g==} + resolution: + { + integrity: sha512-v5PzmTACsJrw3GvNZy2rgPxrNn9InLvLFoKqrSlNhhyvYNIAcuC4KVy00LKLja43Gw/fuB3QwKohYfAtM3yR3g==, + } '@lexical/markdown@0.28.0': - resolution: {integrity: sha512-F3JXClqN4cjmXYLDK0IztxkbZuqkqS/AVbxnhGvnDYHQ9Gp8l7BonczhOiPwmJCDubJrAACP0L9LCqyt0jDRFw==} + resolution: + { + integrity: sha512-F3JXClqN4cjmXYLDK0IztxkbZuqkqS/AVbxnhGvnDYHQ9Gp8l7BonczhOiPwmJCDubJrAACP0L9LCqyt0jDRFw==, + } '@lexical/offset@0.28.0': - resolution: {integrity: sha512-/SMDQgBPeWM936t04mtH6UAn3xAjP/meu9q136bcT3S7p7V8ew9JfNp9aznTPTx+2W3brJORAvUow7Xn1fSHmw==} + resolution: + { + integrity: sha512-/SMDQgBPeWM936t04mtH6UAn3xAjP/meu9q136bcT3S7p7V8ew9JfNp9aznTPTx+2W3brJORAvUow7Xn1fSHmw==, + } '@lexical/overflow@0.28.0': - resolution: {integrity: sha512-ppmhHXEZVicBm05w9EVflzwFavTVNAe4q0bkabWUeW0IoCT3Vg2A3JT7PC9ypmp+mboUD195foFEr1BBSv1Y8Q==} + resolution: + { + integrity: sha512-ppmhHXEZVicBm05w9EVflzwFavTVNAe4q0bkabWUeW0IoCT3Vg2A3JT7PC9ypmp+mboUD195foFEr1BBSv1Y8Q==, + } '@lexical/plain-text@0.28.0': - resolution: {integrity: sha512-Jj2dCMDEfRuVetfDKcUes8J5jvAfZrLnILFlHxnu7y+lC+7R/NR403DYb3NJ8H7+lNiH1K15+U2K7ewbjxS6KQ==} + resolution: + { + integrity: sha512-Jj2dCMDEfRuVetfDKcUes8J5jvAfZrLnILFlHxnu7y+lC+7R/NR403DYb3NJ8H7+lNiH1K15+U2K7ewbjxS6KQ==, + } '@lexical/react@0.28.0': - resolution: {integrity: sha512-dWPnxrKrbQFjNqExqnaAsV0UEUgw/5M1ZYRWd5FGBGjHqVTCaX2jNHlKLMA68Od0VPIoOX2Zy1TYZ8ZKtsj5Dg==} + resolution: + { + integrity: sha512-dWPnxrKrbQFjNqExqnaAsV0UEUgw/5M1ZYRWd5FGBGjHqVTCaX2jNHlKLMA68Od0VPIoOX2Zy1TYZ8ZKtsj5Dg==, + } peerDependencies: react: '>=17.x' react-dom: '>=17.x' '@lexical/rich-text@0.28.0': - resolution: {integrity: sha512-y+vUWI+9uFupIb9UvssKU/DKcT9dFUZuQBu7utFkLadxCNyXQHeRjxzjzmvFiM3DBV0guPUDGu5VS5TPnIA+OA==} + resolution: + { + integrity: sha512-y+vUWI+9uFupIb9UvssKU/DKcT9dFUZuQBu7utFkLadxCNyXQHeRjxzjzmvFiM3DBV0guPUDGu5VS5TPnIA+OA==, + } '@lexical/selection@0.28.0': - resolution: {integrity: sha512-AJDi67Nsexyejzp4dEQSVoPov4P+FJ0t1v6DxUU+YmcvV56QyJQi6ue0i/xd8unr75ZufzLsAC0cDJJCEI7QDA==} + resolution: + { + integrity: sha512-AJDi67Nsexyejzp4dEQSVoPov4P+FJ0t1v6DxUU+YmcvV56QyJQi6ue0i/xd8unr75ZufzLsAC0cDJJCEI7QDA==, + } '@lexical/table@0.28.0': - resolution: {integrity: sha512-HMPCwXdj0sRWdlDzsHcNWRgbeKbEhn3L8LPhFnTq7q61gZ4YW2umdmuvQFKnIBcKq49drTH8cUwZoIwI8+AEEw==} + resolution: + { + integrity: sha512-HMPCwXdj0sRWdlDzsHcNWRgbeKbEhn3L8LPhFnTq7q61gZ4YW2umdmuvQFKnIBcKq49drTH8cUwZoIwI8+AEEw==, + } '@lexical/text@0.28.0': - resolution: {integrity: sha512-PT/A2RZv+ktn7SG/tJkOpGlYE6zjOND59VtRHnV/xciZ+jEJVaqAHtWjhbWibAIZQAkv/O7UouuDqzDaNTSGAA==} + resolution: + { + integrity: sha512-PT/A2RZv+ktn7SG/tJkOpGlYE6zjOND59VtRHnV/xciZ+jEJVaqAHtWjhbWibAIZQAkv/O7UouuDqzDaNTSGAA==, + } '@lexical/utils@0.28.0': - resolution: {integrity: sha512-Qw00DjkS1nRK7DLSgqJpJ77Ti2AuiOQ6m5eM38YojoWXkVmoxqKAUMaIbVNVKqjFgrQvKFF46sXxIJPbUQkB0w==} + resolution: + { + integrity: sha512-Qw00DjkS1nRK7DLSgqJpJ77Ti2AuiOQ6m5eM38YojoWXkVmoxqKAUMaIbVNVKqjFgrQvKFF46sXxIJPbUQkB0w==, + } '@lexical/yjs@0.28.0': - resolution: {integrity: sha512-rKHpUEd3nrvMY7ghmOC0AeGSYT7YIviba+JViaOzrCX4/Wtv5C/3Sl7Io12Z9k+s1BKmy7C28bOdQHvRWaD7vQ==} + resolution: + { + integrity: sha512-rKHpUEd3nrvMY7ghmOC0AeGSYT7YIviba+JViaOzrCX4/Wtv5C/3Sl7Io12Z9k+s1BKmy7C28bOdQHvRWaD7vQ==, + } peerDependencies: yjs: '>=13.5.22' '@monaco-editor/loader@1.5.0': - resolution: {integrity: sha512-hKoGSM+7aAc7eRTRjpqAZucPmoNOC4UUbknb/VNoTkEIkCPhqV8LfbsgM1webRM7S/z21eHEx9Fkwx8Z/C/+Xw==} + resolution: + { + integrity: sha512-hKoGSM+7aAc7eRTRjpqAZucPmoNOC4UUbknb/VNoTkEIkCPhqV8LfbsgM1webRM7S/z21eHEx9Fkwx8Z/C/+Xw==, + } '@monaco-editor/react@4.7.0': - resolution: {integrity: sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==} + resolution: + { + integrity: sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==, + } peerDependencies: monaco-editor: '>= 0.25.0 < 1' react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 '@mongodb-js/saslprep@1.2.0': - resolution: {integrity: sha512-+ywrb0AqkfaYuhHs6LxKWgqbh3I72EpEgESCw37o+9qPx9WTCkgDm2B+eMrwehGtHBWHFU4GXvnSCNiFhhausg==} + resolution: + { + integrity: sha512-+ywrb0AqkfaYuhHs6LxKWgqbh3I72EpEgESCw37o+9qPx9WTCkgDm2B+eMrwehGtHBWHFU4GXvnSCNiFhhausg==, + } '@napi-rs/wasm-runtime@0.2.7': - resolution: {integrity: sha512-5yximcFK5FNompXfJFoWanu5l8v1hNGqNHh9du1xETp9HWk/B/PzvchX55WYOPaIeNglG8++68AAiauBAtbnzw==} + resolution: + { + integrity: sha512-5yximcFK5FNompXfJFoWanu5l8v1hNGqNHh9du1xETp9HWk/B/PzvchX55WYOPaIeNglG8++68AAiauBAtbnzw==, + } '@next/env@13.5.9': - resolution: {integrity: sha512-h9+DconfsLkhHIw950Som5t5DC0kZReRRVhT4XO2DLo5vBK3PQK6CbFr8unxjHwvIcRdDvb8rosKleLdirfShQ==} + resolution: + { + integrity: sha512-h9+DconfsLkhHIw950Som5t5DC0kZReRRVhT4XO2DLo5vBK3PQK6CbFr8unxjHwvIcRdDvb8rosKleLdirfShQ==, + } '@next/env@15.2.3': - resolution: {integrity: sha512-a26KnbW9DFEUsSxAxKBORR/uD9THoYoKbkpFywMN/AFvboTt94b8+g/07T8J6ACsdLag8/PDU60ov4rPxRAixw==} + resolution: + { + integrity: sha512-a26KnbW9DFEUsSxAxKBORR/uD9THoYoKbkpFywMN/AFvboTt94b8+g/07T8J6ACsdLag8/PDU60ov4rPxRAixw==, + } '@next/eslint-plugin-next@15.2.3': - resolution: {integrity: sha512-eNSOIMJtjs+dp4Ms1tB1PPPJUQHP3uZK+OQ7iFY9qXpGO6ojT6imCL+KcUOqE/GXGidWbBZJzYdgAdPHqeCEPA==} + resolution: + { + integrity: sha512-eNSOIMJtjs+dp4Ms1tB1PPPJUQHP3uZK+OQ7iFY9qXpGO6ojT6imCL+KcUOqE/GXGidWbBZJzYdgAdPHqeCEPA==, + } '@next/swc-darwin-arm64@15.2.3': - resolution: {integrity: sha512-uaBhA8aLbXLqwjnsHSkxs353WrRgQgiFjduDpc7YXEU0B54IKx3vU+cxQlYwPCyC8uYEEX7THhtQQsfHnvv8dw==} - engines: {node: '>= 10'} + resolution: + { + integrity: sha512-uaBhA8aLbXLqwjnsHSkxs353WrRgQgiFjduDpc7YXEU0B54IKx3vU+cxQlYwPCyC8uYEEX7THhtQQsfHnvv8dw==, + } + engines: { node: '>= 10' } cpu: [arm64] os: [darwin] '@next/swc-darwin-x64@15.2.3': - resolution: {integrity: sha512-pVwKvJ4Zk7h+4hwhqOUuMx7Ib02u3gDX3HXPKIShBi9JlYllI0nU6TWLbPT94dt7FSi6mSBhfc2JrHViwqbOdw==} - engines: {node: '>= 10'} + resolution: + { + integrity: sha512-pVwKvJ4Zk7h+4hwhqOUuMx7Ib02u3gDX3HXPKIShBi9JlYllI0nU6TWLbPT94dt7FSi6mSBhfc2JrHViwqbOdw==, + } + engines: { node: '>= 10' } cpu: [x64] os: [darwin] '@next/swc-linux-arm64-gnu@15.2.3': - resolution: {integrity: sha512-50ibWdn2RuFFkOEUmo9NCcQbbV9ViQOrUfG48zHBCONciHjaUKtHcYFiCwBVuzD08fzvzkWuuZkd4AqbvKO7UQ==} - engines: {node: '>= 10'} + resolution: + { + integrity: sha512-50ibWdn2RuFFkOEUmo9NCcQbbV9ViQOrUfG48zHBCONciHjaUKtHcYFiCwBVuzD08fzvzkWuuZkd4AqbvKO7UQ==, + } + engines: { node: '>= 10' } cpu: [arm64] os: [linux] '@next/swc-linux-arm64-musl@15.2.3': - resolution: {integrity: sha512-2gAPA7P652D3HzR4cLyAuVYwYqjG0mt/3pHSWTCyKZq/N/dJcUAEoNQMyUmwTZWCJRKofB+JPuDVP2aD8w2J6Q==} - engines: {node: '>= 10'} + resolution: + { + integrity: sha512-2gAPA7P652D3HzR4cLyAuVYwYqjG0mt/3pHSWTCyKZq/N/dJcUAEoNQMyUmwTZWCJRKofB+JPuDVP2aD8w2J6Q==, + } + engines: { node: '>= 10' } cpu: [arm64] os: [linux] '@next/swc-linux-x64-gnu@15.2.3': - resolution: {integrity: sha512-ODSKvrdMgAJOVU4qElflYy1KSZRM3M45JVbeZu42TINCMG3anp7YCBn80RkISV6bhzKwcUqLBAmOiWkaGtBA9w==} - engines: {node: '>= 10'} + resolution: + { + integrity: sha512-ODSKvrdMgAJOVU4qElflYy1KSZRM3M45JVbeZu42TINCMG3anp7YCBn80RkISV6bhzKwcUqLBAmOiWkaGtBA9w==, + } + engines: { node: '>= 10' } cpu: [x64] os: [linux] '@next/swc-linux-x64-musl@15.2.3': - resolution: {integrity: sha512-ZR9kLwCWrlYxwEoytqPi1jhPd1TlsSJWAc+H/CJHmHkf2nD92MQpSRIURR1iNgA/kuFSdxB8xIPt4p/T78kwsg==} - engines: {node: '>= 10'} + resolution: + { + integrity: sha512-ZR9kLwCWrlYxwEoytqPi1jhPd1TlsSJWAc+H/CJHmHkf2nD92MQpSRIURR1iNgA/kuFSdxB8xIPt4p/T78kwsg==, + } + engines: { node: '>= 10' } cpu: [x64] os: [linux] '@next/swc-win32-arm64-msvc@15.2.3': - resolution: {integrity: sha512-+G2FrDcfm2YDbhDiObDU/qPriWeiz/9cRR0yMWJeTLGGX6/x8oryO3tt7HhodA1vZ8r2ddJPCjtLcpaVl7TE2Q==} - engines: {node: '>= 10'} + resolution: + { + integrity: sha512-+G2FrDcfm2YDbhDiObDU/qPriWeiz/9cRR0yMWJeTLGGX6/x8oryO3tt7HhodA1vZ8r2ddJPCjtLcpaVl7TE2Q==, + } + engines: { node: '>= 10' } cpu: [arm64] os: [win32] '@next/swc-win32-x64-msvc@15.2.3': - resolution: {integrity: sha512-gHYS9tc+G2W0ZC8rBL+H6RdtXIyk40uLiaos0yj5US85FNhbFEndMA2nW3z47nzOWiSvXTZ5kBClc3rD0zJg0w==} - engines: {node: '>= 10'} + resolution: + { + integrity: sha512-gHYS9tc+G2W0ZC8rBL+H6RdtXIyk40uLiaos0yj5US85FNhbFEndMA2nW3z47nzOWiSvXTZ5kBClc3rD0zJg0w==, + } + engines: { node: '>= 10' } cpu: [x64] os: [win32] '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==, + } + engines: { node: '>= 8' } '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==, + } + engines: { node: '>= 8' } '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==, + } + engines: { node: '>= 8' } '@nolyfill/is-core-module@1.0.39': - resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} - engines: {node: '>=12.4.0'} + resolution: + { + integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==, + } + engines: { node: '>=12.4.0' } - '@payloadcms/admin-bar@3.29.0': - resolution: {integrity: sha512-Ca6DTlkbLdlTv6s4XpfdeEQq6L3YRXoKXzYN1QkJuIwqXCT7hSFuV7ZclD0NFnEU9Wb7GC+FPRG88pcjI9oy0Q==} + '@payloadcms/admin-bar@3.31.0': + resolution: + { + integrity: sha512-XmrlTj58Y0BhlU0am3vCGe8rlcRHMamxHVcte7l4NpnLP/YiQkV8uFPsC+COqrHf0RH+FSQdNihwWYdccx7u6Q==, + } peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@payloadcms/db-mongodb@3.29.0': - resolution: {integrity: sha512-n9y5njLbc3Q3FrtuCCxsTEN/HJsEIkLrEKLw/2bOIn356gZJGTLi0bazcnFSKEmwsZfyrzzrNsle7gWlrOUOSQ==} + '@payloadcms/db-mongodb@3.31.0': + resolution: + { + integrity: sha512-Eoh/CrT2AXhKtWMr6Gn2pG7TmmR5O4hIXq7zb+kZmiQAZcbwHC4KiTEEnVuqVXg2RXKz9KQDDYsYz9P4FeBk3g==, + } peerDependencies: - payload: 3.29.0 + payload: 3.31.0 - '@payloadcms/email-nodemailer@3.29.0': - resolution: {integrity: sha512-5xIWmTadlpMvdBd96vUUWhvDdFepCBE35vKhdDvObkvqr0g33lJmm7n7V2HHKPCG1C9EmJa4m0c+B7hj8UqH5Q==} - engines: {node: ^18.20.2 || >=20.9.0} + '@payloadcms/email-nodemailer@3.31.0': + resolution: + { + integrity: sha512-F9oqqdVvorbDPMLTumOvupTY4Tpp6ajJzTPQJpvDJyrTRUl2mH3wYkBTtCnm7oCzv8mcurvM9aRfKTSOmySK0g==, + } + engines: { node: ^18.20.2 || >=20.9.0 } peerDependencies: - payload: 3.29.0 + payload: 3.31.0 - '@payloadcms/graphql@3.29.0': - resolution: {integrity: sha512-3xeRzs8D8Oxty2xXRSQIDeJCkfXJDL+7+oTb9lP3vYGMaf5uiYnXvEmpJcciOTg5aigLFA6XY08ghkg0eU7uqw==} + '@payloadcms/graphql@3.31.0': + resolution: + { + integrity: sha512-IJWP+eBzZm7GpQvsvx/+2kfPK6RLhshCXPebtsmLDrjXlySmx1kZOm5F185Zd1yHwMfXfQw4pc6+ipukG1l6sA==, + } hasBin: true peerDependencies: graphql: ^16.8.1 - payload: 3.29.0 + payload: 3.31.0 - '@payloadcms/live-preview-react@3.29.0': - resolution: {integrity: sha512-BchOSaaX6WBw5FouSYQZKfmZ7IXAp91Bt6bgAmcCBfi+REQ7l8rPIxKvyq5+ra4UaJ8eaNPu3j0gc7XXGEIpmw==} + '@payloadcms/live-preview-react@3.31.0': + resolution: + { + integrity: sha512-PXpbBcoslbtq31XnnQmF++L+qyPoE6g2Q7MOPrLnLLSfi28DyhJcG1gcBywUHlg6phP4Phz/KBoKVqSkfEuWgg==, + } peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 - '@payloadcms/live-preview@3.29.0': - resolution: {integrity: sha512-yQOj+qTDjnwl29jngMAgu9qJ8ldAqvEdbsU9c5IW5Hnz2DaFaSFkdOsjSCyjq1FEoQS3bnfBAQkT2yohbuLTjw==} + '@payloadcms/live-preview@3.31.0': + resolution: + { + integrity: sha512-LTIaH0mYo8dgpAUn6gQuJnDO3gq+xHfIMsGZkmXBch55g/NizK2S4Q2niZMK3Oap9cowA0qp2S5HGkQTWCq4UQ==, + } - '@payloadcms/next@3.29.0': - resolution: {integrity: sha512-uq9abb6DB/n0UimKhq0ShXeiD9pC+l4Z1mKd2pyPUYwQa1d0dMW+YjAeW3q3WVUvt2ZQV3JtPO68hjboXlaNUg==} - engines: {node: ^18.20.2 || >=20.9.0} + '@payloadcms/next@3.31.0': + resolution: + { + integrity: sha512-O+1E9bgQPR2bigIjxw6wFz8KVY048ZUgZ+eONjf5eLGlIPU8yHorMyruj5hJRzoXqXhehWNYtk5ru5XbouCQnA==, + } + engines: { node: ^18.20.2 || >=20.9.0 } peerDependencies: graphql: ^16.8.1 - next: ^15.0.0 - payload: 3.29.0 + next: ^15.2.3 + payload: 3.31.0 - '@payloadcms/payload-cloud@3.29.0': - resolution: {integrity: sha512-g8PgPAm2rHbParD9P5w9qZ7AldwU0IRjqlmkJiS21SbR89+hlDJebpIBM0vlnCUU+XQ9M4pnf5XZ0/vt3J1xsA==} + '@payloadcms/payload-cloud@3.31.0': + resolution: + { + integrity: sha512-+JNxgTykSJXNmrVA2Xkn+42d5iwZXc468nLRjiM29LrY6s/75yCaq55iSr0aw2UFy1hsxkHl0MjSEVLREk/LOw==, + } peerDependencies: - payload: 3.29.0 + payload: 3.31.0 - '@payloadcms/plugin-form-builder@3.29.0': - resolution: {integrity: sha512-M/YK4XTNsN23teg0axxEb/vAsvXwoGYazD3JWz0AX0ypo42hug5gJml6yeNDXGL6UThosTbc+xhzh3K9mm84pg==} + '@payloadcms/plugin-form-builder@3.31.0': + resolution: + { + integrity: sha512-XU3tjkp3+0nd1H5LnYgAGFrGB/zu+58SLMfEBKgjwQdpIoxXEn/GkKLE6EPLBXoQcHFUhOzDP0k1nv0uFm8riw==, + } peerDependencies: - payload: 3.29.0 + payload: 3.31.0 react: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 react-dom: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 - '@payloadcms/plugin-nested-docs@3.29.0': - resolution: {integrity: sha512-Q4C9ghU2zEPBwseSMmo9GHhMFDpFxrpNqEQQbunrMGkJCRAy/eU/Jc3iVbH1Ro8tXi0XJ6EGrY3hXI6xJa0BgA==} + '@payloadcms/plugin-nested-docs@3.31.0': + resolution: + { + integrity: sha512-N0rFcv+DX+BC6uiu9Ng5KhBoUoOdplsJKq6RRdDwnOwyByyWpOlRjfdVeIKY6mOOvDi3NxmxWteF0uOMOsQFRg==, + } peerDependencies: - payload: 3.29.0 + payload: 3.31.0 - '@payloadcms/plugin-redirects@3.29.0': - resolution: {integrity: sha512-s/JL88dTTnrEeIrKyPlGIs/9ic/qmpyu5oeE+OIwtNYJy3pw41JLlFzBenwoku8KmeVR67r873N4k4PxrLoJQQ==} + '@payloadcms/plugin-redirects@3.31.0': + resolution: + { + integrity: sha512-aJ0TnKO3ZqKwqQzIKsmE0+aX6T81zfElg6JvNUiKtKZeOFzngF/KzfP8FHG8njgYyHfaRmjrMxdKeXbqkGvN6Q==, + } peerDependencies: - payload: 3.29.0 + payload: 3.31.0 - '@payloadcms/plugin-search@3.29.0': - resolution: {integrity: sha512-p30hOL/kay4Jo84icyseGfANGJq3sSUrctT2JK5gdHe/6ZW76Sbo+/E31H+Y2Jy2STzJegfxrnWsY0v4a8U4sg==} + '@payloadcms/plugin-search@3.31.0': + resolution: + { + integrity: sha512-kA9QK3pQImc1fhwl5FpaNDJq0eG5ww9ZfTzS7lIyc6O6hQ1p4Ipi2bnXfRb0BuXAsu2C8ME2PUQR/cBKsaW0NA==, + } peerDependencies: - payload: 3.29.0 + payload: 3.31.0 react: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 react-dom: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 - '@payloadcms/plugin-seo@3.29.0': - resolution: {integrity: sha512-H212t2dmtuWriNGaSh5ujdK1RX6+V1FP3jRRpYq+PoV/aA3ES0VD0TX9Vko83RU2OLwlNJJx4cmWOD0xjex0kg==} + '@payloadcms/plugin-seo@3.31.0': + resolution: + { + integrity: sha512-gHsN864GoWMg4dmSTJEqX3ef1Td4GZThdYPgChsAvbBHyiFB1e9fJPH8Qne9aAPCj0+nDgRsQIs1QqT4iPn35g==, + } peerDependencies: - payload: 3.29.0 + payload: 3.31.0 react: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 react-dom: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 - '@payloadcms/richtext-lexical@3.29.0': - resolution: {integrity: sha512-OlCgr4/7hUIg4OZwSw3qoI7OUml2glsDPRI0AV6v+dZWQTQrrysCGGGM9KnO2qvAEK2TP1nfQ774v5Tz4yxSYQ==} - engines: {node: ^18.20.2 || >=20.9.0} + '@payloadcms/richtext-lexical@3.31.0': + resolution: + { + integrity: sha512-xSMO3Pd7k3mFF+PbvWEozCT4m2nFGqxdTmxKHHFKjcH2wswQwmNkuddXRXcpRm2aSzpUXPYak+8TfC+vPBC7bA==, + } + engines: { node: ^18.20.2 || >=20.9.0 } peerDependencies: '@faceless-ui/modal': 3.0.0-beta.2 '@faceless-ui/scroll-info': 2.0.0 - '@payloadcms/next': 3.29.0 - payload: 3.29.0 + '@payloadcms/next': 3.31.0 + payload: 3.31.0 react: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 react-dom: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 - '@payloadcms/translations@3.29.0': - resolution: {integrity: sha512-leM0AYBAsXFfmqM7OkQ546f7tAYAXOClDDiFi1D2SL1dcgKzbsWf3jPeCEZmZiUArolrXgWbfuHSnH7Ah78e/g==} + '@payloadcms/translations@3.31.0': + resolution: + { + integrity: sha512-vjbBuHJUZ04R7wkOR1+QhZRO1xG7bvkLgx6zoiKZZmvItqiPA5ZWsyrq3NFhviOH26dH2tOdnO+RLPuaElkWFg==, + } - '@payloadcms/ui@3.29.0': - resolution: {integrity: sha512-uTGB+T71fdlEhCtQAWzW1wDd15EUnc7hqNsM50ImuwPBqq7kMgtySrji0weG5atitXReZXJUEgHNvmhUtO+eWA==} - engines: {node: ^18.20.2 || >=20.9.0} + '@payloadcms/ui@3.31.0': + resolution: + { + integrity: sha512-SvRFqCmCo0PCOrwqFeNmL5EoJjGx7712l7pcvyMxpF0RmziZVAzqttnBizO3ha+7z65dJZFmyVHsawhO+iZk1Q==, + } + engines: { node: ^18.20.2 || >=20.9.0 } peerDependencies: - next: ^15.0.0 - payload: 3.29.0 + next: ^15.2.3 + payload: 3.31.0 react: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 react-dom: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} + resolution: + { + integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==, + } + engines: { node: '>=14' } '@radix-ui/number@1.1.0': - resolution: {integrity: sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==} + resolution: + { + integrity: sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==, + } '@radix-ui/primitive@1.1.1': - resolution: {integrity: sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==} + resolution: + { + integrity: sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==, + } '@radix-ui/react-arrow@1.1.2': - resolution: {integrity: sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==} + resolution: + { + integrity: sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==, + } peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -1116,7 +1747,10 @@ packages: optional: true '@radix-ui/react-checkbox@1.1.4': - resolution: {integrity: sha512-wP0CPAHq+P5I4INKe3hJrIa1WoNqqrejzW+zoU0rOvo1b9gDEJJFl2rYfO1PYJUQCc2H1WZxIJmyv9BS8i5fLw==} + resolution: + { + integrity: sha512-wP0CPAHq+P5I4INKe3hJrIa1WoNqqrejzW+zoU0rOvo1b9gDEJJFl2rYfO1PYJUQCc2H1WZxIJmyv9BS8i5fLw==, + } peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -1129,7 +1763,10 @@ packages: optional: true '@radix-ui/react-collection@1.1.2': - resolution: {integrity: sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==} + resolution: + { + integrity: sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==, + } peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -1142,7 +1779,10 @@ packages: optional: true '@radix-ui/react-compose-refs@1.1.1': - resolution: {integrity: sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==} + resolution: + { + integrity: sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==, + } peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -1151,7 +1791,10 @@ packages: optional: true '@radix-ui/react-context@1.1.1': - resolution: {integrity: sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==} + resolution: + { + integrity: sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==, + } peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -1160,7 +1803,10 @@ packages: optional: true '@radix-ui/react-direction@1.1.0': - resolution: {integrity: sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==} + resolution: + { + integrity: sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==, + } peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -1169,7 +1815,10 @@ packages: optional: true '@radix-ui/react-dismissable-layer@1.1.5': - resolution: {integrity: sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==} + resolution: + { + integrity: sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==, + } peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -1182,7 +1831,10 @@ packages: optional: true '@radix-ui/react-focus-guards@1.1.1': - resolution: {integrity: sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==} + resolution: + { + integrity: sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==, + } peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -1191,7 +1843,10 @@ packages: optional: true '@radix-ui/react-focus-scope@1.1.2': - resolution: {integrity: sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==} + resolution: + { + integrity: sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==, + } peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -1204,7 +1859,10 @@ packages: optional: true '@radix-ui/react-id@1.1.0': - resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==} + resolution: + { + integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==, + } peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -1213,7 +1871,10 @@ packages: optional: true '@radix-ui/react-label@2.1.2': - resolution: {integrity: sha512-zo1uGMTaNlHehDyFQcDZXRJhUPDuukcnHz0/jnrup0JA6qL+AFpAnty+7VKa9esuU5xTblAZzTGYJKSKaBxBhw==} + resolution: + { + integrity: sha512-zo1uGMTaNlHehDyFQcDZXRJhUPDuukcnHz0/jnrup0JA6qL+AFpAnty+7VKa9esuU5xTblAZzTGYJKSKaBxBhw==, + } peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -1226,7 +1887,10 @@ packages: optional: true '@radix-ui/react-popper@1.2.2': - resolution: {integrity: sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA==} + resolution: + { + integrity: sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA==, + } peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -1239,7 +1903,10 @@ packages: optional: true '@radix-ui/react-portal@1.1.4': - resolution: {integrity: sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==} + resolution: + { + integrity: sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==, + } peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -1252,7 +1919,10 @@ packages: optional: true '@radix-ui/react-presence@1.1.2': - resolution: {integrity: sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==} + resolution: + { + integrity: sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==, + } peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -1265,7 +1935,10 @@ packages: optional: true '@radix-ui/react-primitive@2.0.2': - resolution: {integrity: sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==} + resolution: + { + integrity: sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==, + } peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -1278,7 +1951,10 @@ packages: optional: true '@radix-ui/react-select@2.1.6': - resolution: {integrity: sha512-T6ajELxRvTuAMWH0YmRJ1qez+x4/7Nq7QIx7zJ0VK3qaEWdnWpNbEDnmWldG1zBDwqrLy5aLMUWcoGirVj5kMg==} + resolution: + { + integrity: sha512-T6ajELxRvTuAMWH0YmRJ1qez+x4/7Nq7QIx7zJ0VK3qaEWdnWpNbEDnmWldG1zBDwqrLy5aLMUWcoGirVj5kMg==, + } peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -1291,7 +1967,10 @@ packages: optional: true '@radix-ui/react-slot@1.1.2': - resolution: {integrity: sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==} + resolution: + { + integrity: sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==, + } peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -1300,7 +1979,10 @@ packages: optional: true '@radix-ui/react-use-callback-ref@1.1.0': - resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==} + resolution: + { + integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==, + } peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -1309,7 +1991,10 @@ packages: optional: true '@radix-ui/react-use-controllable-state@1.1.0': - resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==} + resolution: + { + integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==, + } peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -1318,7 +2003,10 @@ packages: optional: true '@radix-ui/react-use-escape-keydown@1.1.0': - resolution: {integrity: sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==} + resolution: + { + integrity: sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==, + } peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -1327,7 +2015,10 @@ packages: optional: true '@radix-ui/react-use-layout-effect@1.1.0': - resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==} + resolution: + { + integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==, + } peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -1336,7 +2027,10 @@ packages: optional: true '@radix-ui/react-use-previous@1.1.0': - resolution: {integrity: sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==} + resolution: + { + integrity: sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==, + } peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -1345,7 +2039,10 @@ packages: optional: true '@radix-ui/react-use-rect@1.1.0': - resolution: {integrity: sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==} + resolution: + { + integrity: sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==, + } peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -1354,7 +2051,10 @@ packages: optional: true '@radix-ui/react-use-size@1.1.0': - resolution: {integrity: sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==} + resolution: + { + integrity: sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==, + } peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -1363,7 +2063,10 @@ packages: optional: true '@radix-ui/react-visually-hidden@1.1.2': - resolution: {integrity: sha512-1SzA4ns2M1aRlvxErqhLHsBHoS5eI5UUcI2awAMgGUp4LoaoWOKYmvqDY2s/tltuPkh3Yk77YF/r3IRj+Amx4Q==} + resolution: + { + integrity: sha512-1SzA4ns2M1aRlvxErqhLHsBHoS5eI5UUcI2awAMgGUp4LoaoWOKYmvqDY2s/tltuPkh3Yk77YF/r3IRj+Amx4Q==, + } peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -1376,567 +2079,993 @@ packages: optional: true '@radix-ui/rect@1.1.0': - resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==} + resolution: + { + integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==, + } '@rtsao/scc@1.1.0': - resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + resolution: + { + integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==, + } '@rushstack/eslint-patch@1.11.0': - resolution: {integrity: sha512-zxnHvoMQVqewTJr/W4pKjF0bMGiKJv1WX7bSrkl46Hg0QjESbzBROWK0Wg4RphzSOS5Jiy7eFimmM3UgMrMZbQ==} + resolution: + { + integrity: sha512-zxnHvoMQVqewTJr/W4pKjF0bMGiKJv1WX7bSrkl46Hg0QjESbzBROWK0Wg4RphzSOS5Jiy7eFimmM3UgMrMZbQ==, + } '@smithy/abort-controller@4.0.1': - resolution: {integrity: sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==, + } + engines: { node: '>=18.0.0' } '@smithy/chunked-blob-reader-native@4.0.0': - resolution: {integrity: sha512-R9wM2yPmfEMsUmlMlIgSzOyICs0x9uu7UTHoccMyt7BWw8shcGM8HqB355+BZCPBcySvbTYMs62EgEQkNxz2ig==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-R9wM2yPmfEMsUmlMlIgSzOyICs0x9uu7UTHoccMyt7BWw8shcGM8HqB355+BZCPBcySvbTYMs62EgEQkNxz2ig==, + } + engines: { node: '>=18.0.0' } '@smithy/chunked-blob-reader@5.0.0': - resolution: {integrity: sha512-+sKqDBQqb036hh4NPaUiEkYFkTUGYzRsn3EuFhyfQfMy6oGHEUJDurLP9Ufb5dasr/XiAmPNMr6wa9afjQB+Gw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-+sKqDBQqb036hh4NPaUiEkYFkTUGYzRsn3EuFhyfQfMy6oGHEUJDurLP9Ufb5dasr/XiAmPNMr6wa9afjQB+Gw==, + } + engines: { node: '>=18.0.0' } '@smithy/config-resolver@4.0.1': - resolution: {integrity: sha512-Igfg8lKu3dRVkTSEm98QpZUvKEOa71jDX4vKRcvJVyRc3UgN3j7vFMf0s7xLQhYmKa8kyJGQgUJDOV5V3neVlQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-Igfg8lKu3dRVkTSEm98QpZUvKEOa71jDX4vKRcvJVyRc3UgN3j7vFMf0s7xLQhYmKa8kyJGQgUJDOV5V3neVlQ==, + } + engines: { node: '>=18.0.0' } '@smithy/core@3.1.5': - resolution: {integrity: sha512-HLclGWPkCsekQgsyzxLhCQLa8THWXtB5PxyYN+2O6nkyLt550KQKTlbV2D1/j5dNIQapAZM1+qFnpBFxZQkgCA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-HLclGWPkCsekQgsyzxLhCQLa8THWXtB5PxyYN+2O6nkyLt550KQKTlbV2D1/j5dNIQapAZM1+qFnpBFxZQkgCA==, + } + engines: { node: '>=18.0.0' } '@smithy/credential-provider-imds@4.0.1': - resolution: {integrity: sha512-l/qdInaDq1Zpznpmev/+52QomsJNZ3JkTl5yrTl02V6NBgJOQ4LY0SFw/8zsMwj3tLe8vqiIuwF6nxaEwgf6mg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-l/qdInaDq1Zpznpmev/+52QomsJNZ3JkTl5yrTl02V6NBgJOQ4LY0SFw/8zsMwj3tLe8vqiIuwF6nxaEwgf6mg==, + } + engines: { node: '>=18.0.0' } '@smithy/eventstream-codec@4.0.1': - resolution: {integrity: sha512-Q2bCAAR6zXNVtJgifsU16ZjKGqdw/DyecKNgIgi7dlqw04fqDu0mnq+JmGphqheypVc64CYq3azSuCpAdFk2+A==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-Q2bCAAR6zXNVtJgifsU16ZjKGqdw/DyecKNgIgi7dlqw04fqDu0mnq+JmGphqheypVc64CYq3azSuCpAdFk2+A==, + } + engines: { node: '>=18.0.0' } '@smithy/eventstream-serde-browser@4.0.1': - resolution: {integrity: sha512-HbIybmz5rhNg+zxKiyVAnvdM3vkzjE6ccrJ620iPL8IXcJEntd3hnBl+ktMwIy12Te/kyrSbUb8UCdnUT4QEdA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-HbIybmz5rhNg+zxKiyVAnvdM3vkzjE6ccrJ620iPL8IXcJEntd3hnBl+ktMwIy12Te/kyrSbUb8UCdnUT4QEdA==, + } + engines: { node: '>=18.0.0' } '@smithy/eventstream-serde-config-resolver@4.0.1': - resolution: {integrity: sha512-lSipaiq3rmHguHa3QFF4YcCM3VJOrY9oq2sow3qlhFY+nBSTF/nrO82MUQRPrxHQXA58J5G1UnU2WuJfi465BA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-lSipaiq3rmHguHa3QFF4YcCM3VJOrY9oq2sow3qlhFY+nBSTF/nrO82MUQRPrxHQXA58J5G1UnU2WuJfi465BA==, + } + engines: { node: '>=18.0.0' } '@smithy/eventstream-serde-node@4.0.1': - resolution: {integrity: sha512-o4CoOI6oYGYJ4zXo34U8X9szDe3oGjmHgsMGiZM0j4vtNoT+h80TLnkUcrLZR3+E6HIxqW+G+9WHAVfl0GXK0Q==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-o4CoOI6oYGYJ4zXo34U8X9szDe3oGjmHgsMGiZM0j4vtNoT+h80TLnkUcrLZR3+E6HIxqW+G+9WHAVfl0GXK0Q==, + } + engines: { node: '>=18.0.0' } '@smithy/eventstream-serde-universal@4.0.1': - resolution: {integrity: sha512-Z94uZp0tGJuxds3iEAZBqGU2QiaBHP4YytLUjwZWx+oUeohCsLyUm33yp4MMBmhkuPqSbQCXq5hDet6JGUgHWA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-Z94uZp0tGJuxds3iEAZBqGU2QiaBHP4YytLUjwZWx+oUeohCsLyUm33yp4MMBmhkuPqSbQCXq5hDet6JGUgHWA==, + } + engines: { node: '>=18.0.0' } '@smithy/fetch-http-handler@5.0.1': - resolution: {integrity: sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==, + } + engines: { node: '>=18.0.0' } '@smithy/hash-blob-browser@4.0.1': - resolution: {integrity: sha512-rkFIrQOKZGS6i1D3gKJ8skJ0RlXqDvb1IyAphksaFOMzkn3v3I1eJ8m7OkLj0jf1McP63rcCEoLlkAn/HjcTRw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-rkFIrQOKZGS6i1D3gKJ8skJ0RlXqDvb1IyAphksaFOMzkn3v3I1eJ8m7OkLj0jf1McP63rcCEoLlkAn/HjcTRw==, + } + engines: { node: '>=18.0.0' } '@smithy/hash-node@4.0.1': - resolution: {integrity: sha512-TJ6oZS+3r2Xu4emVse1YPB3Dq3d8RkZDKcPr71Nj/lJsdAP1c7oFzYqEn1IBc915TsgLl2xIJNuxCz+gLbLE0w==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-TJ6oZS+3r2Xu4emVse1YPB3Dq3d8RkZDKcPr71Nj/lJsdAP1c7oFzYqEn1IBc915TsgLl2xIJNuxCz+gLbLE0w==, + } + engines: { node: '>=18.0.0' } '@smithy/hash-stream-node@4.0.1': - resolution: {integrity: sha512-U1rAE1fxmReCIr6D2o/4ROqAQX+GffZpyMt3d7njtGDr2pUNmAKRWa49gsNVhCh2vVAuf3wXzWwNr2YN8PAXIw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-U1rAE1fxmReCIr6D2o/4ROqAQX+GffZpyMt3d7njtGDr2pUNmAKRWa49gsNVhCh2vVAuf3wXzWwNr2YN8PAXIw==, + } + engines: { node: '>=18.0.0' } '@smithy/invalid-dependency@4.0.1': - resolution: {integrity: sha512-gdudFPf4QRQ5pzj7HEnu6FhKRi61BfH/Gk5Yf6O0KiSbr1LlVhgjThcvjdu658VE6Nve8vaIWB8/fodmS1rBPQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-gdudFPf4QRQ5pzj7HEnu6FhKRi61BfH/Gk5Yf6O0KiSbr1LlVhgjThcvjdu658VE6Nve8vaIWB8/fodmS1rBPQ==, + } + engines: { node: '>=18.0.0' } '@smithy/is-array-buffer@2.2.0': - resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} - engines: {node: '>=14.0.0'} + resolution: + { + integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==, + } + engines: { node: '>=14.0.0' } '@smithy/is-array-buffer@4.0.0': - resolution: {integrity: sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==, + } + engines: { node: '>=18.0.0' } '@smithy/md5-js@4.0.1': - resolution: {integrity: sha512-HLZ647L27APi6zXkZlzSFZIjpo8po45YiyjMGJZM3gyDY8n7dPGdmxIIljLm4gPt/7rRvutLTTkYJpZVfG5r+A==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-HLZ647L27APi6zXkZlzSFZIjpo8po45YiyjMGJZM3gyDY8n7dPGdmxIIljLm4gPt/7rRvutLTTkYJpZVfG5r+A==, + } + engines: { node: '>=18.0.0' } '@smithy/middleware-content-length@4.0.1': - resolution: {integrity: sha512-OGXo7w5EkB5pPiac7KNzVtfCW2vKBTZNuCctn++TTSOMpe6RZO/n6WEC1AxJINn3+vWLKW49uad3lo/u0WJ9oQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-OGXo7w5EkB5pPiac7KNzVtfCW2vKBTZNuCctn++TTSOMpe6RZO/n6WEC1AxJINn3+vWLKW49uad3lo/u0WJ9oQ==, + } + engines: { node: '>=18.0.0' } '@smithy/middleware-endpoint@4.0.6': - resolution: {integrity: sha512-ftpmkTHIFqgaFugcjzLZv3kzPEFsBFSnq1JsIkr2mwFzCraZVhQk2gqN51OOeRxqhbPTkRFj39Qd2V91E/mQxg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-ftpmkTHIFqgaFugcjzLZv3kzPEFsBFSnq1JsIkr2mwFzCraZVhQk2gqN51OOeRxqhbPTkRFj39Qd2V91E/mQxg==, + } + engines: { node: '>=18.0.0' } '@smithy/middleware-retry@4.0.7': - resolution: {integrity: sha512-58j9XbUPLkqAcV1kHzVX/kAR16GT+j7DUZJqwzsxh1jtz7G82caZiGyyFgUvogVfNTg3TeAOIJepGc8TXF4AVQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-58j9XbUPLkqAcV1kHzVX/kAR16GT+j7DUZJqwzsxh1jtz7G82caZiGyyFgUvogVfNTg3TeAOIJepGc8TXF4AVQ==, + } + engines: { node: '>=18.0.0' } '@smithy/middleware-serde@4.0.2': - resolution: {integrity: sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==, + } + engines: { node: '>=18.0.0' } '@smithy/middleware-stack@4.0.1': - resolution: {integrity: sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==, + } + engines: { node: '>=18.0.0' } '@smithy/node-config-provider@4.0.1': - resolution: {integrity: sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==, + } + engines: { node: '>=18.0.0' } '@smithy/node-http-handler@4.0.3': - resolution: {integrity: sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA==, + } + engines: { node: '>=18.0.0' } '@smithy/property-provider@4.0.1': - resolution: {integrity: sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==, + } + engines: { node: '>=18.0.0' } '@smithy/protocol-http@5.0.1': - resolution: {integrity: sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==, + } + engines: { node: '>=18.0.0' } '@smithy/querystring-builder@4.0.1': - resolution: {integrity: sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==, + } + engines: { node: '>=18.0.0' } '@smithy/querystring-parser@4.0.1': - resolution: {integrity: sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==, + } + engines: { node: '>=18.0.0' } '@smithy/service-error-classification@4.0.1': - resolution: {integrity: sha512-3JNjBfOWpj/mYfjXJHB4Txc/7E4LVq32bwzE7m28GN79+M1f76XHflUaSUkhOriprPDzev9cX/M+dEB80DNDKA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-3JNjBfOWpj/mYfjXJHB4Txc/7E4LVq32bwzE7m28GN79+M1f76XHflUaSUkhOriprPDzev9cX/M+dEB80DNDKA==, + } + engines: { node: '>=18.0.0' } '@smithy/shared-ini-file-loader@4.0.1': - resolution: {integrity: sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==, + } + engines: { node: '>=18.0.0' } '@smithy/signature-v4@5.0.1': - resolution: {integrity: sha512-nCe6fQ+ppm1bQuw5iKoeJ0MJfz2os7Ic3GBjOkLOPtavbD1ONoyE3ygjBfz2ythFWm4YnRm6OxW+8p/m9uCoIA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-nCe6fQ+ppm1bQuw5iKoeJ0MJfz2os7Ic3GBjOkLOPtavbD1ONoyE3ygjBfz2ythFWm4YnRm6OxW+8p/m9uCoIA==, + } + engines: { node: '>=18.0.0' } '@smithy/smithy-client@4.1.6': - resolution: {integrity: sha512-UYDolNg6h2O0L+cJjtgSyKKvEKCOa/8FHYJnBobyeoeWDmNpXjwOAtw16ezyeu1ETuuLEOZbrynK0ZY1Lx9Jbw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-UYDolNg6h2O0L+cJjtgSyKKvEKCOa/8FHYJnBobyeoeWDmNpXjwOAtw16ezyeu1ETuuLEOZbrynK0ZY1Lx9Jbw==, + } + engines: { node: '>=18.0.0' } '@smithy/types@4.1.0': - resolution: {integrity: sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==, + } + engines: { node: '>=18.0.0' } '@smithy/url-parser@4.0.1': - resolution: {integrity: sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==, + } + engines: { node: '>=18.0.0' } '@smithy/util-base64@4.0.0': - resolution: {integrity: sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==, + } + engines: { node: '>=18.0.0' } '@smithy/util-body-length-browser@4.0.0': - resolution: {integrity: sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==, + } + engines: { node: '>=18.0.0' } '@smithy/util-body-length-node@4.0.0': - resolution: {integrity: sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==, + } + engines: { node: '>=18.0.0' } '@smithy/util-buffer-from@2.2.0': - resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} - engines: {node: '>=14.0.0'} + resolution: + { + integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==, + } + engines: { node: '>=14.0.0' } '@smithy/util-buffer-from@4.0.0': - resolution: {integrity: sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==, + } + engines: { node: '>=18.0.0' } '@smithy/util-config-provider@4.0.0': - resolution: {integrity: sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==, + } + engines: { node: '>=18.0.0' } '@smithy/util-defaults-mode-browser@4.0.7': - resolution: {integrity: sha512-CZgDDrYHLv0RUElOsmZtAnp1pIjwDVCSuZWOPhIOBvG36RDfX1Q9+6lS61xBf+qqvHoqRjHxgINeQz47cYFC2Q==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-CZgDDrYHLv0RUElOsmZtAnp1pIjwDVCSuZWOPhIOBvG36RDfX1Q9+6lS61xBf+qqvHoqRjHxgINeQz47cYFC2Q==, + } + engines: { node: '>=18.0.0' } '@smithy/util-defaults-mode-node@4.0.7': - resolution: {integrity: sha512-79fQW3hnfCdrfIi1soPbK3zmooRFnLpSx3Vxi6nUlqaaQeC5dm8plt4OTNDNqEEEDkvKghZSaoti684dQFVrGQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-79fQW3hnfCdrfIi1soPbK3zmooRFnLpSx3Vxi6nUlqaaQeC5dm8plt4OTNDNqEEEDkvKghZSaoti684dQFVrGQ==, + } + engines: { node: '>=18.0.0' } '@smithy/util-endpoints@3.0.1': - resolution: {integrity: sha512-zVdUENQpdtn9jbpD9SCFK4+aSiavRb9BxEtw9ZGUR1TYo6bBHbIoi7VkrFQ0/RwZlzx0wRBaRmPclj8iAoJCLA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-zVdUENQpdtn9jbpD9SCFK4+aSiavRb9BxEtw9ZGUR1TYo6bBHbIoi7VkrFQ0/RwZlzx0wRBaRmPclj8iAoJCLA==, + } + engines: { node: '>=18.0.0' } '@smithy/util-hex-encoding@4.0.0': - resolution: {integrity: sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==, + } + engines: { node: '>=18.0.0' } '@smithy/util-middleware@4.0.1': - resolution: {integrity: sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==, + } + engines: { node: '>=18.0.0' } '@smithy/util-retry@4.0.1': - resolution: {integrity: sha512-WmRHqNVwn3kI3rKk1LsKcVgPBG6iLTBGC1iYOV3GQegwJ3E8yjzHytPt26VNzOWr1qu0xE03nK0Ug8S7T7oufw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-WmRHqNVwn3kI3rKk1LsKcVgPBG6iLTBGC1iYOV3GQegwJ3E8yjzHytPt26VNzOWr1qu0xE03nK0Ug8S7T7oufw==, + } + engines: { node: '>=18.0.0' } '@smithy/util-stream@4.1.2': - resolution: {integrity: sha512-44PKEqQ303d3rlQuiDpcCcu//hV8sn+u2JBo84dWCE0rvgeiVl0IlLMagbU++o0jCWhYCsHaAt9wZuZqNe05Hw==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-44PKEqQ303d3rlQuiDpcCcu//hV8sn+u2JBo84dWCE0rvgeiVl0IlLMagbU++o0jCWhYCsHaAt9wZuZqNe05Hw==, + } + engines: { node: '>=18.0.0' } '@smithy/util-uri-escape@4.0.0': - resolution: {integrity: sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==, + } + engines: { node: '>=18.0.0' } '@smithy/util-utf8@2.3.0': - resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} - engines: {node: '>=14.0.0'} + resolution: + { + integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==, + } + engines: { node: '>=14.0.0' } '@smithy/util-utf8@4.0.0': - resolution: {integrity: sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==, + } + engines: { node: '>=18.0.0' } '@smithy/util-waiter@4.0.2': - resolution: {integrity: sha512-piUTHyp2Axx3p/kc2CIJkYSv0BAaheBQmbACZgQSSfWUumWNW+R1lL+H9PDBxKJkvOeEX+hKYEFiwO8xagL8AQ==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-piUTHyp2Axx3p/kc2CIJkYSv0BAaheBQmbACZgQSSfWUumWNW+R1lL+H9PDBxKJkvOeEX+hKYEFiwO8xagL8AQ==, + } + engines: { node: '>=18.0.0' } '@swc/counter@0.1.3': - resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + resolution: + { + integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==, + } '@swc/helpers@0.5.15': - resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + resolution: + { + integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==, + } '@tailwindcss/typography@0.5.16': - resolution: {integrity: sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==} + resolution: + { + integrity: sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==, + } peerDependencies: tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' '@tokenizer/token@0.3.0': - resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + resolution: + { + integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==, + } '@tybys/wasm-util@0.9.0': - resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} + resolution: + { + integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==, + } '@types/acorn@4.0.6': - resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==} + resolution: + { + integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==, + } '@types/busboy@1.5.4': - resolution: {integrity: sha512-kG7WrUuAKK0NoyxfQHsVE6j1m01s6kMma64E+OZenQABMQyTJop1DumUWcLwAQ2JzpefU7PDYoRDKl8uZosFjw==} + resolution: + { + integrity: sha512-kG7WrUuAKK0NoyxfQHsVE6j1m01s6kMma64E+OZenQABMQyTJop1DumUWcLwAQ2JzpefU7PDYoRDKl8uZosFjw==, + } '@types/debug@4.1.12': - resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + resolution: + { + integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==, + } '@types/escape-html@1.0.4': - resolution: {integrity: sha512-qZ72SFTgUAZ5a7Tj6kf2SHLetiH5S6f8G5frB2SPQ3EyF02kxdyBFf4Tz4banE3xCgGnKgWLt//a6VuYHKYJTg==} + resolution: + { + integrity: sha512-qZ72SFTgUAZ5a7Tj6kf2SHLetiH5S6f8G5frB2SPQ3EyF02kxdyBFf4Tz4banE3xCgGnKgWLt//a6VuYHKYJTg==, + } '@types/estree-jsx@1.0.5': - resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + resolution: + { + integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==, + } '@types/estree@1.0.6': - resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + resolution: + { + integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==, + } '@types/hast@3.0.4': - resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + resolution: + { + integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==, + } '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + resolution: + { + integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==, + } '@types/json5@0.0.29': - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + resolution: + { + integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==, + } '@types/lodash@4.17.16': - resolution: {integrity: sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==} + resolution: + { + integrity: sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==, + } '@types/mdast@4.0.4': - resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + resolution: + { + integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==, + } '@types/ms@2.1.0': - resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + resolution: + { + integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==, + } '@types/node@22.5.4': - resolution: {integrity: sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==} + resolution: + { + integrity: sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==, + } '@types/parse-json@4.0.2': - resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + resolution: + { + integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==, + } '@types/prismjs@1.26.5': - resolution: {integrity: sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==} + resolution: + { + integrity: sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==, + } '@types/react-dom@19.0.4': - resolution: {integrity: sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==} + resolution: + { + integrity: sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==, + } peerDependencies: '@types/react': ^19.0.0 '@types/react-transition-group@4.4.12': - resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==} + resolution: + { + integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==, + } peerDependencies: '@types/react': '*' '@types/react@19.0.12': - resolution: {integrity: sha512-V6Ar115dBDrjbtXSrS+/Oruobc+qVbbUxDFC1RSbRqLt5SYvxxyIDrSC85RWml54g+jfNeEMZhEj7wW07ONQhA==} + resolution: + { + integrity: sha512-V6Ar115dBDrjbtXSrS+/Oruobc+qVbbUxDFC1RSbRqLt5SYvxxyIDrSC85RWml54g+jfNeEMZhEj7wW07ONQhA==, + } '@types/unist@2.0.11': - resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + resolution: + { + integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==, + } '@types/unist@3.0.3': - resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + resolution: + { + integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==, + } '@types/uuid@10.0.0': - resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + resolution: + { + integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==, + } '@types/webidl-conversions@7.0.3': - resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==} + resolution: + { + integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==, + } '@types/whatwg-url@11.0.5': - resolution: {integrity: sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==} + resolution: + { + integrity: sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==, + } '@typescript-eslint/eslint-plugin@8.27.0': - resolution: {integrity: sha512-4henw4zkePi5p252c8ncBLzLce52SEUz2Ebj8faDnuUXz2UuHEONYcJ+G0oaCF+bYCWVZtrGzq3FD7YXetmnSA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-4henw4zkePi5p252c8ncBLzLce52SEUz2Ebj8faDnuUXz2UuHEONYcJ+G0oaCF+bYCWVZtrGzq3FD7YXetmnSA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } peerDependencies: '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' '@typescript-eslint/parser@8.27.0': - resolution: {integrity: sha512-XGwIabPallYipmcOk45DpsBSgLC64A0yvdAkrwEzwZ2viqGqRUJ8eEYoPz0CWnutgAFbNMPdsGGvzjSmcWVlEA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-XGwIabPallYipmcOk45DpsBSgLC64A0yvdAkrwEzwZ2viqGqRUJ8eEYoPz0CWnutgAFbNMPdsGGvzjSmcWVlEA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' '@typescript-eslint/scope-manager@8.27.0': - resolution: {integrity: sha512-8oI9GwPMQmBryaaxG1tOZdxXVeMDte6NyJA4i7/TWa4fBwgnAXYlIQP+uYOeqAaLJ2JRxlG9CAyL+C+YE9Xknw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-8oI9GwPMQmBryaaxG1tOZdxXVeMDte6NyJA4i7/TWa4fBwgnAXYlIQP+uYOeqAaLJ2JRxlG9CAyL+C+YE9Xknw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } '@typescript-eslint/type-utils@8.27.0': - resolution: {integrity: sha512-wVArTVcz1oJOIEJxui/nRhV0TXzD/zMSOYi/ggCfNq78EIszddXcJb7r4RCp/oBrjt8n9A0BSxRMKxHftpDxDA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-wVArTVcz1oJOIEJxui/nRhV0TXzD/zMSOYi/ggCfNq78EIszddXcJb7r4RCp/oBrjt8n9A0BSxRMKxHftpDxDA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' '@typescript-eslint/types@8.27.0': - resolution: {integrity: sha512-/6cp9yL72yUHAYq9g6DsAU+vVfvQmd1a8KyA81uvfDE21O2DwQ/qxlM4AR8TSdAu+kJLBDrEHKC5/W2/nxsY0A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-/6cp9yL72yUHAYq9g6DsAU+vVfvQmd1a8KyA81uvfDE21O2DwQ/qxlM4AR8TSdAu+kJLBDrEHKC5/W2/nxsY0A==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } '@typescript-eslint/typescript-estree@8.27.0': - resolution: {integrity: sha512-BnKq8cqPVoMw71O38a1tEb6iebEgGA80icSxW7g+kndx0o6ot6696HjG7NdgfuAVmVEtwXUr3L8R9ZuVjoQL6A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-BnKq8cqPVoMw71O38a1tEb6iebEgGA80icSxW7g+kndx0o6ot6696HjG7NdgfuAVmVEtwXUr3L8R9ZuVjoQL6A==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } peerDependencies: typescript: '>=4.8.4 <5.9.0' '@typescript-eslint/utils@8.27.0': - resolution: {integrity: sha512-njkodcwH1yvmo31YWgRHNb/x1Xhhq4/m81PhtvmRngD8iHPehxffz1SNCO+kwaePhATC+kOa/ggmvPoPza5i0Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-njkodcwH1yvmo31YWgRHNb/x1Xhhq4/m81PhtvmRngD8iHPehxffz1SNCO+kwaePhATC+kOa/ggmvPoPza5i0Q==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' '@typescript-eslint/visitor-keys@8.27.0': - resolution: {integrity: sha512-WsXQwMkILJvffP6z4U3FYJPlbf/j07HIxmDjZpbNvBJkMfvwXj5ACRkkHwBDvLBbDbtX5TdU64/rcvKJ/vuInQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-WsXQwMkILJvffP6z4U3FYJPlbf/j07HIxmDjZpbNvBJkMfvwXj5ACRkkHwBDvLBbDbtX5TdU64/rcvKJ/vuInQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } '@unrs/rspack-resolver-binding-darwin-arm64@1.2.2': - resolution: {integrity: sha512-i7z0B+C0P8Q63O/5PXJAzeFtA1ttY3OR2VSJgGv18S+PFNwD98xHgAgPOT1H5HIV6jlQP8Avzbp09qxJUdpPNw==} + resolution: + { + integrity: sha512-i7z0B+C0P8Q63O/5PXJAzeFtA1ttY3OR2VSJgGv18S+PFNwD98xHgAgPOT1H5HIV6jlQP8Avzbp09qxJUdpPNw==, + } cpu: [arm64] os: [darwin] '@unrs/rspack-resolver-binding-darwin-x64@1.2.2': - resolution: {integrity: sha512-YEdFzPjIbDUCfmehC6eS+AdJYtFWY35YYgWUnqqTM2oe/N58GhNy5yRllxYhxwJ9GcfHoNc6Ubze1yjkNv+9Qg==} + resolution: + { + integrity: sha512-YEdFzPjIbDUCfmehC6eS+AdJYtFWY35YYgWUnqqTM2oe/N58GhNy5yRllxYhxwJ9GcfHoNc6Ubze1yjkNv+9Qg==, + } cpu: [x64] os: [darwin] '@unrs/rspack-resolver-binding-freebsd-x64@1.2.2': - resolution: {integrity: sha512-TU4ntNXDgPN2giQyyzSnGWf/dVCem5lvwxg0XYvsvz35h5H19WrhTmHgbrULMuypCB3aHe1enYUC9rPLDw45mA==} + resolution: + { + integrity: sha512-TU4ntNXDgPN2giQyyzSnGWf/dVCem5lvwxg0XYvsvz35h5H19WrhTmHgbrULMuypCB3aHe1enYUC9rPLDw45mA==, + } cpu: [x64] os: [freebsd] '@unrs/rspack-resolver-binding-linux-arm-gnueabihf@1.2.2': - resolution: {integrity: sha512-ik3w4/rU6RujBvNWiDnKdXi1smBhqxEDhccNi/j2rHaMjm0Fk49KkJ6XKsoUnD2kZ5xaMJf9JjailW/okfUPIw==} + resolution: + { + integrity: sha512-ik3w4/rU6RujBvNWiDnKdXi1smBhqxEDhccNi/j2rHaMjm0Fk49KkJ6XKsoUnD2kZ5xaMJf9JjailW/okfUPIw==, + } cpu: [arm] os: [linux] '@unrs/rspack-resolver-binding-linux-arm64-gnu@1.2.2': - resolution: {integrity: sha512-fp4Azi8kHz6TX8SFmKfyScZrMLfp++uRm2srpqRjsRZIIBzH74NtSkdEUHImR4G7f7XJ+sVZjCc6KDDK04YEpQ==} + resolution: + { + integrity: sha512-fp4Azi8kHz6TX8SFmKfyScZrMLfp++uRm2srpqRjsRZIIBzH74NtSkdEUHImR4G7f7XJ+sVZjCc6KDDK04YEpQ==, + } cpu: [arm64] os: [linux] '@unrs/rspack-resolver-binding-linux-arm64-musl@1.2.2': - resolution: {integrity: sha512-gMiG3DCFioJxdGBzhlL86KcFgt9HGz0iDhw0YVYPsShItpN5pqIkNrI+L/Q/0gfDiGrfcE0X3VANSYIPmqEAlQ==} + resolution: + { + integrity: sha512-gMiG3DCFioJxdGBzhlL86KcFgt9HGz0iDhw0YVYPsShItpN5pqIkNrI+L/Q/0gfDiGrfcE0X3VANSYIPmqEAlQ==, + } cpu: [arm64] os: [linux] '@unrs/rspack-resolver-binding-linux-x64-gnu@1.2.2': - resolution: {integrity: sha512-n/4n2CxaUF9tcaJxEaZm+lqvaw2gflfWQ1R9I7WQgYkKEKbRKbpG/R3hopYdUmLSRI4xaW1Cy0Bz40eS2Yi4Sw==} + resolution: + { + integrity: sha512-n/4n2CxaUF9tcaJxEaZm+lqvaw2gflfWQ1R9I7WQgYkKEKbRKbpG/R3hopYdUmLSRI4xaW1Cy0Bz40eS2Yi4Sw==, + } cpu: [x64] os: [linux] '@unrs/rspack-resolver-binding-linux-x64-musl@1.2.2': - resolution: {integrity: sha512-cHyhAr6rlYYbon1L2Ag449YCj3p6XMfcYTP0AQX+KkQo025d1y/VFtPWvjMhuEsE2lLvtHm7GdJozj6BOMtzVg==} + resolution: + { + integrity: sha512-cHyhAr6rlYYbon1L2Ag449YCj3p6XMfcYTP0AQX+KkQo025d1y/VFtPWvjMhuEsE2lLvtHm7GdJozj6BOMtzVg==, + } cpu: [x64] os: [linux] '@unrs/rspack-resolver-binding-wasm32-wasi@1.2.2': - resolution: {integrity: sha512-eogDKuICghDLGc32FtP+WniG38IB1RcGOGz0G3z8406dUdjJvxfHGuGs/dSlM9YEp/v0lEqhJ4mBu6X2nL9pog==} - engines: {node: '>=14.0.0'} + resolution: + { + integrity: sha512-eogDKuICghDLGc32FtP+WniG38IB1RcGOGz0G3z8406dUdjJvxfHGuGs/dSlM9YEp/v0lEqhJ4mBu6X2nL9pog==, + } + engines: { node: '>=14.0.0' } cpu: [wasm32] '@unrs/rspack-resolver-binding-win32-arm64-msvc@1.2.2': - resolution: {integrity: sha512-7sWRJumhpXSi2lccX8aQpfFXHsSVASdWndLv8AmD8nDRA/5PBi8IplQVZNx2mYRx6+Bp91Z00kuVqpXO9NfCTg==} + resolution: + { + integrity: sha512-7sWRJumhpXSi2lccX8aQpfFXHsSVASdWndLv8AmD8nDRA/5PBi8IplQVZNx2mYRx6+Bp91Z00kuVqpXO9NfCTg==, + } cpu: [arm64] os: [win32] '@unrs/rspack-resolver-binding-win32-x64-msvc@1.2.2': - resolution: {integrity: sha512-hewo/UMGP1a7O6FG/ThcPzSJdm/WwrYDNkdGgWl6M18H6K6MSitklomWpT9MUtT5KGj++QJb06va/14QBC4pvw==} + resolution: + { + integrity: sha512-hewo/UMGP1a7O6FG/ThcPzSJdm/WwrYDNkdGgWl6M18H6K6MSitklomWpT9MUtT5KGj++QJb06va/14QBC4pvw==, + } cpu: [x64] os: [win32] acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + resolution: + { + integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==, + } peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 acorn@8.12.1: - resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} - engines: {node: '>=0.4.0'} + resolution: + { + integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==, + } + engines: { node: '>=0.4.0' } hasBin: true acorn@8.14.1: - resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} - engines: {node: '>=0.4.0'} + resolution: + { + integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==, + } + engines: { node: '>=0.4.0' } hasBin: true ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + resolution: + { + integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==, + } ajv@8.17.1: - resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + resolution: + { + integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==, + } amazon-cognito-identity-js@6.3.12: - resolution: {integrity: sha512-s7NKDZgx336cp+oDeUtB2ZzT8jWJp/v2LWuYl+LQtMEODe22RF1IJ4nRiDATp+rp1pTffCZcm44Quw4jx2bqNg==} + resolution: + { + integrity: sha512-s7NKDZgx336cp+oDeUtB2ZzT8jWJp/v2LWuYl+LQtMEODe22RF1IJ4nRiDATp+rp1pTffCZcm44Quw4jx2bqNg==, + } ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==, + } + engines: { node: '>=8' } ansi-regex@6.1.0: - resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==, + } + engines: { node: '>=12' } ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==, + } + engines: { node: '>=8' } ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==, + } + engines: { node: '>=12' } any-promise@1.3.0: - resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + resolution: + { + integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==, + } anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==, + } + engines: { node: '>= 8' } arg@5.0.2: - resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + resolution: + { + integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==, + } argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + resolution: + { + integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, + } aria-hidden@1.2.4: - resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==, + } + engines: { node: '>=10' } aria-query@5.3.2: - resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==, + } + engines: { node: '>= 0.4' } array-buffer-byte-length@1.0.2: - resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==, + } + engines: { node: '>= 0.4' } array-includes@3.1.8: - resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==, + } + engines: { node: '>= 0.4' } array.prototype.findlast@1.2.5: - resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==, + } + engines: { node: '>= 0.4' } array.prototype.findlastindex@1.2.6: - resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==, + } + engines: { node: '>= 0.4' } array.prototype.flat@1.3.3: - resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==, + } + engines: { node: '>= 0.4' } array.prototype.flatmap@1.3.3: - resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==, + } + engines: { node: '>= 0.4' } array.prototype.tosorted@1.1.4: - resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==, + } + engines: { node: '>= 0.4' } arraybuffer.prototype.slice@1.0.4: - resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==, + } + engines: { node: '>= 0.4' } ast-types-flow@0.0.8: - resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + resolution: + { + integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==, + } async-function@1.0.0: - resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==, + } + engines: { node: '>= 0.4' } atomic-sleep@1.0.0: - resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} - engines: {node: '>=8.0.0'} + resolution: + { + integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==, + } + engines: { node: '>=8.0.0' } autoprefixer@10.4.21: - resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==} - engines: {node: ^10 || ^12 || >=14} + resolution: + { + integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==, + } + engines: { node: ^10 || ^12 || >=14 } hasBin: true peerDependencies: postcss: ^8.1.0 available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==, + } + engines: { node: '>= 0.4' } axe-core@4.10.3: - resolution: {integrity: sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==, + } + engines: { node: '>=4' } axobject-query@4.1.0: - resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==, + } + engines: { node: '>= 0.4' } b4a@1.6.7: - resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==} + resolution: + { + integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==, + } babel-plugin-macros@3.1.0: - resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} - engines: {node: '>=10', npm: '>=6'} + resolution: + { + integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==, + } + engines: { node: '>=10', npm: '>=6' } balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + resolution: + { + integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, + } bare-events@2.5.4: - resolution: {integrity: sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==} + resolution: + { + integrity: sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==, + } bare-fs@4.0.1: - resolution: {integrity: sha512-ilQs4fm/l9eMfWY2dY0WCIUplSUp7U0CT1vrqMg1MUdeZl4fypu5UP0XcDBK5WBQPJAKP1b7XEodISmekH/CEg==} - engines: {bare: '>=1.7.0'} + resolution: + { + integrity: sha512-ilQs4fm/l9eMfWY2dY0WCIUplSUp7U0CT1vrqMg1MUdeZl4fypu5UP0XcDBK5WBQPJAKP1b7XEodISmekH/CEg==, + } + engines: { bare: '>=1.7.0' } bare-os@3.6.0: - resolution: {integrity: sha512-BUrFS5TqSBdA0LwHop4OjPJwisqxGy6JsWVqV6qaFoe965qqtaKfDzHY5T2YA1gUL0ZeeQeA+4BBc1FJTcHiPw==} - engines: {bare: '>=1.14.0'} + resolution: + { + integrity: sha512-BUrFS5TqSBdA0LwHop4OjPJwisqxGy6JsWVqV6qaFoe965qqtaKfDzHY5T2YA1gUL0ZeeQeA+4BBc1FJTcHiPw==, + } + engines: { bare: '>=1.14.0' } bare-path@3.0.0: - resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==} + resolution: + { + integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==, + } bare-stream@2.6.5: - resolution: {integrity: sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==} + resolution: + { + integrity: sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==, + } peerDependencies: bare-buffer: '*' bare-events: '*' @@ -1947,228 +3076,423 @@ packages: optional: true base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + resolution: + { + integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==, + } binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==, + } + engines: { node: '>=8' } bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + resolution: + { + integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==, + } body-scroll-lock@4.0.0-beta.0: - resolution: {integrity: sha512-a7tP5+0Mw3YlUJcGAKUqIBkYYGlYxk2fnCasq/FUph1hadxlTRjF+gAcZksxANnaMnALjxEddmSi/H3OR8ugcQ==} + resolution: + { + integrity: sha512-a7tP5+0Mw3YlUJcGAKUqIBkYYGlYxk2fnCasq/FUph1hadxlTRjF+gAcZksxANnaMnALjxEddmSi/H3OR8ugcQ==, + } bowser@2.11.0: - resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} + resolution: + { + integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==, + } brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + resolution: + { + integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==, + } brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + resolution: + { + integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==, + } braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==, + } + engines: { node: '>=8' } browserslist@4.24.4: - resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + resolution: + { + integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==, + } + engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 } hasBin: true bson-objectid@2.0.4: - resolution: {integrity: sha512-vgnKAUzcDoa+AeyYwXCoHyF2q6u/8H46dxu5JN+4/TZeq/Dlinn0K6GvxsCLb3LHUJl0m/TLiEK31kUwtgocMQ==} + resolution: + { + integrity: sha512-vgnKAUzcDoa+AeyYwXCoHyF2q6u/8H46dxu5JN+4/TZeq/Dlinn0K6GvxsCLb3LHUJl0m/TLiEK31kUwtgocMQ==, + } bson@6.10.3: - resolution: {integrity: sha512-MTxGsqgYTwfshYWTRdmZRC+M7FnG1b4y7RO7p2k3X24Wq0yv1m77Wsj0BzlPzd/IowgESfsruQCUToa7vbOpPQ==} - engines: {node: '>=16.20.1'} + resolution: + { + integrity: sha512-MTxGsqgYTwfshYWTRdmZRC+M7FnG1b4y7RO7p2k3X24Wq0yv1m77Wsj0BzlPzd/IowgESfsruQCUToa7vbOpPQ==, + } + engines: { node: '>=16.20.1' } buffer@4.9.2: - resolution: {integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==} + resolution: + { + integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==, + } buffer@5.6.0: - resolution: {integrity: sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==} + resolution: + { + integrity: sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==, + } buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + resolution: + { + integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==, + } busboy@1.6.0: - resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} - engines: {node: '>=10.16.0'} + resolution: + { + integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==, + } + engines: { node: '>=10.16.0' } call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==, + } + engines: { node: '>= 0.4' } call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==, + } + engines: { node: '>= 0.4' } call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==, + } + engines: { node: '>= 0.4' } callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==, + } + engines: { node: '>=6' } camelcase-css@2.0.1: - resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} - engines: {node: '>= 6'} + resolution: + { + integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==, + } + engines: { node: '>= 6' } caniuse-lite@1.0.30001706: - resolution: {integrity: sha512-3ZczoTApMAZwPKYWmwVbQMFpXBDds3/0VciVoUwPUbldlYyVLmRVuRs/PcUZtHpbLRpzzDvrvnFuREsGt6lUug==} + resolution: + { + integrity: sha512-3ZczoTApMAZwPKYWmwVbQMFpXBDds3/0VciVoUwPUbldlYyVLmRVuRs/PcUZtHpbLRpzzDvrvnFuREsGt6lUug==, + } ccount@2.0.1: - resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + resolution: + { + integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==, + } chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==, + } + engines: { node: '>=10' } character-entities-html4@2.1.0: - resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + resolution: + { + integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==, + } character-entities-legacy@3.0.0: - resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + resolution: + { + integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==, + } character-entities@2.0.2: - resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + resolution: + { + integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==, + } character-reference-invalid@2.0.1: - resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + resolution: + { + integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==, + } charenc@0.0.2: - resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} + resolution: + { + integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==, + } chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} + resolution: + { + integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==, + } + engines: { node: '>= 8.10.0' } chownr@1.1.4: - resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + resolution: + { + integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==, + } ci-info@4.2.0: - resolution: {integrity: sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==, + } + engines: { node: '>=8' } class-variance-authority@0.7.1: - resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + resolution: + { + integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==, + } classnames@2.5.1: - resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + resolution: + { + integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==, + } client-only@0.0.1: - resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + resolution: + { + integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==, + } cliui@7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + resolution: + { + integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==, + } clsx@2.1.1: - resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==, + } + engines: { node: '>=6' } color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} + resolution: + { + integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==, + } + engines: { node: '>=7.0.0' } color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + resolution: + { + integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, + } color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + resolution: + { + integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==, + } color@4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: '>=12.5.0'} + resolution: + { + integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==, + } + engines: { node: '>=12.5.0' } colorette@2.0.20: - resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + resolution: + { + integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==, + } commander@2.20.3: - resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + resolution: + { + integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==, + } commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} + resolution: + { + integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==, + } + engines: { node: '>= 6' } concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + resolution: + { + integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==, + } console-table-printer@2.12.1: - resolution: {integrity: sha512-wKGOQRRvdnd89pCeH96e2Fn4wkbenSP6LMHfjfyNLMbGuHEFbMqQNuxXqd0oXG9caIOQ1FTvc5Uijp9/4jujnQ==} + resolution: + { + integrity: sha512-wKGOQRRvdnd89pCeH96e2Fn4wkbenSP6LMHfjfyNLMbGuHEFbMqQNuxXqd0oXG9caIOQ1FTvc5Uijp9/4jujnQ==, + } convert-source-map@1.9.0: - resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + resolution: + { + integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==, + } copyfiles@2.4.1: - resolution: {integrity: sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==} + resolution: + { + integrity: sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==, + } hasBin: true core-util-is@1.0.3: - resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + resolution: + { + integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==, + } cosmiconfig@7.1.0: - resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==, + } + engines: { node: '>=10' } croner@9.0.0: - resolution: {integrity: sha512-onMB0OkDjkXunhdW9htFjEhqrD54+M94i6ackoUkjHKbRnXdyEyKRelp4nJ1kAz32+s27jP1FsebpJCVl0BsvA==} - engines: {node: '>=18.0'} + resolution: + { + integrity: sha512-onMB0OkDjkXunhdW9htFjEhqrD54+M94i6ackoUkjHKbRnXdyEyKRelp4nJ1kAz32+s27jP1FsebpJCVl0BsvA==, + } + engines: { node: '>=18.0' } cross-env@7.0.3: - resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} - engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} + resolution: + { + integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==, + } + engines: { node: '>=10.14', npm: '>=6', yarn: '>=1' } hasBin: true cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==, + } + engines: { node: '>= 8' } crypt@0.0.2: - resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} + resolution: + { + integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==, + } cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==, + } + engines: { node: '>=4' } hasBin: true cssfilter@0.0.10: - resolution: {integrity: sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==} + resolution: + { + integrity: sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==, + } csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + resolution: + { + integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==, + } damerau-levenshtein@1.0.8: - resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + resolution: + { + integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==, + } data-view-buffer@1.0.2: - resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==, + } + engines: { node: '>= 0.4' } data-view-byte-length@1.0.2: - resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==, + } + engines: { node: '>= 0.4' } data-view-byte-offset@1.0.1: - resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==, + } + engines: { node: '>= 0.4' } dataloader@2.2.3: - resolution: {integrity: sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==} + resolution: + { + integrity: sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==, + } date-fns@3.6.0: - resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==} + resolution: + { + integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==, + } date-fns@4.1.0: - resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + resolution: + { + integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==, + } dateformat@4.6.3: - resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} + resolution: + { + integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==, + } debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + resolution: + { + integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==, + } peerDependencies: supports-color: '*' peerDependenciesMeta: @@ -2176,8 +3500,11 @@ packages: optional: true debug@4.4.0: - resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} - engines: {node: '>=6.0'} + resolution: + { + integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==, + } + engines: { node: '>=6.0' } peerDependencies: supports-color: '*' peerDependenciesMeta: @@ -2185,134 +3512,242 @@ packages: optional: true decode-named-character-reference@1.1.0: - resolution: {integrity: sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==} + resolution: + { + integrity: sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==, + } decompress-response@6.0.0: - resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==, + } + engines: { node: '>=10' } deep-extend@0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.0'} + resolution: + { + integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==, + } + engines: { node: '>=4.0.0' } deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + resolution: + { + integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==, + } deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==, + } + engines: { node: '>=0.10.0' } define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==, + } + engines: { node: '>= 0.4' } define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==, + } + engines: { node: '>= 0.4' } dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==, + } + engines: { node: '>=6' } detect-libc@2.0.3: - resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==, + } + engines: { node: '>=8' } detect-node-es@1.1.0: - resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + resolution: + { + integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==, + } devlop@1.1.0: - resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + resolution: + { + integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==, + } didyoumean@1.2.2: - resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + resolution: + { + integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==, + } diff@5.2.0: - resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} - engines: {node: '>=0.3.1'} + resolution: + { + integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==, + } + engines: { node: '>=0.3.1' } dlv@1.1.3: - resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + resolution: + { + integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==, + } doctrine@2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==, + } + engines: { node: '>=0.10.0' } dom-helpers@5.2.1: - resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + resolution: + { + integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==, + } dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==, + } + engines: { node: '>= 0.4' } eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + resolution: + { + integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==, + } electron-to-chromium@1.5.123: - resolution: {integrity: sha512-refir3NlutEZqlKaBLK0tzlVLe5P2wDKS7UQt/3SpibizgsRAPOsqQC3ffw1nlv3ze5gjRQZYHoPymgVZkplFA==} + resolution: + { + integrity: sha512-refir3NlutEZqlKaBLK0tzlVLe5P2wDKS7UQt/3SpibizgsRAPOsqQC3ffw1nlv3ze5gjRQZYHoPymgVZkplFA==, + } emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + resolution: + { + integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==, + } emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + resolution: + { + integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==, + } end-of-stream@1.4.4: - resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + resolution: + { + integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==, + } error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + resolution: + { + integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==, + } es-abstract@1.23.9: - resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==, + } + engines: { node: '>= 0.4' } es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==, + } + engines: { node: '>= 0.4' } es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==, + } + engines: { node: '>= 0.4' } es-iterator-helpers@1.2.1: - resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==, + } + engines: { node: '>= 0.4' } es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==, + } + engines: { node: '>= 0.4' } es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==, + } + engines: { node: '>= 0.4' } es-shim-unscopables@1.1.0: - resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==, + } + engines: { node: '>= 0.4' } es-to-primitive@1.3.0: - resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==, + } + engines: { node: '>= 0.4' } esbuild@0.23.1: - resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==, + } + engines: { node: '>=18' } hasBin: true escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==, + } + engines: { node: '>=6' } escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + resolution: + { + integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==, + } escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==, + } + engines: { node: '>=10' } eslint-config-next@15.2.3: - resolution: {integrity: sha512-VDQwbajhNMFmrhLWVyUXCqsGPN+zz5G8Ys/QwFubfsxTIrkqdx3N3x3QPW+pERz8bzGPP0IgEm8cNbZcd8PFRQ==} + resolution: + { + integrity: sha512-VDQwbajhNMFmrhLWVyUXCqsGPN+zz5G8Ys/QwFubfsxTIrkqdx3N3x3QPW+pERz8bzGPP0IgEm8cNbZcd8PFRQ==, + } peerDependencies: eslint: ^7.23.0 || ^8.0.0 || ^9.0.0 typescript: '>=3.3.1' @@ -2321,11 +3756,17 @@ packages: optional: true eslint-import-resolver-node@0.3.9: - resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + resolution: + { + integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==, + } eslint-import-resolver-typescript@3.9.1: - resolution: {integrity: sha512-euxa5rTGqHeqVxmOHT25hpk58PxkQ4mNoX6Yun4ooGaCHAxOCojJYNvjmyeOQxj/LyW+3fulH0+xtk+p2kPPTw==} - engines: {node: ^14.18.0 || >=16.0.0} + resolution: + { + integrity: sha512-euxa5rTGqHeqVxmOHT25hpk58PxkQ4mNoX6Yun4ooGaCHAxOCojJYNvjmyeOQxj/LyW+3fulH0+xtk+p2kPPTw==, + } + engines: { node: ^14.18.0 || >=16.0.0 } peerDependencies: eslint: '*' eslint-plugin-import: '*' @@ -2337,8 +3778,11 @@ packages: optional: true eslint-module-utils@2.12.0: - resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==, + } + engines: { node: '>=4' } peerDependencies: '@typescript-eslint/parser': '*' eslint: '*' @@ -2358,8 +3802,11 @@ packages: optional: true eslint-plugin-import@2.31.0: - resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==, + } + engines: { node: '>=4' } peerDependencies: '@typescript-eslint/parser': '*' eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 @@ -2368,38 +3815,59 @@ packages: optional: true eslint-plugin-jsx-a11y@6.10.2: - resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} - engines: {node: '>=4.0'} + resolution: + { + integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==, + } + engines: { node: '>=4.0' } peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 eslint-plugin-react-hooks@5.2.0: - resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==, + } + engines: { node: '>=10' } peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 eslint-plugin-react@7.37.4: - resolution: {integrity: sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ==, + } + engines: { node: '>=4' } peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 eslint-scope@8.3.0: - resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + resolution: + { + integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } eslint-visitor-keys@4.2.0: - resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } eslint@9.23.0: - resolution: {integrity: sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } hasBin: true peerDependencies: jiti: '*' @@ -2408,84 +3876,153 @@ packages: optional: true espree@10.3.0: - resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + resolution: + { + integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} - engines: {node: '>=0.10'} + resolution: + { + integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==, + } + engines: { node: '>=0.10' } esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} + resolution: + { + integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==, + } + engines: { node: '>=4.0' } estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} + resolution: + { + integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==, + } + engines: { node: '>=4.0' } estree-util-is-identifier-name@3.0.0: - resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + resolution: + { + integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==, + } estree-util-visit@2.0.0: - resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} + resolution: + { + integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==, + } esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==, + } + engines: { node: '>=0.10.0' } events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} + resolution: + { + integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==, + } + engines: { node: '>=0.8.x' } expand-template@2.0.3: - resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==, + } + engines: { node: '>=6' } fast-base64-decode@1.0.0: - resolution: {integrity: sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==} + resolution: + { + integrity: sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==, + } fast-copy@3.0.2: - resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==} + resolution: + { + integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==, + } fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + resolution: + { + integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, + } fast-fifo@1.3.2: - resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + resolution: + { + integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==, + } fast-glob@3.3.1: - resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} - engines: {node: '>=8.6.0'} + resolution: + { + integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==, + } + engines: { node: '>=8.6.0' } fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} + resolution: + { + integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==, + } + engines: { node: '>=8.6.0' } fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + resolution: + { + integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==, + } fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + resolution: + { + integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==, + } fast-redact@3.5.0: - resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==, + } + engines: { node: '>=6' } fast-safe-stringify@2.1.1: - resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + resolution: + { + integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==, + } fast-uri@3.0.6: - resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} + resolution: + { + integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==, + } fast-xml-parser@4.4.1: - resolution: {integrity: sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==} + resolution: + { + integrity: sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==, + } hasBin: true fastq@1.19.1: - resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + resolution: + { + integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==, + } fdir@6.4.3: - resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==} + resolution: + { + integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==, + } peerDependencies: picomatch: ^3 || ^4 peerDependenciesMeta: @@ -2493,650 +4030,1193 @@ packages: optional: true file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} + resolution: + { + integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==, + } + engines: { node: '>=16.0.0' } file-type@19.3.0: - resolution: {integrity: sha512-mROwiKLZf/Kwa/2Rol+OOZQn1eyTkPB3ZTwC0ExY6OLFCbgxHYZvBm7xI77NvfZFMKBsmuXfmLJnD4eEftEhrA==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-mROwiKLZf/Kwa/2Rol+OOZQn1eyTkPB3ZTwC0ExY6OLFCbgxHYZvBm7xI77NvfZFMKBsmuXfmLJnD4eEftEhrA==, + } + engines: { node: '>=18' } fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==, + } + engines: { node: '>=8' } find-root@1.1.0: - resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} + resolution: + { + integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==, + } find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==, + } + engines: { node: '>=10' } flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} + resolution: + { + integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==, + } + engines: { node: '>=16' } flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + resolution: + { + integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==, + } focus-trap@7.5.4: - resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==} + resolution: + { + integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==, + } for-each@0.3.5: - resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==, + } + engines: { node: '>= 0.4' } foreground-child@3.3.1: - resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} - engines: {node: '>=14'} + resolution: + { + integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==, + } + engines: { node: '>=14' } fraction.js@4.3.7: - resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + resolution: + { + integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==, + } fs-constants@1.0.0: - resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + resolution: + { + integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==, + } fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + resolution: + { + integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==, + } fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + resolution: + { + integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, + } + engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } os: [darwin] function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + resolution: + { + integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==, + } function.prototype.name@1.1.8: - resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==, + } + engines: { node: '>= 0.4' } functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + resolution: + { + integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==, + } geist@1.3.1: - resolution: {integrity: sha512-Q4gC1pBVPN+D579pBaz0TRRnGA4p9UK6elDY/xizXdFk/g4EKR5g0I+4p/Kj6gM0SajDBZ/0FvDV9ey9ud7BWw==} + resolution: + { + integrity: sha512-Q4gC1pBVPN+D579pBaz0TRRnGA4p9UK6elDY/xizXdFk/g4EKR5g0I+4p/Kj6gM0SajDBZ/0FvDV9ey9ud7BWw==, + } peerDependencies: next: '>=13.2.0' get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} + resolution: + { + integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==, + } + engines: { node: 6.* || 8.* || >= 10.* } get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==, + } + engines: { node: '>= 0.4' } get-nonce@1.0.1: - resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==, + } + engines: { node: '>=6' } get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==, + } + engines: { node: '>= 0.4' } get-symbol-description@1.1.0: - resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==, + } + engines: { node: '>= 0.4' } get-tsconfig@4.10.0: - resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==} + resolution: + { + integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==, + } get-tsconfig@4.8.1: - resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} + resolution: + { + integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==, + } github-from-package@0.0.0: - resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + resolution: + { + integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==, + } glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} + resolution: + { + integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==, + } + engines: { node: '>= 6' } glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} + resolution: + { + integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==, + } + engines: { node: '>=10.13.0' } glob@10.4.5: - resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + resolution: + { + integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==, + } hasBin: true glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + resolution: + { + integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==, + } deprecated: Glob versions prior to v9 are no longer supported globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==, + } + engines: { node: '>=4' } globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==, + } + engines: { node: '>=18' } globalthis@1.0.4: - resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==, + } + engines: { node: '>= 0.4' } gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==, + } + engines: { node: '>= 0.4' } graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + resolution: + { + integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==, + } graphql-http@1.22.4: - resolution: {integrity: sha512-OC3ucK988teMf+Ak/O+ZJ0N2ukcgrEurypp8ePyJFWq83VzwRAmHxxr+XxrMpxO/FIwI4a7m/Fzv3tWGJv0wPA==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-OC3ucK988teMf+Ak/O+ZJ0N2ukcgrEurypp8ePyJFWq83VzwRAmHxxr+XxrMpxO/FIwI4a7m/Fzv3tWGJv0wPA==, + } + engines: { node: '>=12' } peerDependencies: graphql: '>=0.11 <=16' graphql-playground-html@1.6.30: - resolution: {integrity: sha512-tpCujhsJMva4aqE8ULnF7/l3xw4sNRZcSHu+R00VV+W0mfp+Q20Plvcrp+5UXD+2yS6oyCXncA+zoQJQqhGCEw==} + resolution: + { + integrity: sha512-tpCujhsJMva4aqE8ULnF7/l3xw4sNRZcSHu+R00VV+W0mfp+Q20Plvcrp+5UXD+2yS6oyCXncA+zoQJQqhGCEw==, + } graphql-scalars@1.22.2: - resolution: {integrity: sha512-my9FB4GtghqXqi/lWSVAOPiTzTnnEzdOXCsAC2bb5V7EFNQjVjwy3cSSbUvgYOtDuDibd+ZsCDhz+4eykYOlhQ==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-my9FB4GtghqXqi/lWSVAOPiTzTnnEzdOXCsAC2bb5V7EFNQjVjwy3cSSbUvgYOtDuDibd+ZsCDhz+4eykYOlhQ==, + } + engines: { node: '>=10' } peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 graphql@16.10.0: - resolution: {integrity: sha512-AjqGKbDGUFRKIRCP9tCKiIGHyriz2oHEbPIbEtcSLSs4YjReZOIPQQWek4+6hjw62H9QShXHyaGivGiYVLeYFQ==} - engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + resolution: + { + integrity: sha512-AjqGKbDGUFRKIRCP9tCKiIGHyriz2oHEbPIbEtcSLSs4YjReZOIPQQWek4+6hjw62H9QShXHyaGivGiYVLeYFQ==, + } + engines: { node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0 } has-bigints@1.1.0: - resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==, + } + engines: { node: '>= 0.4' } has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==, + } + engines: { node: '>=8' } has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + resolution: + { + integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==, + } has-proto@1.2.0: - resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==, + } + engines: { node: '>= 0.4' } has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==, + } + engines: { node: '>= 0.4' } has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==, + } + engines: { node: '>= 0.4' } hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==, + } + engines: { node: '>= 0.4' } help-me@5.0.0: - resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} + resolution: + { + integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==, + } hoist-non-react-statics@3.3.2: - resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + resolution: + { + integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==, + } http-status@2.1.0: - resolution: {integrity: sha512-O5kPr7AW7wYd/BBiOezTwnVAnmSNFY+J7hlZD2X5IOxVBetjcHAiTXhzj0gMrnojQlwy+UT1/Y3H3vJ3UlmvLA==} - engines: {node: '>= 0.4.0'} + resolution: + { + integrity: sha512-O5kPr7AW7wYd/BBiOezTwnVAnmSNFY+J7hlZD2X5IOxVBetjcHAiTXhzj0gMrnojQlwy+UT1/Y3H3vJ3UlmvLA==, + } + engines: { node: '>= 0.4.0' } ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + resolution: + { + integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==, + } ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} + resolution: + { + integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==, + } + engines: { node: '>= 4' } image-size@1.2.0: - resolution: {integrity: sha512-4S8fwbO6w3GeCVN6OPtA9I5IGKkcDMPcKndtUlpJuCwu7JLjtj7JZpwqLuyY2nrmQT3AWsCJLSKPsc2mPBSl3w==} - engines: {node: '>=16.x'} + resolution: + { + integrity: sha512-4S8fwbO6w3GeCVN6OPtA9I5IGKkcDMPcKndtUlpJuCwu7JLjtj7JZpwqLuyY2nrmQT3AWsCJLSKPsc2mPBSl3w==, + } + engines: { node: '>=16.x' } hasBin: true immutable@4.3.7: - resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} + resolution: + { + integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==, + } import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==, + } + engines: { node: '>=6' } imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} + resolution: + { + integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==, + } + engines: { node: '>=0.8.19' } inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + resolution: + { + integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==, + } deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + resolution: + { + integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==, + } ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + resolution: + { + integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==, + } internal-slot@1.1.0: - resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==, + } + engines: { node: '>= 0.4' } is-alphabetical@2.0.1: - resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + resolution: + { + integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==, + } is-alphanumerical@2.0.1: - resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + resolution: + { + integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==, + } is-array-buffer@3.0.5: - resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==, + } + engines: { node: '>= 0.4' } is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + resolution: + { + integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==, + } is-arrayish@0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} + resolution: + { + integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==, + } is-async-function@2.1.1: - resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==, + } + engines: { node: '>= 0.4' } is-bigint@1.1.0: - resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==, + } + engines: { node: '>= 0.4' } is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==, + } + engines: { node: '>=8' } is-boolean-object@1.2.2: - resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==, + } + engines: { node: '>= 0.4' } is-buffer@1.1.6: - resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + resolution: + { + integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==, + } is-bun-module@1.3.0: - resolution: {integrity: sha512-DgXeu5UWI0IsMQundYb5UAOzm6G2eVnarJ0byP6Tm55iZNKceD59LNPA2L4VvsScTtHcw0yEkVwSf7PC+QoLSA==} + resolution: + { + integrity: sha512-DgXeu5UWI0IsMQundYb5UAOzm6G2eVnarJ0byP6Tm55iZNKceD59LNPA2L4VvsScTtHcw0yEkVwSf7PC+QoLSA==, + } is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==, + } + engines: { node: '>= 0.4' } is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==, + } + engines: { node: '>= 0.4' } is-data-view@1.0.2: - resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==, + } + engines: { node: '>= 0.4' } is-date-object@1.1.0: - resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==, + } + engines: { node: '>= 0.4' } is-decimal@2.0.1: - resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + resolution: + { + integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==, + } is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, + } + engines: { node: '>=0.10.0' } is-finalizationregistry@1.1.1: - resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==, + } + engines: { node: '>= 0.4' } is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==, + } + engines: { node: '>=8' } is-generator-function@1.1.0: - resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==, + } + engines: { node: '>= 0.4' } is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==, + } + engines: { node: '>=0.10.0' } is-hexadecimal@2.0.1: - resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + resolution: + { + integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==, + } is-map@2.0.3: - resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==, + } + engines: { node: '>= 0.4' } is-number-object@1.1.1: - resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==, + } + engines: { node: '>= 0.4' } is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} + resolution: + { + integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==, + } + engines: { node: '>=0.12.0' } is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==, + } + engines: { node: '>= 0.4' } is-set@2.0.3: - resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==, + } + engines: { node: '>= 0.4' } is-shared-array-buffer@1.0.4: - resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==, + } + engines: { node: '>= 0.4' } is-string@1.1.1: - resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==, + } + engines: { node: '>= 0.4' } is-symbol@1.1.1: - resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==, + } + engines: { node: '>= 0.4' } is-typed-array@1.1.15: - resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==, + } + engines: { node: '>= 0.4' } is-weakmap@2.0.2: - resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==, + } + engines: { node: '>= 0.4' } is-weakref@1.1.1: - resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==, + } + engines: { node: '>= 0.4' } is-weakset@2.0.4: - resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==, + } + engines: { node: '>= 0.4' } isarray@0.0.1: - resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} + resolution: + { + integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==, + } isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + resolution: + { + integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==, + } isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + resolution: + { + integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==, + } isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + resolution: + { + integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, + } isomorphic-unfetch@3.1.0: - resolution: {integrity: sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==} + resolution: + { + integrity: sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==, + } isomorphic.js@0.2.5: - resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} + resolution: + { + integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==, + } iterator.prototype@1.1.5: - resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==, + } + engines: { node: '>= 0.4' } jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + resolution: + { + integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==, + } jiti@1.21.7: - resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} + resolution: + { + integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==, + } hasBin: true jose@5.9.6: - resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==} + resolution: + { + integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==, + } joycon@3.1.1: - resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==, + } + engines: { node: '>=10' } js-cookie@2.2.1: - resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==} + resolution: + { + integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==, + } js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + resolution: + { + integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, + } js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + resolution: + { + integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==, + } hasBin: true jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==, + } + engines: { node: '>=6' } hasBin: true json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + resolution: + { + integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==, + } json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + resolution: + { + integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==, + } json-schema-to-typescript@15.0.3: - resolution: {integrity: sha512-iOKdzTUWEVM4nlxpFudFsWyUiu/Jakkga4OZPEt7CGoSEsAsUgdOZqR6pcgx2STBek9Gm4hcarJpXSzIvZ/hKA==} - engines: {node: '>=16.0.0'} + resolution: + { + integrity: sha512-iOKdzTUWEVM4nlxpFudFsWyUiu/Jakkga4OZPEt7CGoSEsAsUgdOZqR6pcgx2STBek9Gm4hcarJpXSzIvZ/hKA==, + } + engines: { node: '>=16.0.0' } hasBin: true json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + resolution: + { + integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==, + } json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + resolution: + { + integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==, + } json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + resolution: + { + integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==, + } json5@1.0.2: - resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + resolution: + { + integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==, + } hasBin: true jsox@1.2.121: - resolution: {integrity: sha512-9Ag50tKhpTwS6r5wh3MJSAvpSof0UBr39Pto8OnzFT32Z/pAbxAsKHzyvsyMEHVslELvHyO/4/jaQELHk8wDcw==} + resolution: + { + integrity: sha512-9Ag50tKhpTwS6r5wh3MJSAvpSof0UBr39Pto8OnzFT32Z/pAbxAsKHzyvsyMEHVslELvHyO/4/jaQELHk8wDcw==, + } hasBin: true jsx-ast-utils@3.3.5: - resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} - engines: {node: '>=4.0'} + resolution: + { + integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==, + } + engines: { node: '>=4.0' } kareem@2.6.3: - resolution: {integrity: sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==} - engines: {node: '>=12.0.0'} + resolution: + { + integrity: sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==, + } + engines: { node: '>=12.0.0' } keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + resolution: + { + integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==, + } kleur@3.0.3: - resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==, + } + engines: { node: '>=6' } language-subtag-registry@0.3.23: - resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} + resolution: + { + integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==, + } language-tags@1.0.9: - resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} - engines: {node: '>=0.10'} + resolution: + { + integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==, + } + engines: { node: '>=0.10' } levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} + resolution: + { + integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==, + } + engines: { node: '>= 0.8.0' } lexical@0.28.0: - resolution: {integrity: sha512-dLE3O1PZg0TlZxRQo9YDpjCjDUj8zluGyBO9MHdjo21qZmMUNrxQPeCRt8fn2s5l4HKYFQ1YNgl7k1pOJB/vZQ==} + resolution: + { + integrity: sha512-dLE3O1PZg0TlZxRQo9YDpjCjDUj8zluGyBO9MHdjo21qZmMUNrxQPeCRt8fn2s5l4HKYFQ1YNgl7k1pOJB/vZQ==, + } lib0@0.2.100: - resolution: {integrity: sha512-ACQmtZ8cRD7/SpBEzBP88KrgrjOnhfcOANhhk8ASv+HFEvBSHOprxur3vuhmNw4YLq29y4Yen4jU0jHpIqVYWw==} - engines: {node: '>=16'} + resolution: + { + integrity: sha512-ACQmtZ8cRD7/SpBEzBP88KrgrjOnhfcOANhhk8ASv+HFEvBSHOprxur3vuhmNw4YLq29y4Yen4jU0jHpIqVYWw==, + } + engines: { node: '>=16' } hasBin: true lilconfig@3.1.3: - resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} - engines: {node: '>=14'} + resolution: + { + integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==, + } + engines: { node: '>=14' } lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + resolution: + { + integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==, + } locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==, + } + engines: { node: '>=10' } lodash.castarray@4.4.0: - resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==} + resolution: + { + integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==, + } lodash.isplainobject@4.0.6: - resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + resolution: + { + integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==, + } lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + resolution: + { + integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==, + } lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + resolution: + { + integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==, + } longest-streak@3.1.0: - resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + resolution: + { + integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==, + } loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + resolution: + { + integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==, + } hasBin: true lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + resolution: + { + integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==, + } lucide-react@0.378.0: - resolution: {integrity: sha512-u6EPU8juLUk9ytRcyapkWI18epAv3RU+6+TC23ivjR0e+glWKBobFeSgRwOIJihzktILQuy6E0E80P2jVTDR5g==} + resolution: + { + integrity: sha512-u6EPU8juLUk9ytRcyapkWI18epAv3RU+6+TC23ivjR0e+glWKBobFeSgRwOIJihzktILQuy6E0E80P2jVTDR5g==, + } peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==, + } + engines: { node: '>= 0.4' } md5@2.3.0: - resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} + resolution: + { + integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==, + } mdast-util-from-markdown@2.0.2: - resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + resolution: + { + integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==, + } mdast-util-mdx-jsx@3.1.3: - resolution: {integrity: sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==} + resolution: + { + integrity: sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==, + } mdast-util-phrasing@4.1.0: - resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + resolution: + { + integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==, + } mdast-util-to-markdown@2.1.2: - resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + resolution: + { + integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==, + } mdast-util-to-string@4.0.0: - resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + resolution: + { + integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==, + } memoize-one@6.0.0: - resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} + resolution: + { + integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==, + } memory-pager@1.5.0: - resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==} + resolution: + { + integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==, + } merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==, + } + engines: { node: '>= 8' } micromark-core-commonmark@2.0.3: - resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + resolution: + { + integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==, + } micromark-extension-mdx-jsx@3.0.1: - resolution: {integrity: sha512-vNuFb9czP8QCtAQcEJn0UJQJZA8Dk6DXKBqx+bg/w0WGuSxDxNr7hErW89tHUY31dUW4NqEOWwmEUNhjTFmHkg==} + resolution: + { + integrity: sha512-vNuFb9czP8QCtAQcEJn0UJQJZA8Dk6DXKBqx+bg/w0WGuSxDxNr7hErW89tHUY31dUW4NqEOWwmEUNhjTFmHkg==, + } micromark-factory-destination@2.0.1: - resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + resolution: + { + integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==, + } micromark-factory-label@2.0.1: - resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + resolution: + { + integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==, + } micromark-factory-mdx-expression@2.0.2: - resolution: {integrity: sha512-5E5I2pFzJyg2CtemqAbcyCktpHXuJbABnsb32wX2U8IQKhhVFBqkcZR5LRm1WVoFqa4kTueZK4abep7wdo9nrw==} + resolution: + { + integrity: sha512-5E5I2pFzJyg2CtemqAbcyCktpHXuJbABnsb32wX2U8IQKhhVFBqkcZR5LRm1WVoFqa4kTueZK4abep7wdo9nrw==, + } micromark-factory-space@2.0.1: - resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + resolution: + { + integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==, + } micromark-factory-title@2.0.1: - resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + resolution: + { + integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==, + } micromark-factory-whitespace@2.0.1: - resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + resolution: + { + integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==, + } micromark-util-character@2.1.1: - resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + resolution: + { + integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==, + } micromark-util-chunked@2.0.1: - resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + resolution: + { + integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==, + } micromark-util-classify-character@2.0.1: - resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + resolution: + { + integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==, + } micromark-util-combine-extensions@2.0.1: - resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + resolution: + { + integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==, + } micromark-util-decode-numeric-character-reference@2.0.2: - resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + resolution: + { + integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==, + } micromark-util-decode-string@2.0.1: - resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + resolution: + { + integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==, + } micromark-util-encode@2.0.1: - resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + resolution: + { + integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==, + } micromark-util-events-to-acorn@2.0.2: - resolution: {integrity: sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==} + resolution: + { + integrity: sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==, + } micromark-util-html-tag-name@2.0.1: - resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + resolution: + { + integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==, + } micromark-util-normalize-identifier@2.0.1: - resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + resolution: + { + integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==, + } micromark-util-resolve-all@2.0.1: - resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + resolution: + { + integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==, + } micromark-util-sanitize-uri@2.0.1: - resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + resolution: + { + integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==, + } micromark-util-subtokenize@2.1.0: - resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + resolution: + { + integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==, + } micromark-util-symbol@2.0.1: - resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + resolution: + { + integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==, + } micromark-util-types@2.0.2: - resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + resolution: + { + integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==, + } micromark@4.0.2: - resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + resolution: + { + integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==, + } micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} + resolution: + { + integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==, + } + engines: { node: '>=8.6' } mimic-response@3.1.0: - resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==, + } + engines: { node: '>=10' } minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + resolution: + { + integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==, + } minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} + resolution: + { + integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==, + } + engines: { node: '>=16 || 14 >=14.17' } minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + resolution: + { + integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==, + } minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} - engines: {node: '>=16 || 14 >=14.17'} + resolution: + { + integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==, + } + engines: { node: '>=16 || 14 >=14.17' } mkdirp-classic@0.5.3: - resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + resolution: + { + integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==, + } mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==, + } + engines: { node: '>=10' } hasBin: true monaco-editor@0.52.2: - resolution: {integrity: sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==} + resolution: + { + integrity: sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==, + } mongodb-connection-string-url@3.0.2: - resolution: {integrity: sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==} + resolution: + { + integrity: sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==, + } mongodb@6.12.0: - resolution: {integrity: sha512-RM7AHlvYfS7jv7+BXund/kR64DryVI+cHbVAy9P61fnb1RcWZqOW1/Wj2YhqMCx+MuYhqTRGv7AwHBzmsCKBfA==} - engines: {node: '>=16.20.1'} + resolution: + { + integrity: sha512-RM7AHlvYfS7jv7+BXund/kR64DryVI+cHbVAy9P61fnb1RcWZqOW1/Wj2YhqMCx+MuYhqTRGv7AwHBzmsCKBfA==, + } + engines: { node: '>=16.20.1' } peerDependencies: '@aws-sdk/credential-providers': ^3.188.0 '@mongodb-js/zstd': ^1.1.0 || ^2.0.0 @@ -3162,48 +5242,81 @@ packages: optional: true mongoose-paginate-v2@1.8.5: - resolution: {integrity: sha512-kFxhot+yw9KmpAGSSrF/o+f00aC2uawgNUbhyaM0USS9L7dln1NA77/pLg4lgOaRgXMtfgCENamjqZwIM1Zrig==} - engines: {node: '>=4.0.0'} + resolution: + { + integrity: sha512-kFxhot+yw9KmpAGSSrF/o+f00aC2uawgNUbhyaM0USS9L7dln1NA77/pLg4lgOaRgXMtfgCENamjqZwIM1Zrig==, + } + engines: { node: '>=4.0.0' } mongoose@8.9.5: - resolution: {integrity: sha512-SPhOrgBm0nKV3b+IIHGqpUTOmgVL5Z3OO9AwkFEmvOZznXTvplbomstCnPOGAyungtRXE5pJTgKpKcZTdjeESg==} - engines: {node: '>=16.20.1'} + resolution: + { + integrity: sha512-SPhOrgBm0nKV3b+IIHGqpUTOmgVL5Z3OO9AwkFEmvOZznXTvplbomstCnPOGAyungtRXE5pJTgKpKcZTdjeESg==, + } + engines: { node: '>=16.20.1' } mpath@0.9.0: - resolution: {integrity: sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==} - engines: {node: '>=4.0.0'} + resolution: + { + integrity: sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==, + } + engines: { node: '>=4.0.0' } mquery@5.0.0: - resolution: {integrity: sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==} - engines: {node: '>=14.0.0'} + resolution: + { + integrity: sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==, + } + engines: { node: '>=14.0.0' } ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + resolution: + { + integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, + } mz@2.7.0: - resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + resolution: + { + integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==, + } nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + resolution: + { + integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==, + } + engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 } hasBin: true napi-build-utils@2.0.0: - resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + resolution: + { + integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==, + } natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + resolution: + { + integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==, + } next-sitemap@4.2.3: - resolution: {integrity: sha512-vjdCxeDuWDzldhCnyFCQipw5bfpl4HmZA7uoo3GAaYGjGgfL4Cxb1CiztPuWGmS+auYs7/8OekRS8C2cjdAsjQ==} - engines: {node: '>=14.18'} + resolution: + { + integrity: sha512-vjdCxeDuWDzldhCnyFCQipw5bfpl4HmZA7uoo3GAaYGjGgfL4Cxb1CiztPuWGmS+auYs7/8OekRS8C2cjdAsjQ==, + } + engines: { node: '>=14.18' } hasBin: true peerDependencies: next: '*' next@15.2.3: - resolution: {integrity: sha512-x6eDkZxk2rPpu46E1ZVUWIBhYCLszmUY6fvHBFcbzJ9dD+qRX6vcHusaqqDlnY+VngKzKbAiG2iRCkPbmi8f7w==} - engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + resolution: + { + integrity: sha512-x6eDkZxk2rPpu46E1ZVUWIBhYCLszmUY6fvHBFcbzJ9dD+qRX6vcHusaqqDlnY+VngKzKbAiG2iRCkPbmi8f7w==, + } + engines: { node: ^18.18.0 || ^19.8.0 || >= 20.0.0 } hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -3223,15 +5336,24 @@ packages: optional: true node-abi@3.74.0: - resolution: {integrity: sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==, + } + engines: { node: '>=10' } node-addon-api@6.1.0: - resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} + resolution: + { + integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==, + } node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} + resolution: + { + integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==, + } + engines: { node: 4.x || >=6.0.0 } peerDependencies: encoding: ^0.1.0 peerDependenciesMeta: @@ -3239,192 +5361,336 @@ packages: optional: true node-releases@2.0.19: - resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + resolution: + { + integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==, + } nodemailer@6.9.16: - resolution: {integrity: sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==} - engines: {node: '>=6.0.0'} + resolution: + { + integrity: sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==, + } + engines: { node: '>=6.0.0' } noms@0.0.0: - resolution: {integrity: sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==} + resolution: + { + integrity: sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==, + } normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==, + } + engines: { node: '>=0.10.0' } normalize-range@0.1.2: - resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==, + } + engines: { node: '>=0.10.0' } object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==, + } + engines: { node: '>=0.10.0' } object-hash@3.0.0: - resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} - engines: {node: '>= 6'} + resolution: + { + integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==, + } + engines: { node: '>= 6' } object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==, + } + engines: { node: '>= 0.4' } object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==, + } + engines: { node: '>= 0.4' } object-to-formdata@4.5.1: - resolution: {integrity: sha512-QiM9D0NiU5jV6J6tjE1g7b4Z2tcUnKs1OPUi4iMb2zH+7jwlcUrASghgkFk9GtzqNNq8rTQJtT8AzjBAvLoNMw==} + resolution: + { + integrity: sha512-QiM9D0NiU5jV6J6tjE1g7b4Z2tcUnKs1OPUi4iMb2zH+7jwlcUrASghgkFk9GtzqNNq8rTQJtT8AzjBAvLoNMw==, + } object.assign@4.1.7: - resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==, + } + engines: { node: '>= 0.4' } object.entries@1.1.9: - resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==, + } + engines: { node: '>= 0.4' } object.fromentries@2.0.8: - resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==, + } + engines: { node: '>= 0.4' } object.groupby@1.0.3: - resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==, + } + engines: { node: '>= 0.4' } object.values@1.2.1: - resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==, + } + engines: { node: '>= 0.4' } on-exit-leak-free@2.1.2: - resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} - engines: {node: '>=14.0.0'} + resolution: + { + integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==, + } + engines: { node: '>=14.0.0' } once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + resolution: + { + integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==, + } optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} + resolution: + { + integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==, + } + engines: { node: '>= 0.8.0' } own-keys@1.0.1: - resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==, + } + engines: { node: '>= 0.4' } p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==, + } + engines: { node: '>=10' } p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==, + } + engines: { node: '>=10' } package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + resolution: + { + integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==, + } parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==, + } + engines: { node: '>=6' } parse-entities@4.0.2: - resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + resolution: + { + integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==, + } parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==, + } + engines: { node: '>=8' } path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==, + } + engines: { node: '>=8' } path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==, + } + engines: { node: '>=0.10.0' } path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==, + } + engines: { node: '>=8' } path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + resolution: + { + integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==, + } path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} + resolution: + { + integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==, + } + engines: { node: '>=16 || 14 >=14.18' } path-to-regexp@6.3.0: - resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + resolution: + { + integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==, + } path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==, + } + engines: { node: '>=8' } - payload@3.29.0: - resolution: {integrity: sha512-Y/QPIMEagxo2tbfZs8Z7Nn4Uq2m+JziGMtwYpGr0ACzj625xdOy6FE4tR5lJ1ekTfEo+k1gzTHmCiMJ22sZgUQ==} - engines: {node: ^18.20.2 || >=20.9.0} + payload@3.31.0: + resolution: + { + integrity: sha512-rPP4n8yHa7FGh1uCcdx0nng1i71cPUetsiyVK0ntt/IIx0+iwfk9qcEreDboNe5CxZuIozjAt42R70kGYlVStw==, + } + engines: { node: ^18.20.2 || >=20.9.0 } hasBin: true peerDependencies: graphql: ^16.8.1 peek-readable@5.4.2: - resolution: {integrity: sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg==} - engines: {node: '>=14.16'} + resolution: + { + integrity: sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg==, + } + engines: { node: '>=14.16' } picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + resolution: + { + integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==, + } picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} + resolution: + { + integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==, + } + engines: { node: '>=8.6' } picomatch@4.0.2: - resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==, + } + engines: { node: '>=12' } pify@2.3.0: - resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==, + } + engines: { node: '>=0.10.0' } pino-abstract-transport@2.0.0: - resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} + resolution: + { + integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==, + } pino-pretty@13.0.0: - resolution: {integrity: sha512-cQBBIVG3YajgoUjo1FdKVRX6t9XPxwB9lcNJVD5GCnNM4Y6T12YYx8c6zEejxQsU0wrg9TwmDulcE9LR7qcJqA==} + resolution: + { + integrity: sha512-cQBBIVG3YajgoUjo1FdKVRX6t9XPxwB9lcNJVD5GCnNM4Y6T12YYx8c6zEejxQsU0wrg9TwmDulcE9LR7qcJqA==, + } hasBin: true pino-std-serializers@7.0.0: - resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==} + resolution: + { + integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==, + } pino@9.5.0: - resolution: {integrity: sha512-xSEmD4pLnV54t0NOUN16yCl7RIB1c5UUOse5HSyEXtBp+FgFQyPeDutc+Q2ZO7/22vImV7VfEjH/1zV2QuqvYw==} + resolution: + { + integrity: sha512-xSEmD4pLnV54t0NOUN16yCl7RIB1c5UUOse5HSyEXtBp+FgFQyPeDutc+Q2ZO7/22vImV7VfEjH/1zV2QuqvYw==, + } hasBin: true pirates@4.0.6: - resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} - engines: {node: '>= 6'} + resolution: + { + integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==, + } + engines: { node: '>= 6' } pluralize@8.0.0: - resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==, + } + engines: { node: '>=4' } possible-typed-array-names@1.1.0: - resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==, + } + engines: { node: '>= 0.4' } postcss-import@15.1.0: - resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} - engines: {node: '>=14.0.0'} + resolution: + { + integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==, + } + engines: { node: '>=14.0.0' } peerDependencies: postcss: ^8.0.0 postcss-js@4.0.1: - resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} - engines: {node: ^12 || ^14 || >= 16} + resolution: + { + integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==, + } + engines: { node: ^12 || ^14 || >= 16 } peerDependencies: postcss: ^8.4.21 postcss-load-config@4.0.2: - resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} - engines: {node: '>= 14'} + resolution: + { + integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==, + } + engines: { node: '>= 14' } peerDependencies: postcss: '>=8.0.9' ts-node: '>=9.0.0' @@ -3435,136 +5701,229 @@ packages: optional: true postcss-nested@6.2.0: - resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} - engines: {node: '>=12.0'} + resolution: + { + integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==, + } + engines: { node: '>=12.0' } peerDependencies: postcss: ^8.2.14 postcss-selector-parser@6.0.10: - resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==, + } + engines: { node: '>=4' } postcss-selector-parser@6.1.2: - resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==, + } + engines: { node: '>=4' } postcss-value-parser@4.2.0: - resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + resolution: + { + integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==, + } postcss@8.4.31: - resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} - engines: {node: ^10 || ^12 || >=14} + resolution: + { + integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==, + } + engines: { node: ^10 || ^12 || >=14 } postcss@8.5.3: - resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} - engines: {node: ^10 || ^12 || >=14} + resolution: + { + integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==, + } + engines: { node: ^10 || ^12 || >=14 } prebuild-install@7.1.3: - resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==, + } + engines: { node: '>=10' } hasBin: true prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} + resolution: + { + integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==, + } + engines: { node: '>= 0.8.0' } prettier@3.5.3: - resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==} - engines: {node: '>=14'} + resolution: + { + integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==, + } + engines: { node: '>=14' } hasBin: true prism-react-renderer@2.4.1: - resolution: {integrity: sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig==} + resolution: + { + integrity: sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig==, + } peerDependencies: react: '>=16.0.0' prismjs@1.30.0: - resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==, + } + engines: { node: '>=6' } process-nextick-args@2.0.1: - resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + resolution: + { + integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==, + } process-warning@4.0.1: - resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==} + resolution: + { + integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==, + } prompts@2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} + resolution: + { + integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==, + } + engines: { node: '>= 6' } prop-types@15.8.1: - resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + resolution: + { + integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==, + } pump@3.0.2: - resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} + resolution: + { + integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==, + } punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==, + } + engines: { node: '>=6' } qs-esm@7.0.2: - resolution: {integrity: sha512-D8NAthKSD7SGn748v+GLaaO6k08Mvpoqroa35PqIQC4gtUa8/Pb/k+r0m0NnGBVbHDP1gKZ2nVywqfMisRhV5A==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-D8NAthKSD7SGn748v+GLaaO6k08Mvpoqroa35PqIQC4gtUa8/Pb/k+r0m0NnGBVbHDP1gKZ2nVywqfMisRhV5A==, + } + engines: { node: '>=18' } queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + resolution: + { + integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, + } queue@6.0.2: - resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} + resolution: + { + integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==, + } quick-format-unescaped@4.0.4: - resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + resolution: + { + integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==, + } rc@1.2.8: - resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + resolution: + { + integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==, + } hasBin: true react-datepicker@7.6.0: - resolution: {integrity: sha512-9cQH6Z/qa4LrGhzdc3XoHbhrxNcMi9MKjZmYgF/1MNNaJwvdSjv3Xd+jjvrEEbKEf71ZgCA3n7fQbdwd70qCRw==} + resolution: + { + integrity: sha512-9cQH6Z/qa4LrGhzdc3XoHbhrxNcMi9MKjZmYgF/1MNNaJwvdSjv3Xd+jjvrEEbKEf71ZgCA3n7fQbdwd70qCRw==, + } peerDependencies: react: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc react-dom: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc react-diff-viewer-continued@4.0.5: - resolution: {integrity: sha512-L43gIPdhHgu1MYdip4vNqAt5s2JLICKe2/RyGUr2ohAxfhYaH1+QZ6vBO0qgo4xGBhE3jmvbOA/swq4/gdS/0g==} - engines: {node: '>= 16'} + resolution: + { + integrity: sha512-L43gIPdhHgu1MYdip4vNqAt5s2JLICKe2/RyGUr2ohAxfhYaH1+QZ6vBO0qgo4xGBhE3jmvbOA/swq4/gdS/0g==, + } + engines: { node: '>= 16' } peerDependencies: react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom@19.0.0: - resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==} + resolution: + { + integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==, + } peerDependencies: react: ^19.0.0 react-error-boundary@3.1.4: - resolution: {integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==} - engines: {node: '>=10', npm: '>=6'} + resolution: + { + integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==, + } + engines: { node: '>=10', npm: '>=6' } peerDependencies: react: '>=16.13.1' react-error-boundary@4.1.2: - resolution: {integrity: sha512-GQDxZ5Jd+Aq/qUxbCm1UtzmL/s++V7zKgE8yMktJiCQXCCFZnMZh9ng+6/Ne6PjNSXH0L9CjeOEREfRnq6Duag==} + resolution: + { + integrity: sha512-GQDxZ5Jd+Aq/qUxbCm1UtzmL/s++V7zKgE8yMktJiCQXCCFZnMZh9ng+6/Ne6PjNSXH0L9CjeOEREfRnq6Duag==, + } peerDependencies: react: '>=16.13.1' react-hook-form@7.45.4: - resolution: {integrity: sha512-HGDV1JOOBPZj10LB3+OZgfDBTn+IeEsNOKiq/cxbQAIbKaiJUe/KV8DBUzsx0Gx/7IG/orWqRRm736JwOfUSWQ==} - engines: {node: '>=12.22.0'} + resolution: + { + integrity: sha512-HGDV1JOOBPZj10LB3+OZgfDBTn+IeEsNOKiq/cxbQAIbKaiJUe/KV8DBUzsx0Gx/7IG/orWqRRm736JwOfUSWQ==, + } + engines: { node: '>=12.22.0' } peerDependencies: react: ^16.8.0 || ^17 || ^18 react-image-crop@10.1.8: - resolution: {integrity: sha512-4rb8XtXNx7ZaOZarKKnckgz4xLMvds/YrU6mpJfGhGAsy2Mg4mIw1x+DCCGngVGq2soTBVVOxx2s/C6mTX9+pA==} + resolution: + { + integrity: sha512-4rb8XtXNx7ZaOZarKKnckgz4xLMvds/YrU6mpJfGhGAsy2Mg4mIw1x+DCCGngVGq2soTBVVOxx2s/C6mTX9+pA==, + } peerDependencies: react: '>=16.13.1' react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + resolution: + { + integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==, + } react-remove-scroll-bar@2.3.8: - resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==, + } + engines: { node: '>=10' } peerDependencies: '@types/react': '*' react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -3573,8 +5932,11 @@ packages: optional: true react-remove-scroll@2.6.3: - resolution: {integrity: sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ==, + } + engines: { node: '>=10' } peerDependencies: '@types/react': '*' react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc @@ -3583,14 +5945,20 @@ packages: optional: true react-select@5.9.0: - resolution: {integrity: sha512-nwRKGanVHGjdccsnzhFte/PULziueZxGD8LL2WojON78Mvnq7LdAMEtu2frrwld1fr3geixg3iiMBIc/LLAZpw==} + resolution: + { + integrity: sha512-nwRKGanVHGjdccsnzhFte/PULziueZxGD8LL2WojON78Mvnq7LdAMEtu2frrwld1fr3geixg3iiMBIc/LLAZpw==, + } peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-style-singleton@2.2.3: - resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==, + } + engines: { node: '>=10' } peerDependencies: '@types/react': '*' react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc @@ -3599,308 +5967,554 @@ packages: optional: true react-transition-group@4.4.5: - resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} + resolution: + { + integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==, + } peerDependencies: react: '>=16.6.0' react-dom: '>=16.6.0' react@19.0.0: - resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==, + } + engines: { node: '>=0.10.0' } read-cache@1.0.0: - resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + resolution: + { + integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==, + } readable-stream@1.0.34: - resolution: {integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==} + resolution: + { + integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==, + } readable-stream@2.3.8: - resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + resolution: + { + integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==, + } readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} + resolution: + { + integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==, + } + engines: { node: '>= 6' } readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} + resolution: + { + integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==, + } + engines: { node: '>=8.10.0' } real-require@0.2.0: - resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} - engines: {node: '>= 12.13.0'} + resolution: + { + integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==, + } + engines: { node: '>= 12.13.0' } reflect.getprototypeof@1.0.10: - resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==, + } + engines: { node: '>= 0.4' } regenerator-runtime@0.14.1: - resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + resolution: + { + integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==, + } regexp.prototype.flags@1.5.4: - resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==, + } + engines: { node: '>= 0.4' } require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==, + } + engines: { node: '>=0.10.0' } require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==, + } + engines: { node: '>=0.10.0' } resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==, + } + engines: { node: '>=4' } resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolution: + { + integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==, + } resolve@1.22.10: - resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==, + } + engines: { node: '>= 0.4' } hasBin: true resolve@2.0.0-next.5: - resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + resolution: + { + integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==, + } hasBin: true reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + resolution: + { + integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==, + } + engines: { iojs: '>=1.0.0', node: '>=0.10.0' } rspack-resolver@1.2.2: - resolution: {integrity: sha512-Fwc19jMBA3g+fxDJH2B4WxwZjE0VaaOL7OX/A4Wn5Zv7bOD/vyPZhzXfaO73Xc2GAlfi96g5fGUa378WbIGfFw==} + resolution: + { + integrity: sha512-Fwc19jMBA3g+fxDJH2B4WxwZjE0VaaOL7OX/A4Wn5Zv7bOD/vyPZhzXfaO73Xc2GAlfi96g5fGUa378WbIGfFw==, + } run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + resolution: + { + integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==, + } safe-array-concat@1.1.3: - resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} - engines: {node: '>=0.4'} + resolution: + { + integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==, + } + engines: { node: '>=0.4' } safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + resolution: + { + integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==, + } safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + resolution: + { + integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==, + } safe-push-apply@1.0.0: - resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==, + } + engines: { node: '>= 0.4' } safe-regex-test@1.1.0: - resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==, + } + engines: { node: '>= 0.4' } safe-stable-stringify@2.5.0: - resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==, + } + engines: { node: '>=10' } sanitize-filename@1.6.3: - resolution: {integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==} + resolution: + { + integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==, + } sass@1.77.4: - resolution: {integrity: sha512-vcF3Ckow6g939GMA4PeU7b2K/9FALXk2KF9J87txdHzXbUF9XRQRwSxcAs/fGaTnJeBFd7UoV22j3lzMLdM0Pw==} - engines: {node: '>=14.0.0'} + resolution: + { + integrity: sha512-vcF3Ckow6g939GMA4PeU7b2K/9FALXk2KF9J87txdHzXbUF9XRQRwSxcAs/fGaTnJeBFd7UoV22j3lzMLdM0Pw==, + } + engines: { node: '>=14.0.0' } hasBin: true scheduler@0.25.0: - resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} + resolution: + { + integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==, + } scmp@2.1.0: - resolution: {integrity: sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==} + resolution: + { + integrity: sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==, + } secure-json-parse@2.7.0: - resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + resolution: + { + integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==, + } semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + resolution: + { + integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==, + } hasBin: true semver@7.7.1: - resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==, + } + engines: { node: '>=10' } hasBin: true set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==, + } + engines: { node: '>= 0.4' } set-function-name@2.0.2: - resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==, + } + engines: { node: '>= 0.4' } set-proto@1.0.0: - resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==, + } + engines: { node: '>= 0.4' } sharp@0.32.6: - resolution: {integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==} - engines: {node: '>=14.15.0'} + resolution: + { + integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==, + } + engines: { node: '>=14.15.0' } sharp@0.33.5: - resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + resolution: + { + integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==, + } + engines: { node: '>=8' } shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==, + } + engines: { node: '>=8' } side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==, + } + engines: { node: '>= 0.4' } side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==, + } + engines: { node: '>= 0.4' } side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==, + } + engines: { node: '>= 0.4' } side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==, + } + engines: { node: '>= 0.4' } sift@17.1.3: - resolution: {integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==} + resolution: + { + integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==, + } signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} + resolution: + { + integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==, + } + engines: { node: '>=14' } simple-concat@1.0.1: - resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + resolution: + { + integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==, + } simple-get@4.0.1: - resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + resolution: + { + integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==, + } simple-swizzle@0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + resolution: + { + integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==, + } simple-wcswidth@1.0.1: - resolution: {integrity: sha512-xMO/8eNREtaROt7tJvWJqHBDTMFN4eiQ5I4JRMuilwfnFcV5W9u7RUkueNkdw0jPqGMX36iCywelS5yilTuOxg==} + resolution: + { + integrity: sha512-xMO/8eNREtaROt7tJvWJqHBDTMFN4eiQ5I4JRMuilwfnFcV5W9u7RUkueNkdw0jPqGMX36iCywelS5yilTuOxg==, + } sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + resolution: + { + integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==, + } sonic-boom@4.2.0: - resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} + resolution: + { + integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==, + } sonner@1.7.4: - resolution: {integrity: sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==} + resolution: + { + integrity: sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==, + } peerDependencies: react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==, + } + engines: { node: '>=0.10.0' } source-map@0.5.7: - resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==, + } + engines: { node: '>=0.10.0' } sparse-bitfield@3.0.3: - resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==} + resolution: + { + integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==, + } split2@4.2.0: - resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} - engines: {node: '>= 10.x'} + resolution: + { + integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==, + } + engines: { node: '>= 10.x' } stable-hash@0.0.5: - resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} + resolution: + { + integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==, + } state-local@1.0.7: - resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} + resolution: + { + integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==, + } stream-browserify@3.0.0: - resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==} + resolution: + { + integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==, + } streamsearch@1.1.0: - resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} - engines: {node: '>=10.0.0'} + resolution: + { + integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==, + } + engines: { node: '>=10.0.0' } streamx@2.22.0: - resolution: {integrity: sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==} + resolution: + { + integrity: sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==, + } string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==, + } + engines: { node: '>=8' } string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==, + } + engines: { node: '>=12' } string.prototype.includes@2.0.1: - resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==, + } + engines: { node: '>= 0.4' } string.prototype.matchall@4.0.12: - resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==, + } + engines: { node: '>= 0.4' } string.prototype.repeat@1.0.0: - resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + resolution: + { + integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==, + } string.prototype.trim@1.2.10: - resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==, + } + engines: { node: '>= 0.4' } string.prototype.trimend@1.0.9: - resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==, + } + engines: { node: '>= 0.4' } string.prototype.trimstart@1.0.8: - resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==, + } + engines: { node: '>= 0.4' } string_decoder@0.10.31: - resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==} + resolution: + { + integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==, + } string_decoder@1.1.1: - resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + resolution: + { + integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==, + } string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + resolution: + { + integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==, + } stringify-entities@4.0.4: - resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + resolution: + { + integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==, + } strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==, + } + engines: { node: '>=8' } strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==, + } + engines: { node: '>=12' } strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==, + } + engines: { node: '>=4' } strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==, + } + engines: { node: '>=0.10.0' } strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==, + } + engines: { node: '>=8' } strnum@1.1.2: - resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==} + resolution: + { + integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==, + } strtok3@8.1.0: - resolution: {integrity: sha512-ExzDvHYPj6F6QkSNe/JxSlBxTh3OrI6wrAIz53ulxo1c4hBJ1bT9C/JrAthEKHWG9riVH3Xzg7B03Oxty6S2Lw==} - engines: {node: '>=16'} + resolution: + { + integrity: sha512-ExzDvHYPj6F6QkSNe/JxSlBxTh3OrI6wrAIz53ulxo1c4hBJ1bT9C/JrAthEKHWG9riVH3Xzg7B03Oxty6S2Lw==, + } + engines: { node: '>=16' } styled-jsx@5.1.6: - resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} - engines: {node: '>= 12.0.0'} + resolution: + { + integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==, + } + engines: { node: '>= 12.0.0' } peerDependencies: '@babel/core': '*' babel-plugin-macros: '*' @@ -3912,96 +6526,171 @@ packages: optional: true stylis@4.2.0: - resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} + resolution: + { + integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==, + } sucrase@3.35.0: - resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} - engines: {node: '>=16 || 14 >=14.17'} + resolution: + { + integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==, + } + engines: { node: '>=16 || 14 >=14.17' } hasBin: true supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==, + } + engines: { node: '>=8' } supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==, + } + engines: { node: '>= 0.4' } tabbable@6.2.0: - resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + resolution: + { + integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==, + } tailwind-merge@2.6.0: - resolution: {integrity: sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==} + resolution: + { + integrity: sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==, + } tailwindcss-animate@1.0.7: - resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + resolution: + { + integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==, + } peerDependencies: tailwindcss: '>=3.0.0 || insiders' tailwindcss@3.4.17: - resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==} - engines: {node: '>=14.0.0'} + resolution: + { + integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==, + } + engines: { node: '>=14.0.0' } hasBin: true tar-fs@2.1.2: - resolution: {integrity: sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==} + resolution: + { + integrity: sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==, + } tar-fs@3.0.8: - resolution: {integrity: sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg==} + resolution: + { + integrity: sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg==, + } tar-stream@2.2.0: - resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==, + } + engines: { node: '>=6' } tar-stream@3.1.7: - resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + resolution: + { + integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==, + } text-decoder@1.2.3: - resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} + resolution: + { + integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==, + } thenify-all@1.6.0: - resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} - engines: {node: '>=0.8'} + resolution: + { + integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==, + } + engines: { node: '>=0.8' } thenify@3.3.1: - resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + resolution: + { + integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==, + } thread-stream@3.1.0: - resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + resolution: + { + integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==, + } through2@2.0.5: - resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} + resolution: + { + integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==, + } tinyglobby@0.2.12: - resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==} - engines: {node: '>=12.0.0'} + resolution: + { + integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==, + } + engines: { node: '>=12.0.0' } to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} + resolution: + { + integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==, + } + engines: { node: '>=8.0' } token-types@6.0.0: - resolution: {integrity: sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA==} - engines: {node: '>=14.16'} + resolution: + { + integrity: sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA==, + } + engines: { node: '>=14.16' } tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + resolution: + { + integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==, + } tr46@5.1.0: - resolution: {integrity: sha512-IUWnUK7ADYR5Sl1fZlO1INDUhVhatWl7BtJWsIhwJ0UAK7ilzzIa8uIqOO/aYVWHZPJkKbEL+362wrzoeRF7bw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-IUWnUK7ADYR5Sl1fZlO1INDUhVhatWl7BtJWsIhwJ0UAK7ilzzIa8uIqOO/aYVWHZPJkKbEL+362wrzoeRF7bw==, + } + engines: { node: '>=18' } truncate-utf8-bytes@1.0.2: - resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} + resolution: + { + integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==, + } ts-api-utils@2.1.0: - resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} - engines: {node: '>=18.12'} + resolution: + { + integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==, + } + engines: { node: '>=18.12' } peerDependencies: typescript: '>=4.8.4' ts-essentials@10.0.3: - resolution: {integrity: sha512-/FrVAZ76JLTWxJOERk04fm8hYENDo0PWSP3YLQKxevLwWtxemGcl5JJEzN4iqfDlRve0ckyfFaOBu4xbNH/wZw==} + resolution: + { + integrity: sha512-/FrVAZ76JLTWxJOERk04fm8hYENDo0PWSP3YLQKxevLwWtxemGcl5JJEzN4iqfDlRve0ckyfFaOBu4xbNH/wZw==, + } peerDependencies: typescript: '>=4.5.0' peerDependenciesMeta: @@ -4009,95 +6698,170 @@ packages: optional: true ts-interface-checker@0.1.13: - resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + resolution: + { + integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==, + } tsconfig-paths@3.15.0: - resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + resolution: + { + integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==, + } tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + resolution: + { + integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==, + } tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + resolution: + { + integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==, + } tsx@4.19.2: - resolution: {integrity: sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==} - engines: {node: '>=18.0.0'} + resolution: + { + integrity: sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==, + } + engines: { node: '>=18.0.0' } hasBin: true tunnel-agent@0.6.0: - resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + resolution: + { + integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==, + } type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} + resolution: + { + integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==, + } + engines: { node: '>= 0.8.0' } typed-array-buffer@1.0.3: - resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==, + } + engines: { node: '>= 0.4' } typed-array-byte-length@1.0.3: - resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==, + } + engines: { node: '>= 0.4' } typed-array-byte-offset@1.0.4: - resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==, + } + engines: { node: '>= 0.4' } typed-array-length@1.0.7: - resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==, + } + engines: { node: '>= 0.4' } typescript@5.7.3: - resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} - engines: {node: '>=14.17'} + resolution: + { + integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==, + } + engines: { node: '>=14.17' } hasBin: true uint8array-extras@1.4.0: - resolution: {integrity: sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==, + } + engines: { node: '>=18' } unbox-primitive@1.1.0: - resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==, + } + engines: { node: '>= 0.4' } undici-types@6.19.8: - resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + resolution: + { + integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==, + } unfetch@4.2.0: - resolution: {integrity: sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==} + resolution: + { + integrity: sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==, + } unist-util-is@6.0.0: - resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} + resolution: + { + integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==, + } unist-util-position-from-estree@2.0.0: - resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} + resolution: + { + integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==, + } unist-util-stringify-position@4.0.0: - resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + resolution: + { + integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==, + } unist-util-visit-parents@6.0.1: - resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} + resolution: + { + integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==, + } unist-util-visit@5.0.0: - resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + resolution: + { + integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==, + } untildify@4.0.0: - resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==, + } + engines: { node: '>=8' } update-browserslist-db@1.1.3: - resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + resolution: + { + integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==, + } hasBin: true peerDependencies: browserslist: '>= 4.21.0' uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + resolution: + { + integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==, + } use-callback-ref@1.3.3: - resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==, + } + engines: { node: '>=10' } peerDependencies: '@types/react': '*' react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc @@ -4106,13 +6870,19 @@ packages: optional: true use-context-selector@2.0.0: - resolution: {integrity: sha512-owfuSmUNd3eNp3J9CdDl0kMgfidV+MkDvHPpvthN5ThqM+ibMccNE0k+Iq7TWC6JPFvGZqanqiGCuQx6DyV24g==} + resolution: + { + integrity: sha512-owfuSmUNd3eNp3J9CdDl0kMgfidV+MkDvHPpvthN5ThqM+ibMccNE0k+Iq7TWC6JPFvGZqanqiGCuQx6DyV24g==, + } peerDependencies: react: '>=18.0.0' scheduler: '>=0.19.0' use-isomorphic-layout-effect@1.2.0: - resolution: {integrity: sha512-q6ayo8DWoPZT0VdG4u3D3uxcgONP3Mevx2i2b0434cwWBoL+aelL1DzkXI6w3PhTZzUeR2kaVlZn70iCiseP6w==} + resolution: + { + integrity: sha512-q6ayo8DWoPZT0VdG4u3D3uxcgONP3Mevx2i2b0434cwWBoL+aelL1DzkXI6w3PhTZzUeR2kaVlZn70iCiseP6w==, + } peerDependencies: '@types/react': '*' react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -4121,8 +6891,11 @@ packages: optional: true use-sidecar@1.1.3: - resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==, + } + engines: { node: '>=10' } peerDependencies: '@types/react': '*' react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc @@ -4131,75 +6904,132 @@ packages: optional: true utf8-byte-length@1.0.5: - resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==} + resolution: + { + integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==, + } util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + resolution: + { + integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==, + } uuid@10.0.0: - resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + resolution: + { + integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==, + } hasBin: true uuid@9.0.1: - resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + resolution: + { + integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==, + } hasBin: true vfile-message@4.0.2: - resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} + resolution: + { + integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==, + } webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + resolution: + { + integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==, + } webidl-conversions@7.0.0: - resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==, + } + engines: { node: '>=12' } whatwg-url@14.2.0: - resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==, + } + engines: { node: '>=18' } whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + resolution: + { + integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==, + } which-boxed-primitive@1.1.1: - resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==, + } + engines: { node: '>= 0.4' } which-builtin-type@1.2.1: - resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==, + } + engines: { node: '>= 0.4' } which-collection@1.0.2: - resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==, + } + engines: { node: '>= 0.4' } which-typed-array@1.1.19: - resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==, + } + engines: { node: '>= 0.4' } which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==, + } + engines: { node: '>= 8' } hasBin: true word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==, + } + engines: { node: '>=0.10.0' } wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==, + } + engines: { node: '>=10' } wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==, + } + engines: { node: '>=12' } wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + resolution: + { + integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, + } ws@8.18.1: - resolution: {integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==} - engines: {node: '>=10.0.0'} + resolution: + { + integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==, + } + engines: { node: '>=10.0.0' } peerDependencies: bufferutil: ^4.0.1 utf-8-validate: '>=5.0.2' @@ -4210,48 +7040,77 @@ packages: optional: true xss@1.0.15: - resolution: {integrity: sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==} - engines: {node: '>= 0.10.0'} + resolution: + { + integrity: sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==, + } + engines: { node: '>= 0.10.0' } hasBin: true xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} + resolution: + { + integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==, + } + engines: { node: '>=0.4' } y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==, + } + engines: { node: '>=10' } yaml@1.10.2: - resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} - engines: {node: '>= 6'} + resolution: + { + integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==, + } + engines: { node: '>= 6' } yaml@2.7.0: - resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==} - engines: {node: '>= 14'} + resolution: + { + integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==, + } + engines: { node: '>= 14' } hasBin: true yargs-parser@20.2.9: - resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==, + } + engines: { node: '>=10' } yargs@16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==, + } + engines: { node: '>=10' } yjs@13.6.24: - resolution: {integrity: sha512-xn/pYLTZa3uD1uDG8lpxfLRo5SR/rp0frdASOl2a71aYNvUXdWcLtVL91s2y7j+Q8ppmjZ9H3jsGVgoFMbT2VA==} - engines: {node: '>=16.0.0', npm: '>=8.0.0'} + resolution: + { + integrity: sha512-xn/pYLTZa3uD1uDG8lpxfLRo5SR/rp0frdASOl2a71aYNvUXdWcLtVL91s2y7j+Q8ppmjZ9H3jsGVgoFMbT2VA==, + } + engines: { node: '>=16.0.0', npm: '>=8.0.0' } yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==, + } + engines: { node: '>=10' } zwitch@2.0.4: - resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + resolution: + { + integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==, + } snapshots: - '@alloc/quick-lru@5.2.0': {} '@apidevtools/json-schema-ref-parser@11.9.3': @@ -5488,16 +8347,16 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} - '@payloadcms/admin-bar@3.29.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@payloadcms/admin-bar@3.31.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - '@payloadcms/db-mongodb@3.29.0(@aws-sdk/credential-providers@3.772.0)(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))': + '@payloadcms/db-mongodb@3.31.0(@aws-sdk/credential-providers@3.772.0)(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))': dependencies: mongoose: 8.9.5(@aws-sdk/credential-providers@3.772.0) mongoose-paginate-v2: 1.8.5 - payload: 3.29.0(graphql@16.10.0)(typescript@5.7.3) + payload: 3.31.0(graphql@16.10.0)(typescript@5.7.3) prompts: 2.4.2 uuid: 10.0.0 transitivePeerDependencies: @@ -5510,36 +8369,36 @@ snapshots: - socks - supports-color - '@payloadcms/email-nodemailer@3.29.0(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))': + '@payloadcms/email-nodemailer@3.31.0(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))': dependencies: nodemailer: 6.9.16 - payload: 3.29.0(graphql@16.10.0)(typescript@5.7.3) + payload: 3.31.0(graphql@16.10.0)(typescript@5.7.3) - '@payloadcms/graphql@3.29.0(graphql@16.10.0)(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(typescript@5.7.3)': + '@payloadcms/graphql@3.31.0(graphql@16.10.0)(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(typescript@5.7.3)': dependencies: graphql: 16.10.0 graphql-scalars: 1.22.2(graphql@16.10.0) - payload: 3.29.0(graphql@16.10.0)(typescript@5.7.3) + payload: 3.31.0(graphql@16.10.0)(typescript@5.7.3) pluralize: 8.0.0 ts-essentials: 10.0.3(typescript@5.7.3) tsx: 4.19.2 transitivePeerDependencies: - typescript - '@payloadcms/live-preview-react@3.29.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@payloadcms/live-preview-react@3.31.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@payloadcms/live-preview': 3.29.0 + '@payloadcms/live-preview': 3.31.0 react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - '@payloadcms/live-preview@3.29.0': {} + '@payloadcms/live-preview@3.31.0': {} - '@payloadcms/next@3.29.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)': + '@payloadcms/next@3.31.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)': dependencies: '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@payloadcms/graphql': 3.29.0(graphql@16.10.0)(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(typescript@5.7.3) - '@payloadcms/translations': 3.29.0 - '@payloadcms/ui': 3.29.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + '@payloadcms/graphql': 3.31.0(graphql@16.10.0)(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(typescript@5.7.3) + '@payloadcms/translations': 3.31.0 + '@payloadcms/ui': 3.31.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) busboy: 1.6.0 dequal: 2.0.3 file-type: 19.3.0 @@ -5549,7 +8408,7 @@ snapshots: http-status: 2.1.0 next: 15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) path-to-regexp: 6.3.0 - payload: 3.29.0(graphql@16.10.0)(typescript@5.7.3) + payload: 3.31.0(graphql@16.10.0)(typescript@5.7.3) qs-esm: 7.0.2 react-diff-viewer-continued: 4.0.5(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) sass: 1.77.4 @@ -5562,25 +8421,25 @@ snapshots: - supports-color - typescript - '@payloadcms/payload-cloud@3.29.0(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))': + '@payloadcms/payload-cloud@3.31.0(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))': dependencies: '@aws-sdk/client-cognito-identity': 3.772.0 '@aws-sdk/client-s3': 3.772.0 '@aws-sdk/credential-providers': 3.772.0 '@aws-sdk/lib-storage': 3.772.0(@aws-sdk/client-s3@3.772.0) - '@payloadcms/email-nodemailer': 3.29.0(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3)) + '@payloadcms/email-nodemailer': 3.31.0(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3)) amazon-cognito-identity-js: 6.3.12 nodemailer: 6.9.16 - payload: 3.29.0(graphql@16.10.0)(typescript@5.7.3) + payload: 3.31.0(graphql@16.10.0)(typescript@5.7.3) transitivePeerDependencies: - aws-crt - encoding - '@payloadcms/plugin-form-builder@3.29.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)': + '@payloadcms/plugin-form-builder@3.31.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)': dependencies: - '@payloadcms/ui': 3.29.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + '@payloadcms/ui': 3.31.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) escape-html: 1.0.3 - payload: 3.29.0(graphql@16.10.0)(typescript@5.7.3) + payload: 3.31.0(graphql@16.10.0)(typescript@5.7.3) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) transitivePeerDependencies: @@ -5590,19 +8449,19 @@ snapshots: - supports-color - typescript - '@payloadcms/plugin-nested-docs@3.29.0(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))': + '@payloadcms/plugin-nested-docs@3.31.0(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))': dependencies: - payload: 3.29.0(graphql@16.10.0)(typescript@5.7.3) + payload: 3.31.0(graphql@16.10.0)(typescript@5.7.3) - '@payloadcms/plugin-redirects@3.29.0(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))': + '@payloadcms/plugin-redirects@3.31.0(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))': dependencies: - payload: 3.29.0(graphql@16.10.0)(typescript@5.7.3) + payload: 3.31.0(graphql@16.10.0)(typescript@5.7.3) - '@payloadcms/plugin-search@3.29.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)': + '@payloadcms/plugin-search@3.31.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)': dependencies: - '@payloadcms/next': 3.29.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) - '@payloadcms/ui': 3.29.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) - payload: 3.29.0(graphql@16.10.0)(typescript@5.7.3) + '@payloadcms/next': 3.31.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + '@payloadcms/ui': 3.31.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + payload: 3.31.0(graphql@16.10.0)(typescript@5.7.3) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) transitivePeerDependencies: @@ -5613,11 +8472,11 @@ snapshots: - supports-color - typescript - '@payloadcms/plugin-seo@3.29.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)': + '@payloadcms/plugin-seo@3.31.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)': dependencies: - '@payloadcms/translations': 3.29.0 - '@payloadcms/ui': 3.29.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) - payload: 3.29.0(graphql@16.10.0)(typescript@5.7.3) + '@payloadcms/translations': 3.31.0 + '@payloadcms/ui': 3.31.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + payload: 3.31.0(graphql@16.10.0)(typescript@5.7.3) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) transitivePeerDependencies: @@ -5627,7 +8486,7 @@ snapshots: - supports-color - typescript - '@payloadcms/richtext-lexical@3.29.0(@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@faceless-ui/scroll-info@2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@payloadcms/next@3.29.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3))(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)(yjs@13.6.24)': + '@payloadcms/richtext-lexical@3.31.0(@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@faceless-ui/scroll-info@2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@payloadcms/next@3.31.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3))(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)(yjs@13.6.24)': dependencies: '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@faceless-ui/scroll-info': 2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -5641,9 +8500,9 @@ snapshots: '@lexical/selection': 0.28.0 '@lexical/table': 0.28.0 '@lexical/utils': 0.28.0 - '@payloadcms/next': 3.29.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) - '@payloadcms/translations': 3.29.0 - '@payloadcms/ui': 3.29.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + '@payloadcms/next': 3.31.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + '@payloadcms/translations': 3.31.0 + '@payloadcms/ui': 3.31.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) '@types/uuid': 10.0.0 acorn: 8.12.1 bson-objectid: 2.0.4 @@ -5654,7 +8513,7 @@ snapshots: mdast-util-from-markdown: 2.0.2 mdast-util-mdx-jsx: 3.1.3 micromark-extension-mdx-jsx: 3.0.1 - payload: 3.29.0(graphql@16.10.0)(typescript@5.7.3) + payload: 3.31.0(graphql@16.10.0)(typescript@5.7.3) qs-esm: 7.0.2 react: 19.0.0 react-dom: 19.0.0(react@19.0.0) @@ -5669,11 +8528,11 @@ snapshots: - typescript - yjs - '@payloadcms/translations@3.29.0': + '@payloadcms/translations@3.31.0': dependencies: date-fns: 4.1.0 - '@payloadcms/ui@3.29.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.29.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)': + '@payloadcms/ui@3.31.0(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)': dependencies: '@date-fns/tz': 1.2.0 '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -5682,14 +8541,14 @@ snapshots: '@faceless-ui/scroll-info': 2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@faceless-ui/window-info': 3.0.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@monaco-editor/react': 4.7.0(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@payloadcms/translations': 3.29.0 + '@payloadcms/translations': 3.31.0 bson-objectid: 2.0.4 date-fns: 4.1.0 dequal: 2.0.3 md5: 2.3.0 next: 15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) object-to-formdata: 4.5.1 - payload: 3.29.0(graphql@16.10.0)(typescript@5.7.3) + payload: 3.31.0(graphql@16.10.0)(typescript@5.7.3) qs-esm: 7.0.2 react: 19.0.0 react-datepicker: 7.6.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -8351,10 +11210,10 @@ snapshots: path-type@4.0.0: {} - payload@3.29.0(graphql@16.10.0)(typescript@5.7.3): + payload@3.31.0(graphql@16.10.0)(typescript@5.7.3): dependencies: '@next/env': 15.2.3 - '@payloadcms/translations': 3.29.0 + '@payloadcms/translations': 3.31.0 '@types/busboy': 1.5.4 ajv: 8.17.1 bson-objectid: 2.0.4 @@ -9204,7 +12063,7 @@ snapshots: tsx@4.19.2: dependencies: esbuild: 0.23.1 - get-tsconfig: 4.8.1 + get-tsconfig: 4.10.0 optionalDependencies: fsevents: 2.3.3 diff --git a/templates/with-postgres/package.json b/templates/with-postgres/package.json index a97a5ac26b..4a7cc6b867 100644 --- a/templates/with-postgres/package.json +++ b/templates/with-postgres/package.json @@ -16,17 +16,17 @@ "ci": "payload migrate && pnpm build" }, "dependencies": { - "@payloadcms/next": "latest", - "@payloadcms/payload-cloud": "latest", - "@payloadcms/richtext-lexical": "latest", + "@payloadcms/next": "3.31.0", + "@payloadcms/payload-cloud": "3.31.0", + "@payloadcms/richtext-lexical": "3.31.0", "cross-env": "^7.0.3", "graphql": "^16.8.1", "next": "15.2.3", - "payload": "latest", + "payload": "3.31.0", "react": "19.0.0", "react-dom": "19.0.0", "sharp": "0.32.6", - "@payloadcms/db-postgres": "latest" + "@payloadcms/db-postgres": "3.31.0" }, "devDependencies": { "@eslint/eslintrc": "^3.2.0", diff --git a/templates/with-postgres/src/migrations/20250311_214602_initial.json b/templates/with-postgres/src/migrations/20250326_181533_initial.json similarity index 99% rename from templates/with-postgres/src/migrations/20250311_214602_initial.json rename to templates/with-postgres/src/migrations/20250326_181533_initial.json index 32427268de..c80dfe6bcd 100644 --- a/templates/with-postgres/src/migrations/20250311_214602_initial.json +++ b/templates/with-postgres/src/migrations/20250326_181533_initial.json @@ -1,5 +1,5 @@ { - "id": "9cce5027-9a03-4012-908a-037491622267", + "id": "aa5feeb6-613d-43e6-88eb-07c5d853a81c", "prevId": "00000000-0000-0000-0000-000000000000", "version": "7", "dialect": "postgresql", diff --git a/templates/with-postgres/src/migrations/20250311_214602_initial.ts b/templates/with-postgres/src/migrations/20250326_181533_initial.ts similarity index 100% rename from templates/with-postgres/src/migrations/20250311_214602_initial.ts rename to templates/with-postgres/src/migrations/20250326_181533_initial.ts diff --git a/templates/with-postgres/src/migrations/index.ts b/templates/with-postgres/src/migrations/index.ts index 34d24a7a96..65431fdc73 100644 --- a/templates/with-postgres/src/migrations/index.ts +++ b/templates/with-postgres/src/migrations/index.ts @@ -1,9 +1,9 @@ -import * as migration_20250311_214602_initial from './20250311_214602_initial' +import * as migration_20250326_181533_initial from './20250326_181533_initial' export const migrations = [ { - up: migration_20250311_214602_initial.up, - down: migration_20250311_214602_initial.down, - name: '20250311_214602_initial', + up: migration_20250326_181533_initial.up, + down: migration_20250326_181533_initial.down, + name: '20250326_181533_initial', }, ] diff --git a/templates/with-postgres/src/payload-types.ts b/templates/with-postgres/src/payload-types.ts index 533bc86e73..d3cacc91c9 100644 --- a/templates/with-postgres/src/payload-types.ts +++ b/templates/with-postgres/src/payload-types.ts @@ -54,6 +54,7 @@ export type SupportedTimezones = | 'Asia/Singapore' | 'Asia/Tokyo' | 'Asia/Seoul' + | 'Australia/Brisbane' | 'Australia/Sydney' | 'Pacific/Guam' | 'Pacific/Noumea' diff --git a/templates/with-vercel-mongodb/package.json b/templates/with-vercel-mongodb/package.json index 5f0e37ba34..fa9d194d30 100644 --- a/templates/with-vercel-mongodb/package.json +++ b/templates/with-vercel-mongodb/package.json @@ -15,17 +15,17 @@ "start": "cross-env NODE_OPTIONS=--no-deprecation next start" }, "dependencies": { - "@payloadcms/db-mongodb": "latest", - "@payloadcms/next": "latest", - "@payloadcms/payload-cloud": "latest", - "@payloadcms/richtext-lexical": "latest", + "@payloadcms/db-mongodb": "3.31.0", + "@payloadcms/next": "3.31.0", + "@payloadcms/payload-cloud": "3.31.0", + "@payloadcms/richtext-lexical": "3.31.0", "cross-env": "^7.0.3", "graphql": "^16.8.1", "next": "15.2.3", - "payload": "latest", + "payload": "3.31.0", "react": "19.0.0", "react-dom": "19.0.0", - "@payloadcms/storage-vercel-blob": "latest" + "@payloadcms/storage-vercel-blob": "3.31.0" }, "devDependencies": { "@eslint/eslintrc": "^3.2.0", diff --git a/templates/with-vercel-mongodb/src/app/(payload)/admin/importMap.js b/templates/with-vercel-mongodb/src/app/(payload)/admin/importMap.js index 8ef7021383..ad41a392a5 100644 --- a/templates/with-vercel-mongodb/src/app/(payload)/admin/importMap.js +++ b/templates/with-vercel-mongodb/src/app/(payload)/admin/importMap.js @@ -1 +1,6 @@ -export const importMap = {} +import { VercelBlobClientUploadHandler as VercelBlobClientUploadHandler_16c82c5e25f430251a3e3ba57219ff4e } from '@payloadcms/storage-vercel-blob/client' + +export const importMap = { + '@payloadcms/storage-vercel-blob/client#VercelBlobClientUploadHandler': + VercelBlobClientUploadHandler_16c82c5e25f430251a3e3ba57219ff4e, +} diff --git a/templates/with-vercel-postgres/package.json b/templates/with-vercel-postgres/package.json index 43d0cc0731..731fc2e776 100644 --- a/templates/with-vercel-postgres/package.json +++ b/templates/with-vercel-postgres/package.json @@ -16,17 +16,17 @@ "ci": "payload migrate && pnpm build" }, "dependencies": { - "@payloadcms/next": "latest", - "@payloadcms/payload-cloud": "latest", - "@payloadcms/richtext-lexical": "latest", + "@payloadcms/next": "3.31.0", + "@payloadcms/payload-cloud": "3.31.0", + "@payloadcms/richtext-lexical": "3.31.0", "cross-env": "^7.0.3", "graphql": "^16.8.1", "next": "15.2.3", - "payload": "latest", + "payload": "3.31.0", "react": "19.0.0", "react-dom": "19.0.0", - "@payloadcms/db-vercel-postgres": "latest", - "@payloadcms/storage-vercel-blob": "latest" + "@payloadcms/db-vercel-postgres": "3.31.0", + "@payloadcms/storage-vercel-blob": "3.31.0" }, "devDependencies": { "@eslint/eslintrc": "^3.2.0", diff --git a/templates/with-vercel-postgres/src/app/(payload)/admin/importMap.js b/templates/with-vercel-postgres/src/app/(payload)/admin/importMap.js index 8ef7021383..ad41a392a5 100644 --- a/templates/with-vercel-postgres/src/app/(payload)/admin/importMap.js +++ b/templates/with-vercel-postgres/src/app/(payload)/admin/importMap.js @@ -1 +1,6 @@ -export const importMap = {} +import { VercelBlobClientUploadHandler as VercelBlobClientUploadHandler_16c82c5e25f430251a3e3ba57219ff4e } from '@payloadcms/storage-vercel-blob/client' + +export const importMap = { + '@payloadcms/storage-vercel-blob/client#VercelBlobClientUploadHandler': + VercelBlobClientUploadHandler_16c82c5e25f430251a3e3ba57219ff4e, +} diff --git a/templates/with-vercel-postgres/src/migrations/20250311_214549_initial.json b/templates/with-vercel-postgres/src/migrations/20250326_181520_initial.json similarity index 99% rename from templates/with-vercel-postgres/src/migrations/20250311_214549_initial.json rename to templates/with-vercel-postgres/src/migrations/20250326_181520_initial.json index 35cd2afe8a..c9e30c784c 100644 --- a/templates/with-vercel-postgres/src/migrations/20250311_214549_initial.json +++ b/templates/with-vercel-postgres/src/migrations/20250326_181520_initial.json @@ -1,5 +1,5 @@ { - "id": "de2cf2f0-6fb4-4af1-8a4c-fdeecf2904e8", + "id": "43e7c0ef-81d3-45a7-9d08-0744951f1942", "prevId": "00000000-0000-0000-0000-000000000000", "version": "7", "dialect": "postgresql", diff --git a/templates/with-vercel-postgres/src/migrations/20250311_214549_initial.ts b/templates/with-vercel-postgres/src/migrations/20250326_181520_initial.ts similarity index 100% rename from templates/with-vercel-postgres/src/migrations/20250311_214549_initial.ts rename to templates/with-vercel-postgres/src/migrations/20250326_181520_initial.ts diff --git a/templates/with-vercel-postgres/src/migrations/index.ts b/templates/with-vercel-postgres/src/migrations/index.ts index 2774d72106..533d741c3d 100644 --- a/templates/with-vercel-postgres/src/migrations/index.ts +++ b/templates/with-vercel-postgres/src/migrations/index.ts @@ -1,9 +1,9 @@ -import * as migration_20250311_214549_initial from './20250311_214549_initial' +import * as migration_20250326_181520_initial from './20250326_181520_initial' export const migrations = [ { - up: migration_20250311_214549_initial.up, - down: migration_20250311_214549_initial.down, - name: '20250311_214549_initial', + up: migration_20250326_181520_initial.up, + down: migration_20250326_181520_initial.down, + name: '20250326_181520_initial', }, ] diff --git a/templates/with-vercel-postgres/src/payload-types.ts b/templates/with-vercel-postgres/src/payload-types.ts index 533bc86e73..d3cacc91c9 100644 --- a/templates/with-vercel-postgres/src/payload-types.ts +++ b/templates/with-vercel-postgres/src/payload-types.ts @@ -54,6 +54,7 @@ export type SupportedTimezones = | 'Asia/Singapore' | 'Asia/Tokyo' | 'Asia/Seoul' + | 'Australia/Brisbane' | 'Australia/Sydney' | 'Pacific/Guam' | 'Pacific/Noumea' diff --git a/templates/with-vercel-website/package.json b/templates/with-vercel-website/package.json index 56d143a127..5bbd48f0bf 100644 --- a/templates/with-vercel-website/package.json +++ b/templates/with-vercel-website/package.json @@ -20,17 +20,17 @@ "ci": "payload migrate && pnpm build" }, "dependencies": { - "@payloadcms/admin-bar": "latest", - "@payloadcms/live-preview-react": "latest", - "@payloadcms/next": "latest", - "@payloadcms/payload-cloud": "latest", - "@payloadcms/plugin-form-builder": "latest", - "@payloadcms/plugin-nested-docs": "latest", - "@payloadcms/plugin-redirects": "latest", - "@payloadcms/plugin-search": "latest", - "@payloadcms/plugin-seo": "latest", - "@payloadcms/richtext-lexical": "latest", - "@payloadcms/ui": "latest", + "@payloadcms/admin-bar": "3.31.0", + "@payloadcms/live-preview-react": "3.31.0", + "@payloadcms/next": "3.31.0", + "@payloadcms/payload-cloud": "3.31.0", + "@payloadcms/plugin-form-builder": "3.31.0", + "@payloadcms/plugin-nested-docs": "3.31.0", + "@payloadcms/plugin-redirects": "3.31.0", + "@payloadcms/plugin-search": "3.31.0", + "@payloadcms/plugin-seo": "3.31.0", + "@payloadcms/richtext-lexical": "3.31.0", + "@payloadcms/ui": "3.31.0", "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-select": "^2.0.0", @@ -43,7 +43,7 @@ "lucide-react": "^0.378.0", "next": "15.2.3", "next-sitemap": "^4.2.3", - "payload": "latest", + "payload": "3.31.0", "prism-react-renderer": "^2.3.1", "react": "19.0.0", "react-dom": "19.0.0", @@ -51,8 +51,8 @@ "sharp": "0.32.6", "tailwind-merge": "^2.3.0", "tailwindcss-animate": "^1.0.7", - "@payloadcms/db-vercel-postgres": "latest", - "@payloadcms/storage-vercel-blob": "latest" + "@payloadcms/db-vercel-postgres": "3.31.0", + "@payloadcms/storage-vercel-blob": "3.31.0" }, "devDependencies": { "@eslint/eslintrc": "^3.2.0", diff --git a/templates/with-vercel-website/src/components/Media/ImageMedia/index.tsx b/templates/with-vercel-website/src/components/Media/ImageMedia/index.tsx index 948346ce53..c472254da6 100644 --- a/templates/with-vercel-website/src/components/Media/ImageMedia/index.tsx +++ b/templates/with-vercel-website/src/components/Media/ImageMedia/index.tsx @@ -21,6 +21,7 @@ export const ImageMedia: React.FC = (props) => { const { alt: altFromProps, fill, + pictureClassName, imgClassName, priority, resource, @@ -56,7 +57,7 @@ export const ImageMedia: React.FC = (props) => { .join(', ') return ( - + void onLoad?: () => void diff --git a/templates/with-vercel-website/src/migrations/20250311_214555_initial.json b/templates/with-vercel-website/src/migrations/20250326_181527_initial.json similarity index 99% rename from templates/with-vercel-website/src/migrations/20250311_214555_initial.json rename to templates/with-vercel-website/src/migrations/20250326_181527_initial.json index 830828441b..dcb92e02bc 100644 --- a/templates/with-vercel-website/src/migrations/20250311_214555_initial.json +++ b/templates/with-vercel-website/src/migrations/20250326_181527_initial.json @@ -1,5 +1,5 @@ { - "id": "2dadfab5-c4b0-4ae2-ad54-0b01dbc9a2a9", + "id": "301748ca-6ea5-4be4-a44b-1771a3e1130f", "prevId": "00000000-0000-0000-0000-000000000000", "version": "7", "dialect": "postgresql", @@ -5764,6 +5764,12 @@ "primaryKey": false, "notNull": false }, + "placeholder": { + "name": "placeholder", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, "required": { "name": "required", "type": "boolean", diff --git a/templates/with-vercel-website/src/migrations/20250311_214555_initial.ts b/templates/with-vercel-website/src/migrations/20250326_181527_initial.ts similarity index 99% rename from templates/with-vercel-website/src/migrations/20250311_214555_initial.ts rename to templates/with-vercel-website/src/migrations/20250326_181527_initial.ts index 78ba9f258e..4bbeaae9b3 100644 --- a/templates/with-vercel-website/src/migrations/20250311_214555_initial.ts +++ b/templates/with-vercel-website/src/migrations/20250326_181527_initial.ts @@ -528,6 +528,7 @@ export async function up({ db, payload, req }: MigrateUpArgs): Promise { "label" varchar, "width" numeric, "default_value" varchar, + "placeholder" varchar, "required" boolean, "block_name" varchar ); diff --git a/templates/with-vercel-website/src/migrations/index.ts b/templates/with-vercel-website/src/migrations/index.ts index 22db2ecdc1..6897d678d3 100644 --- a/templates/with-vercel-website/src/migrations/index.ts +++ b/templates/with-vercel-website/src/migrations/index.ts @@ -1,9 +1,9 @@ -import * as migration_20250311_214555_initial from './20250311_214555_initial' +import * as migration_20250326_181527_initial from './20250326_181527_initial' export const migrations = [ { - up: migration_20250311_214555_initial.up, - down: migration_20250311_214555_initial.down, - name: '20250311_214555_initial', + up: migration_20250326_181527_initial.up, + down: migration_20250326_181527_initial.down, + name: '20250326_181527_initial', }, ] diff --git a/templates/with-vercel-website/src/payload-types.ts b/templates/with-vercel-website/src/payload-types.ts index 0873ab7672..4f797274c2 100644 --- a/templates/with-vercel-website/src/payload-types.ts +++ b/templates/with-vercel-website/src/payload-types.ts @@ -54,6 +54,7 @@ export type SupportedTimezones = | 'Asia/Singapore' | 'Asia/Tokyo' | 'Asia/Seoul' + | 'Australia/Brisbane' | 'Australia/Sydney' | 'Pacific/Guam' | 'Pacific/Noumea' @@ -624,6 +625,7 @@ export interface Form { label?: string | null; width?: number | null; defaultValue?: string | null; + placeholder?: string | null; options?: | { label: string; @@ -1355,6 +1357,7 @@ export interface FormsSelect { label?: T; width?: T; defaultValue?: T; + placeholder?: T; options?: | T | { diff --git a/tools/scripts/src/generate-template-variations.ts b/tools/scripts/src/generate-template-variations.ts index c38049a4ab..d57e2dfefd 100644 --- a/tools/scripts/src/generate-template-variations.ts +++ b/tools/scripts/src/generate-template-variations.ts @@ -20,9 +20,9 @@ import minimist from 'minimist' import * as fs from 'node:fs/promises' import path from 'path' -type TemplateVariations = { +type TemplateVariation = { /** Base template to copy from */ - base?: string + base?: 'none' | ({} & string) configureConfig?: boolean db: DbType /** Directory in templates dir */ @@ -56,9 +56,11 @@ async function main() { const args = minimist(process.argv.slice(2)) const template = args['template'] // template directory name + const shouldBuild = args['build'] + const templateRepoUrlBase = `https://github.com/payloadcms/payload/tree/main/templates` - let variations: TemplateVariations[] = [ + let variations: TemplateVariation[] = [ { name: 'payload-vercel-postgres-template', db: 'vercel-postgres', @@ -143,6 +145,21 @@ async function main() { // so we do not configure the payload.config.ts file, which leaves the placeholder comments. configureConfig: false, }, + { + name: 'website', + db: 'mongodb', + dirname: 'website', + generateLockfile: true, + sharp: true, + skipConfig: true, // Do not copy the payload.config.ts file from the base template + storage: 'localDisk', + // The blank template is used as a base for create-payload-app functionality, + // so we do not configure the payload.config.ts file, which leaves the placeholder comments. + configureConfig: false, + base: 'none', + skipDockerCompose: true, + skipReadme: true, + }, ] // If template is set, only generate that template @@ -154,33 +171,37 @@ async function main() { variations = [variation] } - for (const { - name, - base, - configureConfig, - db, - dirname, - envNames, - generateLockfile, - sharp, - skipConfig = false, - skipDockerCompose = false, - skipReadme = false, - storage, - vercelDeployButtonLink, - } of variations) { + for (const variation of variations) { + const { + name, + base, + configureConfig, + db, + dirname, + envNames, + generateLockfile, + sharp, + skipConfig = false, + skipDockerCompose = false, + skipReadme = false, + storage, + vercelDeployButtonLink, + } = variation + header(`Generating ${name}...`) const destDir = path.join(TEMPLATES_DIR, dirname) - copyRecursiveSync(path.join(TEMPLATES_DIR, base || '_template'), destDir, [ - 'node_modules', - '\\*\\.tgz', - '.next', - '.env$', - 'pnpm-lock.yaml', - ...(skipReadme ? ['README.md'] : []), - ...(skipDockerCompose ? ['docker-compose.yml'] : []), - ...(skipConfig ? ['payload.config.ts'] : []), - ]) + if (base !== 'none') { + copyRecursiveSync(path.join(TEMPLATES_DIR, base || '_template'), destDir, [ + 'node_modules', + '\\*\\.tgz', + '.next', + '.env$', + 'pnpm-lock.yaml', + ...(skipReadme ? ['README.md'] : []), + ...(skipDockerCompose ? ['docker-compose.yml'] : []), + ...(skipConfig ? ['payload.config.ts'] : []), + ]) + } log(`Copied to ${destDir}`) @@ -217,6 +238,15 @@ async function main() { }) } + // Fetch latest npm version of payload package: + const version = await getLatestPayloadVersion() + + // Bump package.json versions + await bumpPackageJson({ + templateDir: destDir, + latestVersion: version, + }) + if (generateLockfile) { log('Generating pnpm-lock.yaml') execSyncSafe(`pnpm install --ignore-workspace`, { cwd: destDir }) @@ -254,6 +284,15 @@ async function main() { }) } + // Generate importmap + log('Generating import map') + execSyncSafe(`pnpm --ignore-workspace generate:importmap`, { cwd: destDir }) + + if (shouldBuild) { + log('Building...') + execSyncSafe(`pnpm --ignore-workspace build`, { cwd: destDir }) + } + // TODO: Email? // TODO: Sharp? @@ -271,7 +310,7 @@ async function generateReadme({ destDir, }: { data: { - attributes: Pick + attributes: Pick description: string name: string vercelDeployButtonLink?: string @@ -305,7 +344,7 @@ async function writeEnvExample({ }: { dbType: DbType destDir: string - envNames?: TemplateVariations['envNames'] + envNames?: TemplateVariation['envNames'] }) { const envExamplePath = path.join(destDir, '.env.example') const envFileContents = await fs.readFile(envExamplePath, 'utf8') @@ -378,3 +417,48 @@ function execSyncSafe(command: string, options?: Parameters[1]) throw error } } + +const DO_NOT_BUMP = ['@payloadcms/eslint-config', '@payloadcms/eslint-plugin'] +async function bumpPackageJson({ + templateDir, + latestVersion, +}: { + templateDir: string + latestVersion: string +}) { + const packageJsonString = await fs.readFile(path.resolve(templateDir, 'package.json'), 'utf8') + const packageJson = JSON.parse(packageJsonString) + + for (const key of ['dependencies', 'devDependencies']) { + const dependencies = packageJson[key] + if (dependencies) { + for (const [packageName, _packageVersion] of Object.entries(dependencies)) { + if ( + (packageName === 'payload' || packageName.startsWith('@payloadcms')) && + !DO_NOT_BUMP.includes(packageName) + ) { + dependencies[packageName] = latestVersion + } + } + } + } + + // write it out + await fs.writeFile( + path.resolve(templateDir, 'package.json'), + JSON.stringify(packageJson, null, 2), + ) +} + +async function getLatestPayloadVersion() { + try { + const response = await fetch('https://registry.npmjs.org/payload') + const data = await response.json() + const latestVersion = data['dist-tags'].latest + + return latestVersion + } catch (error) { + console.error('Error fetching Payload version:', error) + throw error + } +} From f34cc637e3fd4738bb5c43fd9f4dbb2db7e8be55 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Wed, 26 Mar 2025 15:04:55 -0600 Subject: [PATCH 28/77] fix(richtext-lexical): incorrectly hidden fields in drawers due to incorrect permissions handling (#11883) Lexical nested fields are currently not set-up to handle access control on the client properly. Despite that, we were passing parent permissions to `RenderFields`, which causes certain fields to not show up if the document does not have `create` permission. --- .../blocks/client/component/index.tsx | 2 +- .../blocks/client/componentInline/index.tsx | 2 +- .../utilities/fieldsDrawer/DrawerContent.tsx | 4 +- .../collections/Lexical/e2e/main/e2e.spec.ts | 28 +++++++++ .../collections/LexicalAccessControl/index.ts | 26 +++++++- test/fields/seed.ts | 62 ++++++++++++++++++- 6 files changed, 117 insertions(+), 7 deletions(-) diff --git a/packages/richtext-lexical/src/features/blocks/client/component/index.tsx b/packages/richtext-lexical/src/features/blocks/client/component/index.tsx index 5b17cda0ad..a8e1990795 100644 --- a/packages/richtext-lexical/src/features/blocks/client/component/index.tsx +++ b/packages/richtext-lexical/src/features/blocks/client/component/index.tsx @@ -507,7 +507,7 @@ export const BlockComponent: React.FC = (props) => { parentIndexPath="" parentPath="" // See Blocks feature path for details as for why this is empty parentSchemaPath={schemaFieldsPath} - permissions={permissions} + permissions={true} readOnly={false} /> {t('fields:saveChanges')} diff --git a/packages/richtext-lexical/src/features/blocks/client/componentInline/index.tsx b/packages/richtext-lexical/src/features/blocks/client/componentInline/index.tsx index b707613386..9df01e47f9 100644 --- a/packages/richtext-lexical/src/features/blocks/client/componentInline/index.tsx +++ b/packages/richtext-lexical/src/features/blocks/client/componentInline/index.tsx @@ -417,7 +417,7 @@ export const InlineBlockComponent: React.FC = (props) => { parentIndexPath="" parentPath="" // See Blocks feature path for details as for why this is empty parentSchemaPath={schemaFieldsPath} - permissions={permissions} + permissions={true} readOnly={false} /> {t('fields:saveChanges')} diff --git a/packages/richtext-lexical/src/utilities/fieldsDrawer/DrawerContent.tsx b/packages/richtext-lexical/src/utilities/fieldsDrawer/DrawerContent.tsx index 0377ce1120..b1d8f535f8 100644 --- a/packages/richtext-lexical/src/utilities/fieldsDrawer/DrawerContent.tsx +++ b/packages/richtext-lexical/src/utilities/fieldsDrawer/DrawerContent.tsx @@ -37,7 +37,7 @@ export const DrawerContent: React.FC(false) const { - fieldProps: { featureClientSchemaMap, permissions }, + fieldProps: { featureClientSchemaMap }, } = useEditorConfigContext() const { getFormState } = useServerFunctions() @@ -155,7 +155,7 @@ export const DrawerContent: React.FC {t('fields:saveChanges')} diff --git a/test/fields/collections/Lexical/e2e/main/e2e.spec.ts b/test/fields/collections/Lexical/e2e/main/e2e.spec.ts index 64027d9fc5..a6eb05fc82 100644 --- a/test/fields/collections/Lexical/e2e/main/e2e.spec.ts +++ b/test/fields/collections/Lexical/e2e/main/e2e.spec.ts @@ -1135,6 +1135,33 @@ describe('lexicalMain', () => { await expect(urlInput).toBeVisible() }) + test('ensure link drawer displays nested block fields if document does not have `create` permission', async () => { + await navigateToLexicalFields(true, 'lexical-access-control') + const richTextField = page.locator('.rich-text-lexical').first() + await richTextField.scrollIntoViewIfNeeded() + await expect(richTextField).toBeVisible() + + const link = richTextField.locator('.LexicalEditorTheme__link').first() + await link.scrollIntoViewIfNeeded() + await expect(link).toBeVisible() + await link.click({ + // eslint-disable-next-line playwright/no-force-option + force: true, + button: 'left', + }) + + await expect(page.locator('.link-edit')).toBeVisible() + await page.locator('.link-edit').click() + + const linkDrawer = page.locator('dialog[id^=drawer_1_lexical-rich-text-link-]').first() + await expect(linkDrawer).toBeVisible() + + const blockTextInput = linkDrawer.locator('#field-blocks__0__text').first() + + await expect(blockTextInput).toBeVisible() + await expect(blockTextInput).toBeEditable() + }) + test('lexical cursor / selection should be preserved when swapping upload field and clicking within with its list drawer', async () => { await navigateToLexicalFields() const richTextField = page.locator('.rich-text-lexical').first() @@ -1494,6 +1521,7 @@ describe('lexicalMain', () => { expect(htmlContent).not.toContain('Cargando...') expect(htmlContent).toContain('Start typing, or press') }) + // eslint-disable-next-line playwright/expect-expect, playwright/no-skipped-test test.skip('ensure simple localized lexical field works', async () => { await navigateToLexicalFields(true, 'lexical-localized-fields') }) diff --git a/test/fields/collections/LexicalAccessControl/index.ts b/test/fields/collections/LexicalAccessControl/index.ts index db015bb9a1..7863c76e74 100644 --- a/test/fields/collections/LexicalAccessControl/index.ts +++ b/test/fields/collections/LexicalAccessControl/index.ts @@ -1,6 +1,6 @@ import type { CollectionConfig } from 'payload' -import { defaultEditorFeatures, lexicalEditor } from '@payloadcms/richtext-lexical' +import { defaultEditorFeatures, lexicalEditor, LinkFeature } from '@payloadcms/richtext-lexical' import { lexicalAccessControlSlug } from '../../slugs.js' @@ -22,7 +22,29 @@ export const LexicalAccessControl: CollectionConfig = { name: 'richText', type: 'richText', editor: lexicalEditor({ - features: [...defaultEditorFeatures], + features: [ + ...defaultEditorFeatures, + LinkFeature({ + fields: ({ defaultFields }) => [ + ...defaultFields, + { + name: 'blocks', + type: 'blocks', + blocks: [ + { + slug: 'block', + fields: [ + { + name: 'text', + type: 'text', + }, + ], + }, + ], + }, + ], + }), + ], }), }, ], diff --git a/test/fields/seed.ts b/test/fields/seed.ts index ead7d9100a..65510dcc32 100644 --- a/test/fields/seed.ts +++ b/test/fields/seed.ts @@ -591,7 +591,67 @@ export const seed = async (_payload: Payload) => { await _payload.create({ collection: 'lexical-access-control', data: { - richText: textToLexicalJSON({ text: 'text' }), + richText: { + root: { + children: [ + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: 'text ', + type: 'text', + version: 1, + }, + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: 'link', + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'link', + version: 3, + fields: { + url: 'https://', + newTab: false, + linkType: 'custom', + blocks: [ + { + id: '67e45673cbd5181ca8cbeef7', + blockType: 'block', + }, + ], + }, + id: '67e4566fcbd5181ca8cbeef5', + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'paragraph', + version: 1, + textFormat: 0, + textStyle: '', + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'root', + version: 1, + }, + }, title: 'title', }, depth: 0, From b863fd0915627d8f07751a2a60f6e089cec116ed Mon Sep 17 00:00:00 2001 From: Pranav <92295653+pranav-vaniya@users.noreply.github.com> Date: Thu, 27 Mar 2025 21:28:25 +0530 Subject: [PATCH 29/77] docs: correct spelling of "it" (#11889) Correct spelling of "it" in configuration/overview.mdx --- docs/configuration/overview.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/overview.mdx b/docs/configuration/overview.mdx index cf14f14a51..092ddb2ab0 100644 --- a/docs/configuration/overview.mdx +++ b/docs/configuration/overview.mdx @@ -147,7 +147,7 @@ _\* Config location detection is different between development and production en **Important:** Ensure your `tsconfig.json` is properly configured for Payload - to auto-detect your config location. If if does not exist, or does not specify + to auto-detect your config location. If it does not exist, or does not specify the proper `compilerOptions`, Payload will default to the current working directory. From 21f7ba7b9d1bdd1b4fc4cd5105058394e781180d Mon Sep 17 00:00:00 2001 From: Philipp Schneider <47689073+philipp-tailor@users.noreply.github.com> Date: Thu, 27 Mar 2025 23:22:41 +0100 Subject: [PATCH 30/77] feat: change version view `modifiedOnly` default to `true` (#11794) Replaces a more elaborate approach from https://github.com/payloadcms/payload/pull/11520 with the simplest solution, just changing the default. --- packages/next/src/views/Version/Default/index.tsx | 6 +++--- packages/next/src/views/Version/index.tsx | 2 +- test/versions/e2e.spec.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/next/src/views/Version/Default/index.tsx b/packages/next/src/views/Version/Default/index.tsx index 034243c3d0..69f0d43f01 100644 --- a/packages/next/src/views/Version/Default/index.tsx +++ b/packages/next/src/views/Version/Default/index.tsx @@ -83,10 +83,10 @@ export const DefaultVersionView: React.FC = ({ current.set('localeCodes', JSON.stringify(selectedLocales.map((locale) => locale.value))) } - if (!modifiedOnly) { - current.delete('modifiedOnly') + if (modifiedOnly === false) { + current.set('modifiedOnly', 'false') } else { - current.set('modifiedOnly', 'true') + current.delete('modifiedOnly') } const search = current.toString() diff --git a/packages/next/src/views/Version/index.tsx b/packages/next/src/views/Version/index.tsx index 30a53a84d7..bd30670ca1 100644 --- a/packages/next/src/views/Version/index.tsx +++ b/packages/next/src/views/Version/index.tsx @@ -40,7 +40,7 @@ export async function VersionView(props: DocumentViewServerProps) { const comparisonVersionIDFromParams: string = searchParams.compareValue as string - const modifiedOnly: boolean = searchParams.modifiedOnly === 'true' + const modifiedOnly: boolean = searchParams.modifiedOnly === 'false' ? false : true const { localization } = config diff --git a/test/versions/e2e.spec.ts b/test/versions/e2e.spec.ts index 42b3ea139b..e02a633030 100644 --- a/test/versions/e2e.spec.ts +++ b/test/versions/e2e.spec.ts @@ -1197,11 +1197,11 @@ describe('Versions', () => { const textInArrayES = page.locator('[data-field-path="arrayLocalized"][data-locale="es"]') - await expect(textInArrayES).toContainText('No Array Localizeds found') + await expect(textInArrayES).toBeHidden() await page.locator('#modifiedOnly').click() - await expect(textInArrayES).toBeHidden() + await expect(textInArrayES).toContainText('No Array Localizeds found') }) test('correctly renders diff for block fields', async () => { From 2b6313ed4854488ee3f1aec267d7a07dd77951ed Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Fri, 28 Mar 2025 00:39:06 -0600 Subject: [PATCH 31/77] docs: fix invalid react-hooks docs (#11895) Our current react-docs page is not accessible due to an mdx parsing error, caused by a recent introduction of invalid syntax. This PR fixes it --- docs/admin/react-hooks.mdx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/admin/react-hooks.mdx b/docs/admin/react-hooks.mdx index 7dcd2a2f80..96c435c31e 100644 --- a/docs/admin/react-hooks.mdx +++ b/docs/admin/react-hooks.mdx @@ -474,7 +474,7 @@ Field: '/path/to/CustomArrayManagerField', rows={[ [ { - value: '**\\`path\\`**', + value: '**\\\`path\\\`**', }, { value: 'The path to the array or block field', @@ -482,7 +482,7 @@ Field: '/path/to/CustomArrayManagerField', ], [ { - value: '**\\`rowIndex\\`**', + value: '**\\\`rowIndex\\\`**', }, { value: 'The index of the row to remove', @@ -561,7 +561,7 @@ Field: '/path/to/CustomArrayManagerField', rows={[ [ { - value: '**\\`path\\`**', + value: '**\\\`path\\\`**', }, { value: 'The path to the array or block field', @@ -569,7 +569,7 @@ Field: '/path/to/CustomArrayManagerField', ], [ { - value: '**\\`rowIndex\\`**', + value: '**\\\`rowIndex\\\`**', }, { value: 'The index of the row to replace', @@ -577,7 +577,7 @@ Field: '/path/to/CustomArrayManagerField', ], [ { - value: '**\\`data\\`**', + value: '**\\\`data\\\`**', }, { value: 'The data to replace within the row', @@ -718,7 +718,7 @@ The `useDocumentInfo` hook provides information about the current document being | **`currentEditor`** | The user currently editing the document. | | **`docConfig`** | Either the Collection or Global config of the document, depending on what is being edited. | | **`docPermissions`** | The current document's permissions. Fallback to collection permissions when no id is present. | -| **`documentIsLocked`** | Whether the document is currently locked by another user. [More details](./locked-documents). | +| **`documentIsLocked`** | Whether the document is currently locked by another user. [More details](./locked-documents). | | **`getDocPermissions`** | Method to retrieve document-level permissions. | | **`getDocPreferences`** | Method to retrieve document-level user preferences. [More details](./preferences). | | **`globalSlug`** | The slug of the global if editing a global document. | @@ -730,7 +730,7 @@ The `useDocumentInfo` hook provides information about the current document being | **`initialData`** | The initial data of the document. | | **`isEditing`** | Whether the document is being edited (as opposed to created). | | **`isInitializing`** | Whether the document info is still initializing. | -| **`isLocked`** | Whether the document is locked. [More details](./locked-documents). | +| **`isLocked`** | Whether the document is locked. [More details](./locked-documents). | | **`lastUpdateTime`** | Timestamp of the last update to the document. | | **`mostRecentVersionIsAutosaved`** | Whether the most recent version is an autosaved version. | | **`preferencesKey`** | The `preferences` key to use when interacting with document-level user preferences. [More details](./preferences). | @@ -739,9 +739,9 @@ The `useDocumentInfo` hook provides information about the current document being | **`setDocumentTitle`** | Method to set the document title. | | **`setHasPublishedDoc`** | Method to update whether the document has been published. | | **`title`** | The title of the document. | -| **`unlockDocument`** | Method to unlock a document. [More details](./locked-documents). | +| **`unlockDocument`** | Method to unlock a document. [More details](./locked-documents). | | **`unpublishedVersionCount`** | The number of unpublished versions of the document. | -| **`updateDocumentEditor`** | Method to update who is currently editing the document. [More details](./locked-documents). | +| **`updateDocumentEditor`** | Method to update who is currently editing the document. [More details](./locked-documents). | | **`updateSavedDocumentData`** | Method to update the saved document data. | | **`uploadStatus`** | Status of any uploads in progress ('idle', 'uploading', or 'failed'). | | **`versionCount`** | The current version count of the document. | From 62c4e81a1faaaed42b91b8ad84626ed7cdc9a1c0 Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Fri, 28 Mar 2025 13:54:15 -0400 Subject: [PATCH 32/77] refactor(ui): replace autosave queue pattern with useQueues hook (#11884) Replaces the queue pattern used within autosave with the `useQueues` hook introduced in #11579. To do this, queued tasks now accept an options object with callbacks which can be used to tie into events of the process, such as before it begins to prevent it from running, and after it has finished to perform side effects. The `useQueues` hook now also maintains an array of queued tasks as opposed to individual refs. --- packages/ui/src/elements/Autosave/index.tsx | 286 +++++++++----------- packages/ui/src/hooks/useQueues.ts | 90 ++++-- 2 files changed, 194 insertions(+), 182 deletions(-) diff --git a/packages/ui/src/elements/Autosave/index.tsx b/packages/ui/src/elements/Autosave/index.tsx index 73f42f4a86..babac56a67 100644 --- a/packages/ui/src/elements/Autosave/index.tsx +++ b/packages/ui/src/elements/Autosave/index.tsx @@ -11,20 +11,20 @@ import { useAllFormFields, useForm, useFormModified, - useFormProcessing, useFormSubmitted, } from '../../forms/Form/context.js' import { useDebounce } from '../../hooks/useDebounce.js' import { useEffectEvent } from '../../hooks/useEffectEvent.js' +import { useQueues } from '../../hooks/useQueues.js' import { useConfig } from '../../providers/Config/index.js' import { useDocumentEvents } from '../../providers/DocumentEvents/index.js' import { useDocumentInfo } from '../../providers/DocumentInfo/index.js' import { useLocale } from '../../providers/Locale/index.js' -import './index.scss' import { useTranslation } from '../../providers/Translation/index.js' import { formatTimeToNow } from '../../utilities/formatDocTitle/formatDateTitle.js' import { reduceFieldsToValuesWithValidation } from '../../utilities/reduceFieldsToValuesWithValidation.js' import { LeaveWithoutSaving } from '../LeaveWithoutSaving/index.js' +import './index.scss' const baseClass = 'autosave' // The minimum time the saving state should be shown @@ -54,12 +54,9 @@ export const Autosave: React.FC = ({ id, collection, global: globalDoc }) setUnpublishedVersionCount, updateSavedDocumentData, } = useDocumentInfo() - const queueRef = useRef([]) - const isProcessingRef = useRef(false) const { reportUpdate } = useDocumentEvents() const { dispatchFields, isValid, setBackgroundProcessing, setIsValid, setSubmitted } = useForm() - const isFormProcessing = useFormProcessing() const [fields] = useAllFormFields() const modified = useFormModified() @@ -105,43 +102,7 @@ export const Autosave: React.FC = ({ id, collection, global: globalDoc }) // can always retrieve the most to date locale localeRef.current = locale - const processQueue = React.useCallback(async () => { - if (isProcessingRef.current || queueRef.current.length === 0) { - return - } - - // Do not autosave if the form is already processing (e.g. if the user clicked the publish button - // right before this autosave runs), as parallel updates could cause conflicts - if (isFormProcessing) { - queueRef.current = [] - return - } - - if (!isValidRef.current) { - // Clear queue so we don't end up in an infinite loop - queueRef.current = [] - // Reset internal validation state so queue processing can run again - isValidRef.current = true - return - } - isProcessingRef.current = true - - const latestAction = queueRef.current[queueRef.current.length - 1] - queueRef.current = [] - - setBackgroundProcessing(true) - - try { - await latestAction() - } finally { - isProcessingRef.current = false - setBackgroundProcessing(false) - if (queueRef.current.length > 0) { - await processQueue() - } - } - setBackgroundProcessing(false) - }, [isFormProcessing, setBackgroundProcessing]) + const { queueTask } = useQueues() const autosaveTimeoutRef = useRef(null) @@ -165,142 +126,155 @@ export const Autosave: React.FC = ({ id, collection, global: globalDoc }) } } - const autosave = async () => { - if (modified) { - startTimestamp = new Date().getTime() + queueTask( + async () => { + if (modified) { + startTimestamp = new Date().getTime() - setSaving(true) + setSaving(true) - let url: string - let method: string - let entitySlug: string + let url: string + let method: string + let entitySlug: string - if (collection && id) { - entitySlug = collection.slug - url = `${serverURL}${api}/${entitySlug}/${id}?draft=true&autosave=true&locale=${localeRef.current}` - method = 'PATCH' - } + if (collection && id) { + entitySlug = collection.slug + url = `${serverURL}${api}/${entitySlug}/${id}?draft=true&autosave=true&locale=${localeRef.current}` + method = 'PATCH' + } - if (globalDoc) { - entitySlug = globalDoc.slug - url = `${serverURL}${api}/globals/${entitySlug}?draft=true&autosave=true&locale=${localeRef.current}` - method = 'POST' - } + if (globalDoc) { + entitySlug = globalDoc.slug + url = `${serverURL}${api}/globals/${entitySlug}?draft=true&autosave=true&locale=${localeRef.current}` + method = 'POST' + } - if (url) { - if (modifiedRef.current) { - const { data, valid } = reduceFieldsToValuesWithValidation(fieldRef.current, true) + if (url) { + if (modifiedRef.current) { + const { data, valid } = reduceFieldsToValuesWithValidation(fieldRef.current, true) - data._status = 'draft' + data._status = 'draft' - const skipSubmission = - submitted && !valid && versionsConfig?.drafts && versionsConfig?.drafts?.validate + const skipSubmission = + submitted && !valid && versionsConfig?.drafts && versionsConfig?.drafts?.validate - if (!skipSubmission && isValidRef.current) { - let res - try { - res = await fetch(url, { - body: JSON.stringify(data), - credentials: 'include', - headers: { - 'Accept-Language': i18n.language, - 'Content-Type': 'application/json', - }, - method, - }) - } catch (error) { - // Swallow Error - } + if (!skipSubmission && isValidRef.current) { + let res - const newDate = new Date() - // We need to log the time in order to figure out if we need to trigger the state off later - endTimestamp = newDate.getTime() - - if (res.status === 200) { - setLastUpdateTime(newDate.getTime()) - - reportUpdate({ - id, - entitySlug, - updatedAt: newDate.toISOString(), - }) - - if (!mostRecentVersionIsAutosaved) { - incrementVersionCount() - setMostRecentVersionIsAutosaved(true) - setUnpublishedVersionCount((prev) => prev + 1) - } - } - const json = await res.json() - - if (versionsConfig?.drafts && versionsConfig?.drafts?.validate && json?.errors) { - if (Array.isArray(json.errors)) { - const [fieldErrors, nonFieldErrors] = json.errors.reduce( - ([fieldErrs, nonFieldErrs], err) => { - const newFieldErrs = [] - const newNonFieldErrs = [] - - if (err?.message) { - newNonFieldErrs.push(err) - } - - if (Array.isArray(err?.data)) { - err.data.forEach((dataError) => { - if (dataError?.field) { - newFieldErrs.push(dataError) - } else { - newNonFieldErrs.push(dataError) - } - }) - } - - return [ - [...fieldErrs, ...newFieldErrs], - [...nonFieldErrs, ...newNonFieldErrs], - ] + try { + res = await fetch(url, { + body: JSON.stringify(data), + credentials: 'include', + headers: { + 'Accept-Language': i18n.language, + 'Content-Type': 'application/json', }, - [[], []], - ) + method, + }) + } catch (_err) { + // Swallow Error + } - dispatchFields({ - type: 'ADD_SERVER_ERRORS', - errors: fieldErrors, + const newDate = new Date() + // We need to log the time in order to figure out if we need to trigger the state off later + endTimestamp = newDate.getTime() + + if (res.status === 200) { + setLastUpdateTime(newDate.getTime()) + + reportUpdate({ + id, + entitySlug, + updatedAt: newDate.toISOString(), }) - nonFieldErrors.forEach((err) => { - toast.error(err.message || i18n.t('error:unknown')) - }) - - // Set valid to false internally so the queue doesn't process - isValidRef.current = false - setIsValid(false) - setSubmitted(true) - hideIndicator() - return + if (!mostRecentVersionIsAutosaved) { + incrementVersionCount() + setMostRecentVersionIsAutosaved(true) + setUnpublishedVersionCount((prev) => prev + 1) + } } - } else { - // If it's not an error then we can update the document data inside the context - const document = json?.doc || json?.result + const json = await res.json() - // Manually update the data since this function doesn't fire the `submit` function from useForm - if (document) { - setIsValid(true) + if (versionsConfig?.drafts && versionsConfig?.drafts?.validate && json?.errors) { + if (Array.isArray(json.errors)) { + const [fieldErrors, nonFieldErrors] = json.errors.reduce( + ([fieldErrs, nonFieldErrs], err) => { + const newFieldErrs = [] + const newNonFieldErrs = [] - // Reset internal state allowing the queue to process - isValidRef.current = true - updateSavedDocumentData(document) + if (err?.message) { + newNonFieldErrs.push(err) + } + + if (Array.isArray(err?.data)) { + err.data.forEach((dataError) => { + if (dataError?.field) { + newFieldErrs.push(dataError) + } else { + newNonFieldErrs.push(dataError) + } + }) + } + + return [ + [...fieldErrs, ...newFieldErrs], + [...nonFieldErrs, ...newNonFieldErrs], + ] + }, + [[], []], + ) + + dispatchFields({ + type: 'ADD_SERVER_ERRORS', + errors: fieldErrors, + }) + + nonFieldErrors.forEach((err) => { + toast.error(err.message || i18n.t('error:unknown')) + }) + + // Set valid to false internally so the queue doesn't process + isValidRef.current = false + setIsValid(false) + setSubmitted(true) + hideIndicator() + return + } + } else { + // If it's not an error then we can update the document data inside the context + const document = json?.doc || json?.result + + // Manually update the data since this function doesn't fire the `submit` function from useForm + if (document) { + setIsValid(true) + + // Reset internal state allowing the queue to process + isValidRef.current = true + updateSavedDocumentData(document) + } } + + hideIndicator() } - - hideIndicator() } } } - } - } + }, + { + afterProcess: () => { + setBackgroundProcessing(false) + }, + beforeProcess: () => { + if (!isValidRef.current) { + isValidRef.current = true + return false + } - queueRef.current.push(autosave) - void processQueue() + setBackgroundProcessing(true) + }, + }, + ) }) const didMount = useRef(false) diff --git a/packages/ui/src/hooks/useQueues.ts b/packages/ui/src/hooks/useQueues.ts index 45121b6858..5dcaf849eb 100644 --- a/packages/ui/src/hooks/useQueues.ts +++ b/packages/ui/src/hooks/useQueues.ts @@ -1,47 +1,85 @@ import { useCallback, useRef } from 'react' +type QueuedFunction = () => Promise + +type QueuedTaskOptions = { + /** + * A function that is called after the queue has processed a function + * Used to perform side effects after processing the queue + * @returns {void} + */ + afterProcess?: () => void + /** + * A function that can be used to prevent the queue from processing under certain conditions + * Can also be used to perform side effects before processing the queue + * @returns {boolean} If `false`, the queue will not process + */ + beforeProcess?: () => boolean +} + +type QueueTask = (fn: QueuedFunction, options?: QueuedTaskOptions) => void + +/** + * A React hook that allows you to queue up functions to be executed in order. + * This is useful when you need to ensure long running networks requests are processed sequentially. + * Builds up a "queue" of functions to be executed in order, only ever processing the last function in the queue. + * This ensures that a long queue of tasks doesn't cause a backlog of tasks to be processed. + * E.g. if you queue a task and it begins running, then you queue 9 more tasks: + * 1. The currently task will finish + * 2. The next task in the queue will run + * 3. All remaining tasks will be discarded + * @returns {queueTask} A function used to queue a function. + * @example + * const { queueTask } = useQueues() + * queueTask(async () => { + * await fetch('https://api.example.com') + * }) + */ export function useQueues(): { - queueTask: (fn: (signal: AbortSignal) => Promise) => void + queueTask: QueueTask } { - const runningTaskRef = useRef>(null) - const queuedTask = useRef<((signal: AbortSignal) => Promise) | null>(null) - const abortControllerRef = useRef(null) + const queue = useRef([]) - const queueTask = useCallback((fn: (signal: AbortSignal) => Promise) => { - // Overwrite the queued task every time a new one arrives - queuedTask.current = fn + const isProcessing = useRef(false) - // If a task is already running, abort it and return - if (runningTaskRef.current !== null) { - if (abortControllerRef.current) { - abortControllerRef.current.abort() + const queueTask = useCallback((fn, options) => { + queue.current.push(fn) + + async function processQueue() { + if (isProcessing.current) { + return } - return - } + // Allow the consumer to prevent the queue from processing under certain conditions + if (typeof options?.beforeProcess === 'function') { + const shouldContinue = options.beforeProcess() - const executeTask = async () => { - while (queuedTask.current) { - const taskToRun = queuedTask.current - queuedTask.current = null // Reset latest task before running + if (shouldContinue === false) { + return + } + } - const controller = new AbortController() - abortControllerRef.current = controller + while (queue.current.length > 0) { + const latestTask = queue.current.pop() // Only process the last task in the queue + queue.current = [] // Discard all other tasks + + isProcessing.current = true try { - runningTaskRef.current = taskToRun(controller.signal) - await runningTaskRef.current // Wait for the task to complete + await latestTask() } catch (err) { - if (err.name !== 'AbortError') { - console.error('Error in queued function:', err) // eslint-disable-line no-console - } + console.error('Error in queued function:', err) // eslint-disable-line no-console } finally { - runningTaskRef.current = null + isProcessing.current = false + + if (typeof options?.afterProcess === 'function') { + options.afterProcess() + } } } } - void executeTask() + void processQueue() }, []) return { queueTask } From 4a0bc869ddeec167c074b628894e31573afbf84c Mon Sep 17 00:00:00 2001 From: Maxim Seshuk Date: Sat, 29 Mar 2025 00:49:28 +0300 Subject: [PATCH 33/77] fix(ui): switching languages does not update cached client config (#11725) ### What? Fixed client config caching to properly update when switching languages in the admin UI. ### Why? Currently, switching languages doesn't fully update the UI because client config stays cached with previous language translations. ### How? Created a language-aware caching system that stores separate configs for each language and only uses cached config when it matches the active language. Before: ```typescript let cachedClientConfig: ClientConfig | null = global._payload_clientConfig if (!cachedClientConfig) { cachedClientConfig = global._payload_clientConfig = null } export const getClientConfig = cache( (args: { config: SanitizedConfig; i18n: I18nClient; importMap: ImportMap }): ClientConfig => { if (cachedClientConfig && !global._payload_doNotCacheClientConfig) { return cachedClientConfig } // ... create new config ... } ); ``` After: ```typescript let cachedClientConfigs: Record = global._payload_localizedClientConfigs if (!cachedClientConfigs) { cachedClientConfigs = global._payload_localizedClientConfigs = {} } export const getClientConfig = cache( (args: { config: SanitizedConfig; i18n: I18nClient; importMap: ImportMap }): ClientConfig => { const { config, i18n, importMap } = args const currentLocale = i18n.language if (!global._payload_doNotCacheClientConfig && cachedClientConfigs[currentLocale]) { return cachedClientConfigs[currentLocale] } // ... create new config with correct translations ... } ); ``` Also added handling for cache clearing during HMR to ensure compatibility with the existing system. Fixes #11406 --------- Co-authored-by: Jacob Fletcher --- packages/payload/src/index.ts | 7 ++++- packages/ui/src/utilities/getClientConfig.ts | 29 ++++++++++++-------- test/i18n/e2e.spec.ts | 23 ++++++++++++++++ 3 files changed, 47 insertions(+), 12 deletions(-) diff --git a/packages/payload/src/index.ts b/packages/payload/src/index.ts index ad401c8cbb..39139fbf89 100644 --- a/packages/payload/src/index.ts +++ b/packages/payload/src/index.ts @@ -65,8 +65,11 @@ import type { } from './types/index.js' import type { TraverseFieldsCallback } from './utilities/traverseFields.js' export type * from './admin/types.js' +import type { SupportedLanguages } from '@payloadcms/translations' + import { Cron } from 'croner' +import type { ClientConfig } from './config/client.js' import type { TypeWithVersion } from './versions/types.js' import { decrypt, encrypt } from './auth/crypto.js' @@ -865,10 +868,12 @@ export const reload = async ( } await payload.db.init() + if (payload.db.connect) { await payload.db.connect({ hotReload: true }) } - global._payload_clientConfig = null + + global._payload_clientConfigs = {} as Record global._payload_schemaMap = null global._payload_clientSchemaMap = null global._payload_doNotCacheClientConfig = true // This will help refreshing the client config cache more reliably. If you remove this, please test HMR + client config refreshing (do new fields appear in the document?) diff --git a/packages/ui/src/utilities/getClientConfig.ts b/packages/ui/src/utilities/getClientConfig.ts index ae5629a868..4bf4c1b54b 100644 --- a/packages/ui/src/utilities/getClientConfig.ts +++ b/packages/ui/src/utilities/getClientConfig.ts @@ -1,31 +1,38 @@ -import type { I18nClient } from '@payloadcms/translations' +import type { I18nClient, SupportedLanguages } from '@payloadcms/translations' import type { ClientConfig, ImportMap, SanitizedConfig } from 'payload' import { createClientConfig } from 'payload' import { cache } from 'react' -let cachedClientConfig: ClientConfig | null = global._payload_clientConfig +let cachedClientConfigs = global._payload_clientConfigs as Record< + keyof SupportedLanguages, + ClientConfig +> -if (!cachedClientConfig) { - cachedClientConfig = global._payload_clientConfig = null +if (!cachedClientConfigs) { + cachedClientConfigs = global._payload_clientConfigs = {} as Record< + keyof SupportedLanguages, + ClientConfig + > } export const getClientConfig = cache( (args: { config: SanitizedConfig; i18n: I18nClient; importMap: ImportMap }): ClientConfig => { - if (cachedClientConfig && !global._payload_doNotCacheClientConfig) { - return cachedClientConfig + const { config, i18n, importMap } = args + const currentLanguage = i18n.language + + if (cachedClientConfigs[currentLanguage] && !global._payload_doNotCacheClientConfig) { + return cachedClientConfigs[currentLanguage] } - const { config, i18n, importMap } = args - - cachedClientConfig = createClientConfig({ + const cachedClientConfig = createClientConfig({ config, i18n, importMap, }) - global._payload_clientConfig = cachedClientConfig - + cachedClientConfigs[currentLanguage] = cachedClientConfig + global._payload_clientConfigs = cachedClientConfigs global._payload_doNotCacheClientConfig = false return cachedClientConfig diff --git a/test/i18n/e2e.spec.ts b/test/i18n/e2e.spec.ts index 8880a8ec05..a1b7587c52 100644 --- a/test/i18n/e2e.spec.ts +++ b/test/i18n/e2e.spec.ts @@ -82,4 +82,27 @@ describe('i18n', () => { page.locator('.componentWithCustomI18n .componentWithCustomI18nCustomValidI18nT'), ).toHaveText('My custom translation') }) + + test('ensure translations update correctly when switching language', async () => { + await page.goto(serverURL + '/admin/account') + + await page.locator('div.rs__control').click() + await page.locator('div.rs__option').filter({ hasText: 'English' }).click() + await expect(page.locator('div.payload-settings h3')).toHaveText('Payload Settings') + + await page.goto(serverURL + '/admin/collections/collection1/create') + await expect(page.locator('label[for="field-fieldDefaultI18nValid"]')).toHaveText( + 'Add {{label}}', + ) + + await page.goto(serverURL + '/admin/account') + await page.locator('div.rs__control').click() + await page.locator('div.rs__option').filter({ hasText: 'Español' }).click() + await expect(page.locator('div.payload-settings h3')).toHaveText('Configuración de la carga') + + await page.goto(serverURL + '/admin/collections/collection1/create') + await expect(page.locator('label[for="field-fieldDefaultI18nValid"]')).toHaveText( + 'Añadir {{label}}', + ) + }) }) From 70b9cab3932ae3ec02ca3309c3890ea3f1652d65 Mon Sep 17 00:00:00 2001 From: Said Akhrarov <36972061+akhrarovsaid@users.noreply.github.com> Date: Fri, 28 Mar 2025 21:02:05 -0400 Subject: [PATCH 34/77] test: deflake indexed e2e (#11911) ### What? This PR aims to deflake the indexed fields e2e test in `test/fields/collections/Indexed/e2e.spec.ts`. The issue is that this test is setup in a way where sometimes two toasts will present themselves in the ui. The second toast assertion will fail with a strict mode violation as the toast locator will resolve to two elements. ### Why? To prevent this test from flaking in ci. ### How? Adding a new `dismissAfterAssertion` flag to the `assertToastErrors` helper function which dismisses the toasts. This way, the toasts will not raise the aforementioned error as they will be dismissed from the ui. The logic is handled in a separate loop through such that the assertions occur first. This is done so that dismissing a toast does not surface errors due to the order of toasts being shown changing. --- test/fields/collections/Indexed/e2e.spec.ts | 1 + test/helpers/assertToastErrors.ts | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/test/fields/collections/Indexed/e2e.spec.ts b/test/fields/collections/Indexed/e2e.spec.ts index b0954cfbb2..cb90de6806 100644 --- a/test/fields/collections/Indexed/e2e.spec.ts +++ b/test/fields/collections/Indexed/e2e.spec.ts @@ -100,6 +100,7 @@ describe('Radio', () => { await assertToastErrors({ page, errors: ['uniqueText'], + dismissAfterAssertion: true, }) await expect.poll(() => page.url(), { timeout: POLL_TOPASS_TIMEOUT }).toContain('create') diff --git a/test/helpers/assertToastErrors.ts b/test/helpers/assertToastErrors.ts index cc39c0e11e..3d1667184c 100644 --- a/test/helpers/assertToastErrors.ts +++ b/test/helpers/assertToastErrors.ts @@ -5,7 +5,9 @@ import { expect } from '@playwright/test' export async function assertToastErrors({ page, errors, + dismissAfterAssertion, }: { + dismissAfterAssertion?: boolean errors: string[] page: Page }): Promise { @@ -24,4 +26,13 @@ export async function assertToastErrors({ ).toHaveText(error) } } + + if (dismissAfterAssertion) { + const closeButtons = page.locator('.payload-toast-container button.payload-toast-close-button') + const count = await closeButtons.count() + + for (let i = 0; i < count; i++) { + await closeButtons.nth(i).click() + } + } } From d1c0989da70d42c02f939bce5bfb0ca09d4d9446 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Sat, 29 Mar 2025 10:58:54 -0600 Subject: [PATCH 35/77] perf: prefer async fs calls (#11918) Synchronous file system operations such as `readFileSync` block the event loop, whereas the asynchronous equivalents (like await `fs.promises.readFile`) do not. This PR replaces certain synchronous fs calls with their asynchronous counterparts in contexts where async operations are already in use, improving performance by avoiding event loop blocking. Most of the synchronous calls were in our file upload code. Converting them to async should theoretically free up the event loop and allow more, other requests to run in parallel without delay --- packages/payload/src/bin/generateImportMap/index.ts | 6 +++--- packages/payload/src/bin/generateTypes.ts | 6 +++--- packages/payload/src/uploads/deleteAssociatedFiles.ts | 6 +++--- packages/payload/src/uploads/fileExists.ts | 4 ++-- packages/payload/src/uploads/generateFileData.ts | 9 ++++----- packages/payload/src/uploads/getFileByPath.ts | 6 +++--- packages/payload/src/uploads/getImageSize.ts | 4 ++-- packages/payload/src/uploads/imageResizer.ts | 4 ++-- packages/payload/src/uploads/saveBufferToFile.ts | 4 ++-- packages/payload/src/uploads/tempFile.ts | 8 ++++---- packages/payload/src/uploads/unlinkTempFiles.ts | 7 ++----- 11 files changed, 30 insertions(+), 34 deletions(-) diff --git a/packages/payload/src/bin/generateImportMap/index.ts b/packages/payload/src/bin/generateImportMap/index.ts index c66e63c8e9..4b3fa6bf82 100644 --- a/packages/payload/src/bin/generateImportMap/index.ts +++ b/packages/payload/src/bin/generateImportMap/index.ts @@ -1,5 +1,5 @@ /* eslint-disable no-console */ -import fs from 'fs' +import fs from 'fs/promises' import process from 'node:process' import type { PayloadComponent, SanitizedConfig } from '../../config/types.js' @@ -147,7 +147,7 @@ ${mapKeys.join(',\n')} if (!force) { // Read current import map and check in the IMPORTS if there are any new imports. If not, don't write the file. - const currentImportMap = await fs.promises.readFile(importMapFilePath, 'utf-8') + const currentImportMap = await fs.readFile(importMapFilePath, 'utf-8') if (currentImportMap?.trim() === importMapOutputFile?.trim()) { if (log) { @@ -161,5 +161,5 @@ ${mapKeys.join(',\n')} console.log('Writing import map to', importMapFilePath) } - await fs.promises.writeFile(importMapFilePath, importMapOutputFile) + await fs.writeFile(importMapFilePath, importMapOutputFile) } diff --git a/packages/payload/src/bin/generateTypes.ts b/packages/payload/src/bin/generateTypes.ts index bad51bceb9..8af5325001 100644 --- a/packages/payload/src/bin/generateTypes.ts +++ b/packages/payload/src/bin/generateTypes.ts @@ -1,7 +1,7 @@ import type { AcceptedLanguages } from '@payloadcms/translations' import { initI18n } from '@payloadcms/translations' -import fs from 'fs' +import fs from 'fs/promises' import { compile } from 'json-schema-to-typescript' import type { SanitizedConfig } from '../config/types.js' @@ -58,7 +58,7 @@ export async function generateTypes( // Diff the compiled types against the existing types file try { - const existingTypes = fs.readFileSync(outputFile, 'utf-8') + const existingTypes = await fs.readFile(outputFile, 'utf-8') if (compiled === existingTypes) { return @@ -67,7 +67,7 @@ export async function generateTypes( // swallow err } - fs.writeFileSync(outputFile, compiled) + await fs.writeFile(outputFile, compiled) if (shouldLog) { logger.info(`Types written to ${outputFile}`) } diff --git a/packages/payload/src/uploads/deleteAssociatedFiles.ts b/packages/payload/src/uploads/deleteAssociatedFiles.ts index 36a3e32754..58c9e16805 100644 --- a/packages/payload/src/uploads/deleteAssociatedFiles.ts +++ b/packages/payload/src/uploads/deleteAssociatedFiles.ts @@ -1,4 +1,4 @@ -import fs from 'fs' +import fs from 'fs/promises' import type { SanitizedCollectionConfig } from '../collections/config/types.js' import type { SanitizedConfig } from '../config/types.js' @@ -34,7 +34,7 @@ export const deleteAssociatedFiles: (args: Args) => Promise = async ({ try { if (await fileExists(fileToDelete)) { - fs.unlinkSync(fileToDelete) + await fs.unlink(fileToDelete) } } catch (err) { throw new ErrorDeletingFile(req.t) @@ -50,7 +50,7 @@ export const deleteAssociatedFiles: (args: Args) => Promise = async ({ const sizeToDelete = `${staticPath}/${size.filename}` try { if (await fileExists(sizeToDelete)) { - fs.unlinkSync(sizeToDelete) + await fs.unlink(sizeToDelete) } } catch (err) { throw new ErrorDeletingFile(req.t) diff --git a/packages/payload/src/uploads/fileExists.ts b/packages/payload/src/uploads/fileExists.ts index 61be442941..9a3fd6b251 100644 --- a/packages/payload/src/uploads/fileExists.ts +++ b/packages/payload/src/uploads/fileExists.ts @@ -1,8 +1,8 @@ -import fs from 'fs' +import fs from 'fs/promises' const fileExists = async (filename: string): Promise => { try { - await fs.promises.stat(filename) + await fs.stat(filename) return true } catch (err) { diff --git a/packages/payload/src/uploads/generateFileData.ts b/packages/payload/src/uploads/generateFileData.ts index c7b69137e3..860be72713 100644 --- a/packages/payload/src/uploads/generateFileData.ts +++ b/packages/payload/src/uploads/generateFileData.ts @@ -2,8 +2,7 @@ import type { OutputInfo, Sharp, SharpOptions } from 'sharp' import { fileTypeFromBuffer } from 'file-type' -import fs from 'fs' -import { mkdirSync } from 'node:fs' +import fs from 'fs/promises' import sanitize from 'sanitize-filename' import type { Collection } from '../collections/config/types.js' @@ -121,7 +120,7 @@ export const generateFileData = async ({ } if (!disableLocalStorage) { - mkdirSync(staticPath, { recursive: true }) + await fs.mkdir(staticPath, { recursive: true }) } let newData = data @@ -291,7 +290,7 @@ export const generateFileData = async ({ } if (file.tempFilePath) { - await fs.promises.writeFile(file.tempFilePath, croppedImage) // write fileBuffer to the temp path + await fs.writeFile(file.tempFilePath, croppedImage) // write fileBuffer to the temp path } else { req.file = fileForResize } @@ -304,7 +303,7 @@ export const generateFileData = async ({ // If using temp files and the image is being resized, write the file to the temp path if (fileBuffer?.data || file.data.length > 0) { if (file.tempFilePath) { - await fs.promises.writeFile(file.tempFilePath, fileBuffer?.data || file.data) // write fileBuffer to the temp path + await fs.writeFile(file.tempFilePath, fileBuffer?.data || file.data) // write fileBuffer to the temp path } else { // Assign the _possibly modified_ file to the request object req.file = { diff --git a/packages/payload/src/uploads/getFileByPath.ts b/packages/payload/src/uploads/getFileByPath.ts index 2a83b760f1..53ce791196 100644 --- a/packages/payload/src/uploads/getFileByPath.ts +++ b/packages/payload/src/uploads/getFileByPath.ts @@ -1,6 +1,6 @@ // @ts-strict-ignore import { fileTypeFromFile } from 'file-type' -import fs from 'fs' +import fs from 'fs/promises' import path from 'path' import type { PayloadRequest } from '../types/index.js' @@ -11,9 +11,9 @@ const mimeTypeEstimate = { export const getFileByPath = async (filePath: string): Promise => { if (typeof filePath === 'string') { - const data = fs.readFileSync(filePath) + const data = await fs.readFile(filePath) const mimetype = fileTypeFromFile(filePath) - const { size } = fs.statSync(filePath) + const { size } = await fs.stat(filePath) const name = path.basename(filePath) const ext = path.extname(filePath).slice(1) diff --git a/packages/payload/src/uploads/getImageSize.ts b/packages/payload/src/uploads/getImageSize.ts index 6497192322..d1dace6b12 100644 --- a/packages/payload/src/uploads/getImageSize.ts +++ b/packages/payload/src/uploads/getImageSize.ts @@ -1,5 +1,5 @@ // @ts-strict-ignore -import fs from 'fs' +import fs from 'fs/promises' import sizeOfImport from 'image-size' import { promisify } from 'util' @@ -21,7 +21,7 @@ export async function getImageSize(file: PayloadRequest['file']): Promise { - fs.writeFileSync(filepath, file.data) + await fs.writeFile(filepath, file.data) return imageSizePromise(filepath) }, { extension: 'tiff' }, diff --git a/packages/payload/src/uploads/imageResizer.ts b/packages/payload/src/uploads/imageResizer.ts index 82560adb5a..364ccbd445 100644 --- a/packages/payload/src/uploads/imageResizer.ts +++ b/packages/payload/src/uploads/imageResizer.ts @@ -2,7 +2,7 @@ import type { Sharp, Metadata as SharpMetadata, SharpOptions } from 'sharp' import { fileTypeFromBuffer } from 'file-type' -import fs from 'fs' +import fs from 'fs/promises' import sanitize from 'sanitize-filename' import type { SanitizedCollectionConfig } from '../collections/config/types.js' @@ -478,7 +478,7 @@ export async function resizeAndTransformImageSizes({ if (await fileExists(imagePath)) { try { - fs.unlinkSync(imagePath) + await fs.unlink(imagePath) } catch { // Ignore unlink errors } diff --git a/packages/payload/src/uploads/saveBufferToFile.ts b/packages/payload/src/uploads/saveBufferToFile.ts index 659d5cabb3..9835d2ac55 100644 --- a/packages/payload/src/uploads/saveBufferToFile.ts +++ b/packages/payload/src/uploads/saveBufferToFile.ts @@ -1,5 +1,5 @@ // @ts-strict-ignore -import fs from 'fs' +import fs from 'fs/promises' import { Readable } from 'stream' /** @@ -16,7 +16,7 @@ const saveBufferToFile = async (buffer: Buffer, filePath: string): Promise streamData = null } // Setup file system writable stream. - return fs.writeFileSync(filePath, buffer) + return await fs.writeFile(filePath, buffer) } export default saveBufferToFile diff --git a/packages/payload/src/uploads/tempFile.ts b/packages/payload/src/uploads/tempFile.ts index 7b978ec787..4d52e16bb6 100644 --- a/packages/payload/src/uploads/tempFile.ts +++ b/packages/payload/src/uploads/tempFile.ts @@ -1,5 +1,5 @@ // @ts-strict-ignore -import { promises as fsPromises } from 'fs' +import fs from 'fs/promises' import os from 'node:os' import path from 'node:path' import { v4 as uuid } from 'uuid' @@ -8,7 +8,7 @@ async function runTask(temporaryPath: string, callback) { try { return await callback(temporaryPath) } finally { - await fsPromises.rm(temporaryPath, { force: true, maxRetries: 2, recursive: true }) + await fs.rm(temporaryPath, { force: true, maxRetries: 2, recursive: true }) } } @@ -41,11 +41,11 @@ async function temporaryFile(options: Options) { async function temporaryDirectory({ prefix = '' } = {}) { const directory = await getPath(prefix) - await fsPromises.mkdir(directory) + await fs.mkdir(directory) return directory } async function getPath(prefix = ''): Promise { - const temporaryDirectory = await fsPromises.realpath(os.tmpdir()) + const temporaryDirectory = await fs.realpath(os.tmpdir()) return path.join(temporaryDirectory, prefix + uuid()) } diff --git a/packages/payload/src/uploads/unlinkTempFiles.ts b/packages/payload/src/uploads/unlinkTempFiles.ts index d3be514a51..624344ce85 100644 --- a/packages/payload/src/uploads/unlinkTempFiles.ts +++ b/packages/payload/src/uploads/unlinkTempFiles.ts @@ -1,5 +1,4 @@ -import fs from 'fs' -import { promisify } from 'util' +import fs from 'fs/promises' import type { SanitizedCollectionConfig } from '../collections/config/types.js' import type { SanitizedConfig } from '../config/types.js' @@ -7,8 +6,6 @@ import type { PayloadRequest } from '../types/index.js' import { mapAsync } from '../utilities/mapAsync.js' -const unlinkFile = promisify(fs.unlink) - type Args = { collectionConfig: SanitizedCollectionConfig config: SanitizedConfig @@ -28,7 +25,7 @@ export const unlinkTempFiles: (args: Args) => Promise = async ({ await mapAsync(fileArray, async ({ file }) => { // Still need this check because this will not be populated if using local API if (file?.tempFilePath) { - await unlinkFile(file.tempFilePath) + await fs.unlink(file.tempFilePath) } }) } From af8c7868d6baacad853dc1af8f84a989cf2e1e88 Mon Sep 17 00:00:00 2001 From: Nate Schneider Date: Mon, 31 Mar 2025 06:50:36 -0400 Subject: [PATCH 36/77] docs: capitalization error (#11912) Fixed a capitalized letter at line 180 --- docs/configuration/collections.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/collections.mdx b/docs/configuration/collections.mdx index 67402182ba..6adc8502f2 100644 --- a/docs/configuration/collections.mdx +++ b/docs/configuration/collections.mdx @@ -177,7 +177,7 @@ The following options are available: ```ts import type { CollectionCOnfig } from 'payload' -export const MyCollection: CollectionCOnfig = { +export const MyCollection: CollectionConfig = { // ... admin: { components: { From 03d4c5b2eeae2e55d43b05d9b826c54473281f15 Mon Sep 17 00:00:00 2001 From: Said Akhrarov <36972061+akhrarovsaid@users.noreply.github.com> Date: Mon, 31 Mar 2025 08:37:43 -0400 Subject: [PATCH 37/77] test: deflake versions with autosave e2e (#11919) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What? This PR aims to deflake the `test/versions/e2e.spec.ts:925:5 › Versions › Collections with draft validation › - with autosave - shows a prevent leave alert when form is submitted but invalid` e2e test. The issue seems to be that the `fill` call followed by a `page.reload` sometimes conflicts with autosave which may cause the test to flake. ### Why? To deflake this test in ci. ### How? Adds a single `waitForAutoSaveToRunAndComplete` function call prior to the last call to `page.reload`. In my testing, on my local machine, adding the `waitForAutoSaveToRunAndComplete` function allows the test to pass every time. Without this, the tests fails on my machine consistently. --- test/versions/e2e.spec.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/versions/e2e.spec.ts b/test/versions/e2e.spec.ts index e02a633030..03f56fd57c 100644 --- a/test/versions/e2e.spec.ts +++ b/test/versions/e2e.spec.ts @@ -981,6 +981,8 @@ describe('Versions', () => { // Fill with invalid data again, then reload and accept the warning, should contain previous data await titleField.fill('') + await waitForAutoSaveToRunAndComplete(page, 'error') + await page.reload() await expect(titleField).toBeEnabled() From a6f7ef837aafda92d0be85dd1ffa2d26cd105f12 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Mon, 31 Mar 2025 09:45:02 -0600 Subject: [PATCH 38/77] feat(db-*): export types from main export (#11914) In 3.0, we made the decision to export all types from the main package export (e.g. `payload/types` => `payload`). This improves type discoverability by IDEs and simplifies importing types. This PR does the same for our db adapters, which still have a separate `/types` subpath export. While those are kept for backwards-compatibility, we can remove them in 4.0. --- packages/db-postgres/package.json | 14 +- .../src/exports/types-deprecated.ts | 20 ++ packages/db-postgres/src/index.ts | 5 + packages/db-sqlite/package.json | 14 +- .../db-sqlite/src/exports/types-deprecated.ts | 79 ++++++++ packages/db-sqlite/src/index.ts | 27 ++- packages/db-vercel-postgres/package.json | 14 +- .../src/exports/types-deprecated.ts | 20 ++ packages/db-vercel-postgres/src/index.ts | 8 + packages/drizzle/package.json | 14 +- .../drizzle/src/exports/types-deprecated.ts | 188 ++++++++++++++++++ packages/drizzle/src/index.ts | 39 ++++ 12 files changed, 410 insertions(+), 32 deletions(-) create mode 100644 packages/db-postgres/src/exports/types-deprecated.ts create mode 100644 packages/db-sqlite/src/exports/types-deprecated.ts create mode 100644 packages/db-vercel-postgres/src/exports/types-deprecated.ts create mode 100644 packages/drizzle/src/exports/types-deprecated.ts diff --git a/packages/db-postgres/package.json b/packages/db-postgres/package.json index 4099ac633a..17f542c6a9 100644 --- a/packages/db-postgres/package.json +++ b/packages/db-postgres/package.json @@ -25,9 +25,9 @@ "default": "./src/index.ts" }, "./types": { - "import": "./src/types.ts", - "types": "./src/types.ts", - "default": "./src/types.ts" + "import": "./src/exports/types-deprecated.ts", + "types": "./src/exports/types-deprecated.ts", + "default": "./src/exports/types-deprecated.ts" }, "./migration-utils": { "import": "./src/exports/migration-utils.ts", @@ -56,7 +56,7 @@ } }, "main": "./src/index.ts", - "types": "./src/types.ts", + "types": "./src/index.ts", "files": [ "dist", "mock.js" @@ -102,9 +102,9 @@ "default": "./dist/index.js" }, "./types": { - "import": "./dist/types.js", - "types": "./dist/types.d.ts", - "default": "./dist/types.js" + "import": "./dist/exports/types-deprecated.js", + "types": "./dist/exports/types-deprecated.d.ts", + "default": "./dist/exports/types-deprecated.js" }, "./migration-utils": { "import": "./dist/exports/migration-utils.js", diff --git a/packages/db-postgres/src/exports/types-deprecated.ts b/packages/db-postgres/src/exports/types-deprecated.ts new file mode 100644 index 0000000000..461f0afa08 --- /dev/null +++ b/packages/db-postgres/src/exports/types-deprecated.ts @@ -0,0 +1,20 @@ +import type { + Args as _Args, + GeneratedDatabaseSchema as _GeneratedDatabaseSchema, + PostgresAdapter as _PostgresAdapter, +} from '../types.js' + +/** + * @deprecated - import from `@payloadcms/db-postgres` instead + */ +export type Args = _Args + +/** + * @deprecated - import from `@payloadcms/db-postgres` instead + */ +export type GeneratedDatabaseSchema = _GeneratedDatabaseSchema + +/** + * @deprecated - import from `@payloadcms/db-postgres` instead + */ +export type PostgresAdapter = _PostgresAdapter diff --git a/packages/db-postgres/src/index.ts b/packages/db-postgres/src/index.ts index 4df6026215..3e6decd797 100644 --- a/packages/db-postgres/src/index.ts +++ b/packages/db-postgres/src/index.ts @@ -214,6 +214,11 @@ export function postgresAdapter(args: Args): DatabaseAdapterObj } } +export type { + Args as PostgresAdapterArgs, + GeneratedDatabaseSchema, + PostgresAdapter, +} from './types.js' export type { MigrateDownArgs, MigrateUpArgs } from '@payloadcms/drizzle/postgres' export { geometryColumn } from '@payloadcms/drizzle/postgres' export { sql } from 'drizzle-orm' diff --git a/packages/db-sqlite/package.json b/packages/db-sqlite/package.json index 717e5df070..52bc4164b4 100644 --- a/packages/db-sqlite/package.json +++ b/packages/db-sqlite/package.json @@ -25,9 +25,9 @@ "types": "./src/index.ts" }, "./types": { - "import": "./src/types.ts", - "require": "./src/types.ts", - "types": "./src/types.ts" + "import": "./src/exports/types-deprecated.ts", + "require": "./src/exports/types-deprecated.ts", + "types": "./src/exports/types-deprecated.ts" }, "./migration-utils": { "import": "./src/exports/migration-utils.ts", @@ -56,7 +56,7 @@ } }, "main": "./src/index.ts", - "types": "./src/types.ts", + "types": "./src/index.ts", "files": [ "dist", "mock.js" @@ -99,9 +99,9 @@ "types": "./dist/index.d.ts" }, "./types": { - "import": "./dist/types.js", - "require": "./dist/types.js", - "types": "./dist/types.d.ts" + "import": "./dist/exports/types-deprecated.js", + "require": "./dist/exports/types-deprecated.js", + "types": "./dist/exports/types-deprecated.d.ts" }, "./migration-utils": { "import": "./dist/exports/migration-utils.js", diff --git a/packages/db-sqlite/src/exports/types-deprecated.ts b/packages/db-sqlite/src/exports/types-deprecated.ts new file mode 100644 index 0000000000..6aadbc1e95 --- /dev/null +++ b/packages/db-sqlite/src/exports/types-deprecated.ts @@ -0,0 +1,79 @@ +import type { + Args as _Args, + CountDistinct as _CountDistinct, + DeleteWhere as _DeleteWhere, + DropDatabase as _DropDatabase, + Execute as _Execute, + GeneratedDatabaseSchema as _GeneratedDatabaseSchema, + GenericColumns as _GenericColumns, + GenericRelation as _GenericRelation, + GenericTable as _GenericTable, + IDType as _IDType, + Insert as _Insert, + MigrateDownArgs as _MigrateDownArgs, + MigrateUpArgs as _MigrateUpArgs, + SQLiteAdapter as _SQLiteAdapter, + SQLiteSchemaHook as _SQLiteSchemaHook, +} from '../types.js' + +/** + * @deprecated - import from `@payloadcms/db-sqlite` instead + */ +export type SQLiteAdapter = _SQLiteAdapter + +/** + * @deprecated - import from `@payloadcms/db-sqlite` instead + */ +export type Args = _Args +/** + * @deprecated - import from `@payloadcms/db-sqlite` instead + */ +export type CountDistinct = _CountDistinct +/** + * @deprecated - import from `@payloadcms/db-sqlite` instead + */ +export type DeleteWhere = _DeleteWhere +/** + * @deprecated - import from `@payloadcms/db-sqlite` instead + */ +export type DropDatabase = _DropDatabase +/** + * @deprecated - import from `@payloadcms/db-sqlite` instead + */ +export type Execute = _Execute +/** + * @deprecated - import from `@payloadcms/db-sqlite` instead + */ +export type GeneratedDatabaseSchema = _GeneratedDatabaseSchema +/** + * @deprecated - import from `@payloadcms/db-sqlite` instead + */ +export type GenericColumns = _GenericColumns +/** + * @deprecated - import from `@payloadcms/db-sqlite` instead + */ +export type GenericRelation = _GenericRelation +/** + * @deprecated - import from `@payloadcms/db-sqlite` instead + */ +export type GenericTable = _GenericTable +/** + * @deprecated - import from `@payloadcms/db-sqlite` instead + */ +export type IDType = _IDType +/** + * @deprecated - import from `@payloadcms/db-sqlite` instead + */ +export type Insert = _Insert +/** + * @deprecated - import from `@payloadcms/db-sqlite` instead + */ +export type MigrateDownArgs = _MigrateDownArgs +/** + * @deprecated - import from `@payloadcms/db-sqlite` instead + */ +export type MigrateUpArgs = _MigrateUpArgs +/** + * @deprecated - import from `@payloadcms/db-sqlite` instead + */ +export type SQLiteSchemaHook = _SQLiteSchemaHook diff --git a/packages/db-sqlite/src/index.ts b/packages/db-sqlite/src/index.ts index 86b15302d6..ee0d5bfc5a 100644 --- a/packages/db-sqlite/src/index.ts +++ b/packages/db-sqlite/src/index.ts @@ -58,10 +58,6 @@ import { init } from './init.js' import { insert } from './insert.js' import { requireDrizzleKit } from './requireDrizzleKit.js' -export type { MigrateDownArgs, MigrateUpArgs } from './types.js' - -export { sql } from 'drizzle-orm' - const filename = fileURLToPath(import.meta.url) export function sqliteAdapter(args: Args): DatabaseAdapterObj { @@ -202,3 +198,26 @@ export function sqliteAdapter(args: Args): DatabaseAdapterObj { init: adapter, } } + +/** + * @todo deprecate /types subpath export in 4.0 + */ +export type { + Args as SQLiteAdapterArgs, + CountDistinct, + DeleteWhere, + DropDatabase, + Execute, + GeneratedDatabaseSchema, + GenericColumns, + GenericRelation, + GenericTable, + IDType, + Insert, + MigrateDownArgs, + MigrateUpArgs, + SQLiteAdapter, + SQLiteSchemaHook, +} from './types.js' + +export { sql } from 'drizzle-orm' diff --git a/packages/db-vercel-postgres/package.json b/packages/db-vercel-postgres/package.json index 0a4f42d701..ac86baf7f4 100644 --- a/packages/db-vercel-postgres/package.json +++ b/packages/db-vercel-postgres/package.json @@ -25,9 +25,9 @@ "default": "./src/index.ts" }, "./types": { - "import": "./src/types.ts", - "types": "./src/types.ts", - "default": "./src/types.ts" + "import": "./src/exports/types-deprecated.ts", + "types": "./src/exports/types-deprecated.ts", + "default": "./src/exports/types-deprecated.ts" }, "./migration-utils": { "import": "./src/exports/migration-utils.ts", @@ -56,7 +56,7 @@ } }, "main": "./src/index.ts", - "types": "./src/types.ts", + "types": "./src/index.ts", "files": [ "dist", "mock.js" @@ -103,9 +103,9 @@ "default": "./dist/index.js" }, "./types": { - "import": "./dist/types.js", - "types": "./dist/types.d.ts", - "default": "./dist/types.js" + "import": "./dist/exports/types-deprecated.js", + "types": "./dist/exports/types-deprecated.d.ts", + "default": "./dist/exports/types-deprecated.js" }, "./migration-utils": { "import": "./dist/exports/migration-utils.js", diff --git a/packages/db-vercel-postgres/src/exports/types-deprecated.ts b/packages/db-vercel-postgres/src/exports/types-deprecated.ts new file mode 100644 index 0000000000..f367a0e23e --- /dev/null +++ b/packages/db-vercel-postgres/src/exports/types-deprecated.ts @@ -0,0 +1,20 @@ +import type { + Args as _Args, + GeneratedDatabaseSchema as _GeneratedDatabaseSchema, + VercelPostgresAdapter as _VercelPostgresAdapter, +} from '../types.js' + +/** + * @deprecated - import from `@payloadcms/db-vercel-postgres` instead + */ +export type Args = _Args + +/** + * @deprecated - import from `@payloadcms/db-vercel-postgres` instead + */ +export type GeneratedDatabaseSchema = _GeneratedDatabaseSchema + +/** + * @deprecated - import from `@payloadcms/db-vercel-postgres` instead + */ +export type VercelPostgresAdapter = _VercelPostgresAdapter diff --git a/packages/db-vercel-postgres/src/index.ts b/packages/db-vercel-postgres/src/index.ts index 410c7ca9a5..65b4ae6d36 100644 --- a/packages/db-vercel-postgres/src/index.ts +++ b/packages/db-vercel-postgres/src/index.ts @@ -211,6 +211,14 @@ export function vercelPostgresAdapter(args: Args = {}): DatabaseAdapterObj = _Execute +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type GenericColumn = _GenericColumn +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type GenericColumns = _GenericColumns +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type GenericPgColumn = _GenericPgColumn +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type GenericRelation = _GenericRelation +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type GenericTable = _GenericTable +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type IDType = _IDType +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type Insert = _Insert +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type IntegerRawColumn = _IntegerRawColumn +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type Migration = _Migration +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type PostgresDB = _PostgresDB +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type RawColumn = _RawColumn +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type RawForeignKey = _RawForeignKey +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type RawIndex = _RawIndex +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type RawRelation = _RawRelation +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type RawTable = _RawTable +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type RelationMap = _RelationMap +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type RequireDrizzleKit = _RequireDrizzleKit +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type SetColumnID = _SetColumnID +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type SQLiteDB = _SQLiteDB +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type TimestampRawColumn = _TimestampRawColumn +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type TransactionPg = _TransactionPg +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type TransactionSQLite = _TransactionSQLite +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type UUIDRawColumn = _UUIDRawColumn +/** + * @deprecated - import from `@payloadcms/drizzle` instead + */ +export type VectorRawColumn = _VectorRawColumn diff --git a/packages/drizzle/src/index.ts b/packages/drizzle/src/index.ts index 00696e6669..fbda6d2356 100644 --- a/packages/drizzle/src/index.ts +++ b/packages/drizzle/src/index.ts @@ -31,6 +31,45 @@ export { buildRawSchema } from './schema/buildRawSchema.js' export { beginTransaction } from './transactions/beginTransaction.js' export { commitTransaction } from './transactions/commitTransaction.js' export { rollbackTransaction } from './transactions/rollbackTransaction.js' +export type { + BaseRawColumn, + BuildDrizzleTable, + BuildQueryJoinAliases, + ChainedMethods, + ColumnToCodeConverter, + CountDistinct, + CreateJSONQueryArgs, + DeleteWhere, + DrizzleAdapter, + DrizzleTransaction, + DropDatabase, + EnumRawColumn, + Execute, + GenericColumn, + GenericColumns, + GenericPgColumn, + GenericRelation, + GenericTable, + IDType, + Insert, + IntegerRawColumn, + Migration, + PostgresDB, + RawColumn, + RawForeignKey, + RawIndex, + RawRelation, + RawTable, + RelationMap, + RequireDrizzleKit, + SetColumnID, + SQLiteDB, + TimestampRawColumn, + TransactionPg, + TransactionSQLite, + UUIDRawColumn, + VectorRawColumn, +} from './types.js' export { updateGlobal } from './updateGlobal.js' export { updateGlobalVersion } from './updateGlobalVersion.js' export { updateJobs } from './updateJobs.js' From 96289bf555cba528393d18695718fe3128130289 Mon Sep 17 00:00:00 2001 From: Patrik Date: Mon, 31 Mar 2025 13:11:34 -0400 Subject: [PATCH 39/77] fix(next): block encoded and escaped open redirects in getSafeRedirect (#11907) ### What This PR improves the `getSafeRedirect` utility to improve security around open redirect handling. ### How - Normalizes and decodes the redirect path using `decodeURIComponent` - Catches malformed encodings with a try/catch fallback - Blocks open redirects --- .../src/utilities/getSafeRedirect.spec.ts | 55 +++++++++++++++++++ .../next/src/utilities/getSafeRedirect.ts | 17 +++++- test/admin-root/payload-types.ts | 1 + 3 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 packages/next/src/utilities/getSafeRedirect.spec.ts diff --git a/packages/next/src/utilities/getSafeRedirect.spec.ts b/packages/next/src/utilities/getSafeRedirect.spec.ts new file mode 100644 index 0000000000..e146e9a33f --- /dev/null +++ b/packages/next/src/utilities/getSafeRedirect.spec.ts @@ -0,0 +1,55 @@ +import { getSafeRedirect } from './getSafeRedirect' + +const fallback = '/admin' // default fallback if the input is unsafe or invalid + +describe('getSafeRedirect', () => { + // Valid - safe redirect paths + it.each([['/dashboard'], ['/admin/settings'], ['/projects?id=123'], ['/hello-world']])( + 'should allow safe relative path: %s', + (input) => { + // If the input is a clean relative path, it should be returned as-is + expect(getSafeRedirect(input, fallback)).toBe(input) + }, + ) + + // Invalid types or empty inputs + it.each(['', null, undefined, 123, {}, []])( + 'should fallback on invalid or non-string input: %s', + (input) => { + // If the input is not a valid string, it should return the fallback + expect(getSafeRedirect(input as any, fallback)).toBe(fallback) + }, + ) + + // Unsafe redirect patterns + it.each([ + '//example.com', // protocol-relative URL + '/javascript:alert(1)', // JavaScript scheme + '/JavaScript:alert(1)', // case-insensitive JavaScript + '/http://unknown.com', // disguised external redirect + '/https://unknown.com', // disguised external redirect + '/%2Funknown.com', // encoded slash — could resolve to // + '/\\/unknown.com', // escaped slash + '/\\\\unknown.com', // double escaped slashes + '/\\unknown.com', // single escaped slash + '%2F%2Funknown.com', // fully encoded protocol-relative path + '%2Fjavascript:alert(1)', // encoded JavaScript scheme + ])('should block unsafe redirect: %s', (input) => { + // All of these should return the fallback because they’re unsafe + expect(getSafeRedirect(input, fallback)).toBe(fallback) + }) + + // Input with extra spaces should still be properly handled + it('should trim whitespace before evaluating', () => { + // A valid path with surrounding spaces should still be accepted + expect(getSafeRedirect(' /dashboard ', fallback)).toBe('/dashboard') + + // An unsafe path with spaces should still be rejected + expect(getSafeRedirect(' //example.com ', fallback)).toBe(fallback) + }) + + // If decoding the input fails (e.g., invalid percent encoding), it should not crash + it('should return fallback on invalid encoding', () => { + expect(getSafeRedirect('%E0%A4%A', fallback)).toBe(fallback) + }) +}) diff --git a/packages/next/src/utilities/getSafeRedirect.ts b/packages/next/src/utilities/getSafeRedirect.ts index 963c6b51fe..4770d7fe88 100644 --- a/packages/next/src/utilities/getSafeRedirect.ts +++ b/packages/next/src/utilities/getSafeRedirect.ts @@ -6,14 +6,25 @@ export const getSafeRedirect = ( return fallback } - // Ensures that any leading or trailing whitespace doesn’t affect the checks - const redirectPath = redirectParam.trim() + // Normalize and decode the path + let redirectPath: string + try { + redirectPath = decodeURIComponent(redirectParam.trim()) + } catch { + return fallback // invalid encoding + } const isSafeRedirect = // Must start with a single forward slash (e.g., "/admin") redirectPath.startsWith('/') && - // Prevent protocol-relative URLs (e.g., "//evil.com") + // Prevent protocol-relative URLs (e.g., "//example.com") !redirectPath.startsWith('//') && + // Prevent encoded slashes that could resolve to protocol-relative + !redirectPath.startsWith('/%2F') && + // Prevent backslash-based escape attempts (e.g., "/\\/example.com", "/\\\\example.com", "/\\example.com") + !redirectPath.startsWith('/\\/') && + !redirectPath.startsWith('/\\\\') && + !redirectPath.startsWith('/\\') && // Prevent javascript-based schemes (e.g., "/javascript:alert(1)") !redirectPath.toLowerCase().startsWith('/javascript:') && // Prevent attempts to redirect to full URLs using "/http:" or "/https:" diff --git a/test/admin-root/payload-types.ts b/test/admin-root/payload-types.ts index ab6df309d8..4ca79e12da 100644 --- a/test/admin-root/payload-types.ts +++ b/test/admin-root/payload-types.ts @@ -54,6 +54,7 @@ export type SupportedTimezones = | 'Asia/Singapore' | 'Asia/Tokyo' | 'Asia/Seoul' + | 'Australia/Brisbane' | 'Australia/Sydney' | 'Pacific/Guam' | 'Pacific/Noumea' From a083d47368c9927c5d3e7c6ee5607776b174f142 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Mon, 31 Mar 2025 12:57:17 -0600 Subject: [PATCH 40/77] feat(db-*): return database name to unsanitized config (#11913) You can access the database name from `sanitizedConfig.db.name`. But currently, it' not possible to access the db name from the unsanitized config. Plugins only have access to the unsanitized config. This change allows db adapters to return the db name early, which will allow plugins to conditionally initialize db-specific functionality --- packages/db-mongodb/src/index.ts | 1 + packages/db-postgres/src/index.ts | 1 + packages/db-sqlite/src/index.ts | 1 + packages/db-vercel-postgres/src/index.ts | 1 + packages/payload/src/database/types.ts | 6 ++++++ 5 files changed, 10 insertions(+) diff --git a/packages/db-mongodb/src/index.ts b/packages/db-mongodb/src/index.ts index d69359b73f..1d4db19421 100644 --- a/packages/db-mongodb/src/index.ts +++ b/packages/db-mongodb/src/index.ts @@ -273,6 +273,7 @@ export function mongooseAdapter({ } return { + name: 'mongoose', allowIDOnCreate, defaultIDType: 'text', init: adapter, diff --git a/packages/db-postgres/src/index.ts b/packages/db-postgres/src/index.ts index 3e6decd797..41258c590b 100644 --- a/packages/db-postgres/src/index.ts +++ b/packages/db-postgres/src/index.ts @@ -208,6 +208,7 @@ export function postgresAdapter(args: Args): DatabaseAdapterObj } return { + name: 'postgres', allowIDOnCreate, defaultIDType: payloadIDType, init: adapter, diff --git a/packages/db-sqlite/src/index.ts b/packages/db-sqlite/src/index.ts index ee0d5bfc5a..b202854b3e 100644 --- a/packages/db-sqlite/src/index.ts +++ b/packages/db-sqlite/src/index.ts @@ -193,6 +193,7 @@ export function sqliteAdapter(args: Args): DatabaseAdapterObj { } return { + name: 'sqlite', allowIDOnCreate, defaultIDType: payloadIDType, init: adapter, diff --git a/packages/db-vercel-postgres/src/index.ts b/packages/db-vercel-postgres/src/index.ts index 65b4ae6d36..f4ed3aada3 100644 --- a/packages/db-vercel-postgres/src/index.ts +++ b/packages/db-vercel-postgres/src/index.ts @@ -205,6 +205,7 @@ export function vercelPostgresAdapter(args: Args = {}): DatabaseAdapterObj = { allowIDOnCreate?: boolean defaultIDType: 'number' | 'text' init: (args: { payload: Payload }) => T + /** + * The name of the database adapter. For example, "postgres" or "mongoose". + * + * @todo make required in 4.0 + */ + name?: string } export type DBIdentifierName = From 9a1c3cf4ccad985d55db295d2c84be6cbf58bec4 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Mon, 31 Mar 2025 13:06:05 -0600 Subject: [PATCH 41/77] fix: support parallel job queue tasks (#11917) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support for running multiple job queue tasks in parallel within the same workflow while preventing conflicts. Previously, this would have caused the following issues: - Job log entries get lost - the final job log is incomplete, despite all tasks having been executed - Write conflicts in postgres, leading to unique constraint violation errors The solution involves handling job log data updates in a way that avoids overwriting, and ensuring the final update reflects the latest job log data. Each job log entry now initializes its own ID, so a given job log entry’s ID remains the same across multiple, parallel task executions. ## Postgres In Postgres, we need to enable transactions for the `payload.db.updateJobs` operation; otherwise, two tasks updating the same job in parallel can conflict. This happens because Postgres handles array rows by deleting them all, then re-inserting (rather than upserting). The rows are stored in a separate table, and the following scenario can occur: Op 1: deletes all job log rows Op 2: deletes all job log rows Op 1: inserts 200 job log rows Op 2: insert the same 200 job log rows again => `error: “duplicate key value violates unique constraint "payload_jobs_log_pkey”` Because transactions were not used, the rows inserted by Op 1 immediately became visible to Op 2, causing the conflict. Enabling transactions fixes this. In theory, it can still happen if Op 1 commits before Op 2 starts inserting (due to the read committed isolation level), but it should occur far less frequently. Alongside this change, we should consider inserting the rows using an upsert (update on conflict), which will get rid of this error completely. That way, if the insertion of Op 1 is visible to Op 2, Op 2 will simply overwrite it, rather than erroring. Individual job entries are immutable and job entries cannot be deleted, thus this shouldn't corrupt any data. ## Mongo In Mongo, the issue is addressed by ensuring that log row deletions caused due to different log states in concurrent operations are not merged back to the client job log, and by making sure the final update includes all job logs. There is no duplicate key error in Mongo because the array log resides in the same document and duplicates are simply upserted. We cannot use transactions in Mongo, as it appears to lock the document in a way that prevents reliable parallel updates, leading to: `MongoServerError: WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction` --- packages/db-mongodb/src/updateJobs.ts | 3 ++ packages/drizzle/src/updateJobs.ts | 4 ++ .../payload/src/database/defaultUpdateJobs.ts | 3 +- .../src/queues/config/types/workflowTypes.ts | 2 +- .../runJobs/runJob/getRunTaskFunction.ts | 8 ++++ .../runJobs/runJob/getUpdateJobFunction.ts | 15 +++++- .../queues/operations/runJobs/runJob/index.ts | 2 + .../queues/utilities/sanitizeUpdateData.ts | 28 ----------- .../payload/src/queues/utilities/updateJob.ts | 20 ++++++-- test/query-presets/payload-types.ts | 32 ++++++------- test/queues/config.ts | 2 + test/queues/int.spec.ts | 36 ++++++++++++++ test/queues/payload-types.ts | 47 ++++++++++++++++++- test/queues/workflows/parallelTaskWorkflow.ts | 29 ++++++++++++ 14 files changed, 177 insertions(+), 54 deletions(-) delete mode 100644 packages/payload/src/queues/utilities/sanitizeUpdateData.ts create mode 100644 test/queues/workflows/parallelTaskWorkflow.ts diff --git a/packages/db-mongodb/src/updateJobs.ts b/packages/db-mongodb/src/updateJobs.ts index 51dd7c0277..ba72887c0a 100644 --- a/packages/db-mongodb/src/updateJobs.ts +++ b/packages/db-mongodb/src/updateJobs.ts @@ -13,6 +13,9 @@ export const updateJobs: UpdateJobs = async function updateMany( this: MongooseAdapter, { id, data, limit, req, returning, where: whereArg }, ) { + if (!(data?.log as object[])?.length) { + delete data.log + } const where = id ? { id: { equals: id } } : (whereArg as Where) const { collectionConfig, Model } = getCollection({ diff --git a/packages/drizzle/src/updateJobs.ts b/packages/drizzle/src/updateJobs.ts index 050b04bfc8..885a0a6581 100644 --- a/packages/drizzle/src/updateJobs.ts +++ b/packages/drizzle/src/updateJobs.ts @@ -12,6 +12,9 @@ export const updateJobs: UpdateJobs = async function updateMany( this: DrizzleAdapter, { id, data, limit: limitArg, req, returning, sort: sortArg, where: whereArg }, ) { + if (!(data?.log as object[])?.length) { + delete data.log + } const whereToUse: Where = id ? { id: { equals: id } } : whereArg const limit = id ? 1 : limitArg @@ -55,6 +58,7 @@ export const updateJobs: UpdateJobs = async function updateMany( req, tableName, }) + results.push(result) } diff --git a/packages/payload/src/database/defaultUpdateJobs.ts b/packages/payload/src/database/defaultUpdateJobs.ts index cc66f6a2fc..135185f80b 100644 --- a/packages/payload/src/database/defaultUpdateJobs.ts +++ b/packages/payload/src/database/defaultUpdateJobs.ts @@ -2,7 +2,6 @@ import type { BaseJob, DatabaseAdapter } from '../index.js' import type { UpdateJobs } from './types.js' import { jobsCollectionSlug } from '../queues/config/index.js' -import { sanitizeUpdateData } from '../queues/utilities/sanitizeUpdateData.js' export const defaultUpdateJobs: UpdateJobs = async function updateMany( this: DatabaseAdapter, @@ -42,7 +41,7 @@ export const defaultUpdateJobs: UpdateJobs = async function updateMany( const updatedJob = await this.updateOne({ id: job.id, collection: jobsCollectionSlug, - data: sanitizeUpdateData({ data: updateData }), + data: updateData, req, returning, }) diff --git a/packages/payload/src/queues/config/types/workflowTypes.ts b/packages/payload/src/queues/config/types/workflowTypes.ts index f4baad000b..e22338052d 100644 --- a/packages/payload/src/queues/config/types/workflowTypes.ts +++ b/packages/payload/src/queues/config/types/workflowTypes.ts @@ -18,7 +18,7 @@ export type JobLog = { /** * ID added by the array field when the log is saved in the database */ - id?: string + id: string input?: Record output?: Record /** diff --git a/packages/payload/src/queues/operations/runJobs/runJob/getRunTaskFunction.ts b/packages/payload/src/queues/operations/runJobs/runJob/getRunTaskFunction.ts index eb4be61d77..d5ff4d7c70 100644 --- a/packages/payload/src/queues/operations/runJobs/runJob/getRunTaskFunction.ts +++ b/packages/payload/src/queues/operations/runJobs/runJob/getRunTaskFunction.ts @@ -1,3 +1,5 @@ +import ObjectIdImport from 'bson-objectid' + // @ts-strict-ignore import type { PayloadRequest } from '../../../../types/index.js' import type { @@ -22,6 +24,9 @@ import type { UpdateJobFunction } from './getUpdateJobFunction.js' import { calculateBackoffWaitUntil } from './calculateBackoffWaitUntil.js' import { importHandlerPath } from './importHandlerPath.js' +const ObjectId = (ObjectIdImport.default || + ObjectIdImport) as unknown as typeof ObjectIdImport.default + // Helper object type to force being passed by reference export type RunTaskFunctionState = { reachedMaxRetries: boolean @@ -96,6 +101,7 @@ export async function handleTaskFailed({ } job.log.push({ + id: new ObjectId().toHexString(), completedAt: new Date().toISOString(), error: errorJSON, executedAt: executedAt.toISOString(), @@ -252,6 +258,7 @@ export const getRunTaskFunction = ( log: [ ...job.log, { + id: new ObjectId().toHexString(), completedAt: new Date().toISOString(), error: errorMessage, executedAt: executedAt.toISOString(), @@ -350,6 +357,7 @@ export const getRunTaskFunction = ( job.log = [] } job.log.push({ + id: new ObjectId().toHexString(), completedAt: new Date().toISOString(), executedAt: executedAt.toISOString(), input, diff --git a/packages/payload/src/queues/operations/runJobs/runJob/getUpdateJobFunction.ts b/packages/payload/src/queues/operations/runJobs/runJob/getUpdateJobFunction.ts index a4b97f88b2..027d7cf32b 100644 --- a/packages/payload/src/queues/operations/runJobs/runJob/getUpdateJobFunction.ts +++ b/packages/payload/src/queues/operations/runJobs/runJob/getUpdateJobFunction.ts @@ -18,7 +18,20 @@ export function getUpdateJobFunction(job: BaseJob, req: PayloadRequest): UpdateJ // Update job object like this to modify the original object - that way, incoming changes (e.g. taskStatus field that will be re-generated through the hook) will be reflected in the calling function for (const key in updatedJob) { - job[key] = updatedJob[key] + if (key === 'log') { + if (!job.log) { + job.log = [] + } + // Add all new log entries to the original job.log object. Do not delete any existing log entries. + // Do not update existing log entries, as existing log entries should be immutable. + for (const logEntry of updatedJob.log) { + if (!job.log.some((entry) => entry.id === logEntry.id)) { + job.log.push(logEntry) + } + } + } else { + job[key] = updatedJob[key] + } } if ((updatedJob.error as Record)?.cancelled) { diff --git a/packages/payload/src/queues/operations/runJobs/runJob/index.ts b/packages/payload/src/queues/operations/runJobs/runJob/index.ts index cbc3dce169..3c80f41303 100644 --- a/packages/payload/src/queues/operations/runJobs/runJob/index.ts +++ b/packages/payload/src/queues/operations/runJobs/runJob/index.ts @@ -70,6 +70,7 @@ export const runJob = async ({ await updateJob({ error: errorJSON, hasError: hasFinalError, // If reached max retries => final error. If hasError is true this job will not be retried + log: job.log, processing: false, totalTried: (job.totalTried ?? 0) + 1, }) @@ -82,6 +83,7 @@ export const runJob = async ({ // Workflow has completed await updateJob({ completedAt: new Date().toISOString(), + log: job.log, processing: false, totalTried: (job.totalTried ?? 0) + 1, }) diff --git a/packages/payload/src/queues/utilities/sanitizeUpdateData.ts b/packages/payload/src/queues/utilities/sanitizeUpdateData.ts deleted file mode 100644 index 9eb7fce2d7..0000000000 --- a/packages/payload/src/queues/utilities/sanitizeUpdateData.ts +++ /dev/null @@ -1,28 +0,0 @@ -import ObjectIdImport from 'bson-objectid' - -import type { BaseJob } from '../config/types/workflowTypes.js' - -const ObjectId = (ObjectIdImport.default || - ObjectIdImport) as unknown as typeof ObjectIdImport.default - -/** - * Our payload operations sanitize the input data to, for example, add missing IDs to array rows. - * This function is used to manually sanitize the data for direct db adapter operations - */ -export function sanitizeUpdateData({ data }: { data: Partial }): Partial { - if (data.log) { - const sanitizedData = { ...data } - sanitizedData.log = sanitizedData?.log?.map((log) => { - if (log.id) { - return log - } - return { - ...log, - id: new ObjectId().toHexString(), - } - }) - return sanitizedData - } - - return data -} diff --git a/packages/payload/src/queues/utilities/updateJob.ts b/packages/payload/src/queues/utilities/updateJob.ts index 113f4d8a34..69525e75b1 100644 --- a/packages/payload/src/queues/utilities/updateJob.ts +++ b/packages/payload/src/queues/utilities/updateJob.ts @@ -4,7 +4,6 @@ import type { PayloadRequest, Sort, Where } from '../../types/index.js' import type { BaseJob } from '../config/types/workflowTypes.js' import { jobAfterRead, jobsCollectionSlug } from '../config/index.js' -import { sanitizeUpdateData } from './sanitizeUpdateData.js' type BaseArgs = { data: Partial @@ -72,17 +71,24 @@ export async function updateJobs({ return result.docs as BaseJob[] } + const jobReq = { + transactionID: + req.payload.db.name !== 'mongoose' + ? ((await req.payload.db.beginTransaction()) as string) + : undefined, + } + const args: UpdateJobsArgs = id ? { id, - data: sanitizeUpdateData({ data }), - req: disableTransaction === true ? undefined : req, + data, + req: jobReq, returning, } : { - data: sanitizeUpdateData({ data }), + data, limit, - req: disableTransaction === true ? undefined : req, + req: jobReq, returning, sort, // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion @@ -91,6 +97,10 @@ export async function updateJobs({ const updatedJobs: BaseJob[] | null = await req.payload.db.updateJobs(args) + if (req.payload.db.name !== 'mongoose' && jobReq.transactionID) { + await req.payload.db.commitTransaction(jobReq.transactionID) + } + if (returning === false || !updatedJobs?.length) { return null } diff --git a/test/query-presets/payload-types.ts b/test/query-presets/payload-types.ts index 2f6ee94ee9..759cc0ae93 100644 --- a/test/query-presets/payload-types.ts +++ b/test/query-presets/payload-types.ts @@ -86,7 +86,7 @@ export interface Config { 'payload-query-presets': PayloadQueryPresetsSelect | PayloadQueryPresetsSelect; }; db: { - defaultIDType: string; + defaultIDType: number; }; globals: {}; globalsSelect: {}; @@ -122,7 +122,7 @@ export interface UserAuthOperations { * via the `definition` "pages". */ export interface Page { - id: string; + id: number; text?: string | null; updatedAt: string; createdAt: string; @@ -133,7 +133,7 @@ export interface Page { * via the `definition` "users". */ export interface User { - id: string; + id: number; name?: string | null; roles?: ('admin' | 'user' | 'anonymous')[] | null; updatedAt: string; @@ -152,7 +152,7 @@ export interface User { * via the `definition` "posts". */ export interface Post { - id: string; + id: number; text?: string | null; updatedAt: string; createdAt: string; @@ -163,24 +163,24 @@ export interface Post { * via the `definition` "payload-locked-documents". */ export interface PayloadLockedDocument { - id: string; + id: number; document?: | ({ relationTo: 'pages'; - value: string | Page; + value: number | Page; } | null) | ({ relationTo: 'users'; - value: string | User; + value: number | User; } | null) | ({ relationTo: 'posts'; - value: string | Post; + value: number | Post; } | null); globalSlug?: string | null; user: { relationTo: 'users'; - value: string | User; + value: number | User; }; updatedAt: string; createdAt: string; @@ -190,10 +190,10 @@ export interface PayloadLockedDocument { * via the `definition` "payload-preferences". */ export interface PayloadPreference { - id: string; + id: number; user: { relationTo: 'users'; - value: string | User; + value: number | User; }; key?: string | null; value?: @@ -213,7 +213,7 @@ export interface PayloadPreference { * via the `definition` "payload-migrations". */ export interface PayloadMigration { - id: string; + id: number; name?: string | null; batch?: number | null; updatedAt: string; @@ -224,23 +224,23 @@ export interface PayloadMigration { * via the `definition` "payload-query-presets". */ export interface PayloadQueryPreset { - id: string; + id: number; title: string; isShared?: boolean | null; access?: { read?: { constraint?: ('everyone' | 'onlyMe' | 'specificUsers' | 'specificRoles') | null; - users?: (string | User)[] | null; + users?: (number | User)[] | null; roles?: ('admin' | 'user' | 'anonymous')[] | null; }; update?: { constraint?: ('everyone' | 'onlyMe' | 'specificUsers' | 'specificRoles') | null; - users?: (string | User)[] | null; + users?: (number | User)[] | null; roles?: ('admin' | 'user' | 'anonymous')[] | null; }; delete?: { constraint?: ('everyone' | 'onlyMe' | 'specificUsers') | null; - users?: (string | User)[] | null; + users?: (number | User)[] | null; }; }; where?: diff --git a/test/queues/config.ts b/test/queues/config.ts index 6ca475f3bf..5cbd83fbcd 100644 --- a/test/queues/config.ts +++ b/test/queues/config.ts @@ -24,6 +24,7 @@ import { updatePostJSONWorkflow } from './workflows/updatePostJSON.js' import { workflowAndTasksRetriesUndefinedWorkflow } from './workflows/workflowAndTasksRetriesUndefined.js' import { workflowRetries2TasksRetries0Workflow } from './workflows/workflowRetries2TasksRetries0.js' import { workflowRetries2TasksRetriesUndefinedWorkflow } from './workflows/workflowRetries2TasksRetriesUndefined.js' +import { parallelTaskWorkflow } from './workflows/parallelTaskWorkflow.js' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) @@ -380,6 +381,7 @@ export default buildConfigWithDefaults({ subTaskWorkflow, subTaskFailsWorkflow, longRunningWorkflow, + parallelTaskWorkflow, ], }, editor: lexicalEditor(), diff --git a/test/queues/int.spec.ts b/test/queues/int.spec.ts index 089445f1dd..d196075d4c 100644 --- a/test/queues/int.spec.ts +++ b/test/queues/int.spec.ts @@ -1265,4 +1265,40 @@ describe('Queues', () => { expect(jobAfterRun.log[0].error.message).toBe('custom error message') expect(jobAfterRun.log[0].state).toBe('failed') }) + + it('can reliably run workflows with parallel tasks', async () => { + const amount = 500 + payload.config.jobs.deleteJobOnComplete = false + + const job = await payload.jobs.queue({ + workflow: 'parallelTask', + input: {}, + }) + + await payload.jobs.run() + + const jobAfterRun = await payload.findByID({ + collection: 'payload-jobs', + id: job.id, + }) + + expect(jobAfterRun.hasError).toBe(false) + expect(jobAfterRun.log?.length).toBe(amount) + + const simpleDocs = await payload.find({ + collection: 'simple', + limit: amount, + depth: 0, + }) + expect(simpleDocs.docs.length).toBe(amount) + + // Ensure all docs are created (= all tasks are run once) + for (let i = 1; i <= simpleDocs.docs.length; i++) { + const simpleDoc = simpleDocs.docs.find((doc) => doc.title === `parallel task ${i}`) + const logEntry = jobAfterRun?.log?.find((log) => log.taskID === `parallel task ${i}`) + expect(simpleDoc).toBeDefined() + expect(logEntry).toBeDefined() + expect((logEntry?.output as any)?.simpleID).toBe(simpleDoc?.id) + } + }) }) diff --git a/test/queues/payload-types.ts b/test/queues/payload-types.ts index 5d34c054f3..ba1be1786f 100644 --- a/test/queues/payload-types.ts +++ b/test/queues/payload-types.ts @@ -54,6 +54,7 @@ export type SupportedTimezones = | 'Asia/Singapore' | 'Asia/Tokyo' | 'Asia/Seoul' + | 'Australia/Brisbane' | 'Australia/Sydney' | 'Pacific/Guam' | 'Pacific/Noumea' @@ -102,6 +103,9 @@ export interface Config { CreateSimpleRetries0: TaskCreateSimpleRetries0; CreateSimpleWithDuplicateMessage: TaskCreateSimpleWithDuplicateMessage; ExternalTask: TaskExternalTask; + ThrowError: TaskThrowError; + ReturnError: TaskReturnError; + ReturnCustomError: TaskReturnCustomError; inline: { input: unknown; output: unknown; @@ -124,6 +128,7 @@ export interface Config { subTask: WorkflowSubTask; subTaskFails: WorkflowSubTaskFails; longRunning: WorkflowLongRunning; + parallelTask: WorkflowParallelTask; }; }; } @@ -259,7 +264,10 @@ export interface PayloadJob { | 'CreateSimpleRetriesUndefined' | 'CreateSimpleRetries0' | 'CreateSimpleWithDuplicateMessage' - | 'ExternalTask'; + | 'ExternalTask' + | 'ThrowError' + | 'ReturnError' + | 'ReturnCustomError'; taskID: string; input?: | { @@ -310,6 +318,7 @@ export interface PayloadJob { | 'subTask' | 'subTaskFails' | 'longRunning' + | 'parallelTask' ) | null; taskSlug?: @@ -322,6 +331,9 @@ export interface PayloadJob { | 'CreateSimpleRetries0' | 'CreateSimpleWithDuplicateMessage' | 'ExternalTask' + | 'ThrowError' + | 'ReturnError' + | 'ReturnCustomError' ) | null; queue?: string | null; @@ -583,6 +595,32 @@ export interface TaskExternalTask { simpleID: string; }; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "TaskThrowError". + */ +export interface TaskThrowError { + input?: unknown; + output?: unknown; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "TaskReturnError". + */ +export interface TaskReturnError { + input?: unknown; + output?: unknown; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "TaskReturnCustomError". + */ +export interface TaskReturnCustomError { + input: { + errorMessage: string; + }; + output?: unknown; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "MyUpdatePostWorkflowType". @@ -727,6 +765,13 @@ export interface WorkflowSubTaskFails { export interface WorkflowLongRunning { input?: unknown; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "WorkflowParallelTask". + */ +export interface WorkflowParallelTask { + input?: unknown; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "auth". diff --git a/test/queues/workflows/parallelTaskWorkflow.ts b/test/queues/workflows/parallelTaskWorkflow.ts new file mode 100644 index 0000000000..1ae2d8ddda --- /dev/null +++ b/test/queues/workflows/parallelTaskWorkflow.ts @@ -0,0 +1,29 @@ +import type { WorkflowConfig } from 'payload' + +export const parallelTaskWorkflow: WorkflowConfig<'parallelTask'> = { + slug: 'parallelTask', + inputSchema: [], + handler: async ({ job, inlineTask }) => { + const taskIDs = Array.from({ length: 500 }, (_, i) => i + 1).map((i) => i.toString()) + + await Promise.all( + taskIDs.map(async (taskID) => { + return await inlineTask(`parallel task ${taskID}`, { + task: async ({ req }) => { + const newSimple = await req.payload.db.create({ + collection: 'simple', + data: { + title: 'parallel task ' + taskID, + }, + }) + return { + output: { + simpleID: newSimple.id, + }, + } + }, + }) + }), + ) + }, +} From 9c88af4b204515593e9885bff538b515ae4cf956 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Mon, 31 Mar 2025 14:37:45 -0600 Subject: [PATCH 42/77] refactor(drizzle): replace query chaining with dynamic query building (#11923) This replaces usage of our `chainMethods` helper to dynamically chain queries with [drizzle dynamic query building](https://orm.drizzle.team/docs/dynamic-query-building). This is more type-safe, more readable and requires less code --- packages/db-sqlite/src/countDistinct.ts | 30 ++++----- packages/drizzle/src/deleteOne.ts | 4 +- packages/drizzle/src/find/chainMethods.ts | 5 ++ packages/drizzle/src/find/findMany.ts | 21 ++---- packages/drizzle/src/find/traverseFields.ts | 64 ++++++++----------- .../drizzle/src/postgres/countDistinct.ts | 32 ++++------ .../drizzle/src/queries/selectDistinct.ts | 38 +++++------ packages/drizzle/src/types.ts | 8 ++- packages/drizzle/src/updateMany.ts | 32 ++-------- packages/drizzle/src/updateOne.ts | 2 +- 10 files changed, 93 insertions(+), 143 deletions(-) diff --git a/packages/db-sqlite/src/countDistinct.ts b/packages/db-sqlite/src/countDistinct.ts index 5a0ada7a9d..de0af7a995 100644 --- a/packages/db-sqlite/src/countDistinct.ts +++ b/packages/db-sqlite/src/countDistinct.ts @@ -1,6 +1,5 @@ -import type { ChainedMethods } from '@payloadcms/drizzle/types' +import type { SQLiteSelect } from 'drizzle-orm/sqlite-core' -import { chainMethods } from '@payloadcms/drizzle' import { count, sql } from 'drizzle-orm' import type { CountDistinct, SQLiteAdapter } from './types.js' @@ -20,30 +19,25 @@ export const countDistinct: CountDistinct = async function countDistinct( return Number(countResult[0]?.count) } - const chainedMethods: ChainedMethods = [] + let query: SQLiteSelect = db + .select({ + count: sql`COUNT(1) OVER()`, + }) + .from(this.tables[tableName]) + .where(where) + .groupBy(this.tables[tableName].id) + .limit(1) + .$dynamic() joins.forEach(({ condition, table }) => { - chainedMethods.push({ - args: [table, condition], - method: 'leftJoin', - }) + query = query.leftJoin(table, condition) }) // When we have any joins, we need to count each individual ID only once. // COUNT(*) doesn't work for this well in this case, as it also counts joined tables. // SELECT (COUNT DISTINCT id) has a very slow performance on large tables. // Instead, COUNT (GROUP BY id) can be used which is still slower than COUNT(*) but acceptable. - const countResult = await chainMethods({ - methods: chainedMethods, - query: db - .select({ - count: sql`COUNT(1) OVER()`, - }) - .from(this.tables[tableName]) - .where(where) - .groupBy(this.tables[tableName].id) - .limit(1), - }) + const countResult = await query return Number(countResult[0]?.count) } diff --git a/packages/drizzle/src/deleteOne.ts b/packages/drizzle/src/deleteOne.ts index 2c2d12c65b..760d78dec5 100644 --- a/packages/drizzle/src/deleteOne.ts +++ b/packages/drizzle/src/deleteOne.ts @@ -13,7 +13,7 @@ import { getTransaction } from './utilities/getTransaction.js' export const deleteOne: DeleteOne = async function deleteOne( this: DrizzleAdapter, - { collection: collectionSlug, req, select, where: whereArg, returning }, + { collection: collectionSlug, req, returning, select, where: whereArg }, ) { const db = await getTransaction(this, req) const collection = this.payload.collections[collectionSlug].config @@ -32,9 +32,9 @@ export const deleteOne: DeleteOne = async function deleteOne( const selectDistinctResult = await selectDistinct({ adapter: this, - chainedMethods: [{ args: [1], method: 'limit' }], db, joins, + query: ({ query }) => query.limit(1), selectFields, tableName, where, diff --git a/packages/drizzle/src/find/chainMethods.ts b/packages/drizzle/src/find/chainMethods.ts index 146ce641ad..3d8d59e76d 100644 --- a/packages/drizzle/src/find/chainMethods.ts +++ b/packages/drizzle/src/find/chainMethods.ts @@ -1,3 +1,6 @@ +/** + * @deprecated - will be removed in 4.0. Use query + $dynamic() instead: https://orm.drizzle.team/docs/dynamic-query-building + */ export type ChainedMethods = { args: unknown[] method: string @@ -7,6 +10,8 @@ export type ChainedMethods = { * Call and returning methods that would normally be chained together but cannot be because of control logic * @param methods * @param query + * + * @deprecated - will be removed in 4.0. Use query + $dynamic() instead: https://orm.drizzle.team/docs/dynamic-query-building */ const chainMethods = ({ methods, query }: { methods: ChainedMethods; query: T }): T => { return methods.reduce((query, { args, method }) => { diff --git a/packages/drizzle/src/find/findMany.ts b/packages/drizzle/src/find/findMany.ts index 6874e74403..d2ba6e129c 100644 --- a/packages/drizzle/src/find/findMany.ts +++ b/packages/drizzle/src/find/findMany.ts @@ -3,7 +3,6 @@ import type { FindArgs, FlattenedField, TypeWithID } from 'payload' import { inArray } from 'drizzle-orm' import type { DrizzleAdapter } from '../types.js' -import type { ChainedMethods } from './chainMethods.js' import buildQuery from '../queries/buildQuery.js' import { selectDistinct } from '../queries/selectDistinct.js' @@ -62,15 +61,6 @@ export const findMany = async function find({ const orderedIDMap: Record = {} let orderedIDs: (number | string)[] - const selectDistinctMethods: ChainedMethods = [] - - if (orderBy) { - selectDistinctMethods.push({ - args: [() => orderBy.map(({ column, order }) => order(column))], - method: 'orderBy', - }) - } - const findManyArgs = buildFindManyArgs({ adapter, collectionSlug, @@ -84,15 +74,16 @@ export const findMany = async function find({ tableName, versions, }) - - selectDistinctMethods.push({ args: [offset], method: 'offset' }) - selectDistinctMethods.push({ args: [limit], method: 'limit' }) - const selectDistinctResult = await selectDistinct({ adapter, - chainedMethods: selectDistinctMethods, db, joins, + query: ({ query }) => { + if (orderBy) { + query = query.orderBy(() => orderBy.map(({ column, order }) => order(column))) + } + return query.offset(offset).limit(limit) + }, selectFields, tableName, where, diff --git a/packages/drizzle/src/find/traverseFields.ts b/packages/drizzle/src/find/traverseFields.ts index 771033cc29..4bb2aae2fd 100644 --- a/packages/drizzle/src/find/traverseFields.ts +++ b/packages/drizzle/src/find/traverseFields.ts @@ -1,5 +1,5 @@ import type { LibSQLDatabase } from 'drizzle-orm/libsql' -import type { SQLiteSelectBase } from 'drizzle-orm/sqlite-core' +import type { SQLiteSelect, SQLiteSelectBase } from 'drizzle-orm/sqlite-core' import { and, asc, count, desc, eq, or, sql } from 'drizzle-orm' import { @@ -16,7 +16,7 @@ import { import { fieldIsVirtual, fieldShouldBeLocalized } from 'payload/shared' import toSnakeCase from 'to-snake-case' -import type { BuildQueryJoinAliases, ChainedMethods, DrizzleAdapter } from '../types.js' +import type { BuildQueryJoinAliases, DrizzleAdapter } from '../types.js' import type { Result } from './buildFindManyArgs.js' import buildQuery from '../queries/buildQuery.js' @@ -25,7 +25,6 @@ import { operatorMap } from '../queries/operatorMap.js' import { getNameFromDrizzleTable } from '../utilities/getNameFromDrizzleTable.js' import { jsonAggBuildObject } from '../utilities/json.js' import { rawConstraint } from '../utilities/rawConstraint.js' -import { chainMethods } from './chainMethods.js' const flattenAllWherePaths = (where: Where, paths: string[]) => { for (const k in where) { @@ -612,34 +611,6 @@ export const traverseFields = ({ where: joinQueryWhere, }) - const chainedMethods: ChainedMethods = [] - - joins.forEach(({ type, condition, table }) => { - chainedMethods.push({ - args: [table, condition], - method: type ?? 'leftJoin', - }) - }) - - if (page && limit !== 0) { - const offset = (page - 1) * limit - 1 - if (offset > 0) { - chainedMethods.push({ - args: [offset], - method: 'offset', - }) - } - } - - if (limit !== 0) { - chainedMethods.push({ - args: [limit], - method: 'limit', - }) - } - - const db = adapter.drizzle as LibSQLDatabase - for (let key in selectFields) { const val = selectFields[key] @@ -654,14 +625,29 @@ export const traverseFields = ({ selectFields.parent = newAliasTable.parent } - const subQuery = chainMethods({ - methods: chainedMethods, - query: db - .select(selectFields as any) - .from(newAliasTable) - .where(subQueryWhere) - .orderBy(() => orderBy.map(({ column, order }) => order(column))), - }).as(subQueryAlias) + let query: SQLiteSelect = db + .select(selectFields as any) + .from(newAliasTable) + .where(subQueryWhere) + .orderBy(() => orderBy.map(({ column, order }) => order(column))) + .$dynamic() + + joins.forEach(({ type, condition, table }) => { + query = query[type ?? 'leftJoin'](table, condition) + }) + + if (page && limit !== 0) { + const offset = (page - 1) * limit - 1 + if (offset > 0) { + query = query.offset(offset) + } + } + + if (limit !== 0) { + query = query.limit(limit) + } + + const subQuery = query.as(subQueryAlias) if (shouldCount) { currentArgs.extras[`${columnName}_count`] = sql`${db diff --git a/packages/drizzle/src/postgres/countDistinct.ts b/packages/drizzle/src/postgres/countDistinct.ts index 2f8f113ac4..16c2f576c9 100644 --- a/packages/drizzle/src/postgres/countDistinct.ts +++ b/packages/drizzle/src/postgres/countDistinct.ts @@ -1,10 +1,9 @@ +import type { PgTableWithColumns } from 'drizzle-orm/pg-core' + import { count, sql } from 'drizzle-orm' -import type { ChainedMethods } from '../types.js' import type { BasePostgresAdapter, CountDistinct } from './types.js' -import { chainMethods } from '../find/chainMethods.js' - export const countDistinct: CountDistinct = async function countDistinct( this: BasePostgresAdapter, { db, joins, tableName, where }, @@ -20,30 +19,25 @@ export const countDistinct: CountDistinct = async function countDistinct( return Number(countResult[0].count) } - const chainedMethods: ChainedMethods = [] + let query = db + .select({ + count: sql`COUNT(1) OVER()`, + }) + .from(this.tables[tableName]) + .where(where) + .groupBy(this.tables[tableName].id) + .limit(1) + .$dynamic() joins.forEach(({ condition, table }) => { - chainedMethods.push({ - args: [table, condition], - method: 'leftJoin', - }) + query = query.leftJoin(table as PgTableWithColumns, condition) }) // When we have any joins, we need to count each individual ID only once. // COUNT(*) doesn't work for this well in this case, as it also counts joined tables. // SELECT (COUNT DISTINCT id) has a very slow performance on large tables. // Instead, COUNT (GROUP BY id) can be used which is still slower than COUNT(*) but acceptable. - const countResult = await chainMethods({ - methods: chainedMethods, - query: db - .select({ - count: sql`COUNT(1) OVER()`, - }) - .from(this.tables[tableName]) - .where(where) - .groupBy(this.tables[tableName].id) - .limit(1), - }) + const countResult = await query return Number(countResult[0].count) } diff --git a/packages/drizzle/src/queries/selectDistinct.ts b/packages/drizzle/src/queries/selectDistinct.ts index 3e393dd82b..6354992f83 100644 --- a/packages/drizzle/src/queries/selectDistinct.ts +++ b/packages/drizzle/src/queries/selectDistinct.ts @@ -1,7 +1,7 @@ import type { QueryPromise, SQL } from 'drizzle-orm' -import type { SQLiteColumn } from 'drizzle-orm/sqlite-core' +import type { PgSelect } from 'drizzle-orm/pg-core' +import type { SQLiteColumn, SQLiteSelect } from 'drizzle-orm/sqlite-core' -import type { ChainedMethods } from '../find/chainMethods.js' import type { DrizzleAdapter, DrizzleTransaction, @@ -12,13 +12,11 @@ import type { } from '../types.js' import type { BuildQueryJoinAliases } from './buildQuery.js' -import { chainMethods } from '../find/chainMethods.js' - type Args = { adapter: DrizzleAdapter - chainedMethods?: ChainedMethods db: DrizzleAdapter['drizzle'] | DrizzleTransaction joins: BuildQueryJoinAliases + query?: (args: { query: SQLiteSelect }) => SQLiteSelect selectFields: Record tableName: string where: SQL @@ -29,42 +27,40 @@ type Args = { */ export const selectDistinct = ({ adapter, - chainedMethods = [], db, joins, + query: queryModifier = ({ query }) => query, selectFields, tableName, where, }: Args): QueryPromise<{ id: number | string }[] & Record> => { if (Object.keys(joins).length > 0) { - if (where) { - chainedMethods.push({ args: [where], method: 'where' }) - } - - joins.forEach(({ condition, table }) => { - chainedMethods.push({ - args: [table, condition], - method: 'leftJoin', - }) - }) - - let query + let query: SQLiteSelect const table = adapter.tables[tableName] if (adapter.name === 'postgres') { query = (db as TransactionPg) .selectDistinct(selectFields as Record) .from(table) + .$dynamic() as unknown as SQLiteSelect } if (adapter.name === 'sqlite') { query = (db as TransactionSQLite) .selectDistinct(selectFields as Record) .from(table) + .$dynamic() } - return chainMethods({ - methods: chainedMethods, - query, + if (where) { + query = query.where(where) + } + + joins.forEach(({ condition, table }) => { + query = query.leftJoin(table, condition) }) + + return queryModifier({ + query, + }) as unknown as QueryPromise<{ id: number | string }[] & Record> } } diff --git a/packages/drizzle/src/types.ts b/packages/drizzle/src/types.ts index da6f148f1f..b34ab6384d 100644 --- a/packages/drizzle/src/types.ts +++ b/packages/drizzle/src/types.ts @@ -37,11 +37,8 @@ import type { DrizzleSnapshotJSON } from 'drizzle-kit/api' import type { SQLiteRaw } from 'drizzle-orm/sqlite-core/query-builders/raw' import type { QueryResult } from 'pg' -import type { ChainedMethods } from './find/chainMethods.js' import type { Operators } from './queries/operatorMap.js' -export { ChainedMethods } - export type PostgresDB = NodePgDatabase> export type SQLiteDB = LibSQLDatabase< @@ -377,3 +374,8 @@ export type RelationMap = Map< type: 'many' | 'one' } > + +/** + * @deprecated - will be removed in 4.0. Use query + $dynamic() instead: https://orm.drizzle.team/docs/dynamic-query-building + */ +export type { ChainedMethods } from './find/chainMethods.js' diff --git a/packages/drizzle/src/updateMany.ts b/packages/drizzle/src/updateMany.ts index 8cde607a59..9cd979fe42 100644 --- a/packages/drizzle/src/updateMany.ts +++ b/packages/drizzle/src/updateMany.ts @@ -3,9 +3,8 @@ import type { UpdateMany } from 'payload' import toSnakeCase from 'to-snake-case' -import type { ChainedMethods, DrizzleAdapter } from './types.js' +import type { DrizzleAdapter } from './types.js' -import { chainMethods } from './find/chainMethods.js' import buildQuery from './queries/buildQuery.js' import { selectDistinct } from './queries/selectDistinct.js' import { upsertRow } from './upsertRow/index.js' @@ -45,16 +44,10 @@ export const updateMany: UpdateMany = async function updateMany( const selectDistinctResult = await selectDistinct({ adapter: this, - chainedMethods: orderBy - ? [ - { - args: [() => orderBy.map(({ column, order }) => order(column))], - method: 'orderBy', - }, - ] - : [], db, joins, + query: ({ query }) => + orderBy ? query.orderBy(() => orderBy.map(({ column, order }) => order(column))) : query, selectFields, tableName, where, @@ -69,28 +62,17 @@ export const updateMany: UpdateMany = async function updateMany( const table = this.tables[tableName] - const query = _db.select({ id: table.id }).from(table).where(where) - - const chainedMethods: ChainedMethods = [] + let query = _db.select({ id: table.id }).from(table).where(where).$dynamic() if (typeof limit === 'number' && limit > 0) { - chainedMethods.push({ - args: [limit], - method: 'limit', - }) + query = query.limit(limit) } if (orderBy) { - chainedMethods.push({ - args: [() => orderBy.map(({ column, order }) => order(column))], - method: 'orderBy', - }) + query = query.orderBy(() => orderBy.map(({ column, order }) => order(column))) } - const docsToUpdate = await chainMethods({ - methods: chainedMethods, - query, - }) + const docsToUpdate = await query idsToUpdate = docsToUpdate?.map((doc) => doc.id) } diff --git a/packages/drizzle/src/updateOne.ts b/packages/drizzle/src/updateOne.ts index 9119e7f8c3..e269961c24 100644 --- a/packages/drizzle/src/updateOne.ts +++ b/packages/drizzle/src/updateOne.ts @@ -41,9 +41,9 @@ export const updateOne: UpdateOne = async function updateOne( // selectDistinct will only return if there are joins const selectDistinctResult = await selectDistinct({ adapter: this, - chainedMethods: [{ args: [1], method: 'limit' }], db, joins, + query: ({ query }) => query.limit(1), selectFields, tableName, where, From c844b4c848c21bc5c73634bf328f98bcc05c0bb3 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Mon, 31 Mar 2025 15:00:36 -0600 Subject: [PATCH 43/77] feat: configurable job queue processing order (LIFO/FIFO), allow sequential execution of jobs (#11897) Previously, jobs were executed in FIFO order on MongoDB, and LIFO on Postgres, with no way to configure this behavior. This PR makes FIFO the default on both MongoDB and Postgres and introduces the following new options to configure the processing order globally or on a queue-by-queue basis: - a `processingOrder` property to the jobs config - a `processingOrder` argument to `payload.jobs.run()` to override what's set in the jobs config It also adds a new `sequential` option to `payload.jobs.run()`, which can be useful for debugging. --- docs/jobs-queue/queues.mdx | 81 +++++++++++++- packages/db-mongodb/src/updateJobs.ts | 22 +++- .../payload/src/queues/config/types/index.ts | 19 +++- packages/payload/src/queues/localAPI.ts | 14 +++ .../src/queues/operations/runJobs/index.ts | 69 +++++++++--- test/queues/config.ts | 7 ++ test/queues/int.spec.ts | 100 ++++++++++++++++++ test/queues/payload-types.ts | 11 ++ .../queues/workflows/inlineTaskTestDelayed.ts | 38 +++++++ 9 files changed, 340 insertions(+), 21 deletions(-) create mode 100644 test/queues/workflows/inlineTaskTestDelayed.ts diff --git a/docs/jobs-queue/queues.mdx b/docs/jobs-queue/queues.mdx index 43c2ab6efe..e255a4f00a 100644 --- a/docs/jobs-queue/queues.mdx +++ b/docs/jobs-queue/queues.mdx @@ -28,7 +28,7 @@ Then, you could configure two different runner strategies: As mentioned above, you can queue jobs, but the jobs won't run unless a worker picks up your jobs and runs them. This can be done in four ways: -#### Cron jobs +### Cron jobs You can use the `jobs.autoRun` property to configure cron jobs: @@ -63,7 +63,7 @@ export default buildConfig({ and should not be used on serverless platforms like Vercel. -#### Endpoint +### Endpoint You can execute jobs by making a fetch request to the `/api/payload-jobs/run` endpoint: @@ -130,7 +130,7 @@ This works because Vercel automatically makes the `CRON_SECRET` environment vari After the project is deployed to Vercel, the Vercel Cron job will automatically trigger the `/api/payload-jobs/run` endpoint in the specified schedule, running the queued jobs in the background. -#### Local API +### Local API If you want to process jobs programmatically from your server-side code, you can use the Local API: @@ -156,7 +156,7 @@ const results = await payload.jobs.runByID({ }) ``` -#### Bin script +### Bin script Finally, you can process jobs via the bin script that comes with Payload out of the box. @@ -169,3 +169,76 @@ In addition, the bin script allows you to pass a `--cron` flag to the `jobs:run` ```sh npx payload jobs:run --cron "*/5 * * * *" ``` + +## Processing Order + +By default, jobs are processed first in, first out (FIFO). This means that the first job added to the queue will be the first one processed. However, you can also configure the order in which jobs are processed. + +### Jobs Configuration + +You can configure the order in which jobs are processed in the jobs configuration by passing the `processingOrder` property. This mimics the Payload [sort](../queries/sort) property that's used for functionality such as `payload.find()`. + +```ts +export default buildConfig({ + // Other configurations... + jobs: { + tasks: [ + // your tasks here + ], + processingOrder: '-createdAt', // Process jobs in reverse order of creation = LIFO + }, +}) +``` + +You can also set this on a queue-by-queue basis: + +```ts +export default buildConfig({ + // Other configurations... + jobs: { + tasks: [ + // your tasks here + ], + processingOrder: { + default: 'createdAt', // FIFO + queues: { + nightly: '-createdAt', // LIFO + myQueue: '-createdAt', // LIFO + }, + }, + }, +}) +``` + +If you need even more control over the processing order, you can pass a function that returns the processing order - this function will be called every time a queue starts processing jobs. + +```ts +export default buildConfig({ + // Other configurations... + jobs: { + tasks: [ + // your tasks here + ], + processingOrder: ({ queue }) => { + if (queue === 'myQueue') { + return '-createdAt' // LIFO + } + return 'createdAt' // FIFO + }, + }, +}) +``` + +### Local API + +You can configure the order in which jobs are processed in the `payload.jobs.queue` method by passing the `processingOrder` property. + +```ts +const createdJob = await payload.jobs.queue({ + workflow: 'createPostAndUpdate', + input: { + title: 'my title', + }, + processingOrder: '-createdAt', // Process jobs in reverse order of creation = LIFO +}) +``` diff --git a/packages/db-mongodb/src/updateJobs.ts b/packages/db-mongodb/src/updateJobs.ts index ba72887c0a..cac9c0dc25 100644 --- a/packages/db-mongodb/src/updateJobs.ts +++ b/packages/db-mongodb/src/updateJobs.ts @@ -4,6 +4,7 @@ import type { BaseJob, UpdateJobs, Where } from 'payload' import type { MongooseAdapter } from './index.js' import { buildQuery } from './queries/buildQuery.js' +import { buildSortParam } from './queries/buildSortParam.js' import { getCollection } from './utilities/getEntity.js' import { getSession } from './utilities/getSession.js' import { handleError } from './utilities/handleError.js' @@ -11,7 +12,7 @@ import { transform } from './utilities/transform.js' export const updateJobs: UpdateJobs = async function updateMany( this: MongooseAdapter, - { id, data, limit, req, returning, where: whereArg }, + { id, data, limit, req, returning, sort: sortArg, where: whereArg }, ) { if (!(data?.log as object[])?.length) { delete data.log @@ -23,6 +24,14 @@ export const updateJobs: UpdateJobs = async function updateMany( collectionSlug: 'payload-jobs', }) + const sort: Record | undefined = buildSortParam({ + adapter: this, + config: this.payload.config, + fields: collectionConfig.flattenedFields, + sort: sortArg || collectionConfig.defaultSort, + timestamps: true, + }) + const options: MongooseUpdateQueryOptions = { lean: true, new: true, @@ -54,7 +63,7 @@ export const updateJobs: UpdateJobs = async function updateMany( const documentsToUpdate = await Model.find( query, {}, - { ...options, limit, projection: { _id: 1 } }, + { ...options, limit, projection: { _id: 1 }, sort }, ) if (documentsToUpdate.length === 0) { return null @@ -69,7 +78,14 @@ export const updateJobs: UpdateJobs = async function updateMany( return null } - result = await Model.find(query, {}, options) + result = await Model.find( + query, + {}, + { + ...options, + sort, + }, + ) } } catch (error) { handleError({ collection: collectionConfig.slug, error, req }) diff --git a/packages/payload/src/queues/config/types/index.ts b/packages/payload/src/queues/config/types/index.ts index d41fbe646b..916724fd8f 100644 --- a/packages/payload/src/queues/config/types/index.ts +++ b/packages/payload/src/queues/config/types/index.ts @@ -1,5 +1,6 @@ import type { CollectionConfig } from '../../../index.js' -import type { Payload, PayloadRequest } from '../../../types/index.js' +import type { Payload, PayloadRequest, Sort } from '../../../types/index.js' +import type { RunJobsArgs } from '../../operations/runJobs/index.js' import type { TaskConfig } from './taskTypes.js' import type { WorkflowConfig } from './workflowTypes.js' @@ -80,6 +81,22 @@ export type JobsConfig = { * a new collection. */ jobsCollectionOverrides?: (args: { defaultJobsCollection: CollectionConfig }) => CollectionConfig + /** + * Adjust the job processing order using a Payload sort string. This can be set globally or per queue. + * + * FIFO would equal `createdAt` and LIFO would equal `-createdAt`. + * + * @default all jobs for all queues will be executed in FIFO order. + */ + processingOrder?: + | ((args: RunJobsArgs) => Promise | Sort) + | { + default?: Sort + queues: { + [queue: string]: Sort + } + } + | Sort /** * By default, the job system uses direct database calls for optimal performance. * If you added custom hooks to your jobs collection, you can set this to true to diff --git a/packages/payload/src/queues/localAPI.ts b/packages/payload/src/queues/localAPI.ts index 01d3b0037b..b23e68936c 100644 --- a/packages/payload/src/queues/localAPI.ts +++ b/packages/payload/src/queues/localAPI.ts @@ -5,6 +5,7 @@ import { type Payload, type PayloadRequest, type RunningJob, + type Sort, type TypedJobs, type Where, } from '../index.js' @@ -99,8 +100,19 @@ export const getJobsLocalAPI = (payload: Payload) => ({ run: async (args?: { limit?: number overrideAccess?: boolean + /** + * Adjust the job processing order using a Payload sort string. + * + * FIFO would equal `createdAt` and LIFO would equal `-createdAt`. + */ + processingOrder?: Sort queue?: string req?: PayloadRequest + /** + * By default, jobs are run in parallel. + * If you want to run them in sequence, set this to true. + */ + sequential?: boolean where?: Where }): Promise> => { const newReq: PayloadRequest = args?.req ?? (await createLocalReq({}, payload)) @@ -108,8 +120,10 @@ export const getJobsLocalAPI = (payload: Payload) => ({ return await runJobs({ limit: args?.limit, overrideAccess: args?.overrideAccess !== false, + processingOrder: args?.processingOrder, queue: args?.queue, req: newReq, + sequential: args?.sequential, where: args?.where, }) }, diff --git a/packages/payload/src/queues/operations/runJobs/index.ts b/packages/payload/src/queues/operations/runJobs/index.ts index 5da73361db..c8ba056a04 100644 --- a/packages/payload/src/queues/operations/runJobs/index.ts +++ b/packages/payload/src/queues/operations/runJobs/index.ts @@ -1,6 +1,5 @@ // @ts-strict-ignore -import type { PaginatedDocs } from '../../../database/types.js' -import type { PayloadRequest, Where } from '../../../types/index.js' +import type { PayloadRequest, Sort, Where } from '../../../types/index.js' import type { WorkflowJSON } from '../../config/types/workflowJSONTypes.js' import type { BaseJob, @@ -26,8 +25,21 @@ export type RunJobsArgs = { id?: number | string limit?: number overrideAccess?: boolean + /** + * Adjust the job processing order + * + * FIFO would equal `createdAt` and LIFO would equal `-createdAt`. + * + * @default all jobs for all queues will be executed in FIFO order. + */ + processingOrder?: Sort queue?: string req: PayloadRequest + /** + * By default, jobs are run in parallel. + * If you want to run them in sequence, set this to true. + */ + sequential?: boolean where?: Where } @@ -43,14 +55,18 @@ export type RunJobsResult = { remainingJobsFromQueried: number } -export const runJobs = async ({ - id, - limit = 10, - overrideAccess, - queue, - req, - where: whereFromProps, -}: RunJobsArgs): Promise => { +export const runJobs = async (args: RunJobsArgs): Promise => { + const { + id, + limit = 10, + overrideAccess, + processingOrder, + queue, + req, + sequential, + where: whereFromProps, + } = args + if (!overrideAccess) { const hasAccess = await req.payload.config.jobs.access.run({ req }) if (!hasAccess) { @@ -124,6 +140,21 @@ export const runJobs = async ({ }), ] } else { + let defaultProcessingOrder: Sort = + req.payload.collections[jobsCollectionSlug].config.defaultSort ?? 'createdAt' + + const processingOrderConfig = req.payload.config.jobs?.processingOrder + if (typeof processingOrderConfig === 'function') { + defaultProcessingOrder = await processingOrderConfig(args) + } else if (typeof processingOrderConfig === 'object' && !Array.isArray(processingOrderConfig)) { + if (queue && processingOrderConfig.queues && processingOrderConfig.queues[queue]) { + defaultProcessingOrder = processingOrderConfig.queues[queue] + } else if (processingOrderConfig.default) { + defaultProcessingOrder = processingOrderConfig.default + } + } else if (typeof processingOrderConfig === 'string') { + defaultProcessingOrder = processingOrderConfig + } const updatedDocs = await updateJobs({ data: { processing: true, @@ -133,6 +164,7 @@ export const runJobs = async ({ limit, req, returning: true, + sort: processingOrder ?? defaultProcessingOrder, where, }) @@ -175,7 +207,7 @@ export const runJobs = async ({ ? [] : undefined - const jobPromises = jobsQuery.docs.map(async (job) => { + const runSingleJob = async (job) => { if (!job.workflowSlug && !job.taskSlug) { throw new Error('Job must have either a workflowSlug or a taskSlug') } @@ -257,9 +289,20 @@ export const runJobs = async ({ return { id: job.id, result } } - }) + } - const resultsArray = await Promise.all(jobPromises) + let resultsArray: { id: number | string; result: RunJobResult }[] = [] + if (sequential) { + for (const job of jobsQuery.docs) { + const result = await runSingleJob(job) + if (result !== null) { + resultsArray.push(result) + } + } + } else { + const jobPromises = jobsQuery.docs.map(runSingleJob) + resultsArray = await Promise.all(jobPromises) + } if (jobsToDelete && jobsToDelete.length > 0) { try { diff --git a/test/queues/config.ts b/test/queues/config.ts index 5cbd83fbcd..5bdc9c8c49 100644 --- a/test/queues/config.ts +++ b/test/queues/config.ts @@ -24,6 +24,7 @@ import { updatePostJSONWorkflow } from './workflows/updatePostJSON.js' import { workflowAndTasksRetriesUndefinedWorkflow } from './workflows/workflowAndTasksRetriesUndefined.js' import { workflowRetries2TasksRetries0Workflow } from './workflows/workflowRetries2TasksRetries0.js' import { workflowRetries2TasksRetriesUndefinedWorkflow } from './workflows/workflowRetries2TasksRetriesUndefined.js' +import { inlineTaskTestDelayedWorkflow } from './workflows/inlineTaskTestDelayed.js' import { parallelTaskWorkflow } from './workflows/parallelTaskWorkflow.js' const filename = fileURLToPath(import.meta.url) @@ -104,6 +105,11 @@ export default buildConfigWithDefaults({ }, } }, + processingOrder: { + queues: { + lifo: '-createdAt', + }, + }, tasks: [ { retries: 2, @@ -376,6 +382,7 @@ export default buildConfigWithDefaults({ workflowRetries2TasksRetriesUndefinedWorkflow, workflowRetries2TasksRetries0Workflow, inlineTaskTestWorkflow, + inlineTaskTestDelayedWorkflow, externalWorkflow, retriesBackoffTestWorkflow, subTaskWorkflow, diff --git a/test/queues/int.spec.ts b/test/queues/int.spec.ts index d196075d4c..315e6581c0 100644 --- a/test/queues/int.spec.ts +++ b/test/queues/int.spec.ts @@ -533,6 +533,106 @@ describe('Queues', () => { payload.config.jobs.deleteJobOnComplete = true }) + it('ensure jobs run in FIFO order by default', async () => { + await payload.jobs.queue({ + workflow: 'inlineTaskTestDelayed', + input: { + message: 'task 1', + }, + }) + + await new Promise((resolve) => setTimeout(resolve, 100)) + + await payload.jobs.queue({ + workflow: 'inlineTaskTestDelayed', + input: { + message: 'task 2', + }, + }) + + await payload.jobs.run({ + sequential: true, + }) + + const allSimples = await payload.find({ + collection: 'simple', + limit: 100, + sort: 'createdAt', + }) + + expect(allSimples.totalDocs).toBe(2) + expect(allSimples.docs?.[0]?.title).toBe('task 1') + expect(allSimples.docs?.[1]?.title).toBe('task 2') + }) + + it('ensure jobs can run LIFO if processingOrder is passed', async () => { + await payload.jobs.queue({ + workflow: 'inlineTaskTestDelayed', + input: { + message: 'task 1', + }, + }) + + await new Promise((resolve) => setTimeout(resolve, 100)) + + await payload.jobs.queue({ + workflow: 'inlineTaskTestDelayed', + input: { + message: 'task 2', + }, + }) + + await payload.jobs.run({ + sequential: true, + processingOrder: '-createdAt', + }) + + const allSimples = await payload.find({ + collection: 'simple', + limit: 100, + sort: 'createdAt', + }) + + expect(allSimples.totalDocs).toBe(2) + expect(allSimples.docs?.[0]?.title).toBe('task 2') + expect(allSimples.docs?.[1]?.title).toBe('task 1') + }) + + it('ensure job config processingOrder using queues object is respected', async () => { + await payload.jobs.queue({ + workflow: 'inlineTaskTestDelayed', + queue: 'lifo', + input: { + message: 'task 1', + }, + }) + + await new Promise((resolve) => setTimeout(resolve, 100)) + + await payload.jobs.queue({ + workflow: 'inlineTaskTestDelayed', + queue: 'lifo', + input: { + message: 'task 2', + }, + }) + + await payload.jobs.run({ + sequential: true, + queue: 'lifo', + }) + + const allSimples = await payload.find({ + collection: 'simple', + limit: 100, + sort: 'createdAt', + }) + + expect(allSimples.totalDocs).toBe(2) + expect(allSimples.docs?.[0]?.title).toBe('task 2') + expect(allSimples.docs?.[1]?.title).toBe('task 1') + }) + it('can create new inline jobs', async () => { await payload.jobs.queue({ workflow: 'inlineTaskTest', diff --git a/test/queues/payload-types.ts b/test/queues/payload-types.ts index ba1be1786f..eb7892fa43 100644 --- a/test/queues/payload-types.ts +++ b/test/queues/payload-types.ts @@ -123,6 +123,7 @@ export interface Config { workflowRetries2TasksRetriesUndefined: WorkflowWorkflowRetries2TasksRetriesUndefined; workflowRetries2TasksRetries0: WorkflowWorkflowRetries2TasksRetries0; inlineTaskTest: WorkflowInlineTaskTest; + inlineTaskTestDelayed: WorkflowInlineTaskTestDelayed; externalWorkflow: WorkflowExternalWorkflow; retriesBackoffTest: WorkflowRetriesBackoffTest; subTask: WorkflowSubTask; @@ -313,6 +314,7 @@ export interface PayloadJob { | 'workflowRetries2TasksRetriesUndefined' | 'workflowRetries2TasksRetries0' | 'inlineTaskTest' + | 'inlineTaskTestDelayed' | 'externalWorkflow' | 'retriesBackoffTest' | 'subTask' @@ -722,6 +724,15 @@ export interface WorkflowInlineTaskTest { message: string; }; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "WorkflowInlineTaskTestDelayed". + */ +export interface WorkflowInlineTaskTestDelayed { + input: { + message: string; + }; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "WorkflowExternalWorkflow". diff --git a/test/queues/workflows/inlineTaskTestDelayed.ts b/test/queues/workflows/inlineTaskTestDelayed.ts new file mode 100644 index 0000000000..5d81a7b7cb --- /dev/null +++ b/test/queues/workflows/inlineTaskTestDelayed.ts @@ -0,0 +1,38 @@ +import type { WorkflowConfig } from 'payload' + +export const inlineTaskTestDelayedWorkflow: WorkflowConfig<'inlineTaskTestDelayed'> = { + slug: 'inlineTaskTestDelayed', + inputSchema: [ + { + name: 'message', + type: 'text', + required: true, + }, + ], + handler: async ({ job, inlineTask }) => { + await inlineTask('1', { + task: async ({ input, req }) => { + // Wait 100ms + await new Promise((resolve) => setTimeout(resolve, 100)) + + const newSimple = await req.payload.create({ + collection: 'simple', + req, + data: { + title: input.message, + }, + }) + await new Promise((resolve) => setTimeout(resolve, 100)) + + return { + output: { + simpleID: newSimple.id, + }, + } + }, + input: { + message: job.input.message, + }, + }) + }, +} From 5b0e0ab788b94aeaf26d4946cfc1960637486079 Mon Sep 17 00:00:00 2001 From: Marcus Forsberg Date: Tue, 1 Apr 2025 12:31:37 +0200 Subject: [PATCH 44/77] fix(translations): improve Swedish translations for query presets (#11937) ### What? Minor changes to Swedish translations added in #11330 to keep wording in line with changes in #11654 --- packages/translations/src/languages/sv.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/translations/src/languages/sv.ts b/packages/translations/src/languages/sv.ts index 009892e999..cfa6fc30f7 100644 --- a/packages/translations/src/languages/sv.ts +++ b/packages/translations/src/languages/sv.ts @@ -343,9 +343,9 @@ export const svTranslations: DefaultTranslationsObject = { upcomingEvents: 'Kommande händelser', updatedAt: 'Uppdaterat', updatedCountSuccessfully: 'Uppdaterade {{count}} {{label}}', - updatedLabelSuccessfully: 'Uppdaterade {{label}} framgångsrikt.', + updatedLabelSuccessfully: 'Uppdaterade {{label}}', updatedSuccessfully: 'Uppdaterades', - updateForEveryone: 'Uppdatering för alla', + updateForEveryone: 'Uppdatera för alla', updating: 'Uppdaterar...', uploading: 'Laddar upp...', uploadingBulk: 'Laddar upp {{current}} av {{total}}', From 6badb5ffcf241d1a8e577896f81e1401ad31efe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Tue, 1 Apr 2025 10:03:39 -0300 Subject: [PATCH 45/77] chore(live-preview): enable TypeScript strict (#11840) --- packages/live-preview/src/handleMessage.ts | 10 +++++-- packages/live-preview/src/mergeData.ts | 14 +++++++-- packages/live-preview/src/subscribe.ts | 2 +- packages/live-preview/src/traverseFields.ts | 29 +++++++++---------- packages/live-preview/src/traverseRichText.ts | 2 +- packages/live-preview/tsconfig.json | 5 ---- 6 files changed, 35 insertions(+), 27 deletions(-) diff --git a/packages/live-preview/src/handleMessage.ts b/packages/live-preview/src/handleMessage.ts index dbf517f7a9..ed7ebeb47f 100644 --- a/packages/live-preview/src/handleMessage.ts +++ b/packages/live-preview/src/handleMessage.ts @@ -1,9 +1,15 @@ +import type { FieldSchemaJSON } from 'payload' + import type { LivePreviewMessageEvent } from './types.js' import { isLivePreviewEvent } from './isLivePreviewEvent.js' import { mergeData } from './mergeData.js' -const _payloadLivePreview = { +const _payloadLivePreview: { + fieldSchema: FieldSchemaJSON | undefined + // eslint-disable-next-line @typescript-eslint/no-explicit-any + previousData: any +} = { /** * For performance reasons, `fieldSchemaJSON` will only be sent once on the initial message * We need to cache this value so that it can be used across subsequent messages @@ -18,7 +24,7 @@ const _payloadLivePreview = { previousData: undefined, } -export const handleMessage = async (args: { +export const handleMessage = async >(args: { apiRoute?: string depth?: number event: LivePreviewMessageEvent diff --git a/packages/live-preview/src/mergeData.ts b/packages/live-preview/src/mergeData.ts index ee7b7cf38d..1448377475 100644 --- a/packages/live-preview/src/mergeData.ts +++ b/packages/live-preview/src/mergeData.ts @@ -4,7 +4,15 @@ import type { PopulationsByCollection } from './types.js' import { traverseFields } from './traverseFields.js' -const defaultRequestHandler = ({ apiPath, endpoint, serverURL }) => { +const defaultRequestHandler = ({ + apiPath, + endpoint, + serverURL, +}: { + apiPath: string + endpoint: string + serverURL: string +}) => { const url = `${serverURL}${apiPath}/${endpoint}` return fetch(url, { credentials: 'include', @@ -19,7 +27,7 @@ const defaultRequestHandler = ({ apiPath, endpoint, serverURL }) => { // Instead, we keep track of the old locale ourselves and trigger a re-population when it changes let prevLocale: string | undefined -export const mergeData = async (args: { +export const mergeData = async >(args: { apiRoute?: string collectionPopulationRequestHandler?: ({ apiPath, @@ -86,7 +94,7 @@ export const mergeData = async (args: { if (res?.docs?.length > 0) { res.docs.forEach((doc) => { - populationsByCollection[collection].forEach((population) => { + populationsByCollection[collection]?.forEach((population) => { if (population.id === doc.id) { population.ref[population.accessor] = doc } diff --git a/packages/live-preview/src/subscribe.ts b/packages/live-preview/src/subscribe.ts index 2f09121be4..6cbe1bf4e7 100644 --- a/packages/live-preview/src/subscribe.ts +++ b/packages/live-preview/src/subscribe.ts @@ -1,6 +1,6 @@ import { handleMessage } from './handleMessage.js' -export const subscribe = (args: { +export const subscribe = >(args: { apiRoute?: string callback: (data: T) => void depth?: number diff --git a/packages/live-preview/src/traverseFields.ts b/packages/live-preview/src/traverseFields.ts index d9f9bbb528..caa024efb4 100644 --- a/packages/live-preview/src/traverseFields.ts +++ b/packages/live-preview/src/traverseFields.ts @@ -1,17 +1,16 @@ -import type { DocumentEvent } from 'payload' -import type { fieldSchemaToJSON } from 'payload/shared' +import type { DocumentEvent, FieldSchemaJSON } from 'payload' import type { PopulationsByCollection } from './types.js' import { traverseRichText } from './traverseRichText.js' -export const traverseFields = (args: { +export const traverseFields = >(args: { externallyUpdatedRelationship?: DocumentEvent - fieldSchema: ReturnType + fieldSchema: FieldSchemaJSON incomingData: T localeChanged: boolean populationsByCollection: PopulationsByCollection - result: T + result: Record }): void => { const { externallyUpdatedRelationship, @@ -48,7 +47,7 @@ export const traverseFields = (args: { traverseFields({ externallyUpdatedRelationship, - fieldSchema: fieldSchema.fields, + fieldSchema: fieldSchema.fields!, incomingData: incomingRow, localeChanged, populationsByCollection, @@ -64,7 +63,7 @@ export const traverseFields = (args: { case 'blocks': if (Array.isArray(incomingData[fieldName])) { result[fieldName] = incomingData[fieldName].map((incomingBlock, i) => { - const incomingBlockJSON = fieldSchema.blocks[incomingBlock.blockType] + const incomingBlockJSON = fieldSchema.blocks?.[incomingBlock.blockType] if (!result[fieldName]) { result[fieldName] = [] @@ -82,7 +81,7 @@ export const traverseFields = (args: { traverseFields({ externallyUpdatedRelationship, - fieldSchema: incomingBlockJSON.fields, + fieldSchema: incomingBlockJSON!.fields!, incomingData: incomingBlock, localeChanged, populationsByCollection, @@ -106,7 +105,7 @@ export const traverseFields = (args: { traverseFields({ externallyUpdatedRelationship, - fieldSchema: fieldSchema.fields, + fieldSchema: fieldSchema.fields!, incomingData: incomingData[fieldName] || {}, localeChanged, populationsByCollection, @@ -166,11 +165,11 @@ export const traverseFields = (args: { incomingRelation === externallyUpdatedRelationship?.id if (hasChanged || hasUpdated || localeChanged) { - if (!populationsByCollection[fieldSchema.relationTo]) { - populationsByCollection[fieldSchema.relationTo] = [] + if (!populationsByCollection[fieldSchema.relationTo!]) { + populationsByCollection[fieldSchema.relationTo!] = [] } - populationsByCollection[fieldSchema.relationTo].push({ + populationsByCollection[fieldSchema.relationTo!]?.push({ id: incomingRelation, accessor: i, ref: result[fieldName], @@ -265,11 +264,11 @@ export const traverseFields = (args: { // if the new value is not empty, populate it // otherwise set the value to null if (newID) { - if (!populationsByCollection[fieldSchema.relationTo]) { - populationsByCollection[fieldSchema.relationTo] = [] + if (!populationsByCollection[fieldSchema.relationTo!]) { + populationsByCollection[fieldSchema.relationTo!] = [] } - populationsByCollection[fieldSchema.relationTo].push({ + populationsByCollection[fieldSchema.relationTo!]?.push({ id: newID, accessor: fieldName, ref: result as Record, diff --git a/packages/live-preview/src/traverseRichText.ts b/packages/live-preview/src/traverseRichText.ts index 5eca16b5a4..878595b01e 100644 --- a/packages/live-preview/src/traverseRichText.ts +++ b/packages/live-preview/src/traverseRichText.ts @@ -79,7 +79,7 @@ export const traverseRichText = ({ populationsByCollection[incomingData.relationTo] = [] } - populationsByCollection[incomingData.relationTo].push({ + populationsByCollection[incomingData.relationTo]?.push({ id: incomingData[key] && typeof incomingData[key] === 'object' ? incomingData[key].id diff --git a/packages/live-preview/tsconfig.json b/packages/live-preview/tsconfig.json index 14564e0715..45209999a2 100644 --- a/packages/live-preview/tsconfig.json +++ b/packages/live-preview/tsconfig.json @@ -1,9 +1,4 @@ { "extends": "../../tsconfig.base.json", - "compilerOptions": { - /* TODO: remove the following lines */ - "strict": false, - "noUncheckedIndexedAccess": false, - }, "references": [{ "path": "../payload" }] } From 329cd0b876d6609ca30acf0cf02fdcbefeff14b5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Apr 2025 09:09:06 -0400 Subject: [PATCH 46/77] chore(deps): bump mongodb-github-action (#10921) Bumps the github_actions group with 1 update in the / directory: [supercharge/mongodb-github-action](https://github.com/supercharge/mongodb-github-action). Bumps the github_actions group with 1 update in the /.github/workflows directory: [supercharge/mongodb-github-action](https://github.com/supercharge/mongodb-github-action). Updates `supercharge/mongodb-github-action` from 1.11.0 to 1.12.0
Release notes

Sourced from supercharge/mongodb-github-action's releases.

1.12.0

Release 1.12.0

Changelog

Sourced from supercharge/mongodb-github-action's changelog.

1.12.0 - 2025-01-05

Added

  • added mongodb-image input: this option allows you to define a custom Docker container image. It uses mongo by default, but you may specify an image from a different registry than Docker hub. Please check the Readme for details.

Updated

  • bump dependencies
Commits

Updates `supercharge/mongodb-github-action` from 1.11.0 to 1.12.0
Release notes

Sourced from supercharge/mongodb-github-action's releases.

1.12.0

Release 1.12.0

Changelog

Sourced from supercharge/mongodb-github-action's changelog.

1.12.0 - 2025-01-05

Added

  • added mongodb-image input: this option allows you to define a custom Docker container image. It uses mongo by default, but you may specify an image from a different registry than Docker hub. Please check the Readme for details.

Updated

  • bump dependencies
Commits

You can trigger a rebase of this PR by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
> **Note** > Automatic rebases have been disabled on this pull request as it has been open for over 30 days. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/post-release-templates.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/post-release-templates.yml b/.github/workflows/post-release-templates.yml index b370c76d77..e322f0ed9b 100644 --- a/.github/workflows/post-release-templates.yml +++ b/.github/workflows/post-release-templates.yml @@ -83,7 +83,7 @@ jobs: echo "DATABASE_URI=postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" >> $GITHUB_ENV - name: Start MongoDB - uses: supercharge/mongodb-github-action@1.11.0 + uses: supercharge/mongodb-github-action@1.12.0 with: mongodb-version: 6.0 From 373f6d1032f146258d12f8783b5726c420975b79 Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Tue, 1 Apr 2025 09:54:22 -0400 Subject: [PATCH 47/77] fix(ui): nested fields disappear when manipulating rows in form state (#11906) Continuation of #11867. When rendering custom fields nested within arrays or blocks, such as the Lexical rich text editor which is treated as a custom field, these fields will sometimes disappear when form state requests are invoked sequentially. This is especially reproducible on slow networks. This is different from the previous PR in that this issue is caused by adding _rows_ back-to-back, whereas the previous issue was caused when adding a single row followed by a change to another field. Here's a screen recording demonstrating the issue: https://github.com/user-attachments/assets/5ecfa9ec-b747-49ed-8618-df282e64519d The problem is that `requiresRender` is never sent in the form state request for row 2. This is because the [task queue](https://github.com/payloadcms/payload/pull/11579) processes tasks within a single `useEffect`. This forces React to batch the results of these tasks into a single rendering cycle. So if request 1 sets state that request 2 relies on, request 2 will never use that state since they'll execute within the same lifecycle. Here's a play-by-play of the current behavior: 1. The "add row" event is dispatched a. This sets `requiresRender: true` in form state 1. A form state request is sent with `requiresRender: true` 1. While that request is processing, another "add row" event is dispatched a. This sets `requiresRender: true` in form state b. This adds a form state request into the queue 1. The initial form state request finishes a. This sets `requiresRender: false` in form state 1. The next form state request that was queued up in 3b is sent with `requiresRender: false` a. THIS IS EXPECTED, BUT SHOULD ACTUALLY BE `true`!! To fix this this, we need to ensure that the `requiresRender` property is persisted into the second request instead of overridden. To do this, we can add a new `serverPropsToIgnore` to form state which is read when the processing results from the server. So if `requiresRender` exists in `serverPropsToIgnore`, we do not merge it. This works because we actually mutate form state in between requests. So request 2 can read the results from request 1 without going through an additional rendering cycle. Here's a play-by-play of the fix: 1. The "add row" event is dispatched a. This sets `requiresRender: true` in form state b. This adds a task in the queue to mutate form state with `requiresRender: true` 1. A form state request is sent with `requiresRender: true` 1. While that request is processing, another "add row" event is dispatched a. This sets `requiresRender: true` in form state AND `serverPropsToIgnore: [ "requiresRender" ]` c. This adds a form state request into the queue 1. The initial form state request finishes a. This returns `requiresRender: false` from the form state endpoint BUT IS IGNORED 1. The next form state request that was queued up in 3c is sent with `requiresRender: true` --- packages/payload/src/admin/forms/Form.ts | 12 +++ packages/ui/src/fields/Array/index.tsx | 16 ++-- packages/ui/src/fields/Blocks/index.tsx | 16 ++-- packages/ui/src/forms/Form/fieldReducer.ts | 45 +++++++++- packages/ui/src/forms/Form/index.tsx | 35 ++++++-- .../ui/src/forms/Form/initContextState.ts | 1 + .../ui/src/forms/Form/mergeServerFormState.ts | 35 ++++++-- packages/ui/src/forms/Form/types.ts | 12 +++ .../addFieldStatePromise.ts | 2 - test/eslint.config.js | 1 + test/form-state/e2e.spec.ts | 90 ++++++++++++++++++- test/helpers/e2e/assertRequestBody.ts | 28 ++++++ tsconfig.base.json | 2 +- 13 files changed, 253 insertions(+), 42 deletions(-) create mode 100644 test/helpers/e2e/assertRequestBody.ts diff --git a/packages/payload/src/admin/forms/Form.ts b/packages/payload/src/admin/forms/Form.ts index 94242f0932..419087a6ec 100644 --- a/packages/payload/src/admin/forms/Form.ts +++ b/packages/payload/src/admin/forms/Form.ts @@ -49,6 +49,18 @@ export type FieldState = { passesCondition?: boolean requiresRender?: boolean rows?: Row[] + /** + * The `serverPropsToIgnore` obj is used to prevent the various properties from being overridden across form state requests. + * This can happen when queueing a form state request with `requiresRender: true` while the another is already processing. + * For example: + * 1. One "add row" action will set `requiresRender: true` and dispatch a form state request + * 2. Another "add row" action will set `requiresRender: true` and queue a form state request + * 3. The first request will return with `requiresRender: false` + * 4. The second request will be dispatched with `requiresRender: false` but should be `true` + * To fix this, only merge the `requiresRender` property if the previous state has not set it to `true`. + * See the `mergeServerFormState` function for implementation details. + */ + serverPropsToIgnore?: Array valid?: boolean validate?: Validate value?: unknown diff --git a/packages/ui/src/fields/Array/index.tsx b/packages/ui/src/fields/Array/index.tsx index 3a6ee75733..a230a93c82 100644 --- a/packages/ui/src/fields/Array/index.tsx +++ b/packages/ui/src/fields/Array/index.tsx @@ -58,7 +58,7 @@ export const ArrayFieldComponent: ArrayFieldClientComponent = (props) => { const minRows = (minRowsProp ?? required) ? 1 : 0 const { setDocFieldPreferences } = useDocumentInfo() - const { addFieldRow, dispatchFields, setModified } = useForm() + const { addFieldRow, dispatchFields, moveFieldRow, removeFieldRow, setModified } = useForm() const submitted = useFormSubmitted() const { code: locale } = useLocale() const { i18n, t } = useTranslation() @@ -153,18 +153,20 @@ export const ArrayFieldComponent: ArrayFieldClientComponent = (props) => { const removeRow = useCallback( (rowIndex: number) => { - dispatchFields({ type: 'REMOVE_ROW', path, rowIndex }) - setModified(true) + removeFieldRow({ path, rowIndex }) }, - [dispatchFields, path, setModified], + [removeFieldRow, path], ) const moveRow = useCallback( (moveFromIndex: number, moveToIndex: number) => { - dispatchFields({ type: 'MOVE_ROW', moveFromIndex, moveToIndex, path }) - setModified(true) + moveFieldRow({ + moveFromIndex, + moveToIndex, + path, + }) }, - [dispatchFields, path, setModified], + [path, moveFieldRow], ) const toggleCollapseAll = useCallback( diff --git a/packages/ui/src/fields/Blocks/index.tsx b/packages/ui/src/fields/Blocks/index.tsx index 8b68ebf6db..10d562742d 100644 --- a/packages/ui/src/fields/Blocks/index.tsx +++ b/packages/ui/src/fields/Blocks/index.tsx @@ -60,7 +60,7 @@ const BlocksFieldComponent: BlocksFieldClientComponent = (props) => { const minRows = (minRowsProp ?? required) ? 1 : 0 const { setDocFieldPreferences } = useDocumentInfo() - const { addFieldRow, dispatchFields, setModified } = useForm() + const { addFieldRow, dispatchFields, moveFieldRow, removeFieldRow, setModified } = useForm() const { code: locale } = useLocale() const { config: { localization }, @@ -141,23 +141,19 @@ const BlocksFieldComponent: BlocksFieldClientComponent = (props) => { const removeRow = useCallback( (rowIndex: number) => { - dispatchFields({ - type: 'REMOVE_ROW', + removeFieldRow({ path, rowIndex, }) - - setModified(true) }, - [path, dispatchFields, setModified], + [path, removeFieldRow], ) const moveRow = useCallback( (moveFromIndex: number, moveToIndex: number) => { - dispatchFields({ type: 'MOVE_ROW', moveFromIndex, moveToIndex, path }) - setModified(true) + moveFieldRow({ moveFromIndex, moveToIndex, path }) }, - [dispatchFields, path, setModified], + [moveFieldRow, path], ) const toggleCollapseAll = useCallback( @@ -166,6 +162,7 @@ const BlocksFieldComponent: BlocksFieldClientComponent = (props) => { collapsed, rows, }) + dispatchFields({ type: 'SET_ALL_ROWS_COLLAPSED', path, updatedRows }) setDocFieldPreferences(path, { collapsed: collapsedIDs }) }, @@ -179,6 +176,7 @@ const BlocksFieldComponent: BlocksFieldClientComponent = (props) => { rowID, rows, }) + dispatchFields({ type: 'SET_ROW_COLLAPSED', path, updatedRows }) setDocFieldPreferences(path, { collapsed: collapsedIDs }) }, diff --git a/packages/ui/src/forms/Form/fieldReducer.ts b/packages/ui/src/forms/Form/fieldReducer.ts index d96294413c..744463eb48 100644 --- a/packages/ui/src/forms/Form/fieldReducer.ts +++ b/packages/ui/src/forms/Form/fieldReducer.ts @@ -63,6 +63,14 @@ export function fieldReducer(state: FormState, action: FieldAction): FormState { requiresRender: true, rows: withNewRow, value: siblingRows.length, + ...(state[path]?.requiresRender === true + ? { + serverPropsToIgnore: [ + ...(state[path]?.serverPropsToIgnore || []), + 'requiresRender', + ], + } + : state[path]?.serverPropsToIgnore || []), }, } @@ -172,6 +180,14 @@ export function fieldReducer(state: FormState, action: FieldAction): FormState { requiresRender: true, rows: rowsMetadata, value: rows.length, + ...(state[path]?.requiresRender === true + ? { + serverPropsToIgnore: [ + ...(state[path]?.serverPropsToIgnore || []), + 'requiresRender', + ], + } + : state[path]?.serverPropsToIgnore || ([] as any)), }, } @@ -200,6 +216,14 @@ export function fieldReducer(state: FormState, action: FieldAction): FormState { ...state[path], requiresRender: true, rows: rowsWithinField, + ...(state[path]?.requiresRender === true + ? { + serverPropsToIgnore: [ + ...(state[path]?.serverPropsToIgnore || []), + 'requiresRender', + ], + } + : state[path]?.serverPropsToIgnore || ([] as any)), }, } @@ -218,9 +242,8 @@ export function fieldReducer(state: FormState, action: FieldAction): FormState { const copyOfMovingLabel = customComponents.RowLabels[moveFromIndex] - // eslint-disable-next-line @typescript-eslint/no-floating-promises customComponents.RowLabels.splice(moveFromIndex, 1) - // eslint-disable-next-line @typescript-eslint/no-floating-promises + customComponents.RowLabels.splice(moveToIndex, 0, copyOfMovingLabel) newState[path].customComponents = customComponents @@ -253,6 +276,14 @@ export function fieldReducer(state: FormState, action: FieldAction): FormState { requiresRender: true, rows: rowsMetadata, value: rows.length, + ...(state[path]?.requiresRender === true + ? { + serverPropsToIgnore: [ + ...(state[path]?.serverPropsToIgnore || []), + 'requiresRender', + ], + } + : state[path]?.serverPropsToIgnore || []), }, ...flattenRows(path, rows), } @@ -292,6 +323,14 @@ export function fieldReducer(state: FormState, action: FieldAction): FormState { disableFormData: true, rows: rowsMetadata, value: siblingRows.length, + ...(state[path]?.requiresRender === true + ? { + serverPropsToIgnore: [ + ...(state[path]?.serverPropsToIgnore || []), + 'requiresRender', + ], + } + : state[path]?.serverPropsToIgnore || []), }, } @@ -327,7 +366,7 @@ export function fieldReducer(state: FormState, action: FieldAction): FormState { return newState } - //TODO: Remove this in 4.0 - this is a temporary fix to prevent a breaking change + // TODO: Remove this in 4.0 - this is a temporary fix to prevent a breaking change if (action.sanitize) { for (const field of Object.values(action.state)) { if (field.valid !== false) { diff --git a/packages/ui/src/forms/Form/index.tsx b/packages/ui/src/forms/Form/index.tsx index 5470ea5a44..8e9246a93a 100644 --- a/packages/ui/src/forms/Form/index.tsx +++ b/packages/ui/src/forms/Form/index.tsx @@ -121,11 +121,11 @@ export const Form: React.FC = (props) => { const fieldsReducer = useReducer(fieldReducer, {}, () => initialState) - const [fields, dispatchFields] = fieldsReducer + const [formState, dispatchFields] = fieldsReducer - contextRef.current.fields = fields + contextRef.current.fields = formState - const prevFields = useRef(fields) + const prevFormState = useRef(formState) const validateForm = useCallback(async () => { const validatedFieldState = {} @@ -611,9 +611,25 @@ export const Form: React.FC = (props) => { [dispatchFields, getDataByPath], ) + const moveFieldRow: FormContextType['moveFieldRow'] = useCallback( + ({ moveFromIndex, moveToIndex, path }) => { + dispatchFields({ + type: 'MOVE_ROW', + moveFromIndex, + moveToIndex, + path, + }) + + setModified(true) + }, + [dispatchFields], + ) + const removeFieldRow: FormContextType['removeFieldRow'] = useCallback( ({ path, rowIndex }) => { dispatchFields({ type: 'REMOVE_ROW', path, rowIndex }) + + setModified(true) }, [dispatchFields], ) @@ -672,6 +688,7 @@ export const Form: React.FC = (props) => { contextRef.current.dispatchFields = dispatchFields contextRef.current.addFieldRow = addFieldRow contextRef.current.removeFieldRow = removeFieldRow + contextRef.current.moveFieldRow = moveFieldRow contextRef.current.replaceFieldRow = replaceFieldRow contextRef.current.uuid = uuid contextRef.current.initializing = initializing @@ -710,7 +727,7 @@ export const Form: React.FC = (props) => { refreshCookie() }, 15000, - [fields], + [formState], ) useEffect(() => { @@ -743,7 +760,7 @@ export const Form: React.FC = (props) => { }) if (changed) { - prevFields.current = newState + prevFormState.current = newState dispatchFields({ type: 'REPLACE_STATE', @@ -757,14 +774,14 @@ export const Form: React.FC = (props) => { useDebouncedEffect( () => { - if ((isFirstRenderRef.current || !dequal(fields, prevFields.current)) && modified) { + if ((isFirstRenderRef.current || !dequal(formState, prevFormState.current)) && modified) { executeOnChange(submitted) } - prevFields.current = fields + prevFormState.current = formState isFirstRenderRef.current = false }, - [modified, submitted, fields], + [modified, submitted, formState], 250, ) @@ -793,7 +810,7 @@ export const Form: React.FC = (props) => { diff --git a/packages/ui/src/forms/Form/initContextState.ts b/packages/ui/src/forms/Form/initContextState.ts index 30ba7295ce..ac3c9a9a11 100644 --- a/packages/ui/src/forms/Form/initContextState.ts +++ b/packages/ui/src/forms/Form/initContextState.ts @@ -41,6 +41,7 @@ export const initContextState: Context = { getSiblingData, initializing: undefined, isValid: true, + moveFieldRow: () => undefined, removeFieldRow: () => undefined, replaceFieldRow: () => undefined, replaceState: () => undefined, diff --git a/packages/ui/src/forms/Form/mergeServerFormState.ts b/packages/ui/src/forms/Form/mergeServerFormState.ts index 753972a4e7..f86ae1a6f5 100644 --- a/packages/ui/src/forms/Form/mergeServerFormState.ts +++ b/packages/ui/src/forms/Form/mergeServerFormState.ts @@ -1,4 +1,6 @@ 'use client' +import type { FieldState } from 'payload' + import { dequal } from 'dequal/lite' // lite: no need for Map and Set support import { type FormState } from 'payload' @@ -27,7 +29,7 @@ export const mergeServerFormState = ({ const newState = {} if (existingState) { - const serverPropsToAccept = [ + const serverPropsToAccept: Array = [ 'passesCondition', 'valid', 'errorMessage', @@ -46,6 +48,7 @@ export const mergeServerFormState = ({ if (!incomingState[path]) { continue } + let fieldChanged = false /** @@ -55,6 +58,7 @@ export const mergeServerFormState = ({ newFieldState.errorPaths, incomingState[path].errorPaths as unknown as string[], ) + if (errorPathsResult.result) { if (errorPathsResult.changed) { changed = errorPathsResult.changed @@ -76,18 +80,33 @@ export const mergeServerFormState = ({ /** * Handle adding all the remaining props that should be updated in the local form state from the server form state */ - serverPropsToAccept.forEach((prop) => { - if (!dequal(incomingState[path]?.[prop], newFieldState[prop])) { + serverPropsToAccept.forEach((propFromServer) => { + if (!dequal(incomingState[path]?.[propFromServer], newFieldState[propFromServer])) { changed = true fieldChanged = true - if (!(prop in incomingState[path])) { + + if (newFieldState?.serverPropsToIgnore?.includes(propFromServer)) { + // Remove the ignored prop for the next request + newFieldState.serverPropsToIgnore = newFieldState.serverPropsToIgnore.filter( + (prop) => prop !== propFromServer, + ) + + // if no keys left, remove the entire object + if (!newFieldState.serverPropsToIgnore.length) { + delete newFieldState.serverPropsToIgnore + } + + return + } + + if (!(propFromServer in incomingState[path])) { // Regarding excluding the customComponents prop from being deleted: the incoming state might not have been rendered, as rendering components for every form onchange is expensive. // Thus, we simply re-use the initial render state - if (prop !== 'customComponents') { - delete newFieldState[prop] + if (propFromServer !== 'customComponents') { + delete newFieldState[propFromServer] } } else { - newFieldState[prop] = incomingState[path][prop] + newFieldState[propFromServer as any] = incomingState[path][propFromServer] } } }) @@ -95,6 +114,7 @@ export const mergeServerFormState = ({ if (newFieldState.valid !== false) { newFieldState.valid = true } + if (newFieldState.passesCondition !== false) { newFieldState.passesCondition = true } @@ -106,7 +126,6 @@ export const mergeServerFormState = ({ // Now loop over values that are part of incoming state but not part of existing state, and add them to the new state. // This can happen if a new array row was added. In our local state, we simply add out stubbed `array` and `array.[index].id` entries to the local form state. // However, all other array sub-fields are not added to the local state - those will be added by the server and may be incoming here. - for (const [path, field] of Object.entries(incomingState)) { if (!existingState[path]) { changed = true diff --git a/packages/ui/src/forms/Form/types.ts b/packages/ui/src/forms/Form/types.ts index 7c0266441b..1a65ba2efb 100644 --- a/packages/ui/src/forms/Form/types.ts +++ b/packages/ui/src/forms/Form/types.ts @@ -80,7 +80,9 @@ export type Submit = ( options?: SubmitOptions, e?: React.FormEvent, ) => Promise + export type ValidateForm = () => Promise + export type CreateFormData = ( overrides?: Record, /** @@ -89,6 +91,7 @@ export type CreateFormData = ( */ options?: { mergeOverrideData?: boolean }, ) => FormData | Promise + export type GetFields = () => FormState export type GetField = (path: string) => FormField export type GetData = () => Data @@ -236,6 +239,15 @@ export type Context = { * For example the state could be submitted but invalid as field errors have been returned. */ isValid: boolean + moveFieldRow: ({ + moveFromIndex, + moveToIndex, + path, + }: { + moveFromIndex: number + moveToIndex: number + path: string + }) => void removeFieldRow: ({ path, rowIndex }: { path: string; rowIndex: number }) => void replaceFieldRow: ({ blockType, diff --git a/packages/ui/src/forms/fieldSchemasToFormState/addFieldStatePromise.ts b/packages/ui/src/forms/fieldSchemasToFormState/addFieldStatePromise.ts index 5760eb7c46..c1b17a9f14 100644 --- a/packages/ui/src/forms/fieldSchemasToFormState/addFieldStatePromise.ts +++ b/packages/ui/src/forms/fieldSchemasToFormState/addFieldStatePromise.ts @@ -356,8 +356,6 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom fieldState.rows = rows } - // Unset requiresRender - // so it will be removed from form state fieldState.requiresRender = false // Add values to field state diff --git a/test/eslint.config.js b/test/eslint.config.js index a39b80786b..1912a6b678 100644 --- a/test/eslint.config.js +++ b/test/eslint.config.js @@ -70,6 +70,7 @@ export const testEslintConfig = [ 'saveDocAndAssert', 'runFilterOptionsTest', 'assertNetworkRequests', + 'assertRequestBody', ], }, ], diff --git a/test/form-state/e2e.spec.ts b/test/form-state/e2e.spec.ts index 72b9ea243f..7c3ed9c0f4 100644 --- a/test/form-state/e2e.spec.ts +++ b/test/form-state/e2e.spec.ts @@ -1,9 +1,11 @@ import type { BrowserContext, Page } from '@playwright/test' import type { PayloadTestSDK } from 'helpers/sdk/index.js' +import type { FormState } from 'payload' import { expect, test } from '@playwright/test' import { addBlock } from 'helpers/e2e/addBlock.js' import { assertNetworkRequests } from 'helpers/e2e/assertNetworkRequests.js' +import { assertRequestBody } from 'helpers/e2e/assertRequestBody.js' import * as path from 'path' import { fileURLToPath } from 'url' @@ -180,7 +182,7 @@ test.describe('Form State', () => { await cdpSession.detach() }) - test('sequentially queued tasks not cause nested custom components to disappear', async () => { + test('should not cause nested custom fields to disappear when queuing form state (1)', async () => { await page.goto(postsUrl.create) const field = page.locator('#field-title') await field.fill('Test') @@ -191,14 +193,25 @@ test.describe('Form State', () => { delay: 'Slow 3G', }) + // Add a row and immediately type into another field + // Test that the rich text field within the row does not disappear await assertNetworkRequests( page, postsUrl.create, async () => { - await page.locator('#field-array .array-field__add-row').click() + // Ensure `requiresRender` is `true` is set for the first request + await assertRequestBody<{ args: { formState: FormState } }[]>(page, { + action: page.locator('#field-array .array-field__add-row').click(), + expect: (body) => body[0]?.args?.formState?.array?.requiresRender === true, + }) - await page.locator('#field-title').fill('Title 2') + // Ensure `requiresRender` is `false` for the second request + await assertRequestBody<{ args: { formState: FormState } }[]>(page, { + action: page.locator('#field-title').fill('Title 2'), + expect: (body) => body[0]?.args?.formState?.array?.requiresRender === false, + }) + // use `waitForSelector` to ensure the element doesn't appear and then disappear // eslint-disable-next-line playwright/no-wait-for-selector await page.waitForSelector('#field-array #array-row-0 .field-type.rich-text-lexical', { timeout: TEST_TIMEOUT, @@ -223,6 +236,77 @@ test.describe('Form State', () => { await cdpSession.detach() }) + + test('should not cause nested custom fields to disappear when queuing form state (2)', async () => { + await page.goto(postsUrl.create) + const field = page.locator('#field-title') + await field.fill('Test') + + const cdpSession = await throttleTest({ + page, + context, + delay: 'Slow 3G', + }) + + // Add two rows quickly + // Test that the rich text fields within the rows do not disappear + await assertNetworkRequests( + page, + postsUrl.create, + async () => { + // Ensure `requiresRender` is `true` is set for the first request + await assertRequestBody<{ args: { formState: FormState } }[]>(page, { + action: page.locator('#field-array .array-field__add-row').click(), + expect: (body) => body[0]?.args?.formState?.array?.requiresRender === true, + }) + + // Ensure `requiresRender` is `true` is set for the second request + await assertRequestBody<{ args: { formState: FormState } }[]>(page, { + action: page.locator('#field-array .array-field__add-row').click(), + expect: (body) => body[0]?.args?.formState?.array?.requiresRender === true, + }) + + // use `waitForSelector` to ensure the element doesn't appear and then disappear + // eslint-disable-next-line playwright/no-wait-for-selector + await page.waitForSelector('#field-array #array-row-0 .field-type.rich-text-lexical', { + timeout: TEST_TIMEOUT, + }) + + // use `waitForSelector` to ensure the element doesn't appear and then disappear + // eslint-disable-next-line playwright/no-wait-for-selector + await page.waitForSelector('#field-array #array-row-1 .field-type.rich-text-lexical', { + timeout: TEST_TIMEOUT, + }) + + await expect( + page.locator('#field-array #array-row-0 .field-type.rich-text-lexical'), + ).toBeVisible() + + await expect( + page.locator('#field-array #array-row-1 .field-type.rich-text-lexical'), + ).toBeVisible() + }, + { + allowedNumberOfRequests: 2, + timeout: 10000, + }, + ) + + // Ensure `requiresRender` is `false` for the third request + await assertRequestBody<{ args: { formState: FormState } }[]>(page, { + action: page.locator('#field-title').fill('Title 2'), + expect: (body) => body[0]?.args?.formState?.array?.requiresRender === false, + }) + + await cdpSession.send('Network.emulateNetworkConditions', { + offline: false, + latency: 0, + downloadThroughput: -1, + uploadThroughput: -1, + }) + + await cdpSession.detach() + }) }) async function createPost(overrides?: Partial): Promise { diff --git a/test/helpers/e2e/assertRequestBody.ts b/test/helpers/e2e/assertRequestBody.ts new file mode 100644 index 0000000000..9873092790 --- /dev/null +++ b/test/helpers/e2e/assertRequestBody.ts @@ -0,0 +1,28 @@ +import type { Page } from '@playwright/test' + +import { expect } from '@playwright/test' + +export const assertRequestBody = async ( + page: Page, + options: { + action: Promise | void + expect?: (requestBody: T) => boolean | Promise + }, +): Promise => { + const [request] = await Promise.all([ + page.waitForRequest((request) => request.method() === 'POST'), // Adjust condition as needed + await options.action, + ]) + + const requestBody = request.postData() + + if (typeof requestBody === 'string') { + const parsedBody = JSON.parse(requestBody) as T + + if (typeof options.expect === 'function') { + expect(await options.expect(parsedBody)).toBeTruthy() + } + + return parsedBody + } +} diff --git a/tsconfig.base.json b/tsconfig.base.json index daa36c7211..e2b64e3bc8 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -31,7 +31,7 @@ } ], "paths": { - "@payload-config": ["./test/query-presets/config.ts"], + "@payload-config": ["./test/form-state/config.ts"], "@payloadcms/admin-bar": ["./packages/admin-bar/src"], "@payloadcms/live-preview": ["./packages/live-preview/src"], "@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"], From 968a066f45c90ccb8b8a5eb4f5e7aa609679283e Mon Sep 17 00:00:00 2001 From: Dan Ribbens Date: Tue, 1 Apr 2025 11:35:31 -0400 Subject: [PATCH 48/77] fix: typescriptSchema override required to false (#11941) ### What? Previously if you used the typescriptSchema and `returned: false`, the field would still be required anyways. ### Why? We were adding fields to be required on the collection without comparing the returned schema from typescriptSchema functions. ### How? This changes the order of logic so that `requiredFieldNames` on the collection is only after running and checking the field schema. --- .../src/utilities/configToJSONSchema.spec.ts | 32 +++++++++++++++++++ .../src/utilities/configToJSONSchema.ts | 6 ++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/packages/payload/src/utilities/configToJSONSchema.spec.ts b/packages/payload/src/utilities/configToJSONSchema.spec.ts index 3bb159559f..5e18c61f2e 100644 --- a/packages/payload/src/utilities/configToJSONSchema.spec.ts +++ b/packages/payload/src/utilities/configToJSONSchema.spec.ts @@ -411,4 +411,36 @@ describe('configToJSONSchema', () => { expect(schema?.definitions?.SharedBlock).toBeDefined() }) + + it('should allow overriding required to false', async () => { + // @ts-expect-error + const config: Config = { + collections: [ + { + slug: 'test', + fields: [ + { + name: 'title', + type: 'text', + required: true, + defaultValue: 'test', + typescriptSchema: [ + () => ({ + type: 'string', + required: false, + }), + ], + }, + ], + timestamps: false, + }, + ], + } + + const sanitizedConfig = await sanitizeConfig(config) + const schema = configToJSONSchema(sanitizedConfig, 'text') + + // @ts-expect-error + expect(schema.definitions.test.properties.title.required).toStrictEqual(false) + }) }) diff --git a/packages/payload/src/utilities/configToJSONSchema.ts b/packages/payload/src/utilities/configToJSONSchema.ts index ddba5263d5..c00c95cbe6 100644 --- a/packages/payload/src/utilities/configToJSONSchema.ts +++ b/packages/payload/src/utilities/configToJSONSchema.ts @@ -258,9 +258,6 @@ export function fieldsToJSONSchema( properties: Object.fromEntries( fields.reduce((fieldSchemas, field, index) => { const isRequired = fieldAffectsData(field) && fieldIsRequired(field) - if (isRequired) { - requiredFieldNames.add(field.name) - } const fieldDescription = entityOrFieldToJsDocs({ entity: field, i18n }) const baseFieldSchema: JSONSchema4 = {} @@ -706,6 +703,9 @@ export function fieldsToJSONSchema( } if (fieldSchema && fieldAffectsData(field)) { + if (isRequired && fieldSchema.required !== false) { + requiredFieldNames.add(field.name) + } fieldSchemas.set(field.name, fieldSchema) } From d963e6a54cf1e273ff3c1b29139ac07b026f3dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Tue, 1 Apr 2025 15:11:11 -0300 Subject: [PATCH 49/77] feat: orderable collections (#11452) Closes https://github.com/payloadcms/payload/discussions/1413 ### What? Introduces a new `orderable` boolean property on collections that allows dragging and dropping rows to reorder them: https://github.com/user-attachments/assets/8ee85cf0-add1-48e5-a0a2-f73ad66aa24a ### Why? [One of the most requested features](https://github.com/payloadcms/payload/discussions/1413). Additionally, poorly implemented it can be very costly in terms of performance. This can be especially useful for implementing custom views like kanban. ### How? We are using fractional indexing. In its simplest form, it consists of calculating the order of an item to be inserted as the average of its two adjacent elements. There is [a famous article by David Greenspan](https://observablehq.com/@dgreensp/implementing-fractional-indexing) that solves the problem of running out of keys after several partitions. We are using his algorithm, implemented [in this library](https://github.com/rocicorp/fractional-indexing). This means that if you insert, delete or move documents in the collection, you do not have to modify the order of the rest of the documents, making the operation more performant. --------- Co-authored-by: Dan Ribbens --- docs/configuration/collections.mdx | 1 + docs/fields/join.mdx | 1 + packages/next/src/views/List/index.tsx | 2 + packages/next/src/views/Versions/index.tsx | 1 + packages/payload/src/admin/functions/index.ts | 1 + .../src/collections/config/sanitize.ts | 1 + .../payload/src/collections/config/types.ts | 11 + .../config/orderable/fractional-indexing.js | 318 ++++++++++++++++++ .../payload/src/config/orderable/index.ts | 278 +++++++++++++++ packages/payload/src/config/sanitize.ts | 4 + packages/payload/src/fields/config/types.ts | 21 +- packages/payload/src/index.ts | 1 + .../payload/src/utilities/flattenAllFields.ts | 5 + .../src/elements/RelationshipTable/index.tsx | 13 + .../ui/src/elements/SortHeader/index.scss | 52 +++ packages/ui/src/elements/SortHeader/index.tsx | 87 +++++ packages/ui/src/elements/SortRow/index.scss | 22 ++ packages/ui/src/elements/SortRow/index.tsx | 20 ++ .../ui/src/elements/Table/OrderableTable.tsx | 198 +++++++++++ packages/ui/src/icons/Sort/index.scss | 14 + packages/ui/src/icons/Sort/index.tsx | 41 +++ packages/ui/src/providers/ListQuery/index.tsx | 2 + packages/ui/src/providers/ListQuery/types.ts | 2 + packages/ui/src/utilities/buildTableState.ts | 4 +- packages/ui/src/utilities/renderTable.tsx | 38 ++- packages/ui/src/views/List/index.scss | 6 + pnpm-lock.yaml | 51 +-- test/fields/collections/Indexed/e2e.spec.ts | 4 +- test/sort/Seed.tsx | 19 ++ test/sort/collections/Orderable/index.ts | 27 ++ test/sort/collections/OrderableJoin/index.ts | 39 +++ test/sort/config.ts | 59 +++- test/sort/e2e.spec.ts | 152 +++++++++ test/sort/int.spec.ts | 85 ++++- test/sort/payload-types.ts | 85 ++++- 35 files changed, 1616 insertions(+), 49 deletions(-) create mode 100644 packages/payload/src/config/orderable/fractional-indexing.js create mode 100644 packages/payload/src/config/orderable/index.ts create mode 100644 packages/ui/src/elements/SortHeader/index.scss create mode 100644 packages/ui/src/elements/SortHeader/index.tsx create mode 100644 packages/ui/src/elements/SortRow/index.scss create mode 100644 packages/ui/src/elements/SortRow/index.tsx create mode 100644 packages/ui/src/elements/Table/OrderableTable.tsx create mode 100644 packages/ui/src/icons/Sort/index.scss create mode 100644 packages/ui/src/icons/Sort/index.tsx create mode 100644 test/sort/Seed.tsx create mode 100644 test/sort/collections/Orderable/index.ts create mode 100644 test/sort/collections/OrderableJoin/index.ts create mode 100644 test/sort/e2e.spec.ts diff --git a/docs/configuration/collections.mdx b/docs/configuration/collections.mdx index 6adc8502f2..9e804750b9 100644 --- a/docs/configuration/collections.mdx +++ b/docs/configuration/collections.mdx @@ -73,6 +73,7 @@ The following options are available: | `fields` \* | Array of field types that will determine the structure and functionality of the data stored within this Collection. [More details](../fields/overview). | | `graphQL` | Manage GraphQL-related properties for this collection. [More](#graphql) | | `hooks` | Entry point for Hooks. [More details](../hooks/overview#collection-hooks). | +| `orderable` | If true, enables custom ordering for the collection, and documents can be reordered via drag and drop. Uses [fractional indexing](https://observablehq.com/@dgreensp/implementing-fractional-indexing) for efficient reordering. | | `labels` | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. | | `enableQueryPresets` | Enable query presets for this Collection. [More details](../query-presets/overview). | | `lockDocuments` | Enables or disables document locking. By default, document locking is enabled. Set to an object to configure, or set to `false` to disable locking. [More details](../admin/locked-documents). | diff --git a/docs/fields/join.mdx b/docs/fields/join.mdx index 5bd0bfb131..fee3841817 100644 --- a/docs/fields/join.mdx +++ b/docs/fields/join.mdx @@ -138,6 +138,7 @@ powerful Admin UI. | **`name`** \* | To be used as the property name when retrieved from the database. [More](./overview#field-names) | | **`collection`** \* | The `slug`s having the relationship field or an array of collection slugs. | | **`on`** \* | The name of the relationship or upload field that relates to the collection document. Use dot notation for nested paths, like 'myGroup.relationName'. If `collection` is an array, this field must exist for all specified collections | +| **`orderable`** | If true, enables custom ordering and joined documents can be reordered via drag and drop. Uses [fractional indexing](https://observablehq.com/@dgreensp/implementing-fractional-indexing) for efficient reordering. | | **`where`** | A `Where` query to hide related documents from appearing. Will be merged with any `where` specified in the request. | | **`maxDepth`** | Default is 1, Sets a maximum population depth for this field, regardless of the remaining depth when this field is reached. [Max Depth](../queries/depth#max-depth). | | **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. | diff --git a/packages/next/src/views/List/index.tsx b/packages/next/src/views/List/index.tsx index 62e08b1262..f4c22c6fce 100644 --- a/packages/next/src/views/List/index.tsx +++ b/packages/next/src/views/List/index.tsx @@ -195,6 +195,7 @@ export const renderListView = async ( drawerSlug, enableRowSelections, i18n: req.i18n, + orderableFieldName: collectionConfig.orderable === true ? '_order' : undefined, payload, useAsTitle: collectionConfig.admin.useAsTitle, }) @@ -259,6 +260,7 @@ export const renderListView = async ( defaultSort={sort} listPreferences={listPreferences} modifySearchParams={!isInDrawer} + orderableFieldName={collectionConfig.orderable === true ? '_order' : undefined} > {RenderServerComponent({ clientProps: { diff --git a/packages/next/src/views/Versions/index.tsx b/packages/next/src/views/Versions/index.tsx index b1048573b4..54e05e0088 100644 --- a/packages/next/src/views/Versions/index.tsx +++ b/packages/next/src/views/Versions/index.tsx @@ -193,6 +193,7 @@ export async function VersionsView(props: DocumentViewServerProps) { defaultLimit={limitToUse} defaultSort={sort as string} modifySearchParams + orderableFieldName={collectionConfig?.orderable === true ? '_order' : undefined} > = { duration: number } | false + /** + * If true, enables custom ordering for the collection, and documents in the listView can be reordered via drag and drop. + * New documents are inserted at the end of the list according to this parameter. + * + * Under the hood, a field with {@link https://observablehq.com/@dgreensp/implementing-fractional-indexing|fractional indexing} is used to optimize inserts and reorderings. + * + * @default false + * + * @experimental There may be frequent breaking changes to this API + */ + orderable?: boolean slug: string /** * Add `createdAt` and `updatedAt` fields diff --git a/packages/payload/src/config/orderable/fractional-indexing.js b/packages/payload/src/config/orderable/fractional-indexing.js new file mode 100644 index 0000000000..4416732b05 --- /dev/null +++ b/packages/payload/src/config/orderable/fractional-indexing.js @@ -0,0 +1,318 @@ +// @ts-check + +/** + * THIS FILE IS COPIED FROM: + * https://github.com/rocicorp/fractional-indexing/blob/main/src/index.js + * + * I AM NOT INSTALLING THAT LIBRARY BECAUSE JEST COMPLAINS ABOUT THE ESM MODULE AND THE TESTS FAIL. + * DO NOT MODIFY IT + */ + +// License: CC0 (no rights reserved). + +// This is based on https://observablehq.com/@dgreensp/implementing-fractional-indexing + +export const BASE_62_DIGITS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' + +// `a` may be empty string, `b` is null or non-empty string. +// `a < b` lexicographically if `b` is non-null. +// no trailing zeros allowed. +// digits is a string such as '0123456789' for base 10. Digits must be in +// ascending character code order! +/** + * @param {string} a + * @param {string | null | undefined} b + * @param {string} digits + * @returns {string} + */ +function midpoint(a, b, digits) { + const zero = digits[0] + if (b != null && a >= b) { + throw new Error(a + ' >= ' + b) + } + if (a.slice(-1) === zero || (b && b.slice(-1) === zero)) { + throw new Error('trailing zero') + } + if (b) { + // remove longest common prefix. pad `a` with 0s as we + // go. note that we don't need to pad `b`, because it can't + // end before `a` while traversing the common prefix. + let n = 0 + while ((a[n] || zero) === b[n]) { + n++ + } + if (n > 0) { + return b.slice(0, n) + midpoint(a.slice(n), b.slice(n), digits) + } + } + // first digits (or lack of digit) are different + const digitA = a ? digits.indexOf(a[0]) : 0 + const digitB = b != null ? digits.indexOf(b[0]) : digits.length + if (digitB - digitA > 1) { + const midDigit = Math.round(0.5 * (digitA + digitB)) + return digits[midDigit] + } else { + // first digits are consecutive + if (b && b.length > 1) { + return b.slice(0, 1) + } else { + // `b` is null or has length 1 (a single digit). + // the first digit of `a` is the previous digit to `b`, + // or 9 if `b` is null. + // given, for example, midpoint('49', '5'), return + // '4' + midpoint('9', null), which will become + // '4' + '9' + midpoint('', null), which is '495' + return digits[digitA] + midpoint(a.slice(1), null, digits) + } + } +} + +/** + * @param {string} int + * @return {void} + */ + +function validateInteger(int) { + if (int.length !== getIntegerLength(int[0])) { + throw new Error('invalid integer part of order key: ' + int) + } +} + +/** + * @param {string} head + * @return {number} + */ + +function getIntegerLength(head) { + if (head >= 'a' && head <= 'z') { + return head.charCodeAt(0) - 'a'.charCodeAt(0) + 2 + } else if (head >= 'A' && head <= 'Z') { + return 'Z'.charCodeAt(0) - head.charCodeAt(0) + 2 + } else { + throw new Error('invalid order key head: ' + head) + } +} + +/** + * @param {string} key + * @return {string} + */ + +function getIntegerPart(key) { + const integerPartLength = getIntegerLength(key[0]) + if (integerPartLength > key.length) { + throw new Error('invalid order key: ' + key) + } + return key.slice(0, integerPartLength) +} + +/** + * @param {string} key + * @param {string} digits + * @return {void} + */ + +function validateOrderKey(key, digits) { + if (key === 'A' + digits[0].repeat(26)) { + throw new Error('invalid order key: ' + key) + } + // getIntegerPart will throw if the first character is bad, + // or the key is too short. we'd call it to check these things + // even if we didn't need the result + const i = getIntegerPart(key) + const f = key.slice(i.length) + if (f.slice(-1) === digits[0]) { + throw new Error('invalid order key: ' + key) + } +} + +// note that this may return null, as there is a largest integer +/** + * @param {string} x + * @param {string} digits + * @return {string | null} + */ +function incrementInteger(x, digits) { + validateInteger(x) + const [head, ...digs] = x.split('') + let carry = true + for (let i = digs.length - 1; carry && i >= 0; i--) { + const d = digits.indexOf(digs[i]) + 1 + if (d === digits.length) { + digs[i] = digits[0] + } else { + digs[i] = digits[d] + carry = false + } + } + if (carry) { + if (head === 'Z') { + return 'a' + digits[0] + } + if (head === 'z') { + return null + } + const h = String.fromCharCode(head.charCodeAt(0) + 1) + if (h > 'a') { + digs.push(digits[0]) + } else { + digs.pop() + } + return h + digs.join('') + } else { + return head + digs.join('') + } +} + +// note that this may return null, as there is a smallest integer +/** + * @param {string} x + * @param {string} digits + * @return {string | null} + */ + +function decrementInteger(x, digits) { + validateInteger(x) + const [head, ...digs] = x.split('') + let borrow = true + for (let i = digs.length - 1; borrow && i >= 0; i--) { + const d = digits.indexOf(digs[i]) - 1 + if (d === -1) { + digs[i] = digits.slice(-1) + } else { + digs[i] = digits[d] + borrow = false + } + } + if (borrow) { + if (head === 'a') { + return 'Z' + digits.slice(-1) + } + if (head === 'A') { + return null + } + const h = String.fromCharCode(head.charCodeAt(0) - 1) + if (h < 'Z') { + digs.push(digits.slice(-1)) + } else { + digs.pop() + } + return h + digs.join('') + } else { + return head + digs.join('') + } +} + +// `a` is an order key or null (START). +// `b` is an order key or null (END). +// `a < b` lexicographically if both are non-null. +// digits is a string such as '0123456789' for base 10. Digits must be in +// ascending character code order! +/** + * @param {string | null | undefined} a + * @param {string | null | undefined} b + * @param {string=} digits + * @return {string} + */ +export function generateKeyBetween(a, b, digits = BASE_62_DIGITS) { + if (a != null) { + validateOrderKey(a, digits) + } + if (b != null) { + validateOrderKey(b, digits) + } + if (a != null && b != null && a >= b) { + throw new Error(a + ' >= ' + b) + } + if (a == null) { + if (b == null) { + return 'a' + digits[0] + } + + const ib = getIntegerPart(b) + const fb = b.slice(ib.length) + if (ib === 'A' + digits[0].repeat(26)) { + return ib + midpoint('', fb, digits) + } + if (ib < b) { + return ib + } + const res = decrementInteger(ib, digits) + if (res == null) { + throw new Error('cannot decrement any more') + } + return res + } + + if (b == null) { + const ia = getIntegerPart(a) + const fa = a.slice(ia.length) + const i = incrementInteger(ia, digits) + return i == null ? ia + midpoint(fa, null, digits) : i + } + + const ia = getIntegerPart(a) + const fa = a.slice(ia.length) + const ib = getIntegerPart(b) + const fb = b.slice(ib.length) + if (ia === ib) { + return ia + midpoint(fa, fb, digits) + } + const i = incrementInteger(ia, digits) + if (i == null) { + throw new Error('cannot increment any more') + } + if (i < b) { + return i + } + return ia + midpoint(fa, null, digits) +} + +/** + * same preconditions as generateKeysBetween. + * n >= 0. + * Returns an array of n distinct keys in sorted order. + * If a and b are both null, returns [a0, a1, ...] + * If one or the other is null, returns consecutive "integer" + * keys. Otherwise, returns relatively short keys between + * a and b. + * @param {string | null | undefined} a + * @param {string | null | undefined} b + * @param {number} n + * @param {string} digits + * @return {string[]} + */ +export function generateNKeysBetween(a, b, n, digits = BASE_62_DIGITS) { + if (n === 0) { + return [] + } + if (n === 1) { + return [generateKeyBetween(a, b, digits)] + } + if (b == null) { + let c = generateKeyBetween(a, b, digits) + const result = [c] + for (let i = 0; i < n - 1; i++) { + c = generateKeyBetween(c, b, digits) + result.push(c) + } + return result + } + if (a == null) { + let c = generateKeyBetween(a, b, digits) + const result = [c] + for (let i = 0; i < n - 1; i++) { + c = generateKeyBetween(a, c, digits) + result.push(c) + } + result.reverse() + return result + } + const mid = Math.floor(n / 2) + const c = generateKeyBetween(a, b, digits) + return [ + ...generateNKeysBetween(a, c, mid, digits), + c, + ...generateNKeysBetween(c, b, n - mid - 1, digits), + ] +} diff --git a/packages/payload/src/config/orderable/index.ts b/packages/payload/src/config/orderable/index.ts new file mode 100644 index 0000000000..742f3e4fd8 --- /dev/null +++ b/packages/payload/src/config/orderable/index.ts @@ -0,0 +1,278 @@ +import type { BeforeChangeHook, CollectionConfig } from '../../collections/config/types.js' +import type { Field } from '../../fields/config/types.js' +import type { Endpoint, PayloadHandler, SanitizedConfig } from '../types.js' + +import executeAccess from '../../auth/executeAccess.js' +import { traverseFields } from '../../utilities/traverseFields.js' +import { generateKeyBetween, generateNKeysBetween } from './fractional-indexing.js' + +/** + * This function creates: + * - N fields per collection, named `_order` or `___order` + * - 1 hook per collection + * - 1 endpoint per app + * + * Also, if collection.defaultSort or joinField.defaultSort is not set, it will be set to the orderable field. + */ +export const setupOrderable = (config: SanitizedConfig) => { + const fieldsToAdd = new Map() + + config.collections.forEach((collection) => { + if (collection.orderable) { + const currentFields = fieldsToAdd.get(collection) || [] + fieldsToAdd.set(collection, [...currentFields, '_order']) + collection.defaultSort = collection.defaultSort ?? '_order' + } + + traverseFields({ + callback: ({ field, parentRef, ref }) => { + if (field.type === 'array' || field.type === 'blocks') { + return false + } + if (field.type === 'group' || field.type === 'tab') { + // @ts-expect-error ref is untyped + const parentPrefix = parentRef?.prefix ? `${parentRef.prefix}_` : '' + // @ts-expect-error ref is untyped + ref.prefix = `${parentPrefix}${field.name}` + } + if (field.type === 'join' && field.orderable === true) { + if (Array.isArray(field.collection)) { + throw new Error('Orderable joins must target a single collection') + } + const relationshipCollection = config.collections.find((c) => c.slug === field.collection) + if (!relationshipCollection) { + return false + } + field.defaultSort = field.defaultSort ?? `_${field.collection}_${field.name}_order` + const currentFields = fieldsToAdd.get(relationshipCollection) || [] + // @ts-expect-error ref is untyped + const prefix = parentRef?.prefix ? `${parentRef.prefix}_` : '' + fieldsToAdd.set(relationshipCollection, [ + ...currentFields, + `_${field.collection}_${prefix}${field.name}_order`, + ]) + } + }, + fields: collection.fields, + }) + }) + + Array.from(fieldsToAdd.entries()).forEach(([collection, orderableFields]) => { + addOrderableFieldsAndHook(collection, orderableFields) + }) + + if (fieldsToAdd.size > 0) { + addOrderableEndpoint(config) + } +} + +export const addOrderableFieldsAndHook = ( + collection: CollectionConfig, + orderableFieldNames: string[], +) => { + // 1. Add field + orderableFieldNames.forEach((orderableFieldName) => { + const orderField: Field = { + name: orderableFieldName, + type: 'text', + admin: { + disableBulkEdit: true, + disabled: true, + disableListColumn: true, + disableListFilter: true, + hidden: true, + readOnly: true, + }, + index: true, + required: true, + // override the schema to make order fields optional for payload.create() + typescriptSchema: [ + () => ({ + type: 'string', + required: false, + }), + ], + unique: true, + } + + collection.fields.unshift(orderField) + }) + + // 2. Add hook + if (!collection.hooks) { + collection.hooks = {} + } + if (!collection.hooks.beforeChange) { + collection.hooks.beforeChange = [] + } + + const orderBeforeChangeHook: BeforeChangeHook = async ({ data, operation, req }) => { + // Only set _order on create, not on update (unless explicitly provided) + if (operation === 'create') { + for (const orderableFieldName of orderableFieldNames) { + if (!data[orderableFieldName]) { + const lastDoc = await req.payload.find({ + collection: collection.slug, + depth: 0, + limit: 1, + pagination: false, + req, + select: { [orderableFieldName]: true }, + sort: `-${orderableFieldName}`, + }) + + const lastOrderValue = lastDoc.docs[0]?.[orderableFieldName] || null + data[orderableFieldName] = generateKeyBetween(lastOrderValue, null) + } + } + } + + return data + } + + collection.hooks.beforeChange.push(orderBeforeChangeHook) +} + +/** + * The body of the reorder endpoint. + * @internal + */ +export type OrderableEndpointBody = { + collectionSlug: string + docsToMove: string[] + newKeyWillBe: 'greater' | 'less' + orderableFieldName: string + target: { + id: string + key: string + } +} + +export const addOrderableEndpoint = (config: SanitizedConfig) => { + // 3. Add endpoint + const reorderHandler: PayloadHandler = async (req) => { + const body = (await req.json?.()) as OrderableEndpointBody + + const { collectionSlug, docsToMove, newKeyWillBe, orderableFieldName, target } = body + + if (!Array.isArray(docsToMove) || docsToMove.length === 0) { + return new Response(JSON.stringify({ error: 'docsToMove must be a non-empty array' }), { + headers: { 'Content-Type': 'application/json' }, + status: 400, + }) + } + if ( + typeof target !== 'object' || + typeof target.id !== 'string' || + typeof target.key !== 'string' + ) { + return new Response(JSON.stringify({ error: 'target must be an object with id and key' }), { + headers: { 'Content-Type': 'application/json' }, + status: 400, + }) + } + if (newKeyWillBe !== 'greater' && newKeyWillBe !== 'less') { + return new Response(JSON.stringify({ error: 'newKeyWillBe must be "greater" or "less"' }), { + headers: { 'Content-Type': 'application/json' }, + status: 400, + }) + } + const collection = config.collections.find((c) => c.slug === collectionSlug) + if (!collection) { + return new Response(JSON.stringify({ error: `Collection ${collectionSlug} not found` }), { + headers: { 'Content-Type': 'application/json' }, + status: 400, + }) + } + if (typeof orderableFieldName !== 'string') { + return new Response(JSON.stringify({ error: 'orderableFieldName must be a string' }), { + headers: { 'Content-Type': 'application/json' }, + status: 400, + }) + } + + // Prevent reordering if user doesn't have editing permissions + if (collection.access?.update) { + await executeAccess( + { + // Currently only one doc can be moved at a time. We should review this if we want to allow + // multiple docs to be moved at once in the future. + id: docsToMove[0], + data: {}, + req, + }, + collection.access.update, + ) + } + + const targetId = target.id + let targetKey = target.key + + // If targetKey = pending, we need to find its current key. + // This can only happen if the user reorders rows quickly with a slow connection. + if (targetKey === 'pending') { + const beforeDoc = await req.payload.findByID({ + id: targetId, + collection: collection.slug, + depth: 0, + select: { [orderableFieldName]: true }, + }) + targetKey = beforeDoc?.[orderableFieldName] || null + } + + // The reason the endpoint does not receive this docId as an argument is that there + // are situations where the user may not see or know what the next or previous one is. For + // example, access control restrictions, if docBefore is the last one on the page, etc. + const adjacentDoc = await req.payload.find({ + collection: collection.slug, + depth: 0, + limit: 1, + pagination: false, + select: { [orderableFieldName]: true }, + sort: newKeyWillBe === 'greater' ? orderableFieldName : `-${orderableFieldName}`, + where: { + [orderableFieldName]: { + [newKeyWillBe === 'greater' ? 'greater_than' : 'less_than']: targetKey, + }, + }, + }) + const adjacentDocKey = adjacentDoc.docs?.[0]?.[orderableFieldName] || null + + // Currently N (= docsToMove.length) is always 1. Maybe in the future we will + // allow dragging and reordering multiple documents at once via the UI. + const orderValues = + newKeyWillBe === 'greater' + ? generateNKeysBetween(targetKey, adjacentDocKey, docsToMove.length) + : generateNKeysBetween(adjacentDocKey, targetKey, docsToMove.length) + + // Update each document with its new order value + for (const [index, id] of docsToMove.entries()) { + await req.payload.update({ + id, + collection: collection.slug, + data: { + [orderableFieldName]: orderValues[index], + }, + depth: 0, + req, + select: { id: true }, + }) + } + + return new Response(JSON.stringify({ orderValues, success: true }), { + headers: { 'Content-Type': 'application/json' }, + status: 200, + }) + } + + const reorderEndpoint: Endpoint = { + handler: reorderHandler, + method: 'post', + path: '/reorder', + } + + if (!config.endpoints) { + config.endpoints = [] + } + config.endpoints.push(reorderEndpoint) +} diff --git a/packages/payload/src/config/sanitize.ts b/packages/payload/src/config/sanitize.ts index 033618a852..2d6346a301 100644 --- a/packages/payload/src/config/sanitize.ts +++ b/packages/payload/src/config/sanitize.ts @@ -36,6 +36,7 @@ import { getDefaultJobsCollection, jobsCollectionSlug } from '../queues/config/i import { flattenBlock } from '../utilities/flattenAllFields.js' import { getSchedulePublishTask } from '../versions/schedule/job.js' import { addDefaultsToConfig } from './defaults.js' +import { setupOrderable } from './orderable/index.js' const sanitizeAdminConfig = (configToSanitize: Config): Partial => { const sanitizedConfig = { ...configToSanitize } @@ -108,6 +109,9 @@ export const sanitizeConfig = async (incomingConfig: Config): Promise = sanitizeAdminConfig(configWithDefaults) + // Add orderable fields + setupOrderable(config as SanitizedConfig) + if (!config.endpoints) { config.endpoints = [] } diff --git a/packages/payload/src/fields/config/types.ts b/packages/payload/src/fields/config/types.ts index cb8df97e57..2119b85683 100644 --- a/packages/payload/src/fields/config/types.ts +++ b/packages/payload/src/fields/config/types.ts @@ -1549,6 +1549,17 @@ export type JoinField = { * A string for the field in the collection being joined to. */ on: string + /** + * If true, enables custom ordering for the collection with the relationship, and joined documents can be reordered via drag and drop. + * New documents are inserted at the end of the list according to this parameter. + * + * Under the hood, a field with {@link https://observablehq.com/@dgreensp/implementing-fractional-indexing|fractional indexing} is used to optimize inserts and reorderings. + * + * @default false + * + * @experimental There may be frequent breaking changes to this API + */ + orderable?: boolean sanitizedMany?: JoinField[] type: 'join' validate?: never @@ -1562,7 +1573,15 @@ export type JoinFieldClient = { } & { targetField: Pick } & FieldBaseClient & Pick< JoinField, - 'collection' | 'defaultLimit' | 'defaultSort' | 'index' | 'maxDepth' | 'on' | 'type' | 'where' + | 'collection' + | 'defaultLimit' + | 'defaultSort' + | 'index' + | 'maxDepth' + | 'on' + | 'orderable' + | 'type' + | 'where' > export type FlattenedBlock = { diff --git a/packages/payload/src/index.ts b/packages/payload/src/index.ts index 39139fbf89..61b537e687 100644 --- a/packages/payload/src/index.ts +++ b/packages/payload/src/index.ts @@ -1090,6 +1090,7 @@ export { } from './config/client.js' export { defaults } from './config/defaults.js' +export { type OrderableEndpointBody } from './config/orderable/index.js' export { sanitizeConfig } from './config/sanitize.js' export type * from './config/types.js' export { combineQueries } from './database/combineQueries.js' diff --git a/packages/payload/src/utilities/flattenAllFields.ts b/packages/payload/src/utilities/flattenAllFields.ts index f1a09c4d2d..97fa0b5dd3 100644 --- a/packages/payload/src/utilities/flattenAllFields.ts +++ b/packages/payload/src/utilities/flattenAllFields.ts @@ -18,6 +18,11 @@ export const flattenBlock = ({ block }: { block: Block }): FlattenedBlock => { const flattenedFieldsCache = new Map() +/** + * Flattens all fields in a collection, preserving the nested field structure. + * @param cache + * @param fields + */ export const flattenAllFields = ({ cache, fields, diff --git a/packages/ui/src/elements/RelationshipTable/index.tsx b/packages/ui/src/elements/RelationshipTable/index.tsx index a6588961cf..3247dd3c94 100644 --- a/packages/ui/src/elements/RelationshipTable/index.tsx +++ b/packages/ui/src/elements/RelationshipTable/index.tsx @@ -139,6 +139,10 @@ export const RelationshipTable: React.FC = (pro columns: transformColumnsToPreferences(query?.columns) || defaultColumns, docs, enableRowSelections: false, + orderableFieldName: + !field.orderable || Array.isArray(field.collection) + ? undefined + : `_${field.collection}_${field.name}_order`, parent, query: newQuery, renderRowTypes: true, @@ -153,6 +157,10 @@ export const RelationshipTable: React.FC = (pro [ field.defaultLimit, field.defaultSort, + field.admin.defaultColumns, + field.collection, + field.name, + field.orderable, collectionConfig?.admin?.pagination?.defaultLimit, collectionConfig?.defaultSort, query, @@ -329,6 +337,11 @@ export const RelationshipTable: React.FC = (pro } modifySearchParams={false} onQueryChange={setQuery} + orderableFieldName={ + !field.orderable || Array.isArray(field.collection) + ? undefined + : `_${field.collection}_${field.name}_order` + } > (querySort === `-${orderableFieldName}` ? 'desc' : 'asc') + const isActive = querySort === `-${orderableFieldName}` || querySort === orderableFieldName + + // This is necessary if you initialize the page without sort url param + // but your preferences are to sort by -_order. + // Since sort isn't updated, the arrow would incorrectly point upward. + useEffect(() => { + if (!isActive) { + return + } + sort.current = querySort === `-${orderableFieldName}` ? 'desc' : 'asc' + }, [orderableFieldName, querySort, isActive]) + + const handleSortPress = () => { + // If it's already sorted by the "_order" field, toggle between "asc" and "desc" + if (isActive) { + void handleSortChange(sort.current === 'asc' ? `-${orderableFieldName}` : orderableFieldName) + sort.current = sort.current === 'asc' ? 'desc' : 'asc' + return + } + // If NOT sorted by the "_order" field, sort by that field but do not toggle the current value of "asc" or "desc". + void handleSortChange(sort.current === 'asc' ? orderableFieldName : `-${orderableFieldName}`) + } + + return { handleSortPress, isActive, sort } +} + +export const SortHeader: React.FC = (props) => { + const { appearance } = props + const { handleSortPress, isActive, sort } = useSort() + const { t } = useTranslation() + + return ( +
+
+ {sort.current === 'desc' ? ( + + ) : ( + + )} +
+
+ ) +} diff --git a/packages/ui/src/elements/SortRow/index.scss b/packages/ui/src/elements/SortRow/index.scss new file mode 100644 index 0000000000..ea56b3252d --- /dev/null +++ b/packages/ui/src/elements/SortRow/index.scss @@ -0,0 +1,22 @@ +@import '../../scss/styles.scss'; + +@layer payload-default { + .sort-row { + opacity: 0.3; + cursor: not-allowed; + + &.active { + cursor: grab; + opacity: 1; + } + + &__icon { + height: 22px; + width: 22px; + margin-left: -2px; + margin-top: -2px; + display: block; + width: min-content; + } + } +} diff --git a/packages/ui/src/elements/SortRow/index.tsx b/packages/ui/src/elements/SortRow/index.tsx new file mode 100644 index 0000000000..cfbe034014 --- /dev/null +++ b/packages/ui/src/elements/SortRow/index.tsx @@ -0,0 +1,20 @@ +'use client' + +import React from 'react' + +import { DragHandleIcon } from '../../icons/DragHandle/index.js' +import './index.scss' +import { useListQuery } from '../../providers/ListQuery/index.js' + +const baseClass = 'sort-row' + +export const SortRow = () => { + const { orderableFieldName, query } = useListQuery() + const isActive = query.sort === orderableFieldName || query.sort === `-${orderableFieldName}` + + return ( +
+ +
+ ) +} diff --git a/packages/ui/src/elements/Table/OrderableTable.tsx b/packages/ui/src/elements/Table/OrderableTable.tsx new file mode 100644 index 0000000000..a25aee1476 --- /dev/null +++ b/packages/ui/src/elements/Table/OrderableTable.tsx @@ -0,0 +1,198 @@ +'use client' + +import type { ClientCollectionConfig, Column, OrderableEndpointBody } from 'payload' + +import './index.scss' + +import React, { useEffect, useState } from 'react' +import { toast } from 'sonner' + +import { useListQuery } from '../../providers/ListQuery/index.js' +import { DraggableSortableItem } from '../DraggableSortable/DraggableSortableItem/index.js' +import { DraggableSortable } from '../DraggableSortable/index.js' + +const baseClass = 'table' + +export type Props = { + readonly appearance?: 'condensed' | 'default' + readonly collection: ClientCollectionConfig + readonly columns?: Column[] + readonly data: Record[] +} + +export const OrderableTable: React.FC = ({ + appearance = 'default', + collection, + columns, + data: initialData, +}) => { + const { data: listQueryData, handleSortChange, orderableFieldName, query } = useListQuery() + // Use the data from ListQueryProvider if available, otherwise use the props + const serverData = listQueryData?.docs || initialData + + // Local state to track the current order of rows + const [localData, setLocalData] = useState(serverData) + + // id -> index for each column + const [cellMap, setCellMap] = useState>({}) + + // Update local data when server data changes + useEffect(() => { + setLocalData(serverData) + setCellMap( + Object.fromEntries(serverData.map((item, index) => [String(item.id ?? item._id), index])), + ) + }, [serverData]) + + const activeColumns = columns?.filter((col) => col?.active) + + if ( + !activeColumns || + activeColumns.filter((col) => !['_dragHandle', '_select'].includes(col.accessor)).length === 0 + ) { + return
No columns selected
+ } + + const handleDragEnd = async ({ moveFromIndex, moveToIndex }) => { + if (query.sort !== orderableFieldName && query.sort !== `-${orderableFieldName}`) { + toast.warning('To reorder the rows you must first sort them by the "Order" column') + return + } + + if (moveFromIndex === moveToIndex) { + return + } + + const movedId = localData[moveFromIndex].id ?? localData[moveFromIndex]._id + const newBeforeRow = + moveToIndex > moveFromIndex ? localData[moveToIndex] : localData[moveToIndex - 1] + const newAfterRow = + moveToIndex > moveFromIndex ? localData[moveToIndex + 1] : localData[moveToIndex] + + // Store the original data for rollback + const previousData = [...localData] + + // Optimisitc update of local state to reorder the rows + setLocalData((currentData) => { + const newData = [...currentData] + // Update the rendered cell for the moved row to show "pending" + newData[moveFromIndex][orderableFieldName] = `pending` + // Move the item in the array + newData.splice(moveToIndex, 0, newData.splice(moveFromIndex, 1)[0]) + return newData + }) + + try { + const target: OrderableEndpointBody['target'] = newBeforeRow + ? { + id: newBeforeRow.id ?? newBeforeRow._id, + key: newBeforeRow[orderableFieldName], + } + : { + id: newAfterRow.id ?? newAfterRow._id, + key: newAfterRow[orderableFieldName], + } + + const newKeyWillBe = + (newBeforeRow && query.sort === orderableFieldName) || + (!newBeforeRow && query.sort === `-${orderableFieldName}`) + ? 'greater' + : 'less' + + const jsonBody: OrderableEndpointBody = { + collectionSlug: collection.slug, + docsToMove: [movedId], + newKeyWillBe, + orderableFieldName, + target, + } + + const response = await fetch(`/api/reorder`, { + body: JSON.stringify(jsonBody), + headers: { + 'Content-Type': 'application/json', + }, + method: 'POST', + }) + + if (response.status === 403) { + throw new Error('You do not have permission to reorder these rows') + } + + if (!response.ok) { + throw new Error( + 'Failed to reorder. This can happen if you reorder several rows too quickly. Please try again.', + ) + } + } catch (err) { + const error = err instanceof Error ? err.message : String(err) + // Rollback to previous state if the request fails + setLocalData(previousData) + toast.error(error) + } + } + + const rowIds = localData.map((row) => row.id ?? row._id) + + return ( +
+ + + + + {activeColumns.map((col, i) => ( + + ))} + + + + {localData.map((row, rowIndex) => ( + + {({ attributes, listeners, setNodeRef, transform, transition }) => ( + + {activeColumns.map((col, colIndex) => { + const { accessor } = col + + // Use the cellMap to find which index in the renderedCells to use + const cell = col.renderedCells[cellMap[row.id ?? row._id]] + + // For drag handles, wrap in div with drag attributes + if (accessor === '_dragHandle') { + return ( + + ) + } + + return ( + + ) + })} + + )} + + ))} + +
+ {col.Heading} +
+
+ {cell} +
+
+ {cell} +
+
+
+ ) +} diff --git a/packages/ui/src/icons/Sort/index.scss b/packages/ui/src/icons/Sort/index.scss new file mode 100644 index 0000000000..5ed487885e --- /dev/null +++ b/packages/ui/src/icons/Sort/index.scss @@ -0,0 +1,14 @@ +@import '../../scss/styles'; + +@layer payload-default { + .icon--sort { + height: $baseline; + width: $baseline; + + .fill { + stroke: currentColor; + stroke-width: $style-stroke-width-s; + fill: var(--theme-elevation-800); + } + } +} diff --git a/packages/ui/src/icons/Sort/index.tsx b/packages/ui/src/icons/Sort/index.tsx new file mode 100644 index 0000000000..af1aa7191f --- /dev/null +++ b/packages/ui/src/icons/Sort/index.tsx @@ -0,0 +1,41 @@ +import React from 'react' + +import './index.scss' + +export const SortDownIcon: React.FC<{ className?: string }> = ({ className }) => ( + + + +) + +export const SortUpIcon: React.FC<{ className?: string }> = ({ className }) => ( + + + +) diff --git a/packages/ui/src/providers/ListQuery/index.tsx b/packages/ui/src/providers/ListQuery/index.tsx index ad9dd0669c..62a55dac86 100644 --- a/packages/ui/src/providers/ListQuery/index.tsx +++ b/packages/ui/src/providers/ListQuery/index.tsx @@ -25,6 +25,7 @@ export const ListQueryProvider: React.FC = ({ listPreferences, modifySearchParams, onQueryChange: onQueryChangeFromProps, + orderableFieldName, }) => { 'use no memo' const router = useRouter() @@ -207,6 +208,7 @@ export const ListQueryProvider: React.FC = ({ handleSearchChange, handleSortChange, handleWhereChange, + orderableFieldName, query: currentQuery, refineListData, setModified, diff --git a/packages/ui/src/providers/ListQuery/types.ts b/packages/ui/src/providers/ListQuery/types.ts index 979b960a1f..9ccdb7e513 100644 --- a/packages/ui/src/providers/ListQuery/types.ts +++ b/packages/ui/src/providers/ListQuery/types.ts @@ -29,6 +29,7 @@ export type ListQueryProps = { readonly listPreferences?: ListPreferences readonly modifySearchParams?: boolean readonly onQueryChange?: OnListQueryChange + readonly orderableFieldName?: string /** * @deprecated */ @@ -40,6 +41,7 @@ export type IListQueryContext = { data: PaginatedDocs defaultLimit?: number defaultSort?: Sort + orderableFieldName?: string modified: boolean query: ListQuery refineListData: (args: ListQuery, setModified?: boolean) => Promise diff --git a/packages/ui/src/utilities/buildTableState.ts b/packages/ui/src/utilities/buildTableState.ts index dd00ac59d2..07a8758ea0 100644 --- a/packages/ui/src/utilities/buildTableState.ts +++ b/packages/ui/src/utilities/buildTableState.ts @@ -66,7 +66,7 @@ export const buildTableStateHandler = async ( } } -export const buildTableState = async ( +const buildTableState = async ( args: BuildTableStateArgs, ): Promise => { const { @@ -74,6 +74,7 @@ export const buildTableState = async ( columns, docs: docsFromArgs, enableRowSelections, + orderableFieldName, parent, query, renderRowTypes, @@ -233,6 +234,7 @@ export const buildTableState = async ( docs, enableRowSelections, i18n: req.i18n, + orderableFieldName, payload, renderRowTypes, tableAppearance, diff --git a/packages/ui/src/utilities/renderTable.tsx b/packages/ui/src/utilities/renderTable.tsx index 1699672972..bab2ec6c60 100644 --- a/packages/ui/src/utilities/renderTable.tsx +++ b/packages/ui/src/utilities/renderTable.tsx @@ -13,16 +13,19 @@ import type { import { getTranslation, type I18nClient } from '@payloadcms/translations' import { fieldAffectsData, fieldIsHiddenOrDisabled, flattenTopLevelFields } from 'payload/shared' +import React from 'react' // eslint-disable-next-line payload/no-imports-from-exports-dir import type { Column } from '../exports/client/index.js' import { RenderServerComponent } from '../elements/RenderServerComponent/index.js' +import { SortHeader } from '../elements/SortHeader/index.js' +import { SortRow } from '../elements/SortRow/index.js' +import { OrderableTable } from '../elements/Table/OrderableTable.js' import { buildColumnState } from '../providers/TableColumns/buildColumnState.js' import { buildPolymorphicColumnState } from '../providers/TableColumns/buildPolymorphicColumnState.js' import { filterFields } from '../providers/TableColumns/filterFields.js' import { getInitialColumns } from '../providers/TableColumns/getInitialColumns.js' - // eslint-disable-next-line payload/no-imports-from-exports-dir import { Pill, SelectAll, SelectRow, Table } from '../exports/client/index.js' @@ -62,6 +65,7 @@ export const renderTable = ({ docs, enableRowSelections, i18n, + orderableFieldName, payload, renderRowTypes, tableAppearance, @@ -78,6 +82,7 @@ export const renderTable = ({ drawerSlug?: string enableRowSelections: boolean i18n: I18nClient + orderableFieldName: string payload: Payload renderRowTypes?: boolean tableAppearance?: 'condensed' | 'default' @@ -195,9 +200,38 @@ export const renderTable = ({ } as Column) } + if (!orderableFieldName) { + return { + columnState, + // key is required since Next.js 15.2.0 to prevent React key error + Table: , + } + } + + columnsToUse.unshift({ + accessor: '_dragHandle', + active: true, + field: { + admin: { + disabled: true, + }, + hidden: true, + }, + Heading: , + renderedCells: docs.map((_, i) => ), + } as Column) + return { columnState, // key is required since Next.js 15.2.0 to prevent React key error - Table:
, + Table: ( + + ), } } diff --git a/packages/ui/src/views/List/index.scss b/packages/ui/src/views/List/index.scss index f600fffafb..f3aea24d58 100644 --- a/packages/ui/src/views/List/index.scss +++ b/packages/ui/src/views/List/index.scss @@ -49,6 +49,12 @@ display: flex; min-width: unset; } + + #heading-_dragHandle, + .cell-_dragHandle { + width: 20px; + min-width: 0; + } } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f95f70fc37..53129ba489 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,7 +45,7 @@ importers: version: 1.50.0 '@sentry/nextjs': specifier: ^8.33.1 - version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15))) + version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15))) '@sentry/node': specifier: ^8.33.1 version: 8.37.1 @@ -135,7 +135,7 @@ importers: version: 10.1.3(@aws-sdk/credential-providers@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)))(socks@2.8.3) next: specifier: 15.2.3 - version: 15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + version: 15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) open: specifier: ^10.1.0 version: 10.1.0 @@ -1076,7 +1076,7 @@ importers: dependencies: next: specifier: ^15.2.3 - version: 15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + version: 15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) devDependencies: '@payloadcms/eslint-config': specifier: workspace:* @@ -1141,7 +1141,7 @@ importers: dependencies: '@sentry/nextjs': specifier: ^8.33.1 - version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15))) + version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15))) '@sentry/types': specifier: ^8.33.1 version: 8.37.1 @@ -1500,7 +1500,7 @@ importers: version: link:../plugin-cloud-storage uploadthing: specifier: 7.3.0 - version: 7.3.0(next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4)) + version: 7.3.0(next@15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4)) devDependencies: payload: specifier: workspace:* @@ -1786,7 +1786,7 @@ importers: version: link:../packages/ui '@sentry/nextjs': specifier: ^8.33.1 - version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15))) + version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15))) '@sentry/react': specifier: ^7.77.0 version: 7.119.2(react@19.0.0) @@ -1843,7 +1843,7 @@ importers: version: 8.9.5(@aws-sdk/credential-providers@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)))(socks@2.8.3) next: specifier: 15.2.3 - version: 15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + version: 15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) nodemailer: specifier: 6.9.16 version: 6.9.16 @@ -13719,7 +13719,7 @@ snapshots: '@sentry/utils': 7.119.2 localforage: 1.10.0 - '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15)))': + '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15)))': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation-http': 0.53.0(@opentelemetry/api@1.9.0) @@ -13735,7 +13735,7 @@ snapshots: '@sentry/vercel-edge': 8.37.1 '@sentry/webpack-plugin': 2.22.6(webpack@5.96.1(@swc/core@1.10.12(@swc/helpers@0.5.15))) chalk: 3.0.0 - next: 15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + next: 15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) resolve: 1.22.8 rollup: 3.29.5 stacktrace-parser: 0.1.10 @@ -18432,35 +18432,6 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4): - dependencies: - '@next/env': 15.2.3 - '@swc/counter': 0.1.3 - '@swc/helpers': 0.5.15 - busboy: 1.6.0 - caniuse-lite: 1.0.30001678 - postcss: 8.4.31 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - styled-jsx: 5.1.6(@babel/core@7.26.7)(babel-plugin-macros@3.1.0)(react@19.0.0) - optionalDependencies: - '@next/swc-darwin-arm64': 15.2.3 - '@next/swc-darwin-x64': 15.2.3 - '@next/swc-linux-arm64-gnu': 15.2.3 - '@next/swc-linux-arm64-musl': 15.2.3 - '@next/swc-linux-x64-gnu': 15.2.3 - '@next/swc-linux-x64-musl': 15.2.3 - '@next/swc-win32-arm64-msvc': 15.2.3 - '@next/swc-win32-x64-msvc': 15.2.3 - '@opentelemetry/api': 1.9.0 - '@playwright/test': 1.50.0 - babel-plugin-react-compiler: 19.0.0-beta-714736e-20250131 - sass: 1.77.4 - sharp: 0.33.5 - transitivePeerDependencies: - - '@babel/core' - - babel-plugin-macros - node-abi@3.71.0: dependencies: semver: 7.6.3 @@ -20203,14 +20174,14 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - uploadthing@7.3.0(next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4)): + uploadthing@7.3.0(next@15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4)): dependencies: '@effect/platform': 0.69.8(effect@3.10.3) '@uploadthing/mime-types': 0.3.2 '@uploadthing/shared': 7.1.1 effect: 3.10.3 optionalDependencies: - next: 15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + next: 15.2.3(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-714736e-20250131)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) uri-js@4.4.1: dependencies: diff --git a/test/fields/collections/Indexed/e2e.spec.ts b/test/fields/collections/Indexed/e2e.spec.ts index cb90de6806..966e2219ba 100644 --- a/test/fields/collections/Indexed/e2e.spec.ts +++ b/test/fields/collections/Indexed/e2e.spec.ts @@ -114,7 +114,9 @@ describe('Radio', () => { // nested in a group error await page.locator('#field-group__unique').fill(uniqueText) - await wait(1000) + // TODO: used because otherwise the toast locator resolves to 2 items + // at the same time. Instead we should uniquely identify each toast. + await wait(2000) // attempt to save await page.locator('#action-save').click() diff --git a/test/sort/Seed.tsx b/test/sort/Seed.tsx new file mode 100644 index 0000000000..0028083733 --- /dev/null +++ b/test/sort/Seed.tsx @@ -0,0 +1,19 @@ +/* eslint-disable no-console */ +'use client' + +export const Seed = () => { + return ( + + ) +} diff --git a/test/sort/collections/Orderable/index.ts b/test/sort/collections/Orderable/index.ts new file mode 100644 index 0000000000..ccf42c4205 --- /dev/null +++ b/test/sort/collections/Orderable/index.ts @@ -0,0 +1,27 @@ +import type { CollectionConfig } from 'payload' + +import { orderableJoinSlug } from '../OrderableJoin/index.js' + +export const orderableSlug = 'orderable' + +export const OrderableCollection: CollectionConfig = { + slug: orderableSlug, + orderable: true, + admin: { + useAsTitle: 'title', + components: { + beforeList: ['/Seed.tsx#Seed'], + }, + }, + fields: [ + { + name: 'title', + type: 'text', + }, + { + name: 'orderableField', + type: 'relationship', + relationTo: orderableJoinSlug, + }, + ], +} diff --git a/test/sort/collections/OrderableJoin/index.ts b/test/sort/collections/OrderableJoin/index.ts new file mode 100644 index 0000000000..8e4ee728cd --- /dev/null +++ b/test/sort/collections/OrderableJoin/index.ts @@ -0,0 +1,39 @@ +import type { CollectionConfig } from 'payload' + +export const orderableJoinSlug = 'orderable-join' + +export const OrderableJoinCollection: CollectionConfig = { + slug: orderableJoinSlug, + admin: { + useAsTitle: 'title', + components: { + beforeList: ['/Seed.tsx#Seed'], + }, + }, + fields: [ + { + name: 'title', + type: 'text', + }, + { + name: 'orderableJoinField1', + type: 'join', + on: 'orderableField', + orderable: true, + collection: 'orderable', + }, + { + name: 'orderableJoinField2', + type: 'join', + on: 'orderableField', + orderable: true, + collection: 'orderable', + }, + { + name: 'nonOrderableJoinField', + type: 'join', + on: 'orderableField', + collection: 'orderable', + }, + ], +} diff --git a/test/sort/config.ts b/test/sort/config.ts index 78868504bc..5e6a1bed98 100644 --- a/test/sort/config.ts +++ b/test/sort/config.ts @@ -1,3 +1,5 @@ +import type { CollectionSlug, Payload } from 'payload' + import { fileURLToPath } from 'node:url' import path from 'path' @@ -6,17 +8,39 @@ import { devUser } from '../credentials.js' import { DefaultSortCollection } from './collections/DefaultSort/index.js' import { DraftsCollection } from './collections/Drafts/index.js' import { LocalizedCollection } from './collections/Localized/index.js' +import { OrderableCollection } from './collections/Orderable/index.js' +import { OrderableJoinCollection } from './collections/OrderableJoin/index.js' import { PostsCollection } from './collections/Posts/index.js' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) export default buildConfigWithDefaults({ - collections: [PostsCollection, DraftsCollection, DefaultSortCollection, LocalizedCollection], + collections: [ + PostsCollection, + DraftsCollection, + DefaultSortCollection, + LocalizedCollection, + OrderableCollection, + OrderableJoinCollection, + ], admin: { importMap: { baseDir: path.resolve(dirname), }, }, + endpoints: [ + { + path: '/seed', + method: 'post', + handler: async (req) => { + await seedSortable(req.payload) + return new Response(JSON.stringify({ success: true }), { + headers: { 'Content-Type': 'application/json' }, + status: 200, + }) + }, + }, + ], cors: ['http://localhost:3000', 'http://localhost:3001'], localization: { locales: ['en', 'nb'], @@ -30,8 +54,41 @@ export default buildConfigWithDefaults({ password: devUser.password, }, }) + await seedSortable(payload) }, typescript: { outputFile: path.resolve(dirname, 'payload-types.ts'), }, }) + +export async function createData( + payload: Payload, + collection: CollectionSlug, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + data: Record[], +) { + for (const item of data) { + await payload.create({ collection, data: item }) + } +} + +async function seedSortable(payload: Payload) { + await payload.delete({ collection: 'orderable', where: {} }) + await payload.delete({ collection: 'orderable-join', where: {} }) + + const joinA = await payload.create({ collection: 'orderable-join', data: { title: 'Join A' } }) + + await createData(payload, 'orderable', [ + { title: 'A', orderableField: joinA.id }, + { title: 'B', orderableField: joinA.id }, + { title: 'C', orderableField: joinA.id }, + { title: 'D', orderableField: joinA.id }, + ]) + + await payload.create({ collection: 'orderable-join', data: { title: 'Join B' } }) + + return new Response(JSON.stringify({ success: true }), { + headers: { 'Content-Type': 'application/json' }, + status: 200, + }) +} diff --git a/test/sort/e2e.spec.ts b/test/sort/e2e.spec.ts new file mode 100644 index 0000000000..fdc53d19dc --- /dev/null +++ b/test/sort/e2e.spec.ts @@ -0,0 +1,152 @@ +import type { BrowserContext, Page } from '@playwright/test' + +import { expect, test } from '@playwright/test' +import { RESTClient } from 'helpers/rest.js' +import path from 'path' +import { fileURLToPath } from 'url' + +import type { PayloadTestSDK } from '../helpers/sdk/index.js' +import type { Config } from './payload-types.js' + +import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js' +import { AdminUrlUtil } from '../helpers/adminUrlUtil.js' +import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' +import { TEST_TIMEOUT_LONG } from '../playwright.config.js' +import { orderableSlug } from './collections/Orderable/index.js' +import { orderableJoinSlug } from './collections/OrderableJoin/index.js' +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +const { beforeAll, describe } = test +let page: Page +// eslint-disable-next-line @typescript-eslint/no-unused-vars +let payload: PayloadTestSDK +let client: RESTClient +let serverURL: string +let context: BrowserContext + +describe('Sort functionality', () => { + beforeAll(async ({ browser }, testInfo) => { + testInfo.setTimeout(TEST_TIMEOUT_LONG) + ;({ payload, serverURL } = await initPayloadE2ENoConfig({ dirname })) + + context = await browser.newContext() + page = await context.newPage() + + initPageConsoleErrorCatch(page) + + client = new RESTClient({ defaultSlug: 'users', serverURL }) + await client.login() + + await ensureCompilationIsDone({ page, serverURL }) + }) + + // NOTES: It works for me in headed browser but not in headless, I don't know why. + // If you are debugging this test, remember to press the seed button before each attempt. + // assertRows contains expect + // eslint-disable-next-line playwright/expect-expect + test('Orderable collection', async () => { + const url = new AdminUrlUtil(serverURL, orderableSlug) + await page.goto(`${url.list}?sort=-_order`) + // SORT BY ORDER ASCENDING + await page.locator('.sort-header button').nth(0).click() + await assertRows(0, 'A', 'B', 'C', 'D') + await moveRow(2, 3) // move to middle + await assertRows(0, 'A', 'C', 'B', 'D') + await moveRow(3, 1) // move to top + await assertRows(0, 'B', 'A', 'C', 'D') + await moveRow(1, 4) // move to bottom + await assertRows(0, 'A', 'C', 'D', 'B') + + // SORT BY ORDER DESCENDING + await page.locator('.sort-header button').nth(0).click() + await page.waitForURL(/sort=-_order/, { timeout: 2000 }) + await assertRows(0, 'B', 'D', 'C', 'A') + await moveRow(1, 3) // move to middle + await assertRows(0, 'D', 'C', 'B', 'A') + await moveRow(3, 1) // move to top + await assertRows(0, 'B', 'D', 'C', 'A') + await moveRow(1, 4) // move to bottom + await assertRows(0, 'D', 'C', 'A', 'B') + + // SORT BY TITLE + await page.getByLabel('Sort by Title Ascending').click() + await page.waitForURL(/sort=title/, { timeout: 2000 }) + await moveRow(1, 3, 'warning') // warning because not sorted by order first + }) + + test('Orderable join fields', async () => { + const url = new AdminUrlUtil(serverURL, orderableJoinSlug) + await page.goto(url.list) + + await page.getByText('Join A').click() + await expect(page.locator('.sort-header button')).toHaveCount(2) + + await page.locator('.sort-header button').nth(0).click() + await assertRows(0, 'A', 'B', 'C', 'D') + await moveRow(2, 3, 'success', 0) // move to middle + await assertRows(0, 'A', 'C', 'B', 'D') + + await page.locator('.sort-header button').nth(1).click() + await assertRows(1, 'A', 'B', 'C', 'D') + await moveRow(1, 4, 'success', 1) // move to end + await assertRows(1, 'B', 'C', 'D', 'A') + + await page.reload() + await page.locator('.sort-header button').nth(0).click() + await page.locator('.sort-header button').nth(1).click() + await assertRows(0, 'A', 'C', 'B', 'D') + await assertRows(1, 'B', 'C', 'D', 'A') + }) +}) + +async function moveRow( + from: number, + to: number, + expected: 'success' | 'warning' = 'success', + nthTable = 0, +) { + // counting from 1, zero excluded + const table = page.locator(`tbody`).nth(nthTable) + const dragHandle = table.locator(`.sort-row`) + const source = dragHandle.nth(from - 1) + const target = dragHandle.nth(to - 1) + + const sourceBox = await source.boundingBox() + const targetBox = await target.boundingBox() + if (!sourceBox || !targetBox) { + throw new Error( + `Could not find elements to DnD. Probably the dndkit animation is not finished. Try increasing the timeout`, + ) + } + // steps is important: move slightly to trigger the drag sensor of DnD-kit + await page.mouse.move(sourceBox.x + sourceBox.width / 2, sourceBox.y + sourceBox.height / 2, { + steps: 10, + }) + await page.mouse.down() + await page.mouse.move(targetBox.x + targetBox.width / 2, targetBox.y + targetBox.height / 2, { + steps: 10, + }) + await page.mouse.up() + // eslint-disable-next-line playwright/no-wait-for-timeout + await page.waitForTimeout(400) // dndkit animation + + if (expected === 'warning') { + const toast = page.locator('.payload-toast-item.toast-warning') + await expect(toast).toHaveText( + 'To reorder the rows you must first sort them by the "Order" column', + ) + } +} + +async function assertRows(nthTable: number, ...expectedRows: Array) { + const table = page.locator('tbody').nth(nthTable) + const cellTitle = table.locator('.cell-title > :first-child') + + const rows = table.locator('.sort-row') + await expect.poll(() => rows.count()).toBe(expectedRows.length) + + for (let i = 0; i < expectedRows.length; i++) { + await expect(cellTitle.nth(i)).toHaveText(expectedRows[i]!) + } +} diff --git a/test/sort/int.spec.ts b/test/sort/int.spec.ts index 805370aa11..12689c3393 100644 --- a/test/sort/int.spec.ts +++ b/test/sort/int.spec.ts @@ -4,8 +4,11 @@ import path from 'path' import { fileURLToPath } from 'url' import type { NextRESTClient } from '../helpers/NextRESTClient.js' +import type { Orderable, OrderableJoin } from './payload-types.js' import { initPayloadInt } from '../helpers/initPayloadInt.js' +import { orderableSlug } from './collections/Orderable/index.js' +import { orderableJoinSlug } from './collections/OrderableJoin/index.js' let payload: Payload let restClient: NextRESTClient @@ -63,7 +66,7 @@ describe('Sort', () => { }) }) - describe('Sinlge sort field', () => { + describe('Single sort field', () => { it('should sort posts by text field', async () => { const posts = await payload.find({ collection: 'posts', @@ -326,6 +329,84 @@ describe('Sort', () => { ]) }) }) + + describe('Orderable join', () => { + let related: OrderableJoin + let orderable1: Orderable + let orderable2: Orderable + let orderable3: Orderable + + beforeAll(async () => { + related = await payload.create({ + collection: orderableJoinSlug, + data: { + title: 'test', + }, + }) + orderable1 = await payload.create({ + collection: orderableSlug, + data: { + title: 'test 1', + orderableField: related.id, + }, + }) + + orderable2 = await payload.create({ + collection: orderableSlug, + data: { + title: 'test 2', + orderableField: related.id, + }, + }) + + orderable3 = await payload.create({ + collection: orderableSlug, + data: { + title: 'test 3', + orderableField: related.id, + }, + }) + }) + + it('should set order by default', () => { + expect(orderable1._orderable_orderableJoinField1_order).toBeDefined() + }) + + it('should allow setting the order with the local API', async () => { + // create two orderableJoinSlug docs + orderable2 = await payload.update({ + collection: orderableSlug, + id: orderable2.id, + data: { + title: 'test', + orderableField: related.id, + _orderable_orderableJoinField1_order: 'e4', + }, + }) + const orderable4 = await payload.create({ + collection: orderableSlug, + data: { + title: 'test', + orderableField: related.id, + _orderable_orderableJoinField1_order: 'e2', + }, + }) + expect(orderable2._orderable_orderableJoinField1_order).toBe('e4') + expect(orderable4._orderable_orderableJoinField1_order).toBe('e2') + }) + it('should sort join docs in the correct', async () => { + related = await payload.findByID({ + collection: orderableJoinSlug, + id: related.id, + depth: 1, + }) + const orders = (related.orderableJoinField1 as { docs: Orderable[] }).docs.map((doc) => + parseInt(doc._orderable_orderableJoinField1_order, 16), + ) as [number, number, number] + expect(orders[0]).toBeLessThan(orders[1]) + expect(orders[1]).toBeLessThan(orders[2]) + }) + }) }) describe('REST API', () => { @@ -344,7 +425,7 @@ describe('Sort', () => { await payload.delete({ collection: 'posts', where: {} }) }) - describe('Sinlge sort field', () => { + describe('Single sort field', () => { it('should sort posts by text field', async () => { const res = await restClient .GET(`/posts`, { diff --git a/test/sort/payload-types.ts b/test/sort/payload-types.ts index 375215f7d4..887eb15457 100644 --- a/test/sort/payload-types.ts +++ b/test/sort/payload-types.ts @@ -54,6 +54,7 @@ export type SupportedTimezones = | 'Asia/Singapore' | 'Asia/Tokyo' | 'Asia/Seoul' + | 'Australia/Brisbane' | 'Australia/Sydney' | 'Pacific/Guam' | 'Pacific/Noumea' @@ -70,17 +71,27 @@ export interface Config { drafts: Draft; 'default-sort': DefaultSort; localized: Localized; + orderable: Orderable; + 'orderable-join': OrderableJoin; users: User; 'payload-locked-documents': PayloadLockedDocument; 'payload-preferences': PayloadPreference; 'payload-migrations': PayloadMigration; }; - collectionsJoins: {}; + collectionsJoins: { + 'orderable-join': { + orderableJoinField1: 'orderable'; + orderableJoinField2: 'orderable'; + nonOrderableJoinField: 'orderable'; + }; + }; collectionsSelect: { posts: PostsSelect | PostsSelect; drafts: DraftsSelect | DraftsSelect; 'default-sort': DefaultSortSelect | DefaultSortSelect; localized: LocalizedSelect | LocalizedSelect; + orderable: OrderableSelect | OrderableSelect; + 'orderable-join': OrderableJoinSelect | OrderableJoinSelect; users: UsersSelect | UsersSelect; 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; @@ -174,6 +185,45 @@ export interface Localized { updatedAt: string; createdAt: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "orderable". + */ +export interface Orderable { + id: string; + _orderable_orderableJoinField2_order?: string; + _orderable_orderableJoinField1_order?: string; + _order?: string; + title?: string | null; + orderableField?: (string | null) | OrderableJoin; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "orderable-join". + */ +export interface OrderableJoin { + id: string; + title?: string | null; + orderableJoinField1?: { + docs?: (string | Orderable)[]; + hasNextPage?: boolean; + totalDocs?: number; + }; + orderableJoinField2?: { + docs?: (string | Orderable)[]; + hasNextPage?: boolean; + totalDocs?: number; + }; + nonOrderableJoinField?: { + docs?: (string | Orderable)[]; + hasNextPage?: boolean; + totalDocs?: number; + }; + updatedAt: string; + createdAt: string; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users". @@ -214,6 +264,14 @@ export interface PayloadLockedDocument { relationTo: 'localized'; value: string | Localized; } | null) + | ({ + relationTo: 'orderable'; + value: string | Orderable; + } | null) + | ({ + relationTo: 'orderable-join'; + value: string | OrderableJoin; + } | null) | ({ relationTo: 'users'; value: string | User; @@ -316,6 +374,31 @@ export interface LocalizedSelect { updatedAt?: T; createdAt?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "orderable_select". + */ +export interface OrderableSelect { + _orderable_orderableJoinField2_order?: T; + _orderable_orderableJoinField1_order?: T; + _order?: T; + title?: T; + orderableField?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "orderable-join_select". + */ +export interface OrderableJoinSelect { + title?: T; + orderableJoinField1?: T; + orderableJoinField2?: T; + nonOrderableJoinField?: T; + updatedAt?: T; + createdAt?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users_select". From 4ac6d21ef6f68b33901a9bb14c73283473e207cd Mon Sep 17 00:00:00 2001 From: Elliot DeNolf Date: Tue, 1 Apr 2025 14:27:01 -0400 Subject: [PATCH 50/77] chore(release): v3.32.0 [skip ci] --- package.json | 2 +- packages/admin-bar/package.json | 2 +- packages/create-payload-app/package.json | 2 +- packages/db-mongodb/package.json | 2 +- packages/db-postgres/package.json | 2 +- packages/db-sqlite/package.json | 2 +- packages/db-vercel-postgres/package.json | 2 +- packages/drizzle/package.json | 2 +- packages/email-nodemailer/package.json | 2 +- packages/email-resend/package.json | 2 +- packages/graphql/package.json | 2 +- packages/live-preview-react/package.json | 2 +- packages/live-preview-vue/package.json | 2 +- packages/live-preview/package.json | 2 +- packages/next/package.json | 2 +- packages/payload-cloud/package.json | 2 +- packages/payload/package.json | 2 +- packages/plugin-cloud-storage/package.json | 2 +- packages/plugin-form-builder/package.json | 2 +- packages/plugin-import-export/package.json | 2 +- packages/plugin-multi-tenant/package.json | 2 +- packages/plugin-nested-docs/package.json | 2 +- packages/plugin-redirects/package.json | 2 +- packages/plugin-search/package.json | 2 +- packages/plugin-sentry/package.json | 2 +- packages/plugin-seo/package.json | 2 +- packages/plugin-stripe/package.json | 2 +- packages/richtext-lexical/package.json | 2 +- packages/richtext-slate/package.json | 2 +- packages/storage-azure/package.json | 2 +- packages/storage-gcs/package.json | 2 +- packages/storage-s3/package.json | 2 +- packages/storage-uploadthing/package.json | 2 +- packages/storage-vercel-blob/package.json | 2 +- packages/translations/package.json | 2 +- packages/ui/package.json | 2 +- 36 files changed, 36 insertions(+), 36 deletions(-) diff --git a/package.json b/package.json index 9e53ddbf75..cd48433dd0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "payload-monorepo", - "version": "3.31.0", + "version": "3.32.0", "private": true, "type": "module", "scripts": { diff --git a/packages/admin-bar/package.json b/packages/admin-bar/package.json index 8597542928..3a0a762a2d 100644 --- a/packages/admin-bar/package.json +++ b/packages/admin-bar/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/admin-bar", - "version": "3.31.0", + "version": "3.32.0", "description": "An admin bar for React apps using Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/create-payload-app/package.json b/packages/create-payload-app/package.json index 12257895d0..71cddb7d75 100644 --- a/packages/create-payload-app/package.json +++ b/packages/create-payload-app/package.json @@ -1,6 +1,6 @@ { "name": "create-payload-app", - "version": "3.31.0", + "version": "3.32.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/db-mongodb/package.json b/packages/db-mongodb/package.json index a0da521a0f..aab3619d76 100644 --- a/packages/db-mongodb/package.json +++ b/packages/db-mongodb/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-mongodb", - "version": "3.31.0", + "version": "3.32.0", "description": "The officially supported MongoDB database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-postgres/package.json b/packages/db-postgres/package.json index 17f542c6a9..3aa5116461 100644 --- a/packages/db-postgres/package.json +++ b/packages/db-postgres/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-postgres", - "version": "3.31.0", + "version": "3.32.0", "description": "The officially supported Postgres database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-sqlite/package.json b/packages/db-sqlite/package.json index 52bc4164b4..63525c9e4e 100644 --- a/packages/db-sqlite/package.json +++ b/packages/db-sqlite/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-sqlite", - "version": "3.31.0", + "version": "3.32.0", "description": "The officially supported SQLite database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-vercel-postgres/package.json b/packages/db-vercel-postgres/package.json index ac86baf7f4..b642ba0d37 100644 --- a/packages/db-vercel-postgres/package.json +++ b/packages/db-vercel-postgres/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-vercel-postgres", - "version": "3.31.0", + "version": "3.32.0", "description": "Vercel Postgres adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/drizzle/package.json b/packages/drizzle/package.json index cd35a453ad..d0091f5479 100644 --- a/packages/drizzle/package.json +++ b/packages/drizzle/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/drizzle", - "version": "3.31.0", + "version": "3.32.0", "description": "A library of shared functions used by different payload database adapters", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/email-nodemailer/package.json b/packages/email-nodemailer/package.json index 3bf9344c12..6ce4983c7c 100644 --- a/packages/email-nodemailer/package.json +++ b/packages/email-nodemailer/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/email-nodemailer", - "version": "3.31.0", + "version": "3.32.0", "description": "Payload Nodemailer Email Adapter", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/email-resend/package.json b/packages/email-resend/package.json index a09853c396..ede7fc1124 100644 --- a/packages/email-resend/package.json +++ b/packages/email-resend/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/email-resend", - "version": "3.31.0", + "version": "3.32.0", "description": "Payload Resend Email Adapter", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/graphql/package.json b/packages/graphql/package.json index b5a84e745d..6fbc58722e 100644 --- a/packages/graphql/package.json +++ b/packages/graphql/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/graphql", - "version": "3.31.0", + "version": "3.32.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/live-preview-react/package.json b/packages/live-preview-react/package.json index 82015534f0..bf7131af04 100644 --- a/packages/live-preview-react/package.json +++ b/packages/live-preview-react/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview-react", - "version": "3.31.0", + "version": "3.32.0", "description": "The official React SDK for Payload Live Preview", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/live-preview-vue/package.json b/packages/live-preview-vue/package.json index 8351a3e2b3..bf1f3584c3 100644 --- a/packages/live-preview-vue/package.json +++ b/packages/live-preview-vue/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview-vue", - "version": "3.31.0", + "version": "3.32.0", "description": "The official Vue SDK for Payload Live Preview", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/live-preview/package.json b/packages/live-preview/package.json index 3d34a4af24..a26e49adc7 100644 --- a/packages/live-preview/package.json +++ b/packages/live-preview/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview", - "version": "3.31.0", + "version": "3.32.0", "description": "The official live preview JavaScript SDK for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/next/package.json b/packages/next/package.json index bb9dfeafab..6cfaa17ee0 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/next", - "version": "3.31.0", + "version": "3.32.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/payload-cloud/package.json b/packages/payload-cloud/package.json index 488e4b7a39..c81ef4a739 100644 --- a/packages/payload-cloud/package.json +++ b/packages/payload-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/payload-cloud", - "version": "3.31.0", + "version": "3.32.0", "description": "The official Payload Cloud plugin", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/payload/package.json b/packages/payload/package.json index 984f95888a..9c3a6eaaf0 100644 --- a/packages/payload/package.json +++ b/packages/payload/package.json @@ -1,6 +1,6 @@ { "name": "payload", - "version": "3.31.0", + "version": "3.32.0", "description": "Node, React, Headless CMS and Application Framework built on Next.js", "keywords": [ "admin panel", diff --git a/packages/plugin-cloud-storage/package.json b/packages/plugin-cloud-storage/package.json index c1870c9609..4a79fde85b 100644 --- a/packages/plugin-cloud-storage/package.json +++ b/packages/plugin-cloud-storage/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-cloud-storage", - "version": "3.31.0", + "version": "3.32.0", "description": "The official cloud storage plugin for Payload CMS", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/plugin-form-builder/package.json b/packages/plugin-form-builder/package.json index da1a4b8a96..7c0d3b4431 100644 --- a/packages/plugin-form-builder/package.json +++ b/packages/plugin-form-builder/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-form-builder", - "version": "3.31.0", + "version": "3.32.0", "description": "Form builder plugin for Payload CMS", "keywords": [ "payload", diff --git a/packages/plugin-import-export/package.json b/packages/plugin-import-export/package.json index 4950e31012..d04cf96186 100644 --- a/packages/plugin-import-export/package.json +++ b/packages/plugin-import-export/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-import-export", - "version": "3.31.0", + "version": "3.32.0", "description": "Import-Export plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-multi-tenant/package.json b/packages/plugin-multi-tenant/package.json index 0abb6159d6..88599b9a40 100644 --- a/packages/plugin-multi-tenant/package.json +++ b/packages/plugin-multi-tenant/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-multi-tenant", - "version": "3.31.0", + "version": "3.32.0", "description": "Multi Tenant plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-nested-docs/package.json b/packages/plugin-nested-docs/package.json index 6e7cb75ac4..1a437516fa 100644 --- a/packages/plugin-nested-docs/package.json +++ b/packages/plugin-nested-docs/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-nested-docs", - "version": "3.31.0", + "version": "3.32.0", "description": "The official Nested Docs plugin for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/plugin-redirects/package.json b/packages/plugin-redirects/package.json index fed8c2fefb..6cacf39e1b 100644 --- a/packages/plugin-redirects/package.json +++ b/packages/plugin-redirects/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-redirects", - "version": "3.31.0", + "version": "3.32.0", "description": "Redirects plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-search/package.json b/packages/plugin-search/package.json index b49292920b..8b09f41f09 100644 --- a/packages/plugin-search/package.json +++ b/packages/plugin-search/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-search", - "version": "3.31.0", + "version": "3.32.0", "description": "Search plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-sentry/package.json b/packages/plugin-sentry/package.json index 4844bc3ce4..af1970f87f 100644 --- a/packages/plugin-sentry/package.json +++ b/packages/plugin-sentry/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-sentry", - "version": "3.31.0", + "version": "3.32.0", "description": "Sentry plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-seo/package.json b/packages/plugin-seo/package.json index 6b7fc9da91..f3f3f1714d 100644 --- a/packages/plugin-seo/package.json +++ b/packages/plugin-seo/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-seo", - "version": "3.31.0", + "version": "3.32.0", "description": "SEO plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-stripe/package.json b/packages/plugin-stripe/package.json index a143986af6..0448b802d6 100644 --- a/packages/plugin-stripe/package.json +++ b/packages/plugin-stripe/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-stripe", - "version": "3.31.0", + "version": "3.32.0", "description": "Stripe plugin for Payload", "keywords": [ "payload", diff --git a/packages/richtext-lexical/package.json b/packages/richtext-lexical/package.json index 92f430dfbc..8df2b9d562 100644 --- a/packages/richtext-lexical/package.json +++ b/packages/richtext-lexical/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/richtext-lexical", - "version": "3.31.0", + "version": "3.32.0", "description": "The officially supported Lexical richtext adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/richtext-slate/package.json b/packages/richtext-slate/package.json index 9297b7096a..a74e0a77d4 100644 --- a/packages/richtext-slate/package.json +++ b/packages/richtext-slate/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/richtext-slate", - "version": "3.31.0", + "version": "3.32.0", "description": "The officially supported Slate richtext adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-azure/package.json b/packages/storage-azure/package.json index f6c46ad88d..d403f1166c 100644 --- a/packages/storage-azure/package.json +++ b/packages/storage-azure/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-azure", - "version": "3.31.0", + "version": "3.32.0", "description": "Payload storage adapter for Azure Blob Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-gcs/package.json b/packages/storage-gcs/package.json index 3df704839b..a2fd474af4 100644 --- a/packages/storage-gcs/package.json +++ b/packages/storage-gcs/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-gcs", - "version": "3.31.0", + "version": "3.32.0", "description": "Payload storage adapter for Google Cloud Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-s3/package.json b/packages/storage-s3/package.json index 6ce49ca71f..18a1f16721 100644 --- a/packages/storage-s3/package.json +++ b/packages/storage-s3/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-s3", - "version": "3.31.0", + "version": "3.32.0", "description": "Payload storage adapter for Amazon S3", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-uploadthing/package.json b/packages/storage-uploadthing/package.json index c67a5319eb..8fcb33a02a 100644 --- a/packages/storage-uploadthing/package.json +++ b/packages/storage-uploadthing/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-uploadthing", - "version": "3.31.0", + "version": "3.32.0", "description": "Payload storage adapter for uploadthing", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-vercel-blob/package.json b/packages/storage-vercel-blob/package.json index f6ba6eac69..48ddeeca20 100644 --- a/packages/storage-vercel-blob/package.json +++ b/packages/storage-vercel-blob/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-vercel-blob", - "version": "3.31.0", + "version": "3.32.0", "description": "Payload storage adapter for Vercel Blob Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/translations/package.json b/packages/translations/package.json index 44f988e557..04ef4b1a62 100644 --- a/packages/translations/package.json +++ b/packages/translations/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/translations", - "version": "3.31.0", + "version": "3.32.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/ui/package.json b/packages/ui/package.json index f0fed6e6bd..e2122231ec 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/ui", - "version": "3.31.0", + "version": "3.32.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", From e5690fcab95fb19b9fb2ac1f3441786f5f2a135e Mon Sep 17 00:00:00 2001 From: Sasha <64744993+r1tsuu@users.noreply.github.com> Date: Tue, 1 Apr 2025 21:41:47 +0300 Subject: [PATCH 51/77] fix(graphql): respect `draft: true` when querying joins (#11869) The same as https://github.com/payloadcms/payload/pull/11763 but also for GraphQL. The previous fix was working only for the Local API and REST API due to a different method for querying joins in GraphQL. --- .../graphql/src/schema/fieldToSchemaMap.ts | 3 + test/joins/collections/Versions.ts | 5 ++ test/joins/int.spec.ts | 64 +++++++++++++++++-- test/joins/payload-types.ts | 8 ++- 4 files changed, 72 insertions(+), 8 deletions(-) diff --git a/packages/graphql/src/schema/fieldToSchemaMap.ts b/packages/graphql/src/schema/fieldToSchemaMap.ts index d268835940..452182996b 100644 --- a/packages/graphql/src/schema/fieldToSchemaMap.ts +++ b/packages/graphql/src/schema/fieldToSchemaMap.ts @@ -379,6 +379,8 @@ export const fieldToSchemaMap: FieldToSchemaMap = { const { limit, page, sort, where } = args const { req } = context + const draft = Boolean(args.draft ?? context.req.query?.draft) + const fullWhere = combineQueries(where, { [field.on]: { equals: parent._id ?? parent.id }, }) @@ -390,6 +392,7 @@ export const fieldToSchemaMap: FieldToSchemaMap = { return await req.payload.find({ collection, depth: 0, + draft, fallbackLocale: req.fallbackLocale, limit, locale: req.locale, diff --git a/test/joins/collections/Versions.ts b/test/joins/collections/Versions.ts index a15a963d3c..b30ba583b2 100644 --- a/test/joins/collections/Versions.ts +++ b/test/joins/collections/Versions.ts @@ -5,6 +5,11 @@ export const versionsSlug = 'versions' export const Versions: CollectionConfig = { slug: versionsSlug, fields: [ + { + name: 'title', + type: 'text', + required: true, + }, { name: 'category', relationTo: 'categories', diff --git a/test/joins/int.spec.ts b/test/joins/int.spec.ts index a725a7939d..049acd4b0f 100644 --- a/test/joins/int.spec.ts +++ b/test/joins/int.spec.ts @@ -569,7 +569,7 @@ describe('Joins Field', () => { const version = await payload.create({ collection: 'versions', - data: { categoryVersion: category.id }, + data: { title: 'version', categoryVersion: category.id }, }) const res = await payload.find({ collection: 'categories-versions', draft: false }) @@ -582,7 +582,7 @@ describe('Joins Field', () => { const version = await payload.create({ collection: 'versions', - data: { categoryVersions: [category.id] }, + data: { title: 'version', categoryVersions: [category.id] }, }) const res = await payload.find({ collection: 'categories-versions', draft: false }) @@ -595,7 +595,7 @@ describe('Joins Field', () => { const version = await payload.create({ collection: 'versions', - data: { categoryVersion: category.id }, + data: { title: 'version', categoryVersion: category.id }, }) const res = await payload.find({ @@ -615,7 +615,14 @@ describe('Joins Field', () => { const version = await payload.create({ collection: 'versions', - data: { _status: 'draft', categoryVersion: category.id }, + data: { title: 'original-title', _status: 'draft', categoryVersion: category.id }, + draft: true, + }) + + await payload.update({ + collection: 'versions', + id: version.id, + data: { title: 'updated-title' }, draft: true, }) @@ -625,6 +632,7 @@ describe('Joins Field', () => { }) expect(res.docs[0].relatedVersions.docs[0].id).toBe(version.id) + expect(res.docs[0].relatedVersions.docs[0].title).toBe('updated-title') }) it('should populate joins when versions on both sides draft true payload.db.queryDrafts', async () => { @@ -632,7 +640,7 @@ describe('Joins Field', () => { const version = await payload.create({ collection: 'versions', - data: { categoryVersions: [category.id] }, + data: { categoryVersions: [category.id], title: 'version' }, }) const res = await payload.find({ @@ -932,6 +940,52 @@ describe('Joins Field', () => { ) }) + it('should populate joins with hasMany when on both sides documents are in draft', async () => { + const category = await payload.create({ + collection: 'categories-versions', + data: { _status: 'draft' }, + draft: true, + }) + + const version = await payload.create({ + collection: 'versions', + data: { _status: 'draft', title: 'original-title', categoryVersion: category.id }, + draft: true, + }) + + await payload.update({ + collection: 'versions', + draft: true, + id: version.id, + data: { title: 'updated-title' }, + }) + + const query = `query { + CategoriesVersions(draft: true) { + docs { + relatedVersions( + limit: 1 + ) { + docs { + id, + title + } + hasNextPage + } + } + } + }` + + const res = await restClient + .GRAPHQL_POST({ body: JSON.stringify({ query }) }) + .then((res) => res.json()) + + expect(res.data.CategoriesVersions.docs[0].relatedVersions.docs[0].id).toBe(version.id) + expect(res.data.CategoriesVersions.docs[0].relatedVersions.docs[0].title).toBe( + 'updated-title', + ) + }) + it('should have simple paginate for joins inside groups', async () => { const queryWithLimit = `query { Categories(where: { diff --git a/test/joins/payload-types.ts b/test/joins/payload-types.ts index ad414e394c..9d5d5ed63b 100644 --- a/test/joins/payload-types.ts +++ b/test/joins/payload-types.ts @@ -54,6 +54,7 @@ export type SupportedTimezones = | 'Asia/Singapore' | 'Asia/Tokyo' | 'Asia/Seoul' + | 'Australia/Brisbane' | 'Australia/Sydney' | 'Pacific/Guam' | 'Pacific/Noumea' @@ -464,6 +465,7 @@ export interface Singular { */ export interface Version { id: string; + title: string; category?: (string | null) | Category; categoryVersion?: (string | null) | CategoriesVersion; categoryVersions?: (string | CategoriesVersion)[] | null; @@ -999,6 +1001,7 @@ export interface UploadsSelect { * via the `definition` "versions_select". */ export interface VersionsSelect { + title?: T; category?: T; categoryVersion?: T; categoryVersions?: T; @@ -1232,7 +1235,6 @@ export interface Auth { declare module 'payload' { - // @ts-ignore + // @ts-ignore export interface GeneratedTypes extends Config {} -} - +} \ No newline at end of file From f34eb228c4b8cdb4c2ab5d21224c2d8d31156549 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Wed, 2 Apr 2025 12:17:39 -0600 Subject: [PATCH 52/77] feat(drizzle): export buildQuery and parseParams (#11935) This exports `buildQuery` and `parseParams` from @payloadcms/drizzle --- packages/drizzle/src/index.ts | 2 ++ packages/drizzle/src/queries/parseParams.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/drizzle/src/index.ts b/packages/drizzle/src/index.ts index fbda6d2356..c07309723f 100644 --- a/packages/drizzle/src/index.ts +++ b/packages/drizzle/src/index.ts @@ -23,8 +23,10 @@ export { migrateFresh } from './migrateFresh.js' export { migrateRefresh } from './migrateRefresh.js' export { migrateReset } from './migrateReset.js' export { migrateStatus } from './migrateStatus.js' +export { default as buildQuery } from './queries/buildQuery.js' export { operatorMap } from './queries/operatorMap.js' export type { Operators } from './queries/operatorMap.js' +export { parseParams } from './queries/parseParams.js' export { queryDrafts } from './queryDrafts.js' export { buildDrizzleRelations } from './schema/buildDrizzleRelations.js' export { buildRawSchema } from './schema/buildRawSchema.js' diff --git a/packages/drizzle/src/queries/parseParams.ts b/packages/drizzle/src/queries/parseParams.ts index 44c277f367..d03876f3ae 100644 --- a/packages/drizzle/src/queries/parseParams.ts +++ b/packages/drizzle/src/queries/parseParams.ts @@ -19,7 +19,7 @@ type Args = { aliasTable?: Table fields: FlattenedField[] joins: BuildQueryJoinAliases - locale: string + locale?: string parentIsLocalized: boolean selectFields: Record selectLocale?: boolean From d29bdfc10fb84cdb2a785f593e396199652f65ef Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Wed, 2 Apr 2025 14:10:20 -0600 Subject: [PATCH 53/77] feat(next): improved lexical richText diffing in version view (#11760) This replaces our JSON-based richtext diffing with HTML-based richtext diffing for lexical. It uses [this HTML diff library](https://github.com/Arman19941113/html-diff) that I then modified to handle diffing more complex elements like links, uploads and relationships. This makes it way easier to spot changes, replacing the lengthy Lexical JSON with a clean visual diff that shows exactly what's different. ## Before ![CleanShot 2025-03-18 at 13 54 51@2x](https://github.com/user-attachments/assets/811a7c14-d592-4fdc-a1f4-07eeb78255fe) ## After ![CleanShot 2025-03-31 at 18 14 10@2x](https://github.com/user-attachments/assets/efb64da0-4ff8-4965-a458-558a18375c46) ![CleanShot 2025-03-31 at 18 14 26@2x](https://github.com/user-attachments/assets/133652ce-503b-4b86-9c4c-e5c7706d8ea6) --- .../DiffCollapser/index.tsx | 7 +- .../RenderFieldsToDiff/buildVersionFields.tsx | 48 +- .../fields/Relationship/index.tsx | 7 +- .../fields/Select/index.tsx | 7 +- .../RenderFieldsToDiff/fields/Text/index.tsx | 7 +- .../RenderFieldsToDiff/fields/styles.ts | 11 +- packages/payload/src/admin/RichText.ts | 21 +- packages/payload/src/fields/config/types.ts | 4 +- .../src/exports/server/rsc.ts | 1 + .../converters/lexicalToHtml/async/types.ts | 1 + .../shared/findConverterForNode.ts | 5 +- .../converters/lexicalToHtml/sync/types.ts | 1 + .../lexicalToJSX/converter/index.tsx | 5 +- .../lexicalToJSX/converter/types.ts | 1 + .../src/field/Diff/colors.scss | 35 + .../src/field/Diff/converters/link.ts | 59 ++ .../field/Diff/converters/listitem/index.scss | 48 ++ .../field/Diff/converters/listitem/index.tsx | 71 ++ .../Diff/converters/relationship/index.scss | 79 +++ .../Diff/converters/relationship/index.tsx | 79 +++ .../field/Diff/converters/unknown/index.scss | 43 ++ .../field/Diff/converters/unknown/index.tsx | 62 ++ .../field/Diff/converters/upload/index.scss | 116 +++ .../field/Diff/converters/upload/index.tsx | 103 +++ .../src/field/Diff/htmlDiff/LICENSE.MD | 21 + .../src/field/Diff/htmlDiff/index.scss | 90 +++ .../src/field/Diff/htmlDiff/index.ts | 659 ++++++++++++++++++ .../src/field/Diff/index.scss | 95 +++ .../richtext-lexical/src/field/Diff/index.tsx | 74 ++ packages/richtext-lexical/src/index.ts | 7 + .../src/utilities/generateImportMap.tsx | 1 + .../src/elements/FieldDiffLabel}/index.scss | 0 .../src/elements/FieldDiffLabel}/index.tsx | 4 +- packages/ui/src/exports/client/index.ts | 1 + packages/ui/src/exports/rsc/index.ts | 3 + .../collections/Diff/generateLexicalData.ts | 628 +++++++++++++++++ .../collections/{Diff.ts => Diff/index.ts} | 2 +- test/versions/collections/Text.ts | 17 + test/versions/config.ts | 4 +- test/versions/e2e.spec.ts | 17 +- test/versions/payload-types.ts | 25 + test/versions/seed.ts | 27 +- test/versions/slugs.ts | 3 + 43 files changed, 2444 insertions(+), 55 deletions(-) create mode 100644 packages/richtext-lexical/src/field/Diff/colors.scss create mode 100644 packages/richtext-lexical/src/field/Diff/converters/link.ts create mode 100644 packages/richtext-lexical/src/field/Diff/converters/listitem/index.scss create mode 100644 packages/richtext-lexical/src/field/Diff/converters/listitem/index.tsx create mode 100644 packages/richtext-lexical/src/field/Diff/converters/relationship/index.scss create mode 100644 packages/richtext-lexical/src/field/Diff/converters/relationship/index.tsx create mode 100644 packages/richtext-lexical/src/field/Diff/converters/unknown/index.scss create mode 100644 packages/richtext-lexical/src/field/Diff/converters/unknown/index.tsx create mode 100644 packages/richtext-lexical/src/field/Diff/converters/upload/index.scss create mode 100644 packages/richtext-lexical/src/field/Diff/converters/upload/index.tsx create mode 100644 packages/richtext-lexical/src/field/Diff/htmlDiff/LICENSE.MD create mode 100644 packages/richtext-lexical/src/field/Diff/htmlDiff/index.scss create mode 100644 packages/richtext-lexical/src/field/Diff/htmlDiff/index.ts create mode 100644 packages/richtext-lexical/src/field/Diff/index.scss create mode 100644 packages/richtext-lexical/src/field/Diff/index.tsx rename packages/{next/src/views/Version/RenderFieldsToDiff/Label => ui/src/elements/FieldDiffLabel}/index.scss (100%) rename packages/{next/src/views/Version/RenderFieldsToDiff/Label => ui/src/elements/FieldDiffLabel}/index.tsx (58%) create mode 100644 test/versions/collections/Diff/generateLexicalData.ts rename test/versions/collections/{Diff.ts => Diff/index.ts} (98%) create mode 100644 test/versions/collections/Text.ts diff --git a/packages/next/src/views/Version/RenderFieldsToDiff/DiffCollapser/index.tsx b/packages/next/src/views/Version/RenderFieldsToDiff/DiffCollapser/index.tsx index 1e642fb5c3..433e3e4f1e 100644 --- a/packages/next/src/views/Version/RenderFieldsToDiff/DiffCollapser/index.tsx +++ b/packages/next/src/views/Version/RenderFieldsToDiff/DiffCollapser/index.tsx @@ -1,11 +1,10 @@ 'use client' import type { ClientField } from 'payload' -import { ChevronIcon, Pill, useConfig, useTranslation } from '@payloadcms/ui' +import { ChevronIcon, FieldDiffLabel, Pill, useConfig, useTranslation } from '@payloadcms/ui' import { fieldIsArrayType, fieldIsBlockType } from 'payload/shared' import React, { useState } from 'react' -import Label from '../Label/index.js' import './index.scss' import { countChangedFields, countChangedFieldsInRows } from '../utilities/countChangedFields.js' @@ -100,7 +99,7 @@ export const DiffCollapser: React.FC = ({ return (
-
) diff --git a/packages/next/src/views/Version/RenderFieldsToDiff/buildVersionFields.tsx b/packages/next/src/views/Version/RenderFieldsToDiff/buildVersionFields.tsx index 5e14d48485..783292db03 100644 --- a/packages/next/src/views/Version/RenderFieldsToDiff/buildVersionFields.tsx +++ b/packages/next/src/views/Version/RenderFieldsToDiff/buildVersionFields.tsx @@ -1,22 +1,23 @@ import type { I18nClient } from '@payloadcms/translations' -import type { - BaseVersionField, - ClientField, - ClientFieldSchemaMap, - Field, - FieldDiffClientProps, - FieldDiffServerProps, - FieldTypes, - FlattenedBlock, - PayloadComponent, - PayloadRequest, - SanitizedFieldPermissions, - VersionField, -} from 'payload' import type { DiffMethod } from 'react-diff-viewer-continued' import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent' import { dequal } from 'dequal/lite' +import { + type BaseVersionField, + type ClientField, + type ClientFieldSchemaMap, + type Field, + type FieldDiffClientProps, + type FieldDiffServerProps, + type FieldTypes, + type FlattenedBlock, + MissingEditorProp, + type PayloadComponent, + type PayloadRequest, + type SanitizedFieldPermissions, + type VersionField, +} from 'payload' import { fieldIsID, fieldShouldBeLocalized, getUniqueListBy, tabHasName } from 'payload/shared' import { diffMethods } from './fields/diffMethods.js' @@ -238,7 +239,24 @@ const buildVersionField = ({ return null } - const CustomComponent = field?.admin?.components?.Diff ?? customDiffComponents?.[field.type] + let CustomComponent = customDiffComponents?.[field.type] + if (field?.type === 'richText') { + if (!field?.editor) { + throw new MissingEditorProp(field) // while we allow disabling editor functionality, you should not have any richText fields defined if you do not have an editor + } + + if (typeof field?.editor === 'function') { + throw new Error('Attempted to access unsanitized rich text editor.') + } + + if (field.editor.CellComponent) { + CustomComponent = field.editor.DiffComponent + } + } + if (field?.admin?.components?.Diff) { + CustomComponent = field.admin.components.Diff + } + const DefaultComponent = diffComponents?.[field.type] const baseVersionField: BaseVersionField = { diff --git a/packages/next/src/views/Version/RenderFieldsToDiff/fields/Relationship/index.tsx b/packages/next/src/views/Version/RenderFieldsToDiff/fields/Relationship/index.tsx index fb71f64fd7..b697bccb0c 100644 --- a/packages/next/src/views/Version/RenderFieldsToDiff/fields/Relationship/index.tsx +++ b/packages/next/src/views/Version/RenderFieldsToDiff/fields/Relationship/index.tsx @@ -7,12 +7,11 @@ import type { } from 'payload' import { getTranslation } from '@payloadcms/translations' -import { useConfig, useTranslation } from '@payloadcms/ui' +import { FieldDiffLabel, useConfig, useTranslation } from '@payloadcms/ui' import { fieldAffectsData, fieldIsPresentationalOnly, fieldShouldBeLocalized } from 'payload/shared' import React from 'react' import ReactDiffViewer from 'react-diff-viewer-continued' -import Label from '../../Label/index.js' import './index.scss' import { diffStyles } from '../styles.js' @@ -169,10 +168,10 @@ export const Relationship: RelationshipFieldDiffClientComponent = ({ return (
- + - + - + = { CellComponent: PayloadComponent - FieldComponent: PayloadComponent + /** + * Component that will be displayed in the version diff view. + * If not provided, richtext content will be diffed as JSON. + */ + DiffComponent?: PayloadComponent< + FieldDiffServerProps, + FieldDiffClientProps + > + FieldComponent: PayloadComponent } & RichTextAdapterBase export type RichTextAdapterProvider< diff --git a/packages/payload/src/fields/config/types.ts b/packages/payload/src/fields/config/types.ts index 2119b85683..442980b6bf 100644 --- a/packages/payload/src/fields/config/types.ts +++ b/packages/payload/src/fields/config/types.ts @@ -57,7 +57,7 @@ import type { EmailFieldLabelServerComponent, FieldDescriptionClientProps, FieldDescriptionServerProps, - FieldDiffClientComponent, + FieldDiffClientProps, FieldDiffServerProps, GroupFieldClientProps, GroupFieldLabelClientComponent, @@ -326,7 +326,7 @@ type Admin = { components?: { Cell?: PayloadComponent Description?: PayloadComponent - Diff?: PayloadComponent + Diff?: PayloadComponent Field?: PayloadComponent /** * The Filter component has to be a client component diff --git a/packages/richtext-lexical/src/exports/server/rsc.ts b/packages/richtext-lexical/src/exports/server/rsc.ts index 28ec1b9a37..f82d8b9192 100644 --- a/packages/richtext-lexical/src/exports/server/rsc.ts +++ b/packages/richtext-lexical/src/exports/server/rsc.ts @@ -1,2 +1,3 @@ export { RscEntryLexicalCell } from '../../cell/rscEntry.js' +export { LexicalDiffComponent } from '../../field/Diff/index.js' export { RscEntryLexicalField } from '../../field/rscEntry.js' diff --git a/packages/richtext-lexical/src/features/converters/lexicalToHtml/async/types.ts b/packages/richtext-lexical/src/features/converters/lexicalToHtml/async/types.ts index 04e5115a86..8a9fafd972 100644 --- a/packages/richtext-lexical/src/features/converters/lexicalToHtml/async/types.ts +++ b/packages/richtext-lexical/src/features/converters/lexicalToHtml/async/types.ts @@ -83,6 +83,7 @@ export type HTMLConvertersAsync< : SerializedInlineBlockNode > } + unknown?: HTMLConverterAsync } export type HTMLConvertersFunctionAsync< diff --git a/packages/richtext-lexical/src/features/converters/lexicalToHtml/shared/findConverterForNode.ts b/packages/richtext-lexical/src/features/converters/lexicalToHtml/shared/findConverterForNode.ts index 0b1b96c74a..b9b4ca91b3 100644 --- a/packages/richtext-lexical/src/features/converters/lexicalToHtml/shared/findConverterForNode.ts +++ b/packages/richtext-lexical/src/features/converters/lexicalToHtml/shared/findConverterForNode.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ import type { SerializedLexicalNode } from 'lexical' import type { SerializedBlockNode, SerializedInlineBlockNode } from '../../../../nodeTypes.js' @@ -30,7 +31,7 @@ export function findConverterForNode< converterForNode = converters?.blocks?.[ (node as SerializedBlockNode)?.fields?.blockType ] as TConverter - if (!converterForNode) { + if (!converterForNode && !unknownConverter) { console.error( `Lexical => HTML converter: Blocks converter: found ${(node as SerializedBlockNode)?.fields?.blockType} block, but no converter is provided`, ) @@ -39,7 +40,7 @@ export function findConverterForNode< converterForNode = converters?.inlineBlocks?.[ (node as SerializedInlineBlockNode)?.fields?.blockType ] as TConverter - if (!converterForNode) { + if (!converterForNode && !unknownConverter) { console.error( `Lexical => HTML converter: Inline Blocks converter: found ${(node as SerializedInlineBlockNode)?.fields?.blockType} inline block, but no converter is provided`, ) diff --git a/packages/richtext-lexical/src/features/converters/lexicalToHtml/sync/types.ts b/packages/richtext-lexical/src/features/converters/lexicalToHtml/sync/types.ts index fa03dc7522..0cca0c2bc4 100644 --- a/packages/richtext-lexical/src/features/converters/lexicalToHtml/sync/types.ts +++ b/packages/richtext-lexical/src/features/converters/lexicalToHtml/sync/types.ts @@ -71,6 +71,7 @@ export type HTMLConverters< : SerializedInlineBlockNode > } + unknown?: HTMLConverter } export type HTMLConvertersFunction< diff --git a/packages/richtext-lexical/src/features/converters/lexicalToJSX/converter/index.tsx b/packages/richtext-lexical/src/features/converters/lexicalToJSX/converter/index.tsx index 5e21da2d6a..15361de29c 100644 --- a/packages/richtext-lexical/src/features/converters/lexicalToJSX/converter/index.tsx +++ b/packages/richtext-lexical/src/features/converters/lexicalToJSX/converter/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ import type { SerializedEditorState, SerializedLexicalNode } from 'lexical' import React from 'react' @@ -51,7 +52,7 @@ export function convertLexicalNodesToJSX({ let converterForNode: JSXConverter | undefined if (node.type === 'block') { converterForNode = converters?.blocks?.[(node as SerializedBlockNode)?.fields?.blockType] - if (!converterForNode) { + if (!converterForNode && !unknownConverter) { console.error( `Lexical => JSX converter: Blocks converter: found ${(node as SerializedBlockNode)?.fields?.blockType} block, but no converter is provided`, ) @@ -59,7 +60,7 @@ export function convertLexicalNodesToJSX({ } else if (node.type === 'inlineBlock') { converterForNode = converters?.inlineBlocks?.[(node as SerializedInlineBlockNode)?.fields?.blockType] - if (!converterForNode) { + if (!converterForNode && !unknownConverter) { console.error( `Lexical => JSX converter: Inline Blocks converter: found ${(node as SerializedInlineBlockNode)?.fields?.blockType} inline block, but no converter is provided`, ) diff --git a/packages/richtext-lexical/src/features/converters/lexicalToJSX/converter/types.ts b/packages/richtext-lexical/src/features/converters/lexicalToJSX/converter/types.ts index 61205f5d7e..721564ae61 100644 --- a/packages/richtext-lexical/src/features/converters/lexicalToJSX/converter/types.ts +++ b/packages/richtext-lexical/src/features/converters/lexicalToJSX/converter/types.ts @@ -66,6 +66,7 @@ export type JSXConverters< : SerializedInlineBlockNode > } + unknown?: JSXConverter } export type SerializedLexicalNodeWithParent = { parent?: SerializedLexicalNode diff --git a/packages/richtext-lexical/src/field/Diff/colors.scss b/packages/richtext-lexical/src/field/Diff/colors.scss new file mode 100644 index 0000000000..af5c5f591f --- /dev/null +++ b/packages/richtext-lexical/src/field/Diff/colors.scss @@ -0,0 +1,35 @@ +@import '../../scss/styles.scss'; + +@layer payload-default { + :root { + --diff-delete-pill-bg: var(--theme-error-200); + --diff-delete-pill-color: var(--theme-error-600); + --diff-delete-pill-border: var(--theme-error-400); + --diff-delete-parent-bg: var(--theme-error-100); + --diff-delete-parent-color: var(--theme-error-800); + --diff-delete-link-color: var(--theme-error-600); + + --diff-create-pill-bg: var(--theme-success-200); + --diff-create-pill-color: var(--theme-success-600); + --diff-create-pill-border: var(--theme-success-400); + --diff-create-parent-bg: var(--theme-success-100); + --diff-create-parent-color: var(--theme-success-800); + --diff-create-link-color: var(--theme-success-600); + } + + html[data-theme='dark'] { + --diff-delete-pill-bg: var(--theme-error-200); + --diff-delete-pill-color: var(--theme-error-650); + --diff-delete-pill-border: var(--theme-error-400); + --diff-delete-parent-bg: var(--theme-error-100); + --diff-delete-parent-color: var(--theme-error-900); + --diff-delete-link-color: var(--theme-error-750); + + --diff-create-pill-bg: var(--theme-success-200); + --diff-create-pill-color: var(--theme-success-650); + --diff-create-pill-border: var(--theme-success-400); + --diff-create-parent-bg: var(--theme-success-100); + --diff-create-parent-color: var(--theme-success-900); + --diff-create-link-color: var(--theme-success-750); + } +} diff --git a/packages/richtext-lexical/src/field/Diff/converters/link.ts b/packages/richtext-lexical/src/field/Diff/converters/link.ts new file mode 100644 index 0000000000..e45feefc5b --- /dev/null +++ b/packages/richtext-lexical/src/field/Diff/converters/link.ts @@ -0,0 +1,59 @@ +import { createHash } from 'crypto' + +import type { + HTMLConvertersAsync, + HTMLPopulateFn, +} from '../../../features/converters/lexicalToHtml/async/types.js' +import type { SerializedAutoLinkNode, SerializedLinkNode } from '../../../nodeTypes.js' + +export const LinkDiffHTMLConverterAsync: (args: { + internalDocToHref?: (args: { + linkNode: SerializedLinkNode + populate?: HTMLPopulateFn + }) => Promise | string +}) => HTMLConvertersAsync = ({ + internalDocToHref, +}) => ({ + autolink: async ({ node, nodesToHTML, providedStyleTag }) => { + const children = ( + await nodesToHTML({ + nodes: node.children, + }) + ).join('') + + // hash fields to ensure they are diffed if they change + const nodeFieldsHash = createHash('sha256').update(JSON.stringify(node.fields)).digest('hex') + + return ` + ${children} + ` + }, + link: async ({ node, nodesToHTML, populate, providedStyleTag }) => { + const children = ( + await nodesToHTML({ + nodes: node.children, + }) + ).join('') + + let href: string = node.fields.url ?? '' + if (node.fields.linkType === 'internal') { + if (internalDocToHref) { + href = await internalDocToHref({ linkNode: node, populate }) + } else { + console.error( + 'Lexical => HTML converter: Link converter: found internal link, but internalDocToHref is not provided', + ) + href = '#' // fallback + } + } + + // hash fields to ensure they are diffed if they change + const nodeFieldsHash = createHash('sha256') + .update(JSON.stringify(node.fields ?? {})) + .digest('hex') + + return ` + ${children} + ` + }, +}) diff --git a/packages/richtext-lexical/src/field/Diff/converters/listitem/index.scss b/packages/richtext-lexical/src/field/Diff/converters/listitem/index.scss new file mode 100644 index 0000000000..ba149406ce --- /dev/null +++ b/packages/richtext-lexical/src/field/Diff/converters/listitem/index.scss @@ -0,0 +1,48 @@ +@import '../../../../scss/styles.scss'; +@import '../../colors.scss'; + +@layer payload-default { + .lexical-diff { + ul.list-check { + padding-left: 0; + } + + .checkboxItem { + list-style-type: none; + + &__wrapper { + display: flex; + align-items: center; + } + + &__icon { + width: 16px; + height: 16px; + margin-right: 8px; // Spacing before label text + border: 1px solid var(--theme-text); + border-radius: 3px; + display: flex; + align-items: center; + justify-content: center; + // Because the checkbox is non-interactive: + pointer-events: none; + + .icon--check { + height: 11px; + } + + &[data-match-type='create'] { + border-color: var(--diff-create-pill-color); + } + + &[data-match-type='delete'] { + border-color: var(--diff-delete-pill-color); + } + } + + &--nested { + margin-left: 1.5rem; + } + } + } +} diff --git a/packages/richtext-lexical/src/field/Diff/converters/listitem/index.tsx b/packages/richtext-lexical/src/field/Diff/converters/listitem/index.tsx new file mode 100644 index 0000000000..195bb7baee --- /dev/null +++ b/packages/richtext-lexical/src/field/Diff/converters/listitem/index.tsx @@ -0,0 +1,71 @@ +import { CheckIcon } from '@payloadcms/ui/rsc' + +import type { HTMLConvertersAsync } from '../../../../features/converters/lexicalToHtml/async/types.js' +import type { SerializedListItemNode } from '../../../../nodeTypes.js' + +import './index.scss' + +export const ListItemDiffHTMLConverterAsync: HTMLConvertersAsync = { + listitem: async ({ node, nodesToHTML, parent, providedCSSString }) => { + const hasSubLists = node.children.some((child) => child.type === 'list') + + const children = ( + await nodesToHTML({ + nodes: node.children, + }) + ).join('') + + if ('listType' in parent && parent?.listType === 'check') { + const ReactDOMServer = (await import('react-dom/server')).default + + const JSX = ( +
  • + {hasSubLists ? ( + // When sublists exist, just render them safely as HTML +
    + ) : ( + // Otherwise, show our custom styled checkbox +
    +
    + {node.checked && } +
    + {children} +
    + )} +
  • + ) + + const html = ReactDOMServer.renderToString(JSX) + + // Add style="list-style-type: none;${providedCSSString}" to html + const styleIndex = html.indexOf('class="list-item-checkbox') + const classIndex = html.indexOf('class="list-item-checkbox', styleIndex) + const classEndIndex = html.indexOf('"', classIndex + 6) + const className = html.substring(classIndex, classEndIndex) + const classNameWithStyle = `${className} style="list-style-type: none;${providedCSSString}"` + const htmlWithStyle = html.replace(className, classNameWithStyle) + + return htmlWithStyle + } else { + return `
  • ${children}
  • ` + } + }, +} diff --git a/packages/richtext-lexical/src/field/Diff/converters/relationship/index.scss b/packages/richtext-lexical/src/field/Diff/converters/relationship/index.scss new file mode 100644 index 0000000000..1f2f71ac24 --- /dev/null +++ b/packages/richtext-lexical/src/field/Diff/converters/relationship/index.scss @@ -0,0 +1,79 @@ +@import '../../../../scss/styles.scss'; +@import '../../colors.scss'; + +@layer payload-default { + .lexical-diff__diff-container { + .lexical-relationship-diff { + @extend %body; + @include shadow-sm; + min-width: calc(var(--base) * 8); + max-width: fit-content; + + display: flex; + align-items: center; + background-color: var(--theme-input-bg); + border-radius: $style-radius-s; + border: 1px solid var(--theme-elevation-100); + position: relative; + font-family: var(--font-body); + margin-block: base(0.5); + max-height: calc(var(--base) * 4); + padding: base(0.6); + + &[data-match-type='create'] { + border-color: var(--diff-create-pill-border); + color: var(--diff-create-parent-color); + + .lexical-relationship-diff__collectionLabel { + color: var(--diff-create-link-color); + } + + [data-match-type='create'] { + color: var(--diff-create-parent-color); + } + } + + &[data-match-type='delete'] { + border-color: var(--diff-delete-pill-border); + color: var(--diff-delete-parent-color); + text-decoration-line: none; + background-color: var(--diff-delete-pill-bg); + + .lexical-relationship-diff__collectionLabel { + color: var(--diff-delete-link-color); + } + + [data-match-type='delete'] { + text-decoration-line: none; + } + + * { + color: var(--diff-delete-parent-color); + } + } + + &__card { + display: flex; + flex-direction: column; + width: 100%; + flex-grow: 1; + display: flex; + align-items: flex-start; + flex-direction: column; + justify-content: space-between; + } + + &__title { + display: flex; + flex-direction: row; + font-weight: 600; + } + + &__collectionLabel { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + } +} diff --git a/packages/richtext-lexical/src/field/Diff/converters/relationship/index.tsx b/packages/richtext-lexical/src/field/Diff/converters/relationship/index.tsx new file mode 100644 index 0000000000..28859d3095 --- /dev/null +++ b/packages/richtext-lexical/src/field/Diff/converters/relationship/index.tsx @@ -0,0 +1,79 @@ +import type { FileData, PayloadRequest, TypeWithID } from 'payload' + +import { getTranslation, type I18nClient } from '@payloadcms/translations' + +import './index.scss' + +import type { HTMLConvertersAsync } from '../../../../features/converters/lexicalToHtml/async/types.js' +import type { SerializedRelationshipNode } from '../../../../nodeTypes.js' + +const baseClass = 'lexical-relationship-diff' + +export const RelationshipDiffHTMLConverterAsync: (args: { + i18n: I18nClient + req: PayloadRequest +}) => HTMLConvertersAsync = ({ i18n, req }) => { + return { + relationship: async ({ node, populate, providedCSSString }) => { + let data: (Record & TypeWithID) | undefined = undefined + + // If there's no valid upload data, populate return an empty string + if (typeof node.value !== 'object') { + if (!populate) { + return '' + } + data = await populate({ + id: node.value, + collectionSlug: node.relationTo, + }) + } else { + data = node.value as unknown as FileData & TypeWithID + } + + const relatedCollection = req.payload.collections[node.relationTo]?.config + + const ReactDOMServer = (await import('react-dom/server')).default + + const JSX = ( +
    +
    +
    + {i18n.t('fields:labelRelationship', { + label: relatedCollection?.labels?.singular + ? getTranslation(relatedCollection?.labels?.singular, i18n) + : relatedCollection?.slug, + })} +
    + {data && + relatedCollection?.admin?.useAsTitle && + data[relatedCollection.admin.useAsTitle] ? ( + + + {data[relatedCollection.admin.useAsTitle]} + + + ) : ( + {node.value as string} + )} +
    +
    + ) + + // Render to HTML + const html = ReactDOMServer.renderToString(JSX) + + return html + }, + } +} diff --git a/packages/richtext-lexical/src/field/Diff/converters/unknown/index.scss b/packages/richtext-lexical/src/field/Diff/converters/unknown/index.scss new file mode 100644 index 0000000000..78686af5f6 --- /dev/null +++ b/packages/richtext-lexical/src/field/Diff/converters/unknown/index.scss @@ -0,0 +1,43 @@ +@import '../../../../scss/styles.scss'; +@import '../../colors.scss'; + +@layer payload-default { + .lexical-diff__diff-container { + .lexical-unknown-diff { + @extend %body; + @include shadow-sm; + max-width: fit-content; + display: flex; + align-items: center; + background: var(--theme-input-bg); + border-radius: $style-radius-s; + border: 1px solid var(--theme-elevation-100); + position: relative; + font-family: var(--font-body); + margin-block: base(0.5); + max-height: calc(var(--base) * 4); + padding: base(0.25); + + &__specifier { + font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; + } + + &[data-match-type='create'] { + border-color: var(--diff-create-pill-border); + color: var(--diff-create-parent-color); + } + + &[data-match-type='delete'] { + border-color: var(--diff-delete-pill-border); + color: var(--diff-delete-parent-color); + text-decoration-line: none; + background-color: var(--diff-delete-pill-bg); + + * { + text-decoration-line: none; + color: var(--diff-delete-parent-color); + } + } + } + } +} diff --git a/packages/richtext-lexical/src/field/Diff/converters/unknown/index.tsx b/packages/richtext-lexical/src/field/Diff/converters/unknown/index.tsx new file mode 100644 index 0000000000..f14c11a0df --- /dev/null +++ b/packages/richtext-lexical/src/field/Diff/converters/unknown/index.tsx @@ -0,0 +1,62 @@ +import type { LexicalNode } from 'lexical' +import type { PayloadRequest } from 'payload' + +import { type I18nClient } from '@payloadcms/translations' + +import './index.scss' + +import { createHash } from 'crypto' + +import type { HTMLConvertersAsync } from '../../../../features/converters/lexicalToHtml/async/types.js' +import type { SerializedBlockNode } from '../../../../nodeTypes.js' + +const baseClass = 'lexical-unknown-diff' + +export const UnknownDiffHTMLConverterAsync: (args: { + i18n: I18nClient + req: PayloadRequest +}) => HTMLConvertersAsync = ({ i18n, req }) => { + return { + unknown: async ({ node, providedCSSString }) => { + const ReactDOMServer = (await import('react-dom/server')).default + + // hash fields to ensure they are diffed if they change + const nodeFieldsHash = createHash('sha256') + .update(JSON.stringify(node ?? {})) + .digest('hex') + + let nodeType = node.type + + let nodeTypeSpecifier: null | string = null + + if (node.type === 'block') { + nodeTypeSpecifier = (node as SerializedBlockNode).fields.blockType + nodeType = 'Block' + } else if (node.type === 'inlineBlock') { + nodeTypeSpecifier = (node as SerializedBlockNode).fields.blockType + nodeType = 'InlineBlock' + } + + const JSX = ( +
    + {nodeTypeSpecifier && ( + {nodeTypeSpecifier}  + )} + {nodeType} +
    +
    +
    +
    + ) + + // Render to HTML + const html = ReactDOMServer.renderToString(JSX) + + return html + }, + } +} diff --git a/packages/richtext-lexical/src/field/Diff/converters/upload/index.scss b/packages/richtext-lexical/src/field/Diff/converters/upload/index.scss new file mode 100644 index 0000000000..ad00ca352f --- /dev/null +++ b/packages/richtext-lexical/src/field/Diff/converters/upload/index.scss @@ -0,0 +1,116 @@ +@import '../../../../scss/styles.scss'; +@import '../../colors.scss'; + +@layer payload-default { + .lexical-diff__diff-container { + .lexical-upload-diff { + @extend %body; + @include shadow-sm; + min-width: calc(var(--base) * 10); + max-width: fit-content; + display: flex; + align-items: center; + background-color: var(--theme-input-bg); + border-radius: $style-radius-s; + border: 1px solid var(--theme-elevation-100); + position: relative; + font-family: var(--font-body); + margin-block: base(0.5); + max-height: calc(var(--base) * 3); + padding: base(0.6); + + &[data-match-type='create'] { + border-color: var(--diff-create-pill-border); + color: var(--diff-create-parent-color); + + * { + color: var(--diff-create-parent-color); + } + + .lexical-upload-diff__meta { + color: var(--diff-create-link-color); + * { + color: var(--diff-create-link-color); + } + } + + .lexical-upload-diff__thumbnail { + border-radius: 0px; + border-color: var(--diff-create-pill-border); + background-color: none; + } + } + + &[data-match-type='delete'] { + border-color: var(--diff-delete-pill-border); + text-decoration-line: none; + color: var(--diff-delete-parent-color); + background-color: var(--diff-delete-pill-bg); + + .lexical-upload-diff__meta { + color: var(--diff-delete-link-color); + * { + color: var(--diff-delete-link-color); + } + } + + * { + text-decoration-line: none; + color: var(--diff-delete-parent-color); + } + + .lexical-upload-diff__thumbnail { + border-radius: 0px; + border-color: var(--diff-delete-pill-border); + background-color: none; + } + } + + &__card { + display: flex; + flex-direction: row; + align-items: center; + width: 100%; + } + + &__thumbnail { + width: calc(var(--base) * 3 - base(0.6) * 2); + height: calc(var(--base) * 3 - base(0.6) * 2); + position: relative; + overflow: hidden; + flex-shrink: 0; + border-radius: 0px; + border: 1px solid var(--theme-elevation-100); + + img, + svg { + position: absolute; + object-fit: cover; + width: 100%; + height: 100%; + border-radius: 0px; + } + } + + &__info { + flex-grow: 1; + display: flex; + align-items: flex-start; + flex-direction: column; + padding: calc(var(--base) * 0.25) calc(var(--base) * 0.75); + justify-content: space-between; + font-weight: 400; + + strong { + font-weight: 600; + } + } + + &__meta { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + } +} diff --git a/packages/richtext-lexical/src/field/Diff/converters/upload/index.tsx b/packages/richtext-lexical/src/field/Diff/converters/upload/index.tsx new file mode 100644 index 0000000000..1e660cfbcb --- /dev/null +++ b/packages/richtext-lexical/src/field/Diff/converters/upload/index.tsx @@ -0,0 +1,103 @@ +import type { FileData, PayloadRequest, TypeWithID } from 'payload' + +import { type I18nClient } from '@payloadcms/translations' +import { File } from '@payloadcms/ui/rsc' +import { createHash } from 'crypto' + +import './index.scss' + +import { formatFilesize } from 'payload/shared' +import React from 'react' + +import type { HTMLConvertersAsync } from '../../../../features/converters/lexicalToHtml/async/types.js' +import type { UploadDataImproved } from '../../../../features/upload/server/nodes/UploadNode.js' +import type { SerializedUploadNode } from '../../../../nodeTypes.js' + +const baseClass = 'lexical-upload-diff' + +export const UploadDiffHTMLConverterAsync: (args: { + i18n: I18nClient + req: PayloadRequest +}) => HTMLConvertersAsync = ({ i18n, req }) => { + return { + upload: async ({ node, populate, providedCSSString }) => { + const uploadNode = node as UploadDataImproved + + let uploadDoc: (FileData & TypeWithID) | undefined = undefined + + // If there's no valid upload data, populate return an empty string + if (typeof uploadNode.value !== 'object') { + if (!populate) { + return '' + } + uploadDoc = await populate({ + id: uploadNode.value, + collectionSlug: uploadNode.relationTo, + }) + } else { + uploadDoc = uploadNode.value as unknown as FileData & TypeWithID + } + + if (!uploadDoc) { + return '' + } + + const relatedCollection = req.payload.collections[uploadNode.relationTo]?.config + + const thumbnailSRC: string = + ('thumbnailURL' in uploadDoc && (uploadDoc?.thumbnailURL as string)) || uploadDoc?.url || '' + + const ReactDOMServer = (await import('react-dom/server')).default + + // hash fields to ensure they are diffed if they change + const nodeFieldsHash = createHash('sha256') + .update(JSON.stringify(node.fields ?? {})) + .digest('hex') + + const JSX = ( +
    +
    +
    + {thumbnailSRC?.length ? ( + {uploadDoc?.filename} + ) : ( + + )} +
    +
    + {uploadDoc?.filename} +
    + {formatFilesize(uploadDoc?.filesize)} + {typeof uploadDoc?.width === 'number' && typeof uploadDoc?.height === 'number' && ( + +  -  + {uploadDoc?.width}x{uploadDoc?.height} + + )} + {uploadDoc?.mimeType && ( + +  -  + {uploadDoc?.mimeType} + + )} +
    +
    +
    +
    + ) + + // Render to HTML + const html = ReactDOMServer.renderToString(JSX) + + return html + }, + } +} diff --git a/packages/richtext-lexical/src/field/Diff/htmlDiff/LICENSE.MD b/packages/richtext-lexical/src/field/Diff/htmlDiff/LICENSE.MD new file mode 100644 index 0000000000..0fb9cac94b --- /dev/null +++ b/packages/richtext-lexical/src/field/Diff/htmlDiff/LICENSE.MD @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Arman Tang + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/richtext-lexical/src/field/Diff/htmlDiff/index.scss b/packages/richtext-lexical/src/field/Diff/htmlDiff/index.scss new file mode 100644 index 0000000000..20384b19e7 --- /dev/null +++ b/packages/richtext-lexical/src/field/Diff/htmlDiff/index.scss @@ -0,0 +1,90 @@ +@import '../../../scss/styles.scss'; +@import '../colors.scss'; + +@layer payload-default { + .lexical-diff__diff-container { + font-family: var(--font-serif); + font-size: base(0.8); + letter-spacing: 0.02em; + + // Apply background color to parents that have children with diffs + p, + li, + h1, + h2, + h3, + h4, + h5, + blockquote, + h6 { + &:has([data-match-type='create']) { + background-color: var(--diff-create-parent-bg); + color: var(--diff-create-parent-color); + } + + &:has([data-match-type='delete']) { + background-color: var(--diff-delete-parent-bg); + color: var(--diff-delete-parent-color); + } + } + + li::marker { + color: var(--theme-text); + } + + [data-match-type='delete'] { + color: var(--diff-delete-pill-color); + text-decoration-color: var(--diff-delete-pill-color); + text-decoration-line: line-through; + background-color: var(--diff-delete-pill-bg); + border-radius: 4px; + text-decoration-thickness: 1px; + } + + a[data-match-type='delete'] { + color: var(--diff-delete-link-color); + } + + a[data-match-type='create']:not(img) { + // :not(img) required to increase specificity + color: var(--diff-create-link-color); + } + + [data-match-type='create']:not(img) { + background-color: var(--diff-create-pill-bg); + color: var(--diff-create-pill-color); + border-radius: 4px; + } + + .html-diff { + &-create-inline-wrapper, + &-delete-inline-wrapper { + display: inline-flex; + } + + &-create-block-wrapper, + &-delete-block-wrapper { + display: flex; + } + + &-create-inline-wrapper, + &-delete-inline-wrapper, + &-create-block-wrapper, + &-delete-block-wrapper { + position: relative; + align-items: center; + flex-direction: row; + + &::after { + position: absolute; + top: 0; + left: 0; + display: block; + width: 100%; + height: 100%; + content: ''; + } + } + } + } +} diff --git a/packages/richtext-lexical/src/field/Diff/htmlDiff/index.ts b/packages/richtext-lexical/src/field/Diff/htmlDiff/index.ts new file mode 100644 index 0000000000..a4b1440ddc --- /dev/null +++ b/packages/richtext-lexical/src/field/Diff/htmlDiff/index.ts @@ -0,0 +1,659 @@ +// Taken and modified from https://github.com/Arman19941113/html-diff/blob/master/packages/html-diff/src/index.ts + +interface MatchedBlock { + newEnd: number + newStart: number + oldEnd: number + oldStart: number + size: number +} + +interface Operation { + /** + * Index of entry in tokenized token list + */ + newEnd: number + newStart: number + oldEnd: number + oldStart: number + type: 'create' | 'delete' | 'equal' | 'replace' +} + +type BaseOpType = 'create' | 'delete' + +interface HtmlDiffConfig { + classNames: { + createBlock: string + createInline: string + deleteBlock: string + deleteInline: string + } + greedyBoundary: number + greedyMatch: boolean + minMatchedSize: number +} + +export interface HtmlDiffOptions { + /** + * The classNames for wrapper DOM. + * Use this to configure your own styles without importing the built-in CSS file + */ + classNames?: Partial<{ + createBlock?: string + createInline?: string + deleteBlock?: string + deleteInline?: string + }> + /** + * @defaultValue 1000 + */ + greedyBoundary?: number + /** + * When greedyMatch is enabled, if the length of the sub-tokens exceeds greedyBoundary, + * we will use the matched sub-tokens that are sufficiently good, even if they are not optimal, to enhance performance. + * @defaultValue true + */ + greedyMatch?: boolean + /** + * Determine the minimum threshold for calculating common sub-tokens. + * You may adjust it to a value larger than 2, but not lower, due to the potential inclusion of HTML tags in the count. + * @defaultValue 2 + */ + minMatchedSize?: number +} + +// eslint-disable-next-line regexp/no-super-linear-backtracking, regexp/optimal-quantifier-concatenation +const htmlStartTagReg = /^<(?[^\s/>]+)[^>]*>$/ +// eslint-disable-next-line regexp/no-super-linear-backtracking, regexp/optimal-quantifier-concatenation +const htmlTagWithNameReg = /^<(?\/)?(?[^\s>]+)[^>]*>$/ + +const htmlTagReg = /^<[^>]+>/ +const htmlImgTagReg = /^]*>$/ +const htmlVideoTagReg = /^]*>.*?<\/video>$/ms + +export class HtmlDiff { + private readonly config: HtmlDiffConfig + private leastCommonLength: number = Infinity + private readonly matchedBlockList: MatchedBlock[] = [] + private readonly newTokens: string[] = [] + private readonly oldTokens: string[] = [] + private readonly operationList: Operation[] = [] + private sideBySideContents?: [string, string] + private unifiedContent?: string + + constructor( + oldHtml: string, + newHtml: string, + { + classNames = { + createBlock: 'html-diff-create-block-wrapper', + createInline: 'html-diff-create-inline-wrapper', + deleteBlock: 'html-diff-delete-block-wrapper', + deleteInline: 'html-diff-delete-inline-wrapper', + }, + greedyBoundary = 1000, + greedyMatch = true, + minMatchedSize = 2, + }: HtmlDiffOptions = {}, + ) { + // init config + this.config = { + classNames: { + createBlock: 'html-diff-create-block-wrapper', + createInline: 'html-diff-create-inline-wrapper', + deleteBlock: 'html-diff-delete-block-wrapper', + deleteInline: 'html-diff-delete-inline-wrapper', + ...classNames, + }, + greedyBoundary, + greedyMatch, + minMatchedSize, + } + // white space is junk + oldHtml = oldHtml.trim() + newHtml = newHtml.trim() + + // no need to diff + if (oldHtml === newHtml) { + this.unifiedContent = oldHtml + let equalSequence = 0 + // eslint-disable-next-line regexp/no-super-linear-backtracking, regexp/optimal-quantifier-concatenation + const content = oldHtml.replace(/<([^\s/>]+)[^>]*>/g, (match: string, name: string) => { + const tagNameLength = name.length + 1 + return `${match.slice(0, tagNameLength)} data-seq="${++equalSequence}"${match.slice(tagNameLength)}` + }) + this.sideBySideContents = [content, content] + return + } + + // step1: split HTML to tokens(atomic tokens) + this.oldTokens = this.tokenize(oldHtml) + this.newTokens = this.tokenize(newHtml) + // step2: find matched blocks + this.matchedBlockList = this.getMatchedBlockList() + + // step3: generate operation list + this.operationList = this.getOperationList() + } + + // Find the longest matched block between tokens + private computeBestMatchedBlock( + oldStart: number, + oldEnd: number, + newStart: number, + newEnd: number, + ): MatchedBlock | null { + let bestMatchedBlock = null + for (let i = oldStart; i < oldEnd; i++) { + const len = Math.min(oldEnd - i, newEnd - newStart) + const ret = this.slideBestMatchedBlock(i, newStart, len) + if (ret && (!bestMatchedBlock || ret.size > bestMatchedBlock.size)) { + bestMatchedBlock = ret + if (ret.size > this.leastCommonLength) { + return bestMatchedBlock + } + } + } + for (let j = newStart; j < newEnd; j++) { + const len = Math.min(oldEnd - oldStart, newEnd - j) + const ret = this.slideBestMatchedBlock(oldStart, j, len) + if (ret && (!bestMatchedBlock || ret.size > bestMatchedBlock.size)) { + bestMatchedBlock = ret + if (ret.size > this.leastCommonLength) { + return bestMatchedBlock + } + } + } + return bestMatchedBlock + } + + private computeMatchedBlockList( + oldStart: number, + oldEnd: number, + newStart: number, + newEnd: number, + matchedBlockList: MatchedBlock[] = [], + ): MatchedBlock[] { + const matchBlock = this.computeBestMatchedBlock(oldStart, oldEnd, newStart, newEnd) + + if (!matchBlock) { + return [] + } + + if (oldStart < matchBlock.oldStart && newStart < matchBlock.newStart) { + this.computeMatchedBlockList( + oldStart, + matchBlock.oldStart, + newStart, + matchBlock.newStart, + matchedBlockList, + ) + } + matchedBlockList.push(matchBlock) + if (oldEnd > matchBlock.oldEnd && newEnd > matchBlock.newEnd) { + this.computeMatchedBlockList( + matchBlock.oldEnd, + oldEnd, + matchBlock.newEnd, + newEnd, + matchedBlockList, + ) + } + return matchedBlockList + } + + private dressUpBlockTag(type: BaseOpType, token: string): string { + if (type === 'create') { + return `
    ${token}
    ` + } + if (type === 'delete') { + return `
    ${token}
    ` + } + return '' + } + + private dressUpDiffContent(type: BaseOpType, tokens: string[]): string { + const tokensLength = tokens.length + if (!tokensLength) { + return '' + } + + let result = '' + let textStartIndex = 0 + let i = -1 + for (const token of tokens) { + i++ + + // If this is true, this HTML should be diffed as well - not just its children + const isMatchElement = token.includes('data-enable-match="true"') + const isMatchExplicitlyDisabled = token.includes('data-enable-match="false"') + const isHtmlTag = !!token.match(htmlTagReg)?.length + + if (isMatchExplicitlyDisabled) { + textStartIndex = i + 1 + result += token + } + // this token is html tag + else if (!isMatchElement && isHtmlTag) { + // handle text tokens before + if (i > textStartIndex) { + result += this.dressUpText(type, tokens.slice(textStartIndex, i)) + } + // handle this tag + textStartIndex = i + 1 + if (token.match(htmlVideoTagReg)) { + result += this.dressUpBlockTag(type, token) + } /* else if ([htmlImgTagReg].some((item) => token.match(item))) { + result += this.dressUpInlineTag(type, token) + }*/ else { + result += token + } + } else if (isMatchElement && isHtmlTag) { + // handle text tokens before + if (i > textStartIndex) { + result += this.dressUpText(type, tokens.slice(textStartIndex, i)) + } + + // handle this tag + textStartIndex = i + 1 + // Add data-match-type to the tag that can be styled + const newToken = this.dressupMatchEnabledHtmlTag(type, token) + + result += newToken + } + } + if (textStartIndex < tokensLength) { + result += this.dressUpText(type, tokens.slice(textStartIndex)) + } + return result + } + + private dressUpInlineTag(type: BaseOpType, token: string): string { + if (type === 'create') { + return `${token}` + } + if (type === 'delete') { + return `${token}` + } + return '' + } + + private dressupMatchEnabledHtmlTag(type: BaseOpType, token: string): string { + // token is a single html tag, e.g. + // add data-match-type to the tag + const tagName = token.match(htmlStartTagReg)?.groups?.name + if (!tagName) { + return token + } + const tagNameLength = tagName.length + 1 + const matchType = type === 'create' ? 'create' : 'delete' + return `${token.slice(0, tagNameLength)} data-match-type="${matchType}"${token.slice( + tagNameLength, + token.length, + )}` + } + + private dressUpText(type: BaseOpType, tokens: string[]): string { + const text = tokens.join('') + if (!text.trim()) { + return '' + } + if (type === 'create') { + return `${text}` + } + if (type === 'delete') { + return `${text}` + } + return '' + } + + /** + * Generates a list of token entries that are matched between the old and new HTML. This list will not + * include token ranges that differ. + */ + private getMatchedBlockList(): MatchedBlock[] { + const n1 = this.oldTokens.length + const n2 = this.newTokens.length + + // 1. sync from start + let start: MatchedBlock | null = null + let i = 0 + while (i < n1 && i < n2 && this.oldTokens[i] === this.newTokens[i]) { + i++ + } + if (i >= this.config.minMatchedSize) { + start = { + newEnd: i, + newStart: 0, + oldEnd: i, + oldStart: 0, + size: i, + } + } + + // 2. sync from end + let end: MatchedBlock | null = null + let e1 = n1 - 1 + let e2 = n2 - 1 + while (i <= e1 && i <= e2 && this.oldTokens[e1] === this.newTokens[e2]) { + e1-- + e2-- + } + const size = n1 - 1 - e1 + if (size >= this.config.minMatchedSize) { + end = { + newEnd: n2, + newStart: e2 + 1, + oldEnd: n1, + oldStart: e1 + 1, + size, + } + } + + // 3. handle rest + const oldStart = start ? i : 0 + const oldEnd = end ? e1 + 1 : n1 + const newStart = start ? i : 0 + const newEnd = end ? e2 + 1 : n2 + // optimize for large tokens + if (this.config.greedyMatch) { + const commonLength = Math.min(oldEnd - oldStart, newEnd - newStart) + if (commonLength > this.config.greedyBoundary) { + this.leastCommonLength = Math.floor(commonLength / 3) + } + } + const ret = this.computeMatchedBlockList(oldStart, oldEnd, newStart, newEnd) + if (start) { + ret.unshift(start) + } + if (end) { + ret.push(end) + } + + return ret + } + + // Generate operation list by matchedBlockList + private getOperationList(): Operation[] { + const operationList: Operation[] = [] + let walkIndexOld = 0 + let walkIndexNew = 0 + for (const matchedBlock of this.matchedBlockList) { + const isOldStartIndexMatched = walkIndexOld === matchedBlock.oldStart + const isNewStartIndexMatched = walkIndexNew === matchedBlock.newStart + const operationBase = { + newEnd: matchedBlock.newStart, + newStart: walkIndexNew, + oldEnd: matchedBlock.oldStart, + oldStart: walkIndexOld, + } + if (!isOldStartIndexMatched && !isNewStartIndexMatched) { + operationList.push(Object.assign(operationBase, { type: 'replace' as const })) + } else if (isOldStartIndexMatched && !isNewStartIndexMatched) { + operationList.push(Object.assign(operationBase, { type: 'create' as const })) + } else if (!isOldStartIndexMatched && isNewStartIndexMatched) { + operationList.push(Object.assign(operationBase, { type: 'delete' as const })) + } + + operationList.push({ + type: 'equal', + newEnd: matchedBlock.newEnd, + newStart: matchedBlock.newStart, + oldEnd: matchedBlock.oldEnd, + oldStart: matchedBlock.oldStart, + }) + walkIndexOld = matchedBlock.oldEnd + walkIndexNew = matchedBlock.newEnd + } + // handle the tail content + const maxIndexOld = this.oldTokens.length + const maxIndexNew = this.newTokens.length + const tailOperationBase = { + newEnd: maxIndexNew, + newStart: walkIndexNew, + oldEnd: maxIndexOld, + oldStart: walkIndexOld, + } + const isOldFinished = walkIndexOld === maxIndexOld + const isNewFinished = walkIndexNew === maxIndexNew + if (!isOldFinished && !isNewFinished) { + operationList.push(Object.assign(tailOperationBase, { type: 'replace' as const })) + } else if (isOldFinished && !isNewFinished) { + operationList.push(Object.assign(tailOperationBase, { type: 'create' as const })) + } else if (!isOldFinished && isNewFinished) { + operationList.push(Object.assign(tailOperationBase, { type: 'delete' as const })) + } + return operationList + } + + private slideBestMatchedBlock(addA: number, addB: number, len: number): MatchedBlock | null { + let maxSize = 0 + let bestMatchedBlock: MatchedBlock | null = null + + let continuousSize = 0 + for (let i = 0; i < len; i++) { + if (this.oldTokens[addA + i] === this.newTokens[addB + i]) { + continuousSize++ + } else { + continuousSize = 0 + } + if (continuousSize > maxSize) { + maxSize = continuousSize + bestMatchedBlock = { + newEnd: addB + i + 1, + newStart: addB + i - continuousSize + 1, + oldEnd: addA + i + 1, + oldStart: addA + i - continuousSize + 1, + size: continuousSize, + } + } + } + + return maxSize >= this.config.minMatchedSize ? bestMatchedBlock : null + } + + /** + * convert HTML to tokens + * @example + * tokenize(" Hello World ") + * [""," ", "Hello", " ", "World", " ", ""] + */ + private tokenize(html: string): string[] { + // atomic token: html tag、continuous numbers or letters、blank spaces、other symbol + return ( + html.match( + /]*>.*?<\/picture>|]*>.*?<\/video>|<[^>]+>|\w+\b|\s+|[^<>\w]/gs, + ) || [] + ) + } + + public getSideBySideContents(): string[] { + if (this.sideBySideContents !== undefined) { + return this.sideBySideContents + } + + let oldHtml = '' + let newHtml = '' + let equalSequence = 0 + this.operationList.forEach((operation) => { + switch (operation.type) { + case 'create': { + newHtml += this.dressUpDiffContent( + 'create', + this.newTokens.slice(operation.newStart, operation.newEnd), + ) + break + } + + case 'delete': { + const deletedTokens = this.oldTokens.slice(operation.oldStart, operation.oldEnd) + oldHtml += this.dressUpDiffContent('delete', deletedTokens) + break + } + case 'equal': { + const equalTokens = this.newTokens.slice(operation.newStart, operation.newEnd) + let equalString = '' + for (const token of equalTokens) { + // find start tags and add data-seq to enable sync scroll + const startTagMatch = token.match(htmlStartTagReg) + if (startTagMatch) { + equalSequence += 1 + const tagNameLength = (startTagMatch?.groups?.name?.length ?? 0) + 1 + equalString += `${token.slice(0, tagNameLength)} data-seq="${equalSequence}"${token.slice(tagNameLength)}` + } else { + equalString += token + } + } + oldHtml += equalString + newHtml += equalString + break + } + + case 'replace': { + oldHtml += this.dressUpDiffContent( + 'delete', + this.oldTokens.slice(operation.oldStart, operation.oldEnd), + ) + newHtml += this.dressUpDiffContent( + 'create', + this.newTokens.slice(operation.newStart, operation.newEnd), + ) + break + } + + default: { + console.error('Richtext diff error - invalid operation: ' + String(operation.type)) + } + } + }) + + const result: [string, string] = [oldHtml, newHtml] + this.sideBySideContents = result + return result + } + + public getUnifiedContent(): string { + if (this.unifiedContent !== undefined) { + return this.unifiedContent + } + + let result = '' + this.operationList.forEach((operation) => { + switch (operation.type) { + case 'create': { + result += this.dressUpDiffContent( + 'create', + this.newTokens.slice(operation.newStart, operation.newEnd), + ) + break + } + + case 'delete': { + result += this.dressUpDiffContent( + 'delete', + this.oldTokens.slice(operation.oldStart, operation.oldEnd), + ) + break + } + + case 'equal': { + for (const token of this.newTokens.slice(operation.newStart, operation.newEnd)) { + result += token + } + break + } + + case 'replace': { + // handle specially tag replace + const olds = this.oldTokens.slice(operation.oldStart, operation.oldEnd) + const news = this.newTokens.slice(operation.newStart, operation.newEnd) + if ( + olds.length === 1 && + news.length === 1 && + olds[0]?.match(htmlTagReg) && + news[0]?.match(htmlTagReg) + ) { + result += news[0] + break + } + + const deletedTokens: string[] = [] + const createdTokens: string[] = [] + let createIndex = operation.newStart + for ( + let deleteIndex = operation.oldStart; + deleteIndex < operation.oldEnd; + deleteIndex++ + ) { + const deletedToken = this.oldTokens[deleteIndex] + + if (!deletedToken) { + continue + } + + const matchTagResultD = deletedToken?.match(htmlTagWithNameReg) + if (matchTagResultD) { + // handle replaced tag token + + // skip special tag + if ([htmlImgTagReg, htmlVideoTagReg].some((item) => deletedToken?.match(item))) { + deletedTokens.push(deletedToken) + continue + } + + // handle normal tag + result += this.dressUpDiffContent('delete', deletedTokens) + deletedTokens.splice(0) + let isTagInNewFind = false + for ( + let tempCreateIndex = createIndex; + tempCreateIndex < operation.newEnd; + tempCreateIndex++ + ) { + const createdToken = this.newTokens[tempCreateIndex] + if (!createdToken) { + continue + } + const matchTagResultC = createdToken?.match(htmlTagWithNameReg) + if ( + matchTagResultC && + matchTagResultC.groups?.name === matchTagResultD.groups?.name && + matchTagResultC.groups?.isEnd === matchTagResultD.groups?.isEnd + ) { + // find first matched tag, but not maybe the expected tag(to optimize) + isTagInNewFind = true + result += this.dressUpDiffContent('create', createdTokens) + result += createdToken + createdTokens.splice(0) + createIndex = tempCreateIndex + 1 + break + } else { + createdTokens.push(createdToken) + } + } + if (!isTagInNewFind) { + result += deletedToken + createdTokens.splice(0) + } + } else { + // token is not a tag + deletedTokens.push(deletedToken) + } + } + if (createIndex < operation.newEnd) { + createdTokens.push(...this.newTokens.slice(createIndex, operation.newEnd)) + } + result += this.dressUpDiffContent('delete', deletedTokens) + result += this.dressUpDiffContent('create', createdTokens) + break + } + + default: { + console.error('Richtext diff error - invalid operation: ' + String(operation.type)) + } + } + }) + this.unifiedContent = result + return result + } +} diff --git a/packages/richtext-lexical/src/field/Diff/index.scss b/packages/richtext-lexical/src/field/Diff/index.scss new file mode 100644 index 0000000000..e6712e9f67 --- /dev/null +++ b/packages/richtext-lexical/src/field/Diff/index.scss @@ -0,0 +1,95 @@ +@import '../../scss/styles.scss'; +@import './colors.scss'; + +@layer payload-default { + .lexical-diff { + &__diff-container { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 20px; + } + + blockquote { + font-size: base(0.8); + margin-block: base(0.8); + margin-inline: base(0.2); + border-inline-start-color: var(--theme-elevation-150); + border-inline-start-width: base(0.2); + border-inline-start-style: solid; + padding-inline-start: base(0.6); + padding-block: base(0.2); + + &:has([data-match-type='create']) { + border-inline-start-color: var(--theme-success-150); + } + + &:has([data-match-type='delete']) { + border-inline-start-color: var(--theme-error-150); + } + } + + a { + border-bottom: 1px dotted; + text-decoration: none; + } + + h1 { + padding: base(0.7) 0px base(0.55); + line-height: base(1.2); + font-weight: 600; + font-size: base(1.4); + font-family: var(--font-body); + } + h2 { + padding: base(0.7) 0px base(0.5); + line-height: base(1); + font-weight: 600; + font-size: base(1.25); + font-family: var(--font-body); + } + h3 { + padding: base(0.65) 0px base(0.45); + line-height: base(0.9); + font-weight: 600; + font-size: base(1.1); + font-family: var(--font-body); + } + h4 { + padding: base(0.65) 0px base(0.4); + line-height: base(0.7); + font-weight: 600; + font-size: base(1); + font-family: var(--font-body); + } + h5 { + padding: base(0.65) 0px base(0.35); + line-height: base(0.5); + font-weight: 600; + font-size: base(0.9); + font-family: var(--font-body); + } + + h6 { + padding: base(0.65) 0px base(0.35); + line-height: base(0.5); + font-weight: 600; + font-size: base(0.8); + font-family: var(--font-body); + } + + p { + padding: base(0.4) 0 base(0.4); + + // First paraagraph has no top padding + &:first-child { + padding: 0 0 base(0.4); + } + } + + ul, + ol { + padding-top: base(0.4); + padding-bottom: base(0.4); + } + } +} diff --git a/packages/richtext-lexical/src/field/Diff/index.tsx b/packages/richtext-lexical/src/field/Diff/index.tsx new file mode 100644 index 0000000000..3306d51f54 --- /dev/null +++ b/packages/richtext-lexical/src/field/Diff/index.tsx @@ -0,0 +1,74 @@ +import type { SerializedEditorState } from 'lexical' +import type { RichTextFieldDiffServerComponent } from 'payload' + +import { getTranslation } from '@payloadcms/translations' +import { FieldDiffLabel } from '@payloadcms/ui/rsc' +import React from 'react' + +import './htmlDiff/index.scss' +import './index.scss' + +import type { HTMLConvertersFunctionAsync } from '../../features/converters/lexicalToHtml/async/types.js' + +import { convertLexicalToHTMLAsync } from '../../features/converters/lexicalToHtml/async/index.js' +import { getPayloadPopulateFn } from '../../features/converters/utilities/payloadPopulateFn.js' +import { LinkDiffHTMLConverterAsync } from './converters/link.js' +import { ListItemDiffHTMLConverterAsync } from './converters/listitem/index.js' +import { RelationshipDiffHTMLConverterAsync } from './converters/relationship/index.js' +import { UnknownDiffHTMLConverterAsync } from './converters/unknown/index.js' +import { UploadDiffHTMLConverterAsync } from './converters/upload/index.js' +import { HtmlDiff } from './htmlDiff/index.js' +const baseClass = 'lexical-diff' + +export const LexicalDiffComponent: RichTextFieldDiffServerComponent = async (args) => { + const { comparisonValue, field, i18n, locale, versionValue } = args + + const converters: HTMLConvertersFunctionAsync = ({ defaultConverters }) => ({ + ...defaultConverters, + ...LinkDiffHTMLConverterAsync({}), + ...ListItemDiffHTMLConverterAsync, + ...UploadDiffHTMLConverterAsync({ i18n: args.i18n, req: args.req }), + ...RelationshipDiffHTMLConverterAsync({ i18n: args.i18n, req: args.req }), + ...UnknownDiffHTMLConverterAsync({ i18n: args.i18n, req: args.req }), + }) + + const payloadPopulateFn = await getPayloadPopulateFn({ + currentDepth: 0, + depth: 1, + req: args.req, + }) + const comparisonHTML = await convertLexicalToHTMLAsync({ + converters, + data: comparisonValue as SerializedEditorState, + populate: payloadPopulateFn, + }) + + const versionHTML = await convertLexicalToHTMLAsync({ + converters, + data: versionValue as SerializedEditorState, + populate: payloadPopulateFn, + }) + + const diffHTML = new HtmlDiff(comparisonHTML, versionHTML) + + const [oldHTML, newHTML] = diffHTML.getSideBySideContents() + + return ( +
    + + {locale && {locale}} + {'label' in field && + typeof field.label !== 'function' && + getTranslation(field.label || '', i18n)} + +
    + {oldHTML && ( +
    + )} + {newHTML && ( +
    + )} +
    +
    + ) +} diff --git a/packages/richtext-lexical/src/index.ts b/packages/richtext-lexical/src/index.ts index cffe78f7db..d1cc2a8a90 100644 --- a/packages/richtext-lexical/src/index.ts +++ b/packages/richtext-lexical/src/index.ts @@ -101,6 +101,13 @@ export function lexicalEditor(args?: LexicalEditorProps): LexicalRichTextAdapter sanitizedEditorConfig: finalSanitizedEditorConfig, }, }, + DiffComponent: { + path: '@payloadcms/richtext-lexical/rsc#LexicalDiffComponent', + serverProps: { + admin: args?.admin, + sanitizedEditorConfig: finalSanitizedEditorConfig, + }, + }, editorConfig: finalSanitizedEditorConfig, features, FieldComponent: { diff --git a/packages/richtext-lexical/src/utilities/generateImportMap.tsx b/packages/richtext-lexical/src/utilities/generateImportMap.tsx index 6f0389ac8d..518468cc76 100644 --- a/packages/richtext-lexical/src/utilities/generateImportMap.tsx +++ b/packages/richtext-lexical/src/utilities/generateImportMap.tsx @@ -10,6 +10,7 @@ export const getGenerateImportMap = ({ addToImportMap, baseDir, config, importMap, imports }) => { addToImportMap('@payloadcms/richtext-lexical/rsc#RscEntryLexicalCell') addToImportMap('@payloadcms/richtext-lexical/rsc#RscEntryLexicalField') + addToImportMap('@payloadcms/richtext-lexical/rsc#LexicalDiffComponent') // iterate just through args.resolvedFeatureMap.values() for (const resolvedFeature of args.resolvedFeatureMap.values()) { diff --git a/packages/next/src/views/Version/RenderFieldsToDiff/Label/index.scss b/packages/ui/src/elements/FieldDiffLabel/index.scss similarity index 100% rename from packages/next/src/views/Version/RenderFieldsToDiff/Label/index.scss rename to packages/ui/src/elements/FieldDiffLabel/index.scss diff --git a/packages/next/src/views/Version/RenderFieldsToDiff/Label/index.tsx b/packages/ui/src/elements/FieldDiffLabel/index.tsx similarity index 58% rename from packages/next/src/views/Version/RenderFieldsToDiff/Label/index.tsx rename to packages/ui/src/elements/FieldDiffLabel/index.tsx index 060a8fc06b..6edca55d83 100644 --- a/packages/next/src/views/Version/RenderFieldsToDiff/Label/index.tsx +++ b/packages/ui/src/elements/FieldDiffLabel/index.tsx @@ -4,8 +4,6 @@ import './index.scss' const baseClass = 'field-diff-label' -const Label: React.FC<{ children?: React.ReactNode }> = ({ children }) => ( +export const FieldDiffLabel: React.FC<{ children?: React.ReactNode }> = ({ children }) => (
    {children}
    ) - -export default Label diff --git a/packages/ui/src/exports/client/index.ts b/packages/ui/src/exports/client/index.ts index c36770f883..d9c95c30a3 100644 --- a/packages/ui/src/exports/client/index.ts +++ b/packages/ui/src/exports/client/index.ts @@ -367,3 +367,4 @@ export { SetDocumentStepNav } from '../../views/Edit/SetDocumentStepNav/index.js export { SetDocumentTitle } from '../../views/Edit/SetDocumentTitle/index.js' export { parseSearchParams } from '../../utilities/parseSearchParams.js' +export { FieldDiffLabel } from '../../elements/FieldDiffLabel/index.js' diff --git a/packages/ui/src/exports/rsc/index.ts b/packages/ui/src/exports/rsc/index.ts index 2f80ab6782..3e73c50cdd 100644 --- a/packages/ui/src/exports/rsc/index.ts +++ b/packages/ui/src/exports/rsc/index.ts @@ -1,3 +1,6 @@ +export { FieldDiffLabel } from '../../elements/FieldDiffLabel/index.js' +export { File } from '../../graphics/File/index.js' +export { CheckIcon } from '../../icons/Check/index.js' export { copyDataFromLocaleHandler } from '../../utilities/copyDataFromLocale.js' export { renderFilters, renderTable } from '../../utilities/renderTable.js' export { resolveFilterOptions } from '../../utilities/resolveFilterOptions.js' diff --git a/test/versions/collections/Diff/generateLexicalData.ts b/test/versions/collections/Diff/generateLexicalData.ts new file mode 100644 index 0000000000..3d145e55b7 --- /dev/null +++ b/test/versions/collections/Diff/generateLexicalData.ts @@ -0,0 +1,628 @@ +import type { DefaultTypedEditorState, SerializedBlockNode } from '@payloadcms/richtext-lexical' + +import { mediaCollectionSlug, textCollectionSlug } from '../../slugs.js' + +export function generateLexicalData(args: { + mediaID: number | string + textID: number | string + updated: boolean +}): DefaultTypedEditorState { + return { + root: { + children: [ + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: `Fugiat esse${args.updated ? ' new ' : ''}in dolor aleiqua ${args.updated ? 'gillum' : 'cillum'} proident ad cillum excepteur mollit reprehenderit mollit commodo. Pariatur incididunt non exercitation est mollit nisi labore${args.updated ? ' ' : 'delete'}officia cupidatat amet commodo commodo proident occaecat.`, + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'paragraph', + version: 1, + textFormat: 0, + textStyle: '', + }, + { + children: [ + { + detail: 0, + format: args.updated ? 1 : 0, + mode: 'normal', + style: '', + text: 'Some ', + type: 'text', + version: 1, + }, + { + detail: 0, + format: args.updated ? 0 : 1, + mode: 'normal', + style: '', + text: 'Bold', + type: 'text', + version: 1, + }, + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: ' and ', + type: 'text', + version: 1, + }, + { + detail: 0, + format: 1, + mode: 'normal', + style: '', + text: 'Italic', + type: 'text', + version: 1, + }, + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: ' text with ', + type: 'text', + version: 1, + }, + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: 'a link', + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'link', + version: 3, + fields: { + url: args.updated ? 'https://www.payloadcms.com' : 'https://www.google.com', + newTab: true, + linkType: 'custom', + }, + id: '67d869aa706b36f346ecffd9', + }, + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: ' and ', + type: 'text', + version: 1, + }, + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: 'another link', + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'link', + version: 3, + fields: { + url: 'https://www.payload.ai', + newTab: args.updated ? true : false, + linkType: 'custom', + }, + id: '67d869aa706b36f346ecffd0', + }, + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: ' text ', + type: 'text', + version: 1, + }, + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: args.updated ? 'third link updated' : 'third link', + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'link', + version: 3, + fields: { + url: 'https://www.payloadcms.com/docs', + newTab: true, + linkType: 'custom', + }, + id: '67d869aa706b36f346ecffd0', + }, + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: '.', + type: 'text', + version: 1, + }, + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: 'link with description', + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'link', + version: 3, + fields: { + url: 'https://www.payloadcms.com/docs', + description: args.updated ? 'updated description' : 'description', + newTab: true, + linkType: 'custom', + }, + id: '67d869aa706b36f346ecffd0', + }, + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: 'text', + type: 'text', + version: 1, + }, + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: 'identical link', + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'link', + version: 3, + fields: { + url: 'https://www.payloadcms.com/docs2', + description: 'description', + newTab: true, + linkType: 'custom', + }, + id: '67d869aa706b36f346ecffd0', + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'paragraph', + version: 1, + textFormat: 0, + textStyle: '', + }, + { + children: [ + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: 'One', + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'listitem', + version: 1, + value: 1, + }, + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: args.updated ? 'Two updated' : 'Two', + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'listitem', + version: 1, + value: 2, + }, + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: 'Three', + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'listitem', + version: 1, + value: 3, + }, + ...(args.updated + ? [ + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: 'Four', + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'listitem', + version: 1, + value: 4, + }, + ] + : []), + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'list', + version: 1, + listType: 'number', + start: 1, + tag: 'ol', + }, + { + children: [ + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: 'One', + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'listitem', + version: 1, + value: 1, + }, + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: 'Two', + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'listitem', + version: 1, + value: 2, + }, + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: args.updated ? 'Three' : 'Three original', + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'listitem', + version: 1, + value: 3, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'list', + version: 1, + listType: 'bullet', + start: 1, + tag: 'ul', + }, + { + children: [ + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: 'Checked', + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'listitem', + version: 1, + checked: true, + value: 1, + }, + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: 'Unchecked', + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'listitem', + version: 1, + checked: args.updated ? false : true, + value: 2, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'list', + version: 1, + listType: 'check', + start: 1, + tag: 'ul', + }, + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: `Heading1${args.updated ? ' updated' : ''}`, + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'heading', + version: 1, + tag: 'h1', + }, + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: `Heading2${args.updated ? ' updated' : ''}`, + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'heading', + version: 1, + tag: 'h2', + }, + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: `Heading3${args.updated ? ' updated' : ''}`, + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'heading', + version: 1, + tag: 'h3', + }, + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: `Heading4${args.updated ? ' updated' : ''}`, + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'heading', + version: 1, + tag: 'h4', + }, + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: `Heading5${args.updated ? ' updated' : ''}`, + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'heading', + version: 1, + tag: 'h5', + }, + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: `Heading6${args.updated ? ' updated' : ''}`, + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'heading', + version: 1, + tag: 'h6', + }, + { + type: 'upload', + version: 3, + format: '', + id: '67d8693c76b36f346ecffd8', + relationTo: mediaCollectionSlug, + value: args.mediaID, + }, + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: `Quote${args.updated ? ' updated' : ''}`, + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'quote', + version: 1, + }, + { + type: 'relationship', + version: 2, + format: '', + relationTo: textCollectionSlug, + value: args.textID, + }, + { + type: 'block', + version: 2, + format: '', + fields: { + id: '67d8693c706b36f346ecffd7', + radios: args.updated ? 'option1' : 'option3', + someText: `Text1${args.updated ? ' updated' : ''}`, + blockName: '', + someTextRequired: 'Text2', + blockType: 'myBlock', + }, + } as SerializedBlockNode, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'root', + version: 1, + }, + } +} diff --git a/test/versions/collections/Diff.ts b/test/versions/collections/Diff/index.ts similarity index 98% rename from test/versions/collections/Diff.ts rename to test/versions/collections/Diff/index.ts index 727758c99b..ffbcc0615f 100644 --- a/test/versions/collections/Diff.ts +++ b/test/versions/collections/Diff/index.ts @@ -1,6 +1,6 @@ import type { CollectionConfig } from 'payload' -import { diffCollectionSlug, draftCollectionSlug } from '../slugs.js' +import { diffCollectionSlug, draftCollectionSlug } from '../../slugs.js' export const Diff: CollectionConfig = { slug: diffCollectionSlug, diff --git a/test/versions/collections/Text.ts b/test/versions/collections/Text.ts new file mode 100644 index 0000000000..4033a1b0e5 --- /dev/null +++ b/test/versions/collections/Text.ts @@ -0,0 +1,17 @@ +import type { CollectionConfig } from 'payload' + +import { textCollectionSlug } from '../slugs.js' + +export const TextCollection: CollectionConfig = { + slug: textCollectionSlug, + admin: { + useAsTitle: 'text', + }, + fields: [ + { + name: 'text', + type: 'text', + required: true, + }, + ], +} diff --git a/test/versions/config.ts b/test/versions/config.ts index a60b7d13d9..1b23833611 100644 --- a/test/versions/config.ts +++ b/test/versions/config.ts @@ -6,7 +6,7 @@ import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' import AutosavePosts from './collections/Autosave.js' import AutosaveWithValidate from './collections/AutosaveWithValidate.js' import CustomIDs from './collections/CustomIDs.js' -import { Diff } from './collections/Diff.js' +import { Diff } from './collections/Diff/index.js' import DisablePublish from './collections/DisablePublish.js' import DraftPosts from './collections/Drafts.js' import DraftWithMax from './collections/DraftsWithMax.js' @@ -14,6 +14,7 @@ import DraftsWithValidate from './collections/DraftsWithValidate.js' import LocalizedPosts from './collections/Localized.js' import { Media } from './collections/Media.js' import Posts from './collections/Posts.js' +import { TextCollection } from './collections/Text.js' import VersionPosts from './collections/Versions.js' import AutosaveGlobal from './globals/Autosave.js' import DisablePublishGlobal from './globals/DisablePublish.js' @@ -42,6 +43,7 @@ export default buildConfigWithDefaults({ VersionPosts, CustomIDs, Diff, + TextCollection, Media, ], globals: [AutosaveGlobal, DraftGlobal, DraftWithMaxGlobal, DisablePublishGlobal, LocalizedGlobal], diff --git a/test/versions/e2e.spec.ts b/test/versions/e2e.spec.ts index 03f56fd57c..ce20a3d124 100644 --- a/test/versions/e2e.spec.ts +++ b/test/versions/e2e.spec.ts @@ -1384,12 +1384,17 @@ describe('Versions', () => { const richtext = page.locator('[data-field-path="richtext"]') - await expect(richtext.locator('tr').nth(16).locator('td').nth(1)).toHaveText( - '"text": "richtext",', - ) - await expect(richtext.locator('tr').nth(16).locator('td').nth(3)).toHaveText( - '"text": "richtext2",', - ) + const oldDiff = richtext.locator('.lexical-diff__diff-old') + const newDiff = richtext.locator('.lexical-diff__diff-new') + + const oldHTML = + `Fugiat essein dolor aleiqua cillum proident ad cillum excepteur mollit reprehenderit mollit commodo. Pariatur incididunt non exercitation est mollit nisi laboredeleteofficia cupidatat amet commodo commodo proident occaecat. + `.trim() + const newHTML = + `Fugiat esse new in dolor aleiqua gillum proident ad cillum excepteur mollit reprehenderit mollit commodo. Pariatur incididunt non exercitation est mollit nisi labore officia cupidatat amet commodo commodo proident occaecat.`.trim() + + expect(await oldDiff.locator('p').first().innerHTML()).toEqual(oldHTML) + expect(await newDiff.locator('p').first().innerHTML()).toEqual(newHTML) }) test('correctly renders diff for richtext fields with custom Diff component', async () => { diff --git a/test/versions/payload-types.ts b/test/versions/payload-types.ts index 95ec5870e9..6e5e4fc8c6 100644 --- a/test/versions/payload-types.ts +++ b/test/versions/payload-types.ts @@ -78,6 +78,7 @@ export interface Config { 'version-posts': VersionPost; 'custom-ids': CustomId; diff: Diff; + text: Text; media: Media; users: User; 'payload-jobs': PayloadJob; @@ -98,6 +99,7 @@ export interface Config { 'version-posts': VersionPostsSelect | VersionPostsSelect; 'custom-ids': CustomIdsSelect | CustomIdsSelect; diff: DiffSelect | DiffSelect; + text: TextSelect | TextSelect; media: MediaSelect | MediaSelect; users: UsersSelect | UsersSelect; 'payload-jobs': PayloadJobsSelect | PayloadJobsSelect; @@ -414,6 +416,16 @@ export interface Media { focalX?: number | null; focalY?: number | null; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "text". + */ +export interface Text { + id: string; + text: string; + updatedAt: string; + createdAt: string; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users". @@ -574,6 +586,10 @@ export interface PayloadLockedDocument { relationTo: 'diff'; value: string | Diff; } | null) + | ({ + relationTo: 'text'; + value: string | Text; + } | null) | ({ relationTo: 'media'; value: string | Media; @@ -842,6 +858,15 @@ export interface DiffSelect { updatedAt?: T; createdAt?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "text_select". + */ +export interface TextSelect { + text?: T; + updatedAt?: T; + createdAt?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "media_select". diff --git a/test/versions/seed.ts b/test/versions/seed.ts index 6785d26ca1..d72549545d 100644 --- a/test/versions/seed.ts +++ b/test/versions/seed.ts @@ -6,6 +6,7 @@ import type { DraftPost } from './payload-types.js' import { devUser } from '../credentials.js' import { executePromises } from '../helpers/executePromises.js' +import { generateLexicalData } from './collections/Diff/generateLexicalData.js' import { autosaveWithValidateCollectionSlug, diffCollectionSlug, @@ -119,6 +120,20 @@ export async function seed(_payload: Payload, parallel: boolean = false) { }, }) + const { id: doc1ID } = await _payload.create({ + collection: 'text', + data: { + text: 'Document 1', + }, + }) + + const { id: doc2ID } = await _payload.create({ + collection: 'text', + data: { + text: 'Document 2', + }, + }) + const diffDoc = await _payload.create({ collection: diffCollectionSlug, locale: 'en', @@ -165,7 +180,11 @@ export async function seed(_payload: Payload, parallel: boolean = false) { point: [1, 2], radio: 'option1', relationship: manyDraftsID, - richtext: textToLexicalJSON({ text: 'richtext' }), + richtext: generateLexicalData({ + mediaID: uploadedImage, + textID: doc1ID, + updated: false, + }) as any, richtextWithCustomDiff: textToLexicalJSON({ text: 'richtextWithCustomDiff' }), select: 'option1', text: 'text', @@ -225,7 +244,11 @@ export async function seed(_payload: Payload, parallel: boolean = false) { point: [1, 3], radio: 'option2', relationship: draft2.id, - richtext: textToLexicalJSON({ text: 'richtext2' }), + richtext: generateLexicalData({ + mediaID: uploadedImage2, + textID: doc2ID, + updated: true, + }) as any, richtextWithCustomDiff: textToLexicalJSON({ text: 'richtextWithCustomDiff2' }), select: 'option2', text: 'text2', diff --git a/test/versions/slugs.ts b/test/versions/slugs.ts index 42f87526c4..2dccdb8b65 100644 --- a/test/versions/slugs.ts +++ b/test/versions/slugs.ts @@ -20,6 +20,8 @@ export const disablePublishSlug = 'disable-publish' export const disablePublishGlobalSlug = 'disable-publish-global' +export const textCollectionSlug = 'text' + export const collectionSlugs = [ autosaveCollectionSlug, draftCollectionSlug, @@ -27,6 +29,7 @@ export const collectionSlugs = [ diffCollectionSlug, mediaCollectionSlug, versionCollectionSlug, + textCollectionSlug, ] export const autoSaveGlobalSlug = 'autosave-global' From 760cfadaadfc35694750a280e189ccda1de8a590 Mon Sep 17 00:00:00 2001 From: Sasha <64744993+r1tsuu@users.noreply.github.com> Date: Thu, 3 Apr 2025 00:12:35 +0300 Subject: [PATCH 54/77] fix: do not append `doc` input for scheduled publish job if it's enabled only for globals (#11892) Fixes https://github.com/payloadcms/payload/issues/11891 Previously, if you had scheduled publish enabled only for globals, not collections - you'd get an error on `payload generate:types`: image This was caused by appending the `doc` field to the scheduled publish job input schema with empty `collections` array. Now we skip this field if we don't have any collections. --- packages/payload/src/versions/schedule/job.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/payload/src/versions/schedule/job.ts b/packages/payload/src/versions/schedule/job.ts index cf3450b5d3..a53ba92727 100644 --- a/packages/payload/src/versions/schedule/job.ts +++ b/packages/payload/src/versions/schedule/job.ts @@ -1,5 +1,6 @@ // @ts-strict-ignore import type { User } from '../../auth/types.js' +import type { Field } from '../../fields/config/types.js' import type { TaskConfig } from '../../queues/config/types/taskTypes.js' import type { SchedulePublishTaskInput } from './types.js' @@ -87,11 +88,15 @@ export const getSchedulePublishTask = ({ name: 'locale', type: 'text', }, - { - name: 'doc', - type: 'relationship', - relationTo: collections, - }, + ...(collections.length > 0 + ? [ + { + name: 'doc', + type: 'relationship', + relationTo: collections, + } satisfies Field, + ] + : []), { name: 'global', type: 'select', From f9c73ad5f2b1f5d1d5a82145406ac2b4b5b5059e Mon Sep 17 00:00:00 2001 From: Sasha <64744993+r1tsuu@users.noreply.github.com> Date: Thu, 3 Apr 2025 00:14:08 +0300 Subject: [PATCH 55/77] feat(storage-uploadthing): configurable upload router input config (#11954) Fixes https://github.com/payloadcms/payload/issues/11949 by setting the default limit to `512MB`. Additionally, makes this configurable via `clientUploads.routerInputConfig`. Details are here https://docs.uploadthing.com/file-routes#route-config --- .../src/getClientUploadRoute.ts | 7 +++++++ packages/storage-uploadthing/src/index.ts | 15 +++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/packages/storage-uploadthing/src/getClientUploadRoute.ts b/packages/storage-uploadthing/src/getClientUploadRoute.ts index 2eea6b1460..ad8ac163c6 100644 --- a/packages/storage-uploadthing/src/getClientUploadRoute.ts +++ b/packages/storage-uploadthing/src/getClientUploadRoute.ts @@ -12,6 +12,7 @@ type Args = { req: PayloadRequest }) => boolean | Promise acl: 'private' | 'public-read' + routerInputConfig?: FileRouterInputConfig token?: string } @@ -22,18 +23,24 @@ import type { FileRouter } from 'uploadthing/server' import { createRouteHandler } from 'uploadthing/next' import { createUploadthing } from 'uploadthing/server' +import type { FileRouterInputConfig } from './index.js' + export const getClientUploadRoute = ({ access = defaultAccess, acl, + routerInputConfig = {}, token, }: Args): PayloadHandler => { const f = createUploadthing() const uploadRouter = { uploader: f({ + ...routerInputConfig, blob: { acl, maxFileCount: 1, + maxFileSize: '512MB', + ...('blob' in routerInputConfig ? routerInputConfig.blob : {}), }, }) .middleware(async ({ req: rawReq }) => { diff --git a/packages/storage-uploadthing/src/index.ts b/packages/storage-uploadthing/src/index.ts index b47b499288..0cd91dcb74 100644 --- a/packages/storage-uploadthing/src/index.ts +++ b/packages/storage-uploadthing/src/index.ts @@ -1,17 +1,17 @@ import type { Adapter, - ClientUploadsConfig, + ClientUploadsAccess, PluginOptions as CloudStoragePluginOptions, CollectionOptions, GeneratedAdapter, } from '@payloadcms/plugin-cloud-storage/types' import type { Config, Field, Plugin, UploadCollectionSlug } from 'payload' +import type { createUploadthing } from 'uploadthing/server' import type { UTApiOptions } from 'uploadthing/types' import { cloudStoragePlugin } from '@payloadcms/plugin-cloud-storage' import { initClientUploads } from '@payloadcms/plugin-cloud-storage/utilities' -import { createRouteHandler } from 'uploadthing/next' -import { createUploadthing, UTApi } from 'uploadthing/server' +import { UTApi } from 'uploadthing/server' import { generateURL } from './generateURL.js' import { getClientUploadRoute } from './getClientUploadRoute.js' @@ -19,11 +19,18 @@ import { getHandleDelete } from './handleDelete.js' import { getHandleUpload } from './handleUpload.js' import { getHandler } from './staticHandler.js' +export type FileRouterInputConfig = Parameters>[0] + export type UploadthingStorageOptions = { /** * Do uploads directly on the client, to bypass limits on Vercel. */ - clientUploads?: ClientUploadsConfig + clientUploads?: + | { + access?: ClientUploadsAccess + routerInputConfig?: FileRouterInputConfig + } + | boolean /** * Collection options to apply the adapter to. From dc793d1d1442dc857b5772e830e6be3be2af06b6 Mon Sep 17 00:00:00 2001 From: Sasha <64744993+r1tsuu@users.noreply.github.com> Date: Thu, 3 Apr 2025 00:38:54 +0300 Subject: [PATCH 56/77] fix: `ValidationError` error message when `label` is a function (#11904) Fixes https://github.com/payloadcms/payload/issues/11901 Previously, when `ValidationError` `errors.path` was referring to a field with `label` defined as a function, the error message was generated with `[object Object]`. Now, we call that function instead. Since the `i18n` argument is required for `StaticLabel`, this PR introduces so you can pass a partial `req` to `ValidationError` from which we thread `req.i18n` to the label args. --- packages/drizzle/src/upsertRow/index.ts | 1 + .../payload/src/errors/ValidationError.ts | 35 ++++++++++++++++++- .../src/fields/hooks/beforeChange/index.ts | 1 + 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/drizzle/src/upsertRow/index.ts b/packages/drizzle/src/upsertRow/index.ts index 211b6463e3..71d0b50ab3 100644 --- a/packages/drizzle/src/upsertRow/index.ts +++ b/packages/drizzle/src/upsertRow/index.ts @@ -423,6 +423,7 @@ export const upsertRow = async | TypeWithID>( path: fieldName, }, ], + req, }, req?.t, ) diff --git a/packages/payload/src/errors/ValidationError.ts b/packages/payload/src/errors/ValidationError.ts index d2d56bab1f..9b17a63bd6 100644 --- a/packages/payload/src/errors/ValidationError.ts +++ b/packages/payload/src/errors/ValidationError.ts @@ -4,6 +4,7 @@ import { en } from '@payloadcms/translations/languages/en' import { status as httpStatus } from 'http-status' import type { LabelFunction, StaticLabel } from '../config/types.js' +import type { PayloadRequest } from '../types/index.js' import { APIError } from './APIError.js' @@ -28,6 +29,10 @@ export class ValidationError extends APIError<{ errors: ValidationFieldError[] global?: string id?: number | string + /** + * req needs to be passed through (if you have one) in order to resolve label functions that may be part of the errors array + */ + req?: Partial }, t?: TFunction, ) { @@ -37,8 +42,36 @@ export class ValidationError extends APIError<{ ? en.translations.error.followingFieldsInvalid_one : en.translations.error.followingFieldsInvalid_other + const req = results.req + // delete to avoid logging the whole req + delete results['req'] + super( - `${message} ${results.errors.map((f) => f.label || f.path).join(', ')}`, + `${message} ${results.errors + .map((f) => { + if (f.label) { + if (typeof f.label === 'function') { + if (!req || !req.i18n || !req.t) { + return f.path + } + + return f.label({ i18n: req.i18n, t: req.t }) + } + + if (typeof f.label === 'object') { + if (req?.i18n?.language) { + return f.label[req.i18n.language] + } + + return f.label[Object.keys(f.label)[0]] + } + + return f.label + } + + return f.path + }) + .join(', ')}`, httpStatus.BAD_REQUEST, results, ) diff --git a/packages/payload/src/fields/hooks/beforeChange/index.ts b/packages/payload/src/fields/hooks/beforeChange/index.ts index 1571893011..3df18dbc56 100644 --- a/packages/payload/src/fields/hooks/beforeChange/index.ts +++ b/packages/payload/src/fields/hooks/beforeChange/index.ts @@ -77,6 +77,7 @@ export const beforeChange = async ({ collection: collection?.slug, errors, global: global?.slug, + req, }, req.t, ) From f310c902113d1dc20cf7c844ab3bd348f3a5f2fe Mon Sep 17 00:00:00 2001 From: Sasha <64744993+r1tsuu@users.noreply.github.com> Date: Thu, 3 Apr 2025 02:33:34 +0300 Subject: [PATCH 57/77] fix(db-postgres): down migration fails because `migrationTableExists` doesn't check in the current transaction (#11910) Fixes https://github.com/payloadcms/payload/issues/11882 Previously, down migration that dropped the `payload_migrations` table was failing because `migrationTableExists` doesn't check the current transaction, only in which you can get a `false` value result. --- packages/drizzle/src/migrateDown.ts | 3 +- packages/drizzle/src/migrateRefresh.ts | 2 +- packages/drizzle/src/migrateReset.ts | 2 +- .../src/utilities/migrationTableExists.ts | 11 +- test/database/up-down-migration/int.spec.ts | 58 +++ .../migrations/20250328_185055.json | 463 ++++++++++++++++++ .../migrations/20250328_185055.ts | 122 +++++ .../up-down-migration/migrations/index.ts | 9 + 8 files changed, 664 insertions(+), 6 deletions(-) create mode 100644 test/database/up-down-migration/int.spec.ts create mode 100644 test/database/up-down-migration/migrations/20250328_185055.json create mode 100644 test/database/up-down-migration/migrations/20250328_185055.ts create mode 100644 test/database/up-down-migration/migrations/index.ts diff --git a/packages/drizzle/src/migrateDown.ts b/packages/drizzle/src/migrateDown.ts index 20eb8714d7..09169b125a 100644 --- a/packages/drizzle/src/migrateDown.ts +++ b/packages/drizzle/src/migrateDown.ts @@ -50,7 +50,8 @@ export async function migrateDown(this: DrizzleAdapter): Promise { msg: `Migrated down: ${migrationFile.name} (${Date.now() - start}ms)`, }) - const tableExists = await migrationTableExists(this) + const tableExists = await migrationTableExists(this, db) + if (tableExists) { await payload.delete({ id: migration.id, diff --git a/packages/drizzle/src/migrateRefresh.ts b/packages/drizzle/src/migrateRefresh.ts index 1a56c825a1..e95133a0d6 100644 --- a/packages/drizzle/src/migrateRefresh.ts +++ b/packages/drizzle/src/migrateRefresh.ts @@ -54,7 +54,7 @@ export async function migrateRefresh(this: DrizzleAdapter) { msg: `Migrated down: ${migration.name} (${Date.now() - start}ms)`, }) - const tableExists = await migrationTableExists(this) + const tableExists = await migrationTableExists(this, db) if (tableExists) { await payload.delete({ collection: 'payload-migrations', diff --git a/packages/drizzle/src/migrateReset.ts b/packages/drizzle/src/migrateReset.ts index ce0d7a3546..99d977a716 100644 --- a/packages/drizzle/src/migrateReset.ts +++ b/packages/drizzle/src/migrateReset.ts @@ -45,7 +45,7 @@ export async function migrateReset(this: DrizzleAdapter): Promise { msg: `Migrated down: ${migrationFile.name} (${Date.now() - start}ms)`, }) - const tableExists = await migrationTableExists(this) + const tableExists = await migrationTableExists(this, db) if (tableExists) { await payload.delete({ id: migration.id, diff --git a/packages/drizzle/src/utilities/migrationTableExists.ts b/packages/drizzle/src/utilities/migrationTableExists.ts index 970de625a5..bbc397a637 100644 --- a/packages/drizzle/src/utilities/migrationTableExists.ts +++ b/packages/drizzle/src/utilities/migrationTableExists.ts @@ -1,6 +1,11 @@ -import type { DrizzleAdapter } from '../types.js' +import type { LibSQLDatabase } from 'drizzle-orm/libsql' -export const migrationTableExists = async (adapter: DrizzleAdapter): Promise => { +import type { DrizzleAdapter, PostgresDB } from '../types.js' + +export const migrationTableExists = async ( + adapter: DrizzleAdapter, + db?: LibSQLDatabase | PostgresDB, +): Promise => { let statement if (adapter.name === 'postgres') { @@ -20,7 +25,7 @@ export const migrationTableExists = async (adapter: DrizzleAdapter): Promise { + if (existsSync(path.resolve(dirname, 'migrations'))) { + rmSync(path.resolve(dirname, 'migrations'), { force: true, recursive: true }) + } +} + +describe('SQL migrations', () => { + // If something fails - an error will be thrown. + // eslint-disable-next-line jest/expect-expect + it('should up and down migration successfully', async () => { + clearMigrations() + + const { databaseAdapter } = await import(path.resolve(dirname, '../../databaseAdapter.js')) + + const init = databaseAdapter.init + + // set options + databaseAdapter.init = ({ payload }) => { + const adapter = init({ payload }) + adapter.migrationDir = path.resolve(dirname, 'migrations') + adapter.push = false + return adapter + } + + const config = await buildConfig({ + db: databaseAdapter, + secret: 'secret', + collections: [ + { + slug: 'users', + auth: true, + fields: [], + }, + ], + }) + + const payload = await getPayload({ config }) + + await payload.db.createMigration({ payload }) + await payload.db.migrate() + await payload.db.migrateDown() + + await payload.db.dropDatabase({ adapter: payload.db as any }) + await payload.db.destroy?.() + }) +}) diff --git a/test/database/up-down-migration/migrations/20250328_185055.json b/test/database/up-down-migration/migrations/20250328_185055.json new file mode 100644 index 0000000000..7ef134f6aa --- /dev/null +++ b/test/database/up-down-migration/migrations/20250328_185055.json @@ -0,0 +1,463 @@ +{ + "version": "6", + "dialect": "sqlite", + "tables": { + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reset_password_token": { + "name": "reset_password_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reset_password_expiration": { + "name": "reset_password_expiration", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "hash": { + "name": "hash", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "login_attempts": { + "name": "login_attempts", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "lock_until": { + "name": "lock_until", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "users_updated_at_idx": { + "name": "users_updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + }, + "users_created_at_idx": { + "name": "users_created_at_idx", + "columns": ["created_at"], + "isUnique": false + }, + "users_email_idx": { + "name": "users_email_idx", + "columns": ["email"], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "payload_locked_documents": { + "name": "payload_locked_documents", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "global_slug": { + "name": "global_slug", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "payload_locked_documents_global_slug_idx": { + "name": "payload_locked_documents_global_slug_idx", + "columns": ["global_slug"], + "isUnique": false + }, + "payload_locked_documents_updated_at_idx": { + "name": "payload_locked_documents_updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + }, + "payload_locked_documents_created_at_idx": { + "name": "payload_locked_documents_created_at_idx", + "columns": ["created_at"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "payload_locked_documents_rels": { + "name": "payload_locked_documents_rels", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "parent_id": { + "name": "parent_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "users_id": { + "name": "users_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "payload_locked_documents_rels_order_idx": { + "name": "payload_locked_documents_rels_order_idx", + "columns": ["order"], + "isUnique": false + }, + "payload_locked_documents_rels_parent_idx": { + "name": "payload_locked_documents_rels_parent_idx", + "columns": ["parent_id"], + "isUnique": false + }, + "payload_locked_documents_rels_path_idx": { + "name": "payload_locked_documents_rels_path_idx", + "columns": ["path"], + "isUnique": false + }, + "payload_locked_documents_rels_users_id_idx": { + "name": "payload_locked_documents_rels_users_id_idx", + "columns": ["users_id"], + "isUnique": false + } + }, + "foreignKeys": { + "payload_locked_documents_rels_parent_fk": { + "name": "payload_locked_documents_rels_parent_fk", + "tableFrom": "payload_locked_documents_rels", + "tableTo": "payload_locked_documents", + "columnsFrom": ["parent_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "payload_locked_documents_rels_users_fk": { + "name": "payload_locked_documents_rels_users_fk", + "tableFrom": "payload_locked_documents_rels", + "tableTo": "users", + "columnsFrom": ["users_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "payload_preferences": { + "name": "payload_preferences", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "payload_preferences_key_idx": { + "name": "payload_preferences_key_idx", + "columns": ["key"], + "isUnique": false + }, + "payload_preferences_updated_at_idx": { + "name": "payload_preferences_updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + }, + "payload_preferences_created_at_idx": { + "name": "payload_preferences_created_at_idx", + "columns": ["created_at"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "payload_preferences_rels": { + "name": "payload_preferences_rels", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "parent_id": { + "name": "parent_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "users_id": { + "name": "users_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "payload_preferences_rels_order_idx": { + "name": "payload_preferences_rels_order_idx", + "columns": ["order"], + "isUnique": false + }, + "payload_preferences_rels_parent_idx": { + "name": "payload_preferences_rels_parent_idx", + "columns": ["parent_id"], + "isUnique": false + }, + "payload_preferences_rels_path_idx": { + "name": "payload_preferences_rels_path_idx", + "columns": ["path"], + "isUnique": false + }, + "payload_preferences_rels_users_id_idx": { + "name": "payload_preferences_rels_users_id_idx", + "columns": ["users_id"], + "isUnique": false + } + }, + "foreignKeys": { + "payload_preferences_rels_parent_fk": { + "name": "payload_preferences_rels_parent_fk", + "tableFrom": "payload_preferences_rels", + "tableTo": "payload_preferences", + "columnsFrom": ["parent_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "payload_preferences_rels_users_fk": { + "name": "payload_preferences_rels_users_fk", + "tableFrom": "payload_preferences_rels", + "tableTo": "users", + "columnsFrom": ["users_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "payload_migrations": { + "name": "payload_migrations", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "batch": { + "name": "batch", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "payload_migrations_updated_at_idx": { + "name": "payload_migrations_updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + }, + "payload_migrations_created_at_idx": { + "name": "payload_migrations_created_at_idx", + "columns": ["created_at"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + }, + "id": "2b2f5008-c761-40d0-a858-67d6b4233615", + "prevId": "00000000-0000-0000-0000-000000000000" +} diff --git a/test/database/up-down-migration/migrations/20250328_185055.ts b/test/database/up-down-migration/migrations/20250328_185055.ts new file mode 100644 index 0000000000..02bc61092a --- /dev/null +++ b/test/database/up-down-migration/migrations/20250328_185055.ts @@ -0,0 +1,122 @@ +import type { MigrateDownArgs, MigrateUpArgs} from '@payloadcms/db-sqlite'; + +import { sql } from '@payloadcms/db-sqlite' + +export async function up({ db, payload, req }: MigrateUpArgs): Promise { + await db.run(sql`CREATE TABLE \`users\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`updated_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL, + \`created_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL, + \`email\` text NOT NULL, + \`reset_password_token\` text, + \`reset_password_expiration\` text, + \`salt\` text, + \`hash\` text, + \`login_attempts\` numeric DEFAULT 0, + \`lock_until\` text + ); + `) + await db.run(sql`CREATE INDEX \`users_updated_at_idx\` ON \`users\` (\`updated_at\`);`) + await db.run(sql`CREATE INDEX \`users_created_at_idx\` ON \`users\` (\`created_at\`);`) + await db.run(sql`CREATE UNIQUE INDEX \`users_email_idx\` ON \`users\` (\`email\`);`) + await db.run(sql`CREATE TABLE \`payload_locked_documents\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`global_slug\` text, + \`updated_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL, + \`created_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL + ); + `) + await db.run( + sql`CREATE INDEX \`payload_locked_documents_global_slug_idx\` ON \`payload_locked_documents\` (\`global_slug\`);`, + ) + await db.run( + sql`CREATE INDEX \`payload_locked_documents_updated_at_idx\` ON \`payload_locked_documents\` (\`updated_at\`);`, + ) + await db.run( + sql`CREATE INDEX \`payload_locked_documents_created_at_idx\` ON \`payload_locked_documents\` (\`created_at\`);`, + ) + await db.run(sql`CREATE TABLE \`payload_locked_documents_rels\` ( + \`id\` integer PRIMARY KEY NOT NULL, + \`order\` integer, + \`parent_id\` integer NOT NULL, + \`path\` text NOT NULL, + \`users_id\` integer, + FOREIGN KEY (\`parent_id\`) REFERENCES \`payload_locked_documents\`(\`id\`) ON UPDATE no action ON DELETE cascade, + FOREIGN KEY (\`users_id\`) REFERENCES \`users\`(\`id\`) ON UPDATE no action ON DELETE cascade + ); + `) + await db.run( + sql`CREATE INDEX \`payload_locked_documents_rels_order_idx\` ON \`payload_locked_documents_rels\` (\`order\`);`, + ) + await db.run( + sql`CREATE INDEX \`payload_locked_documents_rels_parent_idx\` ON \`payload_locked_documents_rels\` (\`parent_id\`);`, + ) + await db.run( + sql`CREATE INDEX \`payload_locked_documents_rels_path_idx\` ON \`payload_locked_documents_rels\` (\`path\`);`, + ) + await db.run( + sql`CREATE INDEX \`payload_locked_documents_rels_users_id_idx\` ON \`payload_locked_documents_rels\` (\`users_id\`);`, + ) + await db.run(sql`CREATE TABLE \`payload_preferences\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`key\` text, + \`value\` text, + \`updated_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL, + \`created_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL + ); + `) + await db.run( + sql`CREATE INDEX \`payload_preferences_key_idx\` ON \`payload_preferences\` (\`key\`);`, + ) + await db.run( + sql`CREATE INDEX \`payload_preferences_updated_at_idx\` ON \`payload_preferences\` (\`updated_at\`);`, + ) + await db.run( + sql`CREATE INDEX \`payload_preferences_created_at_idx\` ON \`payload_preferences\` (\`created_at\`);`, + ) + await db.run(sql`CREATE TABLE \`payload_preferences_rels\` ( + \`id\` integer PRIMARY KEY NOT NULL, + \`order\` integer, + \`parent_id\` integer NOT NULL, + \`path\` text NOT NULL, + \`users_id\` integer, + FOREIGN KEY (\`parent_id\`) REFERENCES \`payload_preferences\`(\`id\`) ON UPDATE no action ON DELETE cascade, + FOREIGN KEY (\`users_id\`) REFERENCES \`users\`(\`id\`) ON UPDATE no action ON DELETE cascade + ); + `) + await db.run( + sql`CREATE INDEX \`payload_preferences_rels_order_idx\` ON \`payload_preferences_rels\` (\`order\`);`, + ) + await db.run( + sql`CREATE INDEX \`payload_preferences_rels_parent_idx\` ON \`payload_preferences_rels\` (\`parent_id\`);`, + ) + await db.run( + sql`CREATE INDEX \`payload_preferences_rels_path_idx\` ON \`payload_preferences_rels\` (\`path\`);`, + ) + await db.run( + sql`CREATE INDEX \`payload_preferences_rels_users_id_idx\` ON \`payload_preferences_rels\` (\`users_id\`);`, + ) + await db.run(sql`CREATE TABLE \`payload_migrations\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`name\` text, + \`batch\` numeric, + \`updated_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL, + \`created_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL + ); + `) + await db.run( + sql`CREATE INDEX \`payload_migrations_updated_at_idx\` ON \`payload_migrations\` (\`updated_at\`);`, + ) + await db.run( + sql`CREATE INDEX \`payload_migrations_created_at_idx\` ON \`payload_migrations\` (\`created_at\`);`, + ) +} + +export async function down({ db, payload, req }: MigrateDownArgs): Promise { + await db.run(sql`DROP TABLE \`users\`;`) + await db.run(sql`DROP TABLE \`payload_locked_documents\`;`) + await db.run(sql`DROP TABLE \`payload_locked_documents_rels\`;`) + await db.run(sql`DROP TABLE \`payload_preferences\`;`) + await db.run(sql`DROP TABLE \`payload_preferences_rels\`;`) + await db.run(sql`DROP TABLE \`payload_migrations\`;`) +} diff --git a/test/database/up-down-migration/migrations/index.ts b/test/database/up-down-migration/migrations/index.ts new file mode 100644 index 0000000000..c7646c19ea --- /dev/null +++ b/test/database/up-down-migration/migrations/index.ts @@ -0,0 +1,9 @@ +import * as migration_20250328_185055 from './20250328_185055.js' + +export const migrations = [ + { + up: migration_20250328_185055.up, + down: migration_20250328_185055.down, + name: '20250328_185055', + }, +] From 8e93ad8f5f8f329955afc22b64963d592fab3f94 Mon Sep 17 00:00:00 2001 From: Sasha <64744993+r1tsuu@users.noreply.github.com> Date: Thu, 3 Apr 2025 02:51:30 +0300 Subject: [PATCH 58/77] fix(storage-uploadthing): pass `clientUploads.routerInputConfig` to the handler (#11962) PR https://github.com/payloadcms/payload/pull/11954 added this property but didn't actually pass it through to the handler. --- packages/storage-uploadthing/src/index.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/storage-uploadthing/src/index.ts b/packages/storage-uploadthing/src/index.ts index 0cd91dcb74..54a139b01b 100644 --- a/packages/storage-uploadthing/src/index.ts +++ b/packages/storage-uploadthing/src/index.ts @@ -76,6 +76,10 @@ export const uploadthingStorage: UploadthingPlugin = ? uploadthingStorageOptions.clientUploads.access : undefined, acl: uploadthingStorageOptions.options.acl || 'public-read', + routerInputConfig: + typeof uploadthingStorageOptions.clientUploads === 'object' + ? uploadthingStorageOptions.clientUploads.routerInputConfig + : undefined, token: uploadthingStorageOptions.options.token, }), serverHandlerPath: '/storage-uploadthing-client-upload-route', From 06d937e903958d5e72e3460c72723ad4b1596f02 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Thu, 3 Apr 2025 00:21:27 -0600 Subject: [PATCH 59/77] docs: fix variable names for lexical markdown conversion (#11963) --- docs/rich-text/converting-markdown.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/rich-text/converting-markdown.mdx b/docs/rich-text/converting-markdown.mdx index ff0b2b8ff5..c34047abb6 100644 --- a/docs/rich-text/converting-markdown.mdx +++ b/docs/rich-text/converting-markdown.mdx @@ -21,7 +21,7 @@ import { // Your richtext data here const data: SerializedEditorState = {} -const html = convertLexicalToMarkdown({ +const markdown = convertLexicalToMarkdown({ data, editorConfig: await editorConfigFactory.default({ config, // <= make sure you have access to your Payload Config @@ -101,7 +101,7 @@ import { editorConfigFactory, } from '@payloadcms/richtext-lexical' -const html = convertMarkdownToLexical({ +const lexicalJSON = convertMarkdownToLexical({ editorConfig: await editorConfigFactory.default({ config, // <= make sure you have access to your Payload Config }), From a58ff57e4f74feb43478d35d01df61b66355e816 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Thu, 3 Apr 2025 10:01:13 -0300 Subject: [PATCH 60/77] chore(plugin-form-builder): enable TypeScript strict (#11929) --- .../src/collections/FormSubmissions/hooks/sendEmail.ts | 2 +- .../src/collections/FormSubmissions/index.ts | 3 ++- .../src/collections/Forms/DynamicFieldSelector.tsx | 5 ++--- packages/plugin-form-builder/src/collections/Forms/index.ts | 6 +++--- .../src/utilities/replaceDoubleCurlys.ts | 2 +- .../src/utilities/slate/serializeSlate.ts | 2 +- packages/plugin-form-builder/tsconfig.json | 4 ---- 7 files changed, 10 insertions(+), 14 deletions(-) diff --git a/packages/plugin-form-builder/src/collections/FormSubmissions/hooks/sendEmail.ts b/packages/plugin-form-builder/src/collections/FormSubmissions/hooks/sendEmail.ts index 5f9506cb4b..7223f4aead 100644 --- a/packages/plugin-form-builder/src/collections/FormSubmissions/hooks/sendEmail.ts +++ b/packages/plugin-form-builder/src/collections/FormSubmissions/hooks/sendEmail.ts @@ -36,7 +36,7 @@ export const sendEmail = async ( if (emails && emails.length) { const formattedEmails: FormattedEmail[] = await Promise.all( - emails.map(async (email: Email): Promise => { + emails.map(async (email: Email): Promise => { const { bcc: emailBCC, cc: emailCC, diff --git a/packages/plugin-form-builder/src/collections/FormSubmissions/index.ts b/packages/plugin-form-builder/src/collections/FormSubmissions/index.ts index b8252453f5..c710fbb07a 100644 --- a/packages/plugin-form-builder/src/collections/FormSubmissions/index.ts +++ b/packages/plugin-form-builder/src/collections/FormSubmissions/index.ts @@ -23,6 +23,7 @@ export const generateSubmissionCollection = ( }, relationTo: formSlug, required: true, + // @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve validate: async (value, { req: { payload }, req }) => { /* Don't run in the client side */ if (!payload) { @@ -40,7 +41,7 @@ export const generateSubmissionCollection = ( }) return true - } catch (error) { + } catch (_error) { return 'Cannot create this submission because this form does not exist.' } } diff --git a/packages/plugin-form-builder/src/collections/Forms/DynamicFieldSelector.tsx b/packages/plugin-form-builder/src/collections/Forms/DynamicFieldSelector.tsx index 1994b9f8d4..87f3fbbaa1 100644 --- a/packages/plugin-form-builder/src/collections/Forms/DynamicFieldSelector.tsx +++ b/packages/plugin-form-builder/src/collections/Forms/DynamicFieldSelector.tsx @@ -31,7 +31,7 @@ export const DynamicFieldSelector: React.FC< return null }) - .filter(Boolean) + .filter((field) => field !== null) setOptions(allNonPaymentFields) } }, [fields, getDataByPath]) @@ -40,9 +40,8 @@ export const DynamicFieldSelector: React.FC< ) diff --git a/packages/plugin-form-builder/src/collections/Forms/index.ts b/packages/plugin-form-builder/src/collections/Forms/index.ts index 06b0f252c0..c668f3b00d 100644 --- a/packages/plugin-form-builder/src/collections/Forms/index.ts +++ b/packages/plugin-form-builder/src/collections/Forms/index.ts @@ -57,11 +57,11 @@ export const generateFormCollection = (formConfig: FormBuilderPluginConfig): Col ], }) - if (redirect.fields[2].type !== 'row') { - redirect.fields[2].label = 'Custom URL' + if (redirect.fields[2]!.type !== 'row') { + redirect.fields[2]!.label = 'Custom URL' } - redirect.fields[2].admin = { + redirect.fields[2]!.admin = { condition: (_, siblingData) => siblingData?.type === 'custom', } } diff --git a/packages/plugin-form-builder/src/utilities/replaceDoubleCurlys.ts b/packages/plugin-form-builder/src/utilities/replaceDoubleCurlys.ts index 1ecef76ab6..2d6d6691c8 100644 --- a/packages/plugin-form-builder/src/utilities/replaceDoubleCurlys.ts +++ b/packages/plugin-form-builder/src/utilities/replaceDoubleCurlys.ts @@ -16,7 +16,7 @@ export const replaceDoubleCurlys = (str: string, variables?: EmailVariables): st return variables.map(({ field, value }) => `${field} : ${value}`).join('
    ') } else if (variable === '*:table') { return keyValuePairToHtmlTable( - variables.reduce((acc, { field, value }) => { + variables.reduce>((acc, { field, value }) => { acc[field] = value return acc }, {}), diff --git a/packages/plugin-form-builder/src/utilities/slate/serializeSlate.ts b/packages/plugin-form-builder/src/utilities/slate/serializeSlate.ts index 1b359b1902..ea5c16bb4e 100644 --- a/packages/plugin-form-builder/src/utilities/slate/serializeSlate.ts +++ b/packages/plugin-form-builder/src/utilities/slate/serializeSlate.ts @@ -106,7 +106,7 @@ export const serializeSlate = (children?: Node[], submissionData?: any): string ` case 'link': return ` - + ${serializeSlate(node.children, submissionData)} ` diff --git a/packages/plugin-form-builder/tsconfig.json b/packages/plugin-form-builder/tsconfig.json index 99d6fca7fb..dd036fd84f 100644 --- a/packages/plugin-form-builder/tsconfig.json +++ b/packages/plugin-form-builder/tsconfig.json @@ -1,8 +1,4 @@ { "extends": "../../tsconfig.base.json", - "compilerOptions": { - /* TODO: remove the following lines */ - "strict": false, - }, "references": [{ "path": "../payload" }, { "path": "../ui" }] } From fd42ad5f52ad95ecc345d11f7e3fdd7d6dd262e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Thu, 3 Apr 2025 10:04:04 -0300 Subject: [PATCH 61/77] chore(plugin-nested-docs): enable TypeScript strict (#11930) --- .../plugin-nested-docs/src/fields/parentFilterOptions.ts | 2 +- packages/plugin-nested-docs/src/hooks/resaveChildren.ts | 6 ++++-- .../plugin-nested-docs/src/hooks/resaveSelfAfterCreate.ts | 4 ++-- .../plugin-nested-docs/src/utilities/formatBreadcrumb.ts | 4 ++-- packages/plugin-nested-docs/src/utilities/getParents.ts | 4 ++-- packages/plugin-nested-docs/tsconfig.json | 4 ---- 6 files changed, 11 insertions(+), 13 deletions(-) diff --git a/packages/plugin-nested-docs/src/fields/parentFilterOptions.ts b/packages/plugin-nested-docs/src/fields/parentFilterOptions.ts index 1c38e14cd4..96e4ae41d9 100644 --- a/packages/plugin-nested-docs/src/fields/parentFilterOptions.ts +++ b/packages/plugin-nested-docs/src/fields/parentFilterOptions.ts @@ -10,5 +10,5 @@ export const parentFilterOptions: (breadcrumbsFieldSlug?: string) => FilterOptio } } - return null + return true } diff --git a/packages/plugin-nested-docs/src/hooks/resaveChildren.ts b/packages/plugin-nested-docs/src/hooks/resaveChildren.ts index bac3467a9e..dca94c7285 100644 --- a/packages/plugin-nested-docs/src/hooks/resaveChildren.ts +++ b/packages/plugin-nested-docs/src/hooks/resaveChildren.ts @@ -58,9 +58,11 @@ const resave = async ({ collection, doc, draft, pluginConfig, req }: ResaveArgs) }, }) - const childrenById = [...draftChildren, ...publishedChildren.docs].reduce((acc, child) => { + const childrenById = [...draftChildren, ...publishedChildren.docs].reduce< + Record + >((acc, child) => { acc[child.id] = acc[child.id] || [] - acc[child.id].push(child) + acc[child.id]!.push(child) return acc }, {}) diff --git a/packages/plugin-nested-docs/src/hooks/resaveSelfAfterCreate.ts b/packages/plugin-nested-docs/src/hooks/resaveSelfAfterCreate.ts index b912560511..14368b248d 100644 --- a/packages/plugin-nested-docs/src/hooks/resaveSelfAfterCreate.ts +++ b/packages/plugin-nested-docs/src/hooks/resaveSelfAfterCreate.ts @@ -1,6 +1,6 @@ import type { CollectionAfterChangeHook, CollectionConfig } from 'payload' -import type { NestedDocsPluginConfig } from '../types.js' +import type { Breadcrumb, NestedDocsPluginConfig } from '../types.js' // This hook automatically re-saves a document after it is created // so that we can build its breadcrumbs with the newly created document's ID. @@ -10,7 +10,7 @@ export const resaveSelfAfterCreate = async ({ doc, operation, req }) => { const { locale, payload } = req const breadcrumbSlug = pluginConfig.breadcrumbsFieldSlug || 'breadcrumbs' - const breadcrumbs = doc[breadcrumbSlug] + const breadcrumbs = doc[breadcrumbSlug] as unknown as Breadcrumb[] if (operation === 'create') { const originalDocWithDepth0 = await payload.findByID({ diff --git a/packages/plugin-nested-docs/src/utilities/formatBreadcrumb.ts b/packages/plugin-nested-docs/src/utilities/formatBreadcrumb.ts index 92acac71ea..2bb92a2365 100644 --- a/packages/plugin-nested-docs/src/utilities/formatBreadcrumb.ts +++ b/packages/plugin-nested-docs/src/utilities/formatBreadcrumb.ts @@ -10,7 +10,7 @@ export const formatBreadcrumb = ( let url: string | undefined = undefined let label: string - const lastDoc = docs[docs.length - 1] + const lastDoc = docs[docs.length - 1]! if (typeof pluginConfig?.generateURL === 'function') { url = pluginConfig.generateURL(docs, lastDoc) @@ -19,7 +19,7 @@ export const formatBreadcrumb = ( if (typeof pluginConfig?.generateLabel === 'function') { label = pluginConfig.generateLabel(docs, lastDoc) } else { - const title = lastDoc[collection.admin.useAsTitle] + const title = collection.admin?.useAsTitle ? lastDoc[collection.admin.useAsTitle] : '' label = typeof title === 'string' || typeof title === 'number' ? String(title) : '' } diff --git a/packages/plugin-nested-docs/src/utilities/getParents.ts b/packages/plugin-nested-docs/src/utilities/getParents.ts index 2349f09de4..68ebacd7fc 100644 --- a/packages/plugin-nested-docs/src/utilities/getParents.ts +++ b/packages/plugin-nested-docs/src/utilities/getParents.ts @@ -11,7 +11,7 @@ export const getParents = async ( ): Promise>> => { const parentSlug = pluginConfig?.parentFieldSlug || 'parent' const parent = doc[parentSlug] - let retrievedParent + let retrievedParent: null | Record = null if (parent) { // If not auto-populated, and we have an ID @@ -27,7 +27,7 @@ export const getParents = async ( // If auto-populated if (typeof parent === 'object') { - retrievedParent = parent + retrievedParent = parent as Record } if (retrievedParent) { diff --git a/packages/plugin-nested-docs/tsconfig.json b/packages/plugin-nested-docs/tsconfig.json index 35bda5a051..45209999a2 100644 --- a/packages/plugin-nested-docs/tsconfig.json +++ b/packages/plugin-nested-docs/tsconfig.json @@ -1,8 +1,4 @@ { "extends": "../../tsconfig.base.json", - "compilerOptions": { - /* TODO: remove the following lines */ - "strict": false, - }, "references": [{ "path": "../payload" }] } From 6c735effff7cdbbe864ffc404b7ed9ca6dc4a9d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Thu, 3 Apr 2025 10:04:21 -0300 Subject: [PATCH 62/77] chore(plugin-redirects): enable TypeScript strict (#11931) --- packages/plugin-redirects/src/index.ts | 4 +++- packages/plugin-redirects/tsconfig.json | 4 ---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/plugin-redirects/src/index.ts b/packages/plugin-redirects/src/index.ts index c62f71b208..397f360187 100644 --- a/packages/plugin-redirects/src/index.ts +++ b/packages/plugin-redirects/src/index.ts @@ -16,7 +16,9 @@ export const redirectsPlugin = pluginConfig?.redirectTypes?.includes(option.value), ), required: true, - ...((pluginConfig?.redirectTypeFieldOverride || {}) as SelectField), + ...((pluginConfig?.redirectTypeFieldOverride || {}) as { + hasMany: boolean + } & Partial), } const defaultFields: Field[] = [ diff --git a/packages/plugin-redirects/tsconfig.json b/packages/plugin-redirects/tsconfig.json index 35bda5a051..45209999a2 100644 --- a/packages/plugin-redirects/tsconfig.json +++ b/packages/plugin-redirects/tsconfig.json @@ -1,8 +1,4 @@ { "extends": "../../tsconfig.base.json", - "compilerOptions": { - /* TODO: remove the following lines */ - "strict": false, - }, "references": [{ "path": "../payload" }] } From 308cb64b9c7f46c4bb0c4cf9704a348b32165a5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Thu, 3 Apr 2025 10:06:07 -0300 Subject: [PATCH 63/77] chore(richtext-lexical): add DebugJsxConverterFeature (#10856) Display the editor content below using the JSX converter Added for debugging reasons, similar to TreeViewFeature usage: ```ts { name: 'content', type: 'richText', editor: lexicalEditor({ features: ({ defaultFeatures }) => [...defaultFeatures, DebugJsxConverterFeature()], }), }, ``` --- .../src/exports/client/index.ts | 1 + .../debug/jsxConverter/client/index.tsx | 13 ++++++++++++ .../jsxConverter/client/plugin/index.tsx | 20 +++++++++++++++++++ .../debug/jsxConverter/server/index.ts | 8 ++++++++ packages/richtext-lexical/src/index.ts | 1 + 5 files changed, 43 insertions(+) create mode 100644 packages/richtext-lexical/src/features/debug/jsxConverter/client/index.tsx create mode 100644 packages/richtext-lexical/src/features/debug/jsxConverter/client/plugin/index.tsx create mode 100644 packages/richtext-lexical/src/features/debug/jsxConverter/server/index.ts diff --git a/packages/richtext-lexical/src/exports/client/index.ts b/packages/richtext-lexical/src/exports/client/index.ts index 22dbab89a1..57f539f5e4 100644 --- a/packages/richtext-lexical/src/exports/client/index.ts +++ b/packages/richtext-lexical/src/exports/client/index.ts @@ -30,6 +30,7 @@ export { UnorderedListFeatureClient } from '../../features/lists/unorderedList/c export { LexicalPluginToLexicalFeatureClient } from '../../features/migrations/lexicalPluginToLexical/feature.client.js' export { SlateToLexicalFeatureClient } from '../../features/migrations/slateToLexical/feature.client.js' export { ParagraphFeatureClient } from '../../features/paragraph/client/index.js' +export { DebugJsxConverterFeatureClient } from '../../features/debug/jsxConverter/client/index.js' export { RelationshipFeatureClient } from '../../features/relationship/client/index.js' diff --git a/packages/richtext-lexical/src/features/debug/jsxConverter/client/index.tsx b/packages/richtext-lexical/src/features/debug/jsxConverter/client/index.tsx new file mode 100644 index 0000000000..0d9938e273 --- /dev/null +++ b/packages/richtext-lexical/src/features/debug/jsxConverter/client/index.tsx @@ -0,0 +1,13 @@ +'use client' + +import { createClientFeature } from '../../../../utilities/createClientFeature.js' +import { RichTextPlugin } from './plugin/index.js' + +export const DebugJsxConverterFeatureClient = createClientFeature({ + plugins: [ + { + Component: RichTextPlugin, + position: 'bottom', + }, + ], +}) diff --git a/packages/richtext-lexical/src/features/debug/jsxConverter/client/plugin/index.tsx b/packages/richtext-lexical/src/features/debug/jsxConverter/client/plugin/index.tsx new file mode 100644 index 0000000000..1553d9fb16 --- /dev/null +++ b/packages/richtext-lexical/src/features/debug/jsxConverter/client/plugin/index.tsx @@ -0,0 +1,20 @@ +'use client' + +import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext' +import { useEffect, useState } from 'react' + +// eslint-disable-next-line payload/no-imports-from-exports-dir +import { defaultJSXConverters, RichText } from '../../../../../exports/react/index.js' + +export function RichTextPlugin() { + const [editor] = useLexicalComposerContext() + const [editorState, setEditorState] = useState(editor.getEditorState().toJSON()) + + useEffect(() => { + return editor.registerUpdateListener(({ editorState }) => { + setEditorState(editorState.toJSON()) + }) + }, [editor]) + + return +} diff --git a/packages/richtext-lexical/src/features/debug/jsxConverter/server/index.ts b/packages/richtext-lexical/src/features/debug/jsxConverter/server/index.ts new file mode 100644 index 0000000000..29bac144ef --- /dev/null +++ b/packages/richtext-lexical/src/features/debug/jsxConverter/server/index.ts @@ -0,0 +1,8 @@ +import { createServerFeature } from '../../../../utilities/createServerFeature.js' + +export const DebugJsxConverterFeature = createServerFeature({ + feature: { + ClientFeature: '@payloadcms/richtext-lexical/client#DebugJsxConverterFeatureClient', + }, + key: 'jsxConverter', +}) diff --git a/packages/richtext-lexical/src/index.ts b/packages/richtext-lexical/src/index.ts index d1cc2a8a90..78f6b95551 100644 --- a/packages/richtext-lexical/src/index.ts +++ b/packages/richtext-lexical/src/index.ts @@ -901,6 +901,7 @@ export { HTMLConverterFeature, type HTMLConverterFeatureProps, } from './features/converters/lexicalToHtml_deprecated/index.js' +export { DebugJsxConverterFeature } from './features/debug/jsxConverter/server/index.js' export { convertLexicalToMarkdown } from './features/converters/lexicalToMarkdown/index.js' export { convertMarkdownToLexical } from './features/converters/markdownToLexical/index.js' From d47b753898085f5dc83f68f043e74ae5877c50c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Thu, 3 Apr 2025 10:06:25 -0300 Subject: [PATCH 64/77] chore(plugin-cloud-storage): enable TypeScript strict (#11850) --- packages/plugin-cloud-storage/src/admin/fields/getFields.ts | 4 ++-- packages/plugin-cloud-storage/src/fields/getFields.ts | 4 ++-- packages/plugin-cloud-storage/src/hooks/afterDelete.ts | 4 +++- packages/plugin-cloud-storage/src/hooks/afterRead.ts | 2 +- packages/plugin-cloud-storage/src/hooks/beforeChange.ts | 2 +- packages/plugin-cloud-storage/src/plugin.ts | 3 --- .../plugin-cloud-storage/src/utilities/initClientUploads.ts | 2 +- packages/plugin-cloud-storage/tsconfig.json | 5 ----- 8 files changed, 10 insertions(+), 16 deletions(-) diff --git a/packages/plugin-cloud-storage/src/admin/fields/getFields.ts b/packages/plugin-cloud-storage/src/admin/fields/getFields.ts index 30f9070ee6..ea58964b5a 100644 --- a/packages/plugin-cloud-storage/src/admin/fields/getFields.ts +++ b/packages/plugin-cloud-storage/src/admin/fields/getFields.ts @@ -88,11 +88,11 @@ export const getFields = ({ collection, prefix }: Args): Field[] => { type: 'group', fields: [ { - ...(existingSizeURLField || ({} as any)), + ...(existingSizeURLField || {}), ...baseURLField, }, ], - } + } as Field }), } diff --git a/packages/plugin-cloud-storage/src/fields/getFields.ts b/packages/plugin-cloud-storage/src/fields/getFields.ts index 63c0b3662b..acfe138ed9 100644 --- a/packages/plugin-cloud-storage/src/fields/getFields.ts +++ b/packages/plugin-cloud-storage/src/fields/getFields.ts @@ -108,7 +108,7 @@ export const getFields = ({ fields: [ ...(adapter.fields || []), { - ...(existingSizeURLField || ({} as any)), + ...(existingSizeURLField || {}), ...baseURLField, hooks: { afterRead: [ @@ -124,7 +124,7 @@ export const getFields = ({ }, }, ], - } + } as Field }), } diff --git a/packages/plugin-cloud-storage/src/hooks/afterDelete.ts b/packages/plugin-cloud-storage/src/hooks/afterDelete.ts index 4e63a7a0b8..9eefb7050f 100644 --- a/packages/plugin-cloud-storage/src/hooks/afterDelete.ts +++ b/packages/plugin-cloud-storage/src/hooks/afterDelete.ts @@ -15,7 +15,9 @@ export const getAfterDeleteHook = ({ try { const filesToDelete: string[] = [ doc.filename, - ...Object.values(doc?.sizes || []).map((resizedFileData) => resizedFileData?.filename), + ...Object.values(doc?.sizes || []).map( + (resizedFileData) => resizedFileData?.filename as string, + ), ] const promises = filesToDelete.map(async (filename) => { diff --git a/packages/plugin-cloud-storage/src/hooks/afterRead.ts b/packages/plugin-cloud-storage/src/hooks/afterRead.ts index 7e83fa564a..6fdf961888 100644 --- a/packages/plugin-cloud-storage/src/hooks/afterRead.ts +++ b/packages/plugin-cloud-storage/src/hooks/afterRead.ts @@ -18,7 +18,7 @@ export const getAfterReadHook = let url = value if (disablePayloadAccessControl && filename) { - url = await adapter.generateURL({ + url = await adapter.generateURL?.({ collection, data, filename, diff --git a/packages/plugin-cloud-storage/src/hooks/beforeChange.ts b/packages/plugin-cloud-storage/src/hooks/beforeChange.ts index 0503ba5b0c..c2aa74484b 100644 --- a/packages/plugin-cloud-storage/src/hooks/beforeChange.ts +++ b/packages/plugin-cloud-storage/src/hooks/beforeChange.ts @@ -29,7 +29,7 @@ export const getBeforeChangeHook = if (typeof originalDoc.sizes === 'object') { filesToDelete = filesToDelete.concat( Object.values(originalDoc?.sizes || []).map( - (resizedFileData) => resizedFileData?.filename, + (resizedFileData) => resizedFileData?.filename as string, ), ) } diff --git a/packages/plugin-cloud-storage/src/plugin.ts b/packages/plugin-cloud-storage/src/plugin.ts index ae789cc936..90b8daac24 100644 --- a/packages/plugin-cloud-storage/src/plugin.ts +++ b/packages/plugin-cloud-storage/src/plugin.ts @@ -67,9 +67,6 @@ export const cloudStoragePlugin = if ('clientUploadContext' in args.params) { return adapter.staticHandler(req, args) } - - // Otherwise still skip staticHandler - return null }) } diff --git a/packages/plugin-cloud-storage/src/utilities/initClientUploads.ts b/packages/plugin-cloud-storage/src/utilities/initClientUploads.ts index 0fb0acec67..2062b29384 100644 --- a/packages/plugin-cloud-storage/src/utilities/initClientUploads.ts +++ b/packages/plugin-cloud-storage/src/utilities/initClientUploads.ts @@ -89,7 +89,7 @@ export const initClientUploads = , T> clientProps: { collectionSlug, enabled, - extra: extraClientHandlerProps ? extraClientHandlerProps(collection) : undefined, + extra: extraClientHandlerProps ? extraClientHandlerProps(collection!) : undefined, prefix, serverHandlerPath, }, diff --git a/packages/plugin-cloud-storage/tsconfig.json b/packages/plugin-cloud-storage/tsconfig.json index 6c57b9f880..dd036fd84f 100644 --- a/packages/plugin-cloud-storage/tsconfig.json +++ b/packages/plugin-cloud-storage/tsconfig.json @@ -1,9 +1,4 @@ { "extends": "../../tsconfig.base.json", - "compilerOptions": { - /* TODO: remove the following lines */ - "strict": false, - "noUncheckedIndexedAccess": false, - }, "references": [{ "path": "../payload" }, { "path": "../ui" }] } From 857e984fbb39284b525056258607b8117f68cc7c Mon Sep 17 00:00:00 2001 From: Sasha <64744993+r1tsuu@users.noreply.github.com> Date: Thu, 3 Apr 2025 16:07:10 +0300 Subject: [PATCH 65/77] fix(db-mongodb): querying relationships with where clause as an object with several conditions (#11953) Fixes https://github.com/payloadcms/payload/issues/11927 When trying to use the following notation: ```ts const { docs } = await payload.find({ collection: 'movies', depth: 0, where: { 'director.name': { equals: 'Director1' }, 'director.localized': { equals: 'Director1_Localized' }, }, }) ``` Currently, it respects only the latest condition and the first is ignored. However, this works fine: ```ts const { docs } = await payload.find({ collection: 'movies', depth: 0, where: { and: [ { 'director.name': { equals: 'Director1' }, }, { 'director.localized': { equals: 'Director1_Localized' }, }, ], }, }) ``` But this should be an equivalent to ``` where: { 'director.name': { equals: 'Director1' }, 'director.localized': { equals: 'Director1_Localized' }, }, ``` --- .../db-mongodb/src/queries/parseParams.ts | 14 +++++++- test/relationships/int.spec.ts | 35 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/packages/db-mongodb/src/queries/parseParams.ts b/packages/db-mongodb/src/queries/parseParams.ts index fc4e75ab38..7f49da8146 100644 --- a/packages/db-mongodb/src/queries/parseParams.ts +++ b/packages/db-mongodb/src/queries/parseParams.ts @@ -81,7 +81,19 @@ export async function parseParams({ [searchParam.path]: searchParam.value, }) } else { - result[searchParam.path] = searchParam.value + if (result[searchParam.path]) { + if (!result.$and) { + result.$and = [] + } + + result.$and.push({ [searchParam.path]: result[searchParam.path] }) + result.$and.push({ + [searchParam.path]: searchParam.value, + }) + delete result[searchParam.path] + } else { + result[searchParam.path] = searchParam.value + } } } else if (typeof searchParam?.value === 'object') { result = deepMergeWithCombinedArrays(result, searchParam.value ?? {}, { diff --git a/test/relationships/int.spec.ts b/test/relationships/int.spec.ts index 1502409659..3694df14f5 100644 --- a/test/relationships/int.spec.ts +++ b/test/relationships/int.spec.ts @@ -336,6 +336,41 @@ describe('Relationships', () => { expect(query.docs).toHaveLength(1) // Due to limit: 1 }) + it('should allow querying by relationships with an object where as AND', async () => { + const director = await payload.create({ + collection: 'directors', + data: { name: 'Director1', localized: 'Director1_Localized' }, + }) + + const movie = await payload.create({ + collection: 'movies', + data: { director: director.id }, + depth: 0, + }) + + const { docs: trueRes } = await payload.find({ + collection: 'movies', + depth: 0, + where: { + 'director.name': { equals: 'Director1' }, + 'director.localized': { equals: 'Director1_Localized' }, + }, + }) + + expect(trueRes).toStrictEqual([movie]) + + const { docs: falseRes } = await payload.find({ + collection: 'movies', + depth: 0, + where: { + 'director.name': { equals: 'Director1_Fake' }, + 'director.localized': { equals: 'Director1_Localized' }, + }, + }) + + expect(falseRes).toStrictEqual([]) + }) + it('should allow querying within blocks', async () => { const rel = await payload.create({ collection: relationSlug, From 816fb28f552dfefc11704c7b379ca7fb31abd687 Mon Sep 17 00:00:00 2001 From: Said Akhrarov <36972061+akhrarovsaid@users.noreply.github.com> Date: Thu, 3 Apr 2025 09:17:19 -0400 Subject: [PATCH 66/77] feat(ui): use drag overlay in orderable table (#11959) ### What? This PR introduces a new `DragOverlay` to the existing `OrderableTable` component along with a few new utility components. This enables a more fluid and seamless drag-and-drop experience for end-users who have enabled `orderable: true` on their collections. ### Why? Previously, the rows in the `OrderableTable` component were confined within the table element that renders them. This is troublesome for a few reasons: - It clips rows when dragging even slightly outside of the bounds of the table. - It creates unnecessary scrollbars within the containing element as the container is not geared for comprehensive drag-and-drop interactions. ### How? Introducing a `DragOverlay` component gives the draggable rows an area to render freely without clipping. This PR also introduces a new `OrderableRow` (for rendering orderable rows in the table as well as in a drag preview), and an `OrderableRowDragPreview` component to render a drag-preview of the active row 1:1 as you would see in the table without violating HTML rules. This PR also adds an `onDragStart` event handler to the `DraggableDroppable` component to allow for listening for the start of a drag event, necessary for interactions with a `DragOverlay` to communicate which row initiated the event. Before: [orderable-before.webm](https://github.com/user-attachments/assets/ccf32bb0-91db-44f3-8c2a-4f81bb762529) After: [orderable-after.webm](https://github.com/user-attachments/assets/d320e7e6-fab8-4ea4-9cb1-38b581cbc50e) After (With overflow on page): [orderable-overflow-y.webm](https://github.com/user-attachments/assets/418b9018-901d-4217-980c-8d04d58d19c8) --- .../src/elements/DraggableSortable/index.tsx | 20 ++++++- .../src/elements/DraggableSortable/types.ts | 3 +- .../ui/src/elements/Table/OrderableRow.tsx | 47 +++++++++++++++ .../Table/OrderableRowDragPreview.tsx | 16 +++++ .../ui/src/elements/Table/OrderableTable.tsx | 60 ++++++++++--------- packages/ui/src/elements/Table/index.scss | 5 ++ 6 files changed, 120 insertions(+), 31 deletions(-) create mode 100644 packages/ui/src/elements/Table/OrderableRow.tsx create mode 100644 packages/ui/src/elements/Table/OrderableRowDragPreview.tsx diff --git a/packages/ui/src/elements/DraggableSortable/index.tsx b/packages/ui/src/elements/DraggableSortable/index.tsx index d76ffc7f93..8536b27208 100644 --- a/packages/ui/src/elements/DraggableSortable/index.tsx +++ b/packages/ui/src/elements/DraggableSortable/index.tsx @@ -1,5 +1,5 @@ 'use client' -import type { DragEndEvent } from '@dnd-kit/core' +import type { DragEndEvent, DragStartEvent } from '@dnd-kit/core' import { closestCenter, @@ -18,7 +18,7 @@ import type { Props } from './types.js' export { Props } export const DraggableSortable: React.FC = (props) => { - const { children, className, ids, onDragEnd } = props + const { children, className, ids, onDragEnd, onDragStart } = props const id = useId() @@ -58,11 +58,27 @@ export const DraggableSortable: React.FC = (props) => { [onDragEnd, ids], ) + const handleDragStart = useCallback( + (event: DragStartEvent) => { + const { active } = event + + if (!active) { + return + } + + if (typeof onDragStart === 'function') { + onDragStart({ id: active.id, event }) + } + }, + [onDragStart], + ) + return ( diff --git a/packages/ui/src/elements/DraggableSortable/types.ts b/packages/ui/src/elements/DraggableSortable/types.ts index 302ec1ac87..b6e16efecb 100644 --- a/packages/ui/src/elements/DraggableSortable/types.ts +++ b/packages/ui/src/elements/DraggableSortable/types.ts @@ -1,4 +1,4 @@ -import type { DragEndEvent } from '@dnd-kit/core' +import type { DragEndEvent, DragStartEvent } from '@dnd-kit/core' import type { Ref } from 'react' export type Props = { @@ -7,4 +7,5 @@ export type Props = { droppableRef?: Ref ids: string[] onDragEnd: (e: { event: DragEndEvent; moveFromIndex: number; moveToIndex: number }) => void + onDragStart?: (e: { event: DragStartEvent; id: number | string }) => void } diff --git a/packages/ui/src/elements/Table/OrderableRow.tsx b/packages/ui/src/elements/Table/OrderableRow.tsx new file mode 100644 index 0000000000..9bb23d3c1f --- /dev/null +++ b/packages/ui/src/elements/Table/OrderableRow.tsx @@ -0,0 +1,47 @@ +import type { DraggableSyntheticListeners } from '@dnd-kit/core' +import type { Column } from 'payload' +import type { HTMLAttributes, Ref } from 'react' + +export type Props = { + readonly cellMap: Record + readonly columns: Column[] + readonly dragAttributes?: HTMLAttributes + readonly dragListeners?: DraggableSyntheticListeners + readonly ref?: Ref + readonly rowId: number | string +} & HTMLAttributes + +export const OrderableRow = ({ + cellMap, + columns, + dragAttributes = {}, + dragListeners = {}, + rowId, + ...rest +}: Props) => ( +
    + {columns.map((col, colIndex) => { + const { accessor } = col + + // Use the cellMap to find which index in the renderedCells to use + const cell = col.renderedCells[cellMap[rowId]] + + // For drag handles, wrap in div with drag attributes + if (accessor === '_dragHandle') { + return ( + + ) + } + + return ( + + ) + })} + +) diff --git a/packages/ui/src/elements/Table/OrderableRowDragPreview.tsx b/packages/ui/src/elements/Table/OrderableRowDragPreview.tsx new file mode 100644 index 0000000000..e16134dd77 --- /dev/null +++ b/packages/ui/src/elements/Table/OrderableRowDragPreview.tsx @@ -0,0 +1,16 @@ +import type { ReactNode } from 'react' + +export type Props = { + readonly children: ReactNode + readonly className?: string + readonly rowId?: number | string +} + +export const OrderableRowDragPreview = ({ children, className, rowId }: Props) => + typeof rowId === 'undefined' ? null : ( +
    +
    +
    + {cell} +
    +
    + {cell} +
    + {children} +
    +
    + ) diff --git a/packages/ui/src/elements/Table/OrderableTable.tsx b/packages/ui/src/elements/Table/OrderableTable.tsx index a25aee1476..e00d210354 100644 --- a/packages/ui/src/elements/Table/OrderableTable.tsx +++ b/packages/ui/src/elements/Table/OrderableTable.tsx @@ -4,12 +4,15 @@ import type { ClientCollectionConfig, Column, OrderableEndpointBody } from 'payl import './index.scss' +import { DragOverlay } from '@dnd-kit/core' import React, { useEffect, useState } from 'react' import { toast } from 'sonner' import { useListQuery } from '../../providers/ListQuery/index.js' import { DraggableSortableItem } from '../DraggableSortable/DraggableSortableItem/index.js' import { DraggableSortable } from '../DraggableSortable/index.js' +import { OrderableRow } from './OrderableRow.js' +import { OrderableRowDragPreview } from './OrderableRowDragPreview.js' const baseClass = 'table' @@ -36,6 +39,8 @@ export const OrderableTable: React.FC = ({ // id -> index for each column const [cellMap, setCellMap] = useState>({}) + const [dragActiveRowId, setDragActiveRowId] = useState() + // Update local data when server data changes useEffect(() => { setLocalData(serverData) @@ -56,10 +61,12 @@ export const OrderableTable: React.FC = ({ const handleDragEnd = async ({ moveFromIndex, moveToIndex }) => { if (query.sort !== orderableFieldName && query.sort !== `-${orderableFieldName}`) { toast.warning('To reorder the rows you must first sort them by the "Order" column') + setDragActiveRowId(undefined) return } if (moveFromIndex === moveToIndex) { + setDragActiveRowId(undefined) return } @@ -129,9 +136,15 @@ export const OrderableTable: React.FC = ({ // Rollback to previous state if the request fails setLocalData(previousData) toast.error(error) + } finally { + setDragActiveRowId(undefined) } } + const handleDragStart = ({ id }) => { + setDragActiveRowId(id) + } + const rowIds = localData.map((row) => row.id ?? row._id) return ( @@ -140,7 +153,7 @@ export const OrderableTable: React.FC = ({ .filter(Boolean) .join(' ')} > - + @@ -154,44 +167,35 @@ export const OrderableTable: React.FC = ({ {localData.map((row, rowIndex) => ( - {({ attributes, listeners, setNodeRef, transform, transition }) => ( - ( + - {activeColumns.map((col, colIndex) => { - const { accessor } = col - - // Use the cellMap to find which index in the renderedCells to use - const cell = col.renderedCells[cellMap[row.id ?? row._id]] - - // For drag handles, wrap in div with drag attributes - if (accessor === '_dragHandle') { - return ( - - ) - } - - return ( - - ) - })} - + /> )} ))}
    -
    - {cell} -
    -
    - {cell} -
    + + + + + +
    ) diff --git a/packages/ui/src/elements/Table/index.scss b/packages/ui/src/elements/Table/index.scss index f4c5e5bd01..b984d83766 100644 --- a/packages/ui/src/elements/Table/index.scss +++ b/packages/ui/src/elements/Table/index.scss @@ -96,6 +96,11 @@ } } + &--drag-preview { + cursor: grabbing; + z-index: var(--z-popup); + } + @include mid-break { th, td { From 018bdad247807fffc6029c31ffa4acb0842d856e Mon Sep 17 00:00:00 2001 From: reiv Date: Thu, 3 Apr 2025 17:17:23 +0200 Subject: [PATCH 67/77] feat(graphql): improve non-nullability in query result types (#11952) ### What? Makes several fields and list item types in query results (e.g. `docs`) non-nullable. ### Why? When dealing with code generated from a Payload GraphQL schema, it is often necessary to use type guards and optional chaining. For example: ```graphql type Posts { docs: [Post] ... } ``` This implies that the `docs` field itself is nullable and that the array can contain nulls. In reality, neither of these is true. But because of the types generated by tools like `graphql-code-generator`, the way to access `posts` ends up something like this: ```ts const posts = (query.data.docs ?? []).filter(doc => doc != null); ``` Instead, we would like the schema to be: ```graphql type Posts { docs: [Post!]! ... } ``` ### How? The proposed change involves adding `GraphQLNonNull` where appropriate. --------- Co-authored-by: Dan Ribbens --- .../src/schema/buildPaginatedListType.ts | 22 +- .../graphql/src/schema/fieldToSchemaMap.ts | 19 +- test/_community/schema.graphql | 3375 ++++++++++++++--- 3 files changed, 2896 insertions(+), 520 deletions(-) diff --git a/packages/graphql/src/schema/buildPaginatedListType.ts b/packages/graphql/src/schema/buildPaginatedListType.ts index 296bee0a78..343fd28cba 100644 --- a/packages/graphql/src/schema/buildPaginatedListType.ts +++ b/packages/graphql/src/schema/buildPaginatedListType.ts @@ -1,21 +1,21 @@ -import { GraphQLBoolean, GraphQLInt, GraphQLList, GraphQLObjectType } from 'graphql' +import { GraphQLBoolean, GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLObjectType } from 'graphql' export const buildPaginatedListType = (name, docType) => new GraphQLObjectType({ name, fields: { docs: { - type: new GraphQLList(docType), + type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(docType))), }, - hasNextPage: { type: GraphQLBoolean }, - hasPrevPage: { type: GraphQLBoolean }, - limit: { type: GraphQLInt }, - nextPage: { type: GraphQLInt }, + hasNextPage: { type: new GraphQLNonNull(GraphQLBoolean) }, + hasPrevPage: { type: new GraphQLNonNull(GraphQLBoolean) }, + limit: { type: new GraphQLNonNull(GraphQLInt) }, + nextPage: { type: new GraphQLNonNull(GraphQLInt) }, offset: { type: GraphQLInt }, - page: { type: GraphQLInt }, - pagingCounter: { type: GraphQLInt }, - prevPage: { type: GraphQLInt }, - totalDocs: { type: GraphQLInt }, - totalPages: { type: GraphQLInt }, + page: { type: new GraphQLNonNull(GraphQLInt) }, + pagingCounter: { type: new GraphQLNonNull(GraphQLInt) }, + prevPage: { type: new GraphQLNonNull(GraphQLInt) }, + totalDocs: { type: new GraphQLNonNull(GraphQLInt) }, + totalPages: { type: new GraphQLNonNull(GraphQLInt) }, }, }) diff --git a/packages/graphql/src/schema/fieldToSchemaMap.ts b/packages/graphql/src/schema/fieldToSchemaMap.ts index 452182996b..fefd598393 100644 --- a/packages/graphql/src/schema/fieldToSchemaMap.ts +++ b/packages/graphql/src/schema/fieldToSchemaMap.ts @@ -348,11 +348,15 @@ export const fieldToSchemaMap: FieldToSchemaMap = { name: joinName, fields: { docs: { - type: Array.isArray(field.collection) - ? GraphQLJSON - : new GraphQLList(graphqlResult.collections[field.collection].graphQL.type), + type: new GraphQLNonNull( + Array.isArray(field.collection) + ? GraphQLJSON + : new GraphQLList( + new GraphQLNonNull(graphqlResult.collections[field.collection].graphQL.type), + ), + ), }, - hasNextPage: { type: GraphQLBoolean }, + hasNextPage: { type: new GraphQLNonNull(GraphQLBoolean) }, }, }), args: { @@ -428,7 +432,7 @@ export const fieldToSchemaMap: FieldToSchemaMap = { ...objectTypeConfig, [formatName(field.name)]: formattedNameResolver({ type: withNullableType({ - type: field?.hasMany === true ? new GraphQLList(type) : type, + type: field?.hasMany === true ? new GraphQLList(new GraphQLNonNull(type)) : type, field, forceNullable, parentIsLocalized, @@ -856,7 +860,10 @@ export const fieldToSchemaMap: FieldToSchemaMap = { ...objectTypeConfig, [formatName(field.name)]: formattedNameResolver({ type: withNullableType({ - type: field.hasMany === true ? new GraphQLList(GraphQLString) : GraphQLString, + type: + field.hasMany === true + ? new GraphQLList(new GraphQLNonNull(GraphQLString)) + : GraphQLString, field, forceNullable, parentIsLocalized, diff --git a/test/_community/schema.graphql b/test/_community/schema.graphql index 1038d843d6..c35db21ee7 100644 --- a/test/_community/schema.graphql +++ b/test/_community/schema.graphql @@ -1,24 +1,24 @@ type Query { Post(id: String!, draft: Boolean): Post - Posts(draft: Boolean, where: Post_where, limit: Int, page: Int, sort: String): Posts + Posts(draft: Boolean, where: Post_where, limit: Int, page: Int, pagination: Boolean, sort: String): Posts countPosts(draft: Boolean, where: Post_where): countPosts docAccessPost(id: String!): postsDocAccess - versionPost(id: String): PostVersion - versionsPosts(where: versionsPost_where, limit: Int, page: Int, sort: String): versionsPosts + Media(id: String!, draft: Boolean): Media + allMedia(draft: Boolean, where: Media_where, limit: Int, page: Int, pagination: Boolean, sort: String): allMedia + countallMedia(draft: Boolean, where: Media_where): countallMedia + docAccessMedia(id: String!): mediaDocAccess User(id: String!, draft: Boolean): User - Users(draft: Boolean, where: User_where, limit: Int, page: Int, sort: String): Users + Users(draft: Boolean, where: User_where, limit: Int, page: Int, pagination: Boolean, sort: String): Users countUsers(draft: Boolean, where: User_where): countUsers docAccessUser(id: String!): usersDocAccess meUser: usersMe initializedUser: Boolean + PayloadLockedDocument(id: String!, draft: Boolean): PayloadLockedDocument + PayloadLockedDocuments(draft: Boolean, where: PayloadLockedDocument_where, limit: Int, page: Int, pagination: Boolean, sort: String): PayloadLockedDocuments + countPayloadLockedDocuments(draft: Boolean, where: PayloadLockedDocument_where): countPayloadLockedDocuments + docAccessPayloadLockedDocument(id: String!): payload_locked_documentsDocAccess PayloadPreference(id: String!, draft: Boolean): PayloadPreference - PayloadPreferences( - draft: Boolean - where: PayloadPreference_where - limit: Int - page: Int - sort: String - ): PayloadPreferences + PayloadPreferences(draft: Boolean, where: PayloadPreference_where, limit: Int, page: Int, pagination: Boolean, sort: String): PayloadPreferences countPayloadPreferences(draft: Boolean, where: PayloadPreference_where): countPayloadPreferences docAccessPayloadPreference(id: String!): payload_preferencesDocAccess Menu(draft: Boolean): Menu @@ -27,58 +27,48 @@ type Query { } type Post { - id: String - text: String - richText(depth: Int): JSON - richText2(depth: Int): JSON + id: String! + title: String + content(depth: Int): JSON updatedAt: DateTime createdAt: DateTime - _status: Post__status } """ The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). """ -scalar JSON - @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf") +scalar JSON @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf") """ A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `date-time` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar. """ scalar DateTime -enum Post__status { - draft - published -} - type Posts { - docs: [Post] - hasNextPage: Boolean - hasPrevPage: Boolean - limit: Int - nextPage: Int + docs: [Post!]! + hasNextPage: Boolean! + hasPrevPage: Boolean! + limit: Int! + nextPage: Int! offset: Int - page: Int - pagingCounter: Int - prevPage: Int - totalDocs: Int - totalPages: Int + page: Int! + pagingCounter: Int! + prevPage: Int! + totalDocs: Int! + totalPages: Int! } input Post_where { - text: Post_text_operator - richText: Post_richText_operator - richText2: Post_richText2_operator + title: Post_title_operator + content: Post_content_operator updatedAt: Post_updatedAt_operator createdAt: Post_createdAt_operator - _status: Post__status_operator id: Post_id_operator AND: [Post_where_and] OR: [Post_where_or] } -input Post_text_operator { +input Post_title_operator { equals: String not_equals: String like: String @@ -89,15 +79,7 @@ input Post_text_operator { exists: Boolean } -input Post_richText_operator { - equals: JSON - not_equals: JSON - like: JSON - contains: JSON - exists: Boolean -} - -input Post_richText2_operator { +input Post_content_operator { equals: JSON not_equals: JSON like: JSON @@ -127,20 +109,6 @@ input Post_createdAt_operator { exists: Boolean } -input Post__status_operator { - equals: Post__status_Input - not_equals: Post__status_Input - in: [Post__status_Input] - not_in: [Post__status_Input] - all: [Post__status_Input] - exists: Boolean -} - -enum Post__status_Input { - draft - published -} - input Post_id_operator { equals: String not_equals: String @@ -153,24 +121,20 @@ input Post_id_operator { } input Post_where_and { - text: Post_text_operator - richText: Post_richText_operator - richText2: Post_richText2_operator + title: Post_title_operator + content: Post_content_operator updatedAt: Post_updatedAt_operator createdAt: Post_createdAt_operator - _status: Post__status_operator id: Post_id_operator AND: [Post_where_and] OR: [Post_where_or] } input Post_where_or { - text: Post_text_operator - richText: Post_richText_operator - richText2: Post_richText2_operator + title: Post_title_operator + content: Post_content_operator updatedAt: Post_updatedAt_operator createdAt: Post_createdAt_operator - _status: Post__status_operator id: Post_id_operator AND: [Post_where_and] OR: [Post_where_or] @@ -186,84 +150,58 @@ type postsDocAccess { read: PostsReadDocAccess update: PostsUpdateDocAccess delete: PostsDeleteDocAccess - readVersions: PostsReadVersionsDocAccess } type PostsDocAccessFields { - text: PostsDocAccessFields_text - richText: PostsDocAccessFields_richText - richText2: PostsDocAccessFields_richText2 + title: PostsDocAccessFields_title + content: PostsDocAccessFields_content updatedAt: PostsDocAccessFields_updatedAt createdAt: PostsDocAccessFields_createdAt - _status: PostsDocAccessFields__status } -type PostsDocAccessFields_text { - create: PostsDocAccessFields_text_Create - read: PostsDocAccessFields_text_Read - update: PostsDocAccessFields_text_Update - delete: PostsDocAccessFields_text_Delete +type PostsDocAccessFields_title { + create: PostsDocAccessFields_title_Create + read: PostsDocAccessFields_title_Read + update: PostsDocAccessFields_title_Update + delete: PostsDocAccessFields_title_Delete } -type PostsDocAccessFields_text_Create { +type PostsDocAccessFields_title_Create { permission: Boolean! } -type PostsDocAccessFields_text_Read { +type PostsDocAccessFields_title_Read { permission: Boolean! } -type PostsDocAccessFields_text_Update { +type PostsDocAccessFields_title_Update { permission: Boolean! } -type PostsDocAccessFields_text_Delete { +type PostsDocAccessFields_title_Delete { permission: Boolean! } -type PostsDocAccessFields_richText { - create: PostsDocAccessFields_richText_Create - read: PostsDocAccessFields_richText_Read - update: PostsDocAccessFields_richText_Update - delete: PostsDocAccessFields_richText_Delete +type PostsDocAccessFields_content { + create: PostsDocAccessFields_content_Create + read: PostsDocAccessFields_content_Read + update: PostsDocAccessFields_content_Update + delete: PostsDocAccessFields_content_Delete } -type PostsDocAccessFields_richText_Create { +type PostsDocAccessFields_content_Create { permission: Boolean! } -type PostsDocAccessFields_richText_Read { +type PostsDocAccessFields_content_Read { permission: Boolean! } -type PostsDocAccessFields_richText_Update { +type PostsDocAccessFields_content_Update { permission: Boolean! } -type PostsDocAccessFields_richText_Delete { - permission: Boolean! -} - -type PostsDocAccessFields_richText2 { - create: PostsDocAccessFields_richText2_Create - read: PostsDocAccessFields_richText2_Read - update: PostsDocAccessFields_richText2_Update - delete: PostsDocAccessFields_richText2_Delete -} - -type PostsDocAccessFields_richText2_Create { - permission: Boolean! -} - -type PostsDocAccessFields_richText2_Read { - permission: Boolean! -} - -type PostsDocAccessFields_richText2_Update { - permission: Boolean! -} - -type PostsDocAccessFields_richText2_Delete { +type PostsDocAccessFields_content_Delete { permission: Boolean! } @@ -313,29 +251,6 @@ type PostsDocAccessFields_createdAt_Delete { permission: Boolean! } -type PostsDocAccessFields__status { - create: PostsDocAccessFields__status_Create - read: PostsDocAccessFields__status_Read - update: PostsDocAccessFields__status_Update - delete: PostsDocAccessFields__status_Delete -} - -type PostsDocAccessFields__status_Create { - permission: Boolean! -} - -type PostsDocAccessFields__status_Read { - permission: Boolean! -} - -type PostsDocAccessFields__status_Update { - permission: Boolean! -} - -type PostsDocAccessFields__status_Delete { - permission: Boolean! -} - type PostsCreateDocAccess { permission: Boolean! where: JSONObject @@ -344,8 +259,7 @@ type PostsCreateDocAccess { """ The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). """ -scalar JSONObject - @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf") +scalar JSONObject @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf") type PostsReadDocAccess { permission: Boolean! @@ -362,209 +276,1335 @@ type PostsDeleteDocAccess { where: JSONObject } -type PostsReadVersionsDocAccess { +type Media { + id: String! + updatedAt: DateTime + createdAt: DateTime + url: String + thumbnailURL: String + filename: String + mimeType: String + filesize: Float + width: Float + height: Float + focalX: Float + focalY: Float + sizes: Media_Sizes +} + +type Media_Sizes { + thumbnail: Media_Sizes_Thumbnail + medium: Media_Sizes_Medium + large: Media_Sizes_Large +} + +type Media_Sizes_Thumbnail { + url: String + width: Float + height: Float + mimeType: String + filesize: Float + filename: String +} + +type Media_Sizes_Medium { + url: String + width: Float + height: Float + mimeType: String + filesize: Float + filename: String +} + +type Media_Sizes_Large { + url: String + width: Float + height: Float + mimeType: String + filesize: Float + filename: String +} + +type allMedia { + docs: [Media!]! + hasNextPage: Boolean! + hasPrevPage: Boolean! + limit: Int! + nextPage: Int! + offset: Int + page: Int! + pagingCounter: Int! + prevPage: Int! + totalDocs: Int! + totalPages: Int! +} + +input Media_where { + updatedAt: Media_updatedAt_operator + createdAt: Media_createdAt_operator + url: Media_url_operator + thumbnailURL: Media_thumbnailURL_operator + filename: Media_filename_operator + mimeType: Media_mimeType_operator + filesize: Media_filesize_operator + width: Media_width_operator + height: Media_height_operator + focalX: Media_focalX_operator + focalY: Media_focalY_operator + sizes__thumbnail__url: Media_sizes__thumbnail__url_operator + sizes__thumbnail__width: Media_sizes__thumbnail__width_operator + sizes__thumbnail__height: Media_sizes__thumbnail__height_operator + sizes__thumbnail__mimeType: Media_sizes__thumbnail__mimeType_operator + sizes__thumbnail__filesize: Media_sizes__thumbnail__filesize_operator + sizes__thumbnail__filename: Media_sizes__thumbnail__filename_operator + sizes__medium__url: Media_sizes__medium__url_operator + sizes__medium__width: Media_sizes__medium__width_operator + sizes__medium__height: Media_sizes__medium__height_operator + sizes__medium__mimeType: Media_sizes__medium__mimeType_operator + sizes__medium__filesize: Media_sizes__medium__filesize_operator + sizes__medium__filename: Media_sizes__medium__filename_operator + sizes__large__url: Media_sizes__large__url_operator + sizes__large__width: Media_sizes__large__width_operator + sizes__large__height: Media_sizes__large__height_operator + sizes__large__mimeType: Media_sizes__large__mimeType_operator + sizes__large__filesize: Media_sizes__large__filesize_operator + sizes__large__filename: Media_sizes__large__filename_operator + id: Media_id_operator + AND: [Media_where_and] + OR: [Media_where_or] +} + +input Media_updatedAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input Media_createdAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input Media_url_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_thumbnailURL_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_filename_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_mimeType_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_filesize_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_width_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_height_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_focalX_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_focalY_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_sizes__thumbnail__url_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_sizes__thumbnail__width_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_sizes__thumbnail__height_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_sizes__thumbnail__mimeType_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_sizes__thumbnail__filesize_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_sizes__thumbnail__filename_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_sizes__medium__url_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_sizes__medium__width_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_sizes__medium__height_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_sizes__medium__mimeType_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_sizes__medium__filesize_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_sizes__medium__filename_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_sizes__large__url_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_sizes__large__width_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_sizes__large__height_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_sizes__large__mimeType_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_sizes__large__filesize_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_sizes__large__filename_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_id_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_where_and { + updatedAt: Media_updatedAt_operator + createdAt: Media_createdAt_operator + url: Media_url_operator + thumbnailURL: Media_thumbnailURL_operator + filename: Media_filename_operator + mimeType: Media_mimeType_operator + filesize: Media_filesize_operator + width: Media_width_operator + height: Media_height_operator + focalX: Media_focalX_operator + focalY: Media_focalY_operator + sizes__thumbnail__url: Media_sizes__thumbnail__url_operator + sizes__thumbnail__width: Media_sizes__thumbnail__width_operator + sizes__thumbnail__height: Media_sizes__thumbnail__height_operator + sizes__thumbnail__mimeType: Media_sizes__thumbnail__mimeType_operator + sizes__thumbnail__filesize: Media_sizes__thumbnail__filesize_operator + sizes__thumbnail__filename: Media_sizes__thumbnail__filename_operator + sizes__medium__url: Media_sizes__medium__url_operator + sizes__medium__width: Media_sizes__medium__width_operator + sizes__medium__height: Media_sizes__medium__height_operator + sizes__medium__mimeType: Media_sizes__medium__mimeType_operator + sizes__medium__filesize: Media_sizes__medium__filesize_operator + sizes__medium__filename: Media_sizes__medium__filename_operator + sizes__large__url: Media_sizes__large__url_operator + sizes__large__width: Media_sizes__large__width_operator + sizes__large__height: Media_sizes__large__height_operator + sizes__large__mimeType: Media_sizes__large__mimeType_operator + sizes__large__filesize: Media_sizes__large__filesize_operator + sizes__large__filename: Media_sizes__large__filename_operator + id: Media_id_operator + AND: [Media_where_and] + OR: [Media_where_or] +} + +input Media_where_or { + updatedAt: Media_updatedAt_operator + createdAt: Media_createdAt_operator + url: Media_url_operator + thumbnailURL: Media_thumbnailURL_operator + filename: Media_filename_operator + mimeType: Media_mimeType_operator + filesize: Media_filesize_operator + width: Media_width_operator + height: Media_height_operator + focalX: Media_focalX_operator + focalY: Media_focalY_operator + sizes__thumbnail__url: Media_sizes__thumbnail__url_operator + sizes__thumbnail__width: Media_sizes__thumbnail__width_operator + sizes__thumbnail__height: Media_sizes__thumbnail__height_operator + sizes__thumbnail__mimeType: Media_sizes__thumbnail__mimeType_operator + sizes__thumbnail__filesize: Media_sizes__thumbnail__filesize_operator + sizes__thumbnail__filename: Media_sizes__thumbnail__filename_operator + sizes__medium__url: Media_sizes__medium__url_operator + sizes__medium__width: Media_sizes__medium__width_operator + sizes__medium__height: Media_sizes__medium__height_operator + sizes__medium__mimeType: Media_sizes__medium__mimeType_operator + sizes__medium__filesize: Media_sizes__medium__filesize_operator + sizes__medium__filename: Media_sizes__medium__filename_operator + sizes__large__url: Media_sizes__large__url_operator + sizes__large__width: Media_sizes__large__width_operator + sizes__large__height: Media_sizes__large__height_operator + sizes__large__mimeType: Media_sizes__large__mimeType_operator + sizes__large__filesize: Media_sizes__large__filesize_operator + sizes__large__filename: Media_sizes__large__filename_operator + id: Media_id_operator + AND: [Media_where_and] + OR: [Media_where_or] +} + +type countallMedia { + totalDocs: Int +} + +type mediaDocAccess { + fields: MediaDocAccessFields + create: MediaCreateDocAccess + read: MediaReadDocAccess + update: MediaUpdateDocAccess + delete: MediaDeleteDocAccess +} + +type MediaDocAccessFields { + updatedAt: MediaDocAccessFields_updatedAt + createdAt: MediaDocAccessFields_createdAt + url: MediaDocAccessFields_url + thumbnailURL: MediaDocAccessFields_thumbnailURL + filename: MediaDocAccessFields_filename + mimeType: MediaDocAccessFields_mimeType + filesize: MediaDocAccessFields_filesize + width: MediaDocAccessFields_width + height: MediaDocAccessFields_height + focalX: MediaDocAccessFields_focalX + focalY: MediaDocAccessFields_focalY + sizes: MediaDocAccessFields_sizes +} + +type MediaDocAccessFields_updatedAt { + create: MediaDocAccessFields_updatedAt_Create + read: MediaDocAccessFields_updatedAt_Read + update: MediaDocAccessFields_updatedAt_Update + delete: MediaDocAccessFields_updatedAt_Delete +} + +type MediaDocAccessFields_updatedAt_Create { + permission: Boolean! +} + +type MediaDocAccessFields_updatedAt_Read { + permission: Boolean! +} + +type MediaDocAccessFields_updatedAt_Update { + permission: Boolean! +} + +type MediaDocAccessFields_updatedAt_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_createdAt { + create: MediaDocAccessFields_createdAt_Create + read: MediaDocAccessFields_createdAt_Read + update: MediaDocAccessFields_createdAt_Update + delete: MediaDocAccessFields_createdAt_Delete +} + +type MediaDocAccessFields_createdAt_Create { + permission: Boolean! +} + +type MediaDocAccessFields_createdAt_Read { + permission: Boolean! +} + +type MediaDocAccessFields_createdAt_Update { + permission: Boolean! +} + +type MediaDocAccessFields_createdAt_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_url { + create: MediaDocAccessFields_url_Create + read: MediaDocAccessFields_url_Read + update: MediaDocAccessFields_url_Update + delete: MediaDocAccessFields_url_Delete +} + +type MediaDocAccessFields_url_Create { + permission: Boolean! +} + +type MediaDocAccessFields_url_Read { + permission: Boolean! +} + +type MediaDocAccessFields_url_Update { + permission: Boolean! +} + +type MediaDocAccessFields_url_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_thumbnailURL { + create: MediaDocAccessFields_thumbnailURL_Create + read: MediaDocAccessFields_thumbnailURL_Read + update: MediaDocAccessFields_thumbnailURL_Update + delete: MediaDocAccessFields_thumbnailURL_Delete +} + +type MediaDocAccessFields_thumbnailURL_Create { + permission: Boolean! +} + +type MediaDocAccessFields_thumbnailURL_Read { + permission: Boolean! +} + +type MediaDocAccessFields_thumbnailURL_Update { + permission: Boolean! +} + +type MediaDocAccessFields_thumbnailURL_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_filename { + create: MediaDocAccessFields_filename_Create + read: MediaDocAccessFields_filename_Read + update: MediaDocAccessFields_filename_Update + delete: MediaDocAccessFields_filename_Delete +} + +type MediaDocAccessFields_filename_Create { + permission: Boolean! +} + +type MediaDocAccessFields_filename_Read { + permission: Boolean! +} + +type MediaDocAccessFields_filename_Update { + permission: Boolean! +} + +type MediaDocAccessFields_filename_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_mimeType { + create: MediaDocAccessFields_mimeType_Create + read: MediaDocAccessFields_mimeType_Read + update: MediaDocAccessFields_mimeType_Update + delete: MediaDocAccessFields_mimeType_Delete +} + +type MediaDocAccessFields_mimeType_Create { + permission: Boolean! +} + +type MediaDocAccessFields_mimeType_Read { + permission: Boolean! +} + +type MediaDocAccessFields_mimeType_Update { + permission: Boolean! +} + +type MediaDocAccessFields_mimeType_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_filesize { + create: MediaDocAccessFields_filesize_Create + read: MediaDocAccessFields_filesize_Read + update: MediaDocAccessFields_filesize_Update + delete: MediaDocAccessFields_filesize_Delete +} + +type MediaDocAccessFields_filesize_Create { + permission: Boolean! +} + +type MediaDocAccessFields_filesize_Read { + permission: Boolean! +} + +type MediaDocAccessFields_filesize_Update { + permission: Boolean! +} + +type MediaDocAccessFields_filesize_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_width { + create: MediaDocAccessFields_width_Create + read: MediaDocAccessFields_width_Read + update: MediaDocAccessFields_width_Update + delete: MediaDocAccessFields_width_Delete +} + +type MediaDocAccessFields_width_Create { + permission: Boolean! +} + +type MediaDocAccessFields_width_Read { + permission: Boolean! +} + +type MediaDocAccessFields_width_Update { + permission: Boolean! +} + +type MediaDocAccessFields_width_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_height { + create: MediaDocAccessFields_height_Create + read: MediaDocAccessFields_height_Read + update: MediaDocAccessFields_height_Update + delete: MediaDocAccessFields_height_Delete +} + +type MediaDocAccessFields_height_Create { + permission: Boolean! +} + +type MediaDocAccessFields_height_Read { + permission: Boolean! +} + +type MediaDocAccessFields_height_Update { + permission: Boolean! +} + +type MediaDocAccessFields_height_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_focalX { + create: MediaDocAccessFields_focalX_Create + read: MediaDocAccessFields_focalX_Read + update: MediaDocAccessFields_focalX_Update + delete: MediaDocAccessFields_focalX_Delete +} + +type MediaDocAccessFields_focalX_Create { + permission: Boolean! +} + +type MediaDocAccessFields_focalX_Read { + permission: Boolean! +} + +type MediaDocAccessFields_focalX_Update { + permission: Boolean! +} + +type MediaDocAccessFields_focalX_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_focalY { + create: MediaDocAccessFields_focalY_Create + read: MediaDocAccessFields_focalY_Read + update: MediaDocAccessFields_focalY_Update + delete: MediaDocAccessFields_focalY_Delete +} + +type MediaDocAccessFields_focalY_Create { + permission: Boolean! +} + +type MediaDocAccessFields_focalY_Read { + permission: Boolean! +} + +type MediaDocAccessFields_focalY_Update { + permission: Boolean! +} + +type MediaDocAccessFields_focalY_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes { + create: MediaDocAccessFields_sizes_Create + read: MediaDocAccessFields_sizes_Read + update: MediaDocAccessFields_sizes_Update + delete: MediaDocAccessFields_sizes_Delete + fields: MediaDocAccessFields_sizes_Fields +} + +type MediaDocAccessFields_sizes_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_Fields { + thumbnail: MediaDocAccessFields_sizes_thumbnail + medium: MediaDocAccessFields_sizes_medium + large: MediaDocAccessFields_sizes_large +} + +type MediaDocAccessFields_sizes_thumbnail { + create: MediaDocAccessFields_sizes_thumbnail_Create + read: MediaDocAccessFields_sizes_thumbnail_Read + update: MediaDocAccessFields_sizes_thumbnail_Update + delete: MediaDocAccessFields_sizes_thumbnail_Delete + fields: MediaDocAccessFields_sizes_thumbnail_Fields +} + +type MediaDocAccessFields_sizes_thumbnail_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_Fields { + url: MediaDocAccessFields_sizes_thumbnail_url + width: MediaDocAccessFields_sizes_thumbnail_width + height: MediaDocAccessFields_sizes_thumbnail_height + mimeType: MediaDocAccessFields_sizes_thumbnail_mimeType + filesize: MediaDocAccessFields_sizes_thumbnail_filesize + filename: MediaDocAccessFields_sizes_thumbnail_filename +} + +type MediaDocAccessFields_sizes_thumbnail_url { + create: MediaDocAccessFields_sizes_thumbnail_url_Create + read: MediaDocAccessFields_sizes_thumbnail_url_Read + update: MediaDocAccessFields_sizes_thumbnail_url_Update + delete: MediaDocAccessFields_sizes_thumbnail_url_Delete +} + +type MediaDocAccessFields_sizes_thumbnail_url_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_url_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_url_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_url_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_width { + create: MediaDocAccessFields_sizes_thumbnail_width_Create + read: MediaDocAccessFields_sizes_thumbnail_width_Read + update: MediaDocAccessFields_sizes_thumbnail_width_Update + delete: MediaDocAccessFields_sizes_thumbnail_width_Delete +} + +type MediaDocAccessFields_sizes_thumbnail_width_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_width_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_width_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_width_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_height { + create: MediaDocAccessFields_sizes_thumbnail_height_Create + read: MediaDocAccessFields_sizes_thumbnail_height_Read + update: MediaDocAccessFields_sizes_thumbnail_height_Update + delete: MediaDocAccessFields_sizes_thumbnail_height_Delete +} + +type MediaDocAccessFields_sizes_thumbnail_height_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_height_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_height_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_height_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_mimeType { + create: MediaDocAccessFields_sizes_thumbnail_mimeType_Create + read: MediaDocAccessFields_sizes_thumbnail_mimeType_Read + update: MediaDocAccessFields_sizes_thumbnail_mimeType_Update + delete: MediaDocAccessFields_sizes_thumbnail_mimeType_Delete +} + +type MediaDocAccessFields_sizes_thumbnail_mimeType_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_mimeType_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_mimeType_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_mimeType_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_filesize { + create: MediaDocAccessFields_sizes_thumbnail_filesize_Create + read: MediaDocAccessFields_sizes_thumbnail_filesize_Read + update: MediaDocAccessFields_sizes_thumbnail_filesize_Update + delete: MediaDocAccessFields_sizes_thumbnail_filesize_Delete +} + +type MediaDocAccessFields_sizes_thumbnail_filesize_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_filesize_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_filesize_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_filesize_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_filename { + create: MediaDocAccessFields_sizes_thumbnail_filename_Create + read: MediaDocAccessFields_sizes_thumbnail_filename_Read + update: MediaDocAccessFields_sizes_thumbnail_filename_Update + delete: MediaDocAccessFields_sizes_thumbnail_filename_Delete +} + +type MediaDocAccessFields_sizes_thumbnail_filename_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_filename_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_filename_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_filename_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium { + create: MediaDocAccessFields_sizes_medium_Create + read: MediaDocAccessFields_sizes_medium_Read + update: MediaDocAccessFields_sizes_medium_Update + delete: MediaDocAccessFields_sizes_medium_Delete + fields: MediaDocAccessFields_sizes_medium_Fields +} + +type MediaDocAccessFields_sizes_medium_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_Fields { + url: MediaDocAccessFields_sizes_medium_url + width: MediaDocAccessFields_sizes_medium_width + height: MediaDocAccessFields_sizes_medium_height + mimeType: MediaDocAccessFields_sizes_medium_mimeType + filesize: MediaDocAccessFields_sizes_medium_filesize + filename: MediaDocAccessFields_sizes_medium_filename +} + +type MediaDocAccessFields_sizes_medium_url { + create: MediaDocAccessFields_sizes_medium_url_Create + read: MediaDocAccessFields_sizes_medium_url_Read + update: MediaDocAccessFields_sizes_medium_url_Update + delete: MediaDocAccessFields_sizes_medium_url_Delete +} + +type MediaDocAccessFields_sizes_medium_url_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_url_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_url_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_url_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_width { + create: MediaDocAccessFields_sizes_medium_width_Create + read: MediaDocAccessFields_sizes_medium_width_Read + update: MediaDocAccessFields_sizes_medium_width_Update + delete: MediaDocAccessFields_sizes_medium_width_Delete +} + +type MediaDocAccessFields_sizes_medium_width_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_width_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_width_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_width_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_height { + create: MediaDocAccessFields_sizes_medium_height_Create + read: MediaDocAccessFields_sizes_medium_height_Read + update: MediaDocAccessFields_sizes_medium_height_Update + delete: MediaDocAccessFields_sizes_medium_height_Delete +} + +type MediaDocAccessFields_sizes_medium_height_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_height_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_height_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_height_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_mimeType { + create: MediaDocAccessFields_sizes_medium_mimeType_Create + read: MediaDocAccessFields_sizes_medium_mimeType_Read + update: MediaDocAccessFields_sizes_medium_mimeType_Update + delete: MediaDocAccessFields_sizes_medium_mimeType_Delete +} + +type MediaDocAccessFields_sizes_medium_mimeType_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_mimeType_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_mimeType_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_mimeType_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_filesize { + create: MediaDocAccessFields_sizes_medium_filesize_Create + read: MediaDocAccessFields_sizes_medium_filesize_Read + update: MediaDocAccessFields_sizes_medium_filesize_Update + delete: MediaDocAccessFields_sizes_medium_filesize_Delete +} + +type MediaDocAccessFields_sizes_medium_filesize_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_filesize_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_filesize_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_filesize_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_filename { + create: MediaDocAccessFields_sizes_medium_filename_Create + read: MediaDocAccessFields_sizes_medium_filename_Read + update: MediaDocAccessFields_sizes_medium_filename_Update + delete: MediaDocAccessFields_sizes_medium_filename_Delete +} + +type MediaDocAccessFields_sizes_medium_filename_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_filename_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_filename_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_filename_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large { + create: MediaDocAccessFields_sizes_large_Create + read: MediaDocAccessFields_sizes_large_Read + update: MediaDocAccessFields_sizes_large_Update + delete: MediaDocAccessFields_sizes_large_Delete + fields: MediaDocAccessFields_sizes_large_Fields +} + +type MediaDocAccessFields_sizes_large_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_Fields { + url: MediaDocAccessFields_sizes_large_url + width: MediaDocAccessFields_sizes_large_width + height: MediaDocAccessFields_sizes_large_height + mimeType: MediaDocAccessFields_sizes_large_mimeType + filesize: MediaDocAccessFields_sizes_large_filesize + filename: MediaDocAccessFields_sizes_large_filename +} + +type MediaDocAccessFields_sizes_large_url { + create: MediaDocAccessFields_sizes_large_url_Create + read: MediaDocAccessFields_sizes_large_url_Read + update: MediaDocAccessFields_sizes_large_url_Update + delete: MediaDocAccessFields_sizes_large_url_Delete +} + +type MediaDocAccessFields_sizes_large_url_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_url_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_url_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_url_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_width { + create: MediaDocAccessFields_sizes_large_width_Create + read: MediaDocAccessFields_sizes_large_width_Read + update: MediaDocAccessFields_sizes_large_width_Update + delete: MediaDocAccessFields_sizes_large_width_Delete +} + +type MediaDocAccessFields_sizes_large_width_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_width_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_width_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_width_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_height { + create: MediaDocAccessFields_sizes_large_height_Create + read: MediaDocAccessFields_sizes_large_height_Read + update: MediaDocAccessFields_sizes_large_height_Update + delete: MediaDocAccessFields_sizes_large_height_Delete +} + +type MediaDocAccessFields_sizes_large_height_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_height_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_height_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_height_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_mimeType { + create: MediaDocAccessFields_sizes_large_mimeType_Create + read: MediaDocAccessFields_sizes_large_mimeType_Read + update: MediaDocAccessFields_sizes_large_mimeType_Update + delete: MediaDocAccessFields_sizes_large_mimeType_Delete +} + +type MediaDocAccessFields_sizes_large_mimeType_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_mimeType_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_mimeType_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_mimeType_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_filesize { + create: MediaDocAccessFields_sizes_large_filesize_Create + read: MediaDocAccessFields_sizes_large_filesize_Read + update: MediaDocAccessFields_sizes_large_filesize_Update + delete: MediaDocAccessFields_sizes_large_filesize_Delete +} + +type MediaDocAccessFields_sizes_large_filesize_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_filesize_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_filesize_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_filesize_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_filename { + create: MediaDocAccessFields_sizes_large_filename_Create + read: MediaDocAccessFields_sizes_large_filename_Read + update: MediaDocAccessFields_sizes_large_filename_Update + delete: MediaDocAccessFields_sizes_large_filename_Delete +} + +type MediaDocAccessFields_sizes_large_filename_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_filename_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_filename_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_filename_Delete { + permission: Boolean! +} + +type MediaCreateDocAccess { permission: Boolean! where: JSONObject } -type PostVersion { - parent(draft: Boolean): Post - version: PostVersion_Version - createdAt: DateTime - updatedAt: DateTime - latest: Boolean - id: String +type MediaReadDocAccess { + permission: Boolean! + where: JSONObject } -type PostVersion_Version { - text: String - richText(depth: Int): JSON - richText2(depth: Int): JSON - updatedAt: DateTime - createdAt: DateTime - _status: PostVersion_Version__status +type MediaUpdateDocAccess { + permission: Boolean! + where: JSONObject } -enum PostVersion_Version__status { - draft - published -} - -type versionsPosts { - docs: [PostVersion] - hasNextPage: Boolean - hasPrevPage: Boolean - limit: Int - nextPage: Int - offset: Int - page: Int - pagingCounter: Int - prevPage: Int - totalDocs: Int - totalPages: Int -} - -input versionsPost_where { - parent: versionsPost_parent_operator - version__text: versionsPost_version__text_operator - version__richText: versionsPost_version__richText_operator - version__richText2: versionsPost_version__richText2_operator - version__updatedAt: versionsPost_version__updatedAt_operator - version__createdAt: versionsPost_version__createdAt_operator - version___status: versionsPost_version___status_operator - createdAt: versionsPost_createdAt_operator - updatedAt: versionsPost_updatedAt_operator - latest: versionsPost_latest_operator - id: versionsPost_id_operator - AND: [versionsPost_where_and] - OR: [versionsPost_where_or] -} - -input versionsPost_parent_operator { - equals: JSON - not_equals: JSON - in: [JSON] - not_in: [JSON] - all: [JSON] - exists: Boolean -} - -input versionsPost_version__text_operator { - equals: String - not_equals: String - like: String - contains: String - in: [String] - not_in: [String] - all: [String] - exists: Boolean -} - -input versionsPost_version__richText_operator { - equals: JSON - not_equals: JSON - like: JSON - contains: JSON - exists: Boolean -} - -input versionsPost_version__richText2_operator { - equals: JSON - not_equals: JSON - like: JSON - contains: JSON - exists: Boolean -} - -input versionsPost_version__updatedAt_operator { - equals: DateTime - not_equals: DateTime - greater_than_equal: DateTime - greater_than: DateTime - less_than_equal: DateTime - less_than: DateTime - like: DateTime - exists: Boolean -} - -input versionsPost_version__createdAt_operator { - equals: DateTime - not_equals: DateTime - greater_than_equal: DateTime - greater_than: DateTime - less_than_equal: DateTime - less_than: DateTime - like: DateTime - exists: Boolean -} - -input versionsPost_version___status_operator { - equals: versionsPost_version___status_Input - not_equals: versionsPost_version___status_Input - in: [versionsPost_version___status_Input] - not_in: [versionsPost_version___status_Input] - all: [versionsPost_version___status_Input] - exists: Boolean -} - -enum versionsPost_version___status_Input { - draft - published -} - -input versionsPost_createdAt_operator { - equals: DateTime - not_equals: DateTime - greater_than_equal: DateTime - greater_than: DateTime - less_than_equal: DateTime - less_than: DateTime - like: DateTime - exists: Boolean -} - -input versionsPost_updatedAt_operator { - equals: DateTime - not_equals: DateTime - greater_than_equal: DateTime - greater_than: DateTime - less_than_equal: DateTime - less_than: DateTime - like: DateTime - exists: Boolean -} - -input versionsPost_latest_operator { - equals: Boolean - not_equals: Boolean - exists: Boolean -} - -input versionsPost_id_operator { - equals: String - not_equals: String - like: String - contains: String - in: [String] - not_in: [String] - all: [String] - exists: Boolean -} - -input versionsPost_where_and { - parent: versionsPost_parent_operator - version__text: versionsPost_version__text_operator - version__richText: versionsPost_version__richText_operator - version__richText2: versionsPost_version__richText2_operator - version__updatedAt: versionsPost_version__updatedAt_operator - version__createdAt: versionsPost_version__createdAt_operator - version___status: versionsPost_version___status_operator - createdAt: versionsPost_createdAt_operator - updatedAt: versionsPost_updatedAt_operator - latest: versionsPost_latest_operator - id: versionsPost_id_operator - AND: [versionsPost_where_and] - OR: [versionsPost_where_or] -} - -input versionsPost_where_or { - parent: versionsPost_parent_operator - version__text: versionsPost_version__text_operator - version__richText: versionsPost_version__richText_operator - version__richText2: versionsPost_version__richText2_operator - version__updatedAt: versionsPost_version__updatedAt_operator - version__createdAt: versionsPost_version__createdAt_operator - version___status: versionsPost_version___status_operator - createdAt: versionsPost_createdAt_operator - updatedAt: versionsPost_updatedAt_operator - latest: versionsPost_latest_operator - id: versionsPost_id_operator - AND: [versionsPost_where_and] - OR: [versionsPost_where_or] +type MediaDeleteDocAccess { + permission: Boolean! + where: JSONObject } type User { - id: String + id: String! updatedAt: DateTime createdAt: DateTime email: EmailAddress! @@ -574,27 +1614,25 @@ type User { hash: String loginAttempts: Float lockUntil: DateTime - password: String! } """ A field whose value conforms to the standard internet email address format as specified in HTML Spec: https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address. """ -scalar EmailAddress - @specifiedBy(url: "https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address") +scalar EmailAddress @specifiedBy(url: "https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address") type Users { - docs: [User] - hasNextPage: Boolean - hasPrevPage: Boolean - limit: Int - nextPage: Int + docs: [User!]! + hasNextPage: Boolean! + hasPrevPage: Boolean! + limit: Int! + nextPage: Int! offset: Int - page: Int - pagingCounter: Int - prevPage: Int - totalDocs: Int - totalPages: Int + page: Int! + pagingCounter: Int! + prevPage: Int! + totalDocs: Int! + totalPages: Int! } input User_where { @@ -684,7 +1722,6 @@ type UsersDocAccessFields { updatedAt: UsersDocAccessFields_updatedAt createdAt: UsersDocAccessFields_createdAt email: UsersDocAccessFields_email - password: UsersDocAccessFields_password } type UsersDocAccessFields_updatedAt { @@ -756,29 +1793,6 @@ type UsersDocAccessFields_email_Delete { permission: Boolean! } -type UsersDocAccessFields_password { - create: UsersDocAccessFields_password_Create - read: UsersDocAccessFields_password_Read - update: UsersDocAccessFields_password_Update - delete: UsersDocAccessFields_password_Delete -} - -type UsersDocAccessFields_password_Create { - permission: Boolean! -} - -type UsersDocAccessFields_password_Read { - permission: Boolean! -} - -type UsersDocAccessFields_password_Update { - permission: Boolean! -} - -type UsersDocAccessFields_password_Delete { - permission: Boolean! -} - type UsersCreateDocAccess { permission: Boolean! where: JSONObject @@ -807,12 +1821,312 @@ type UsersUnlockDocAccess { type usersMe { collection: String exp: Int + strategy: String token: String user: User } +type PayloadLockedDocument { + id: String! + document: PayloadLockedDocument_Document_Relationship + globalSlug: String + user: PayloadLockedDocument_User_Relationship! + updatedAt: DateTime + createdAt: DateTime +} + +type PayloadLockedDocument_Document_Relationship { + relationTo: PayloadLockedDocument_Document_RelationTo + value: PayloadLockedDocument_Document +} + +enum PayloadLockedDocument_Document_RelationTo { + posts + media + users +} + +union PayloadLockedDocument_Document = Post | Media | User + +type PayloadLockedDocument_User_Relationship { + relationTo: PayloadLockedDocument_User_RelationTo + value: PayloadLockedDocument_User +} + +enum PayloadLockedDocument_User_RelationTo { + users +} + +union PayloadLockedDocument_User = User + +type PayloadLockedDocuments { + docs: [PayloadLockedDocument!]! + hasNextPage: Boolean! + hasPrevPage: Boolean! + limit: Int! + nextPage: Int! + offset: Int + page: Int! + pagingCounter: Int! + prevPage: Int! + totalDocs: Int! + totalPages: Int! +} + +input PayloadLockedDocument_where { + document: PayloadLockedDocument_document_Relation + globalSlug: PayloadLockedDocument_globalSlug_operator + user: PayloadLockedDocument_user_Relation + updatedAt: PayloadLockedDocument_updatedAt_operator + createdAt: PayloadLockedDocument_createdAt_operator + id: PayloadLockedDocument_id_operator + AND: [PayloadLockedDocument_where_and] + OR: [PayloadLockedDocument_where_or] +} + +input PayloadLockedDocument_document_Relation { + relationTo: PayloadLockedDocument_document_Relation_RelationTo + value: JSON +} + +enum PayloadLockedDocument_document_Relation_RelationTo { + posts + media + users +} + +input PayloadLockedDocument_globalSlug_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input PayloadLockedDocument_user_Relation { + relationTo: PayloadLockedDocument_user_Relation_RelationTo + value: JSON +} + +enum PayloadLockedDocument_user_Relation_RelationTo { + users +} + +input PayloadLockedDocument_updatedAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input PayloadLockedDocument_createdAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input PayloadLockedDocument_id_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input PayloadLockedDocument_where_and { + document: PayloadLockedDocument_document_Relation + globalSlug: PayloadLockedDocument_globalSlug_operator + user: PayloadLockedDocument_user_Relation + updatedAt: PayloadLockedDocument_updatedAt_operator + createdAt: PayloadLockedDocument_createdAt_operator + id: PayloadLockedDocument_id_operator + AND: [PayloadLockedDocument_where_and] + OR: [PayloadLockedDocument_where_or] +} + +input PayloadLockedDocument_where_or { + document: PayloadLockedDocument_document_Relation + globalSlug: PayloadLockedDocument_globalSlug_operator + user: PayloadLockedDocument_user_Relation + updatedAt: PayloadLockedDocument_updatedAt_operator + createdAt: PayloadLockedDocument_createdAt_operator + id: PayloadLockedDocument_id_operator + AND: [PayloadLockedDocument_where_and] + OR: [PayloadLockedDocument_where_or] +} + +type countPayloadLockedDocuments { + totalDocs: Int +} + +type payload_locked_documentsDocAccess { + fields: PayloadLockedDocumentsDocAccessFields + create: PayloadLockedDocumentsCreateDocAccess + read: PayloadLockedDocumentsReadDocAccess + update: PayloadLockedDocumentsUpdateDocAccess + delete: PayloadLockedDocumentsDeleteDocAccess +} + +type PayloadLockedDocumentsDocAccessFields { + document: PayloadLockedDocumentsDocAccessFields_document + globalSlug: PayloadLockedDocumentsDocAccessFields_globalSlug + user: PayloadLockedDocumentsDocAccessFields_user + updatedAt: PayloadLockedDocumentsDocAccessFields_updatedAt + createdAt: PayloadLockedDocumentsDocAccessFields_createdAt +} + +type PayloadLockedDocumentsDocAccessFields_document { + create: PayloadLockedDocumentsDocAccessFields_document_Create + read: PayloadLockedDocumentsDocAccessFields_document_Read + update: PayloadLockedDocumentsDocAccessFields_document_Update + delete: PayloadLockedDocumentsDocAccessFields_document_Delete +} + +type PayloadLockedDocumentsDocAccessFields_document_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_document_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_document_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_document_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_globalSlug { + create: PayloadLockedDocumentsDocAccessFields_globalSlug_Create + read: PayloadLockedDocumentsDocAccessFields_globalSlug_Read + update: PayloadLockedDocumentsDocAccessFields_globalSlug_Update + delete: PayloadLockedDocumentsDocAccessFields_globalSlug_Delete +} + +type PayloadLockedDocumentsDocAccessFields_globalSlug_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_globalSlug_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_globalSlug_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_globalSlug_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_user { + create: PayloadLockedDocumentsDocAccessFields_user_Create + read: PayloadLockedDocumentsDocAccessFields_user_Read + update: PayloadLockedDocumentsDocAccessFields_user_Update + delete: PayloadLockedDocumentsDocAccessFields_user_Delete +} + +type PayloadLockedDocumentsDocAccessFields_user_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_user_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_user_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_user_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_updatedAt { + create: PayloadLockedDocumentsDocAccessFields_updatedAt_Create + read: PayloadLockedDocumentsDocAccessFields_updatedAt_Read + update: PayloadLockedDocumentsDocAccessFields_updatedAt_Update + delete: PayloadLockedDocumentsDocAccessFields_updatedAt_Delete +} + +type PayloadLockedDocumentsDocAccessFields_updatedAt_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_updatedAt_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_updatedAt_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_updatedAt_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_createdAt { + create: PayloadLockedDocumentsDocAccessFields_createdAt_Create + read: PayloadLockedDocumentsDocAccessFields_createdAt_Read + update: PayloadLockedDocumentsDocAccessFields_createdAt_Update + delete: PayloadLockedDocumentsDocAccessFields_createdAt_Delete +} + +type PayloadLockedDocumentsDocAccessFields_createdAt_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_createdAt_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_createdAt_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_createdAt_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsCreateDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsReadDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsUpdateDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsDeleteDocAccess { + permission: Boolean! + where: JSONObject +} + type PayloadPreference { - id: String + id: String! user: PayloadPreference_User_Relationship! key: String value: JSON @@ -832,17 +2146,17 @@ enum PayloadPreference_User_RelationTo { union PayloadPreference_User = User type PayloadPreferences { - docs: [PayloadPreference] - hasNextPage: Boolean - hasPrevPage: Boolean - limit: Int - nextPage: Int + docs: [PayloadPreference!]! + hasNextPage: Boolean! + hasPrevPage: Boolean! + limit: Int! + nextPage: Int! offset: Int - page: Int - pagingCounter: Int - prevPage: Int - totalDocs: Int - totalPages: Int + page: Int! + pagingCounter: Int! + prevPage: Int! + totalDocs: Int! + totalPages: Int! } input PayloadPreference_where { @@ -1196,7 +2510,9 @@ type MenuUpdateDocAccess { type Access { canAccessAdmin: Boolean! posts: postsAccess + media: mediaAccess users: usersAccess + payload_locked_documents: payload_locked_documentsAccess payload_preferences: payload_preferencesAccess menu: menuAccess } @@ -1207,84 +2523,58 @@ type postsAccess { read: PostsReadAccess update: PostsUpdateAccess delete: PostsDeleteAccess - readVersions: PostsReadVersionsAccess } type PostsFields { - text: PostsFields_text - richText: PostsFields_richText - richText2: PostsFields_richText2 + title: PostsFields_title + content: PostsFields_content updatedAt: PostsFields_updatedAt createdAt: PostsFields_createdAt - _status: PostsFields__status } -type PostsFields_text { - create: PostsFields_text_Create - read: PostsFields_text_Read - update: PostsFields_text_Update - delete: PostsFields_text_Delete +type PostsFields_title { + create: PostsFields_title_Create + read: PostsFields_title_Read + update: PostsFields_title_Update + delete: PostsFields_title_Delete } -type PostsFields_text_Create { +type PostsFields_title_Create { permission: Boolean! } -type PostsFields_text_Read { +type PostsFields_title_Read { permission: Boolean! } -type PostsFields_text_Update { +type PostsFields_title_Update { permission: Boolean! } -type PostsFields_text_Delete { +type PostsFields_title_Delete { permission: Boolean! } -type PostsFields_richText { - create: PostsFields_richText_Create - read: PostsFields_richText_Read - update: PostsFields_richText_Update - delete: PostsFields_richText_Delete +type PostsFields_content { + create: PostsFields_content_Create + read: PostsFields_content_Read + update: PostsFields_content_Update + delete: PostsFields_content_Delete } -type PostsFields_richText_Create { +type PostsFields_content_Create { permission: Boolean! } -type PostsFields_richText_Read { +type PostsFields_content_Read { permission: Boolean! } -type PostsFields_richText_Update { +type PostsFields_content_Update { permission: Boolean! } -type PostsFields_richText_Delete { - permission: Boolean! -} - -type PostsFields_richText2 { - create: PostsFields_richText2_Create - read: PostsFields_richText2_Read - update: PostsFields_richText2_Update - delete: PostsFields_richText2_Delete -} - -type PostsFields_richText2_Create { - permission: Boolean! -} - -type PostsFields_richText2_Read { - permission: Boolean! -} - -type PostsFields_richText2_Update { - permission: Boolean! -} - -type PostsFields_richText2_Delete { +type PostsFields_content_Delete { permission: Boolean! } @@ -1334,29 +2624,6 @@ type PostsFields_createdAt_Delete { permission: Boolean! } -type PostsFields__status { - create: PostsFields__status_Create - read: PostsFields__status_Read - update: PostsFields__status_Update - delete: PostsFields__status_Delete -} - -type PostsFields__status_Create { - permission: Boolean! -} - -type PostsFields__status_Read { - permission: Boolean! -} - -type PostsFields__status_Update { - permission: Boolean! -} - -type PostsFields__status_Delete { - permission: Boolean! -} - type PostsCreateAccess { permission: Boolean! where: JSONObject @@ -1377,7 +2644,841 @@ type PostsDeleteAccess { where: JSONObject } -type PostsReadVersionsAccess { +type mediaAccess { + fields: MediaFields + create: MediaCreateAccess + read: MediaReadAccess + update: MediaUpdateAccess + delete: MediaDeleteAccess +} + +type MediaFields { + updatedAt: MediaFields_updatedAt + createdAt: MediaFields_createdAt + url: MediaFields_url + thumbnailURL: MediaFields_thumbnailURL + filename: MediaFields_filename + mimeType: MediaFields_mimeType + filesize: MediaFields_filesize + width: MediaFields_width + height: MediaFields_height + focalX: MediaFields_focalX + focalY: MediaFields_focalY + sizes: MediaFields_sizes +} + +type MediaFields_updatedAt { + create: MediaFields_updatedAt_Create + read: MediaFields_updatedAt_Read + update: MediaFields_updatedAt_Update + delete: MediaFields_updatedAt_Delete +} + +type MediaFields_updatedAt_Create { + permission: Boolean! +} + +type MediaFields_updatedAt_Read { + permission: Boolean! +} + +type MediaFields_updatedAt_Update { + permission: Boolean! +} + +type MediaFields_updatedAt_Delete { + permission: Boolean! +} + +type MediaFields_createdAt { + create: MediaFields_createdAt_Create + read: MediaFields_createdAt_Read + update: MediaFields_createdAt_Update + delete: MediaFields_createdAt_Delete +} + +type MediaFields_createdAt_Create { + permission: Boolean! +} + +type MediaFields_createdAt_Read { + permission: Boolean! +} + +type MediaFields_createdAt_Update { + permission: Boolean! +} + +type MediaFields_createdAt_Delete { + permission: Boolean! +} + +type MediaFields_url { + create: MediaFields_url_Create + read: MediaFields_url_Read + update: MediaFields_url_Update + delete: MediaFields_url_Delete +} + +type MediaFields_url_Create { + permission: Boolean! +} + +type MediaFields_url_Read { + permission: Boolean! +} + +type MediaFields_url_Update { + permission: Boolean! +} + +type MediaFields_url_Delete { + permission: Boolean! +} + +type MediaFields_thumbnailURL { + create: MediaFields_thumbnailURL_Create + read: MediaFields_thumbnailURL_Read + update: MediaFields_thumbnailURL_Update + delete: MediaFields_thumbnailURL_Delete +} + +type MediaFields_thumbnailURL_Create { + permission: Boolean! +} + +type MediaFields_thumbnailURL_Read { + permission: Boolean! +} + +type MediaFields_thumbnailURL_Update { + permission: Boolean! +} + +type MediaFields_thumbnailURL_Delete { + permission: Boolean! +} + +type MediaFields_filename { + create: MediaFields_filename_Create + read: MediaFields_filename_Read + update: MediaFields_filename_Update + delete: MediaFields_filename_Delete +} + +type MediaFields_filename_Create { + permission: Boolean! +} + +type MediaFields_filename_Read { + permission: Boolean! +} + +type MediaFields_filename_Update { + permission: Boolean! +} + +type MediaFields_filename_Delete { + permission: Boolean! +} + +type MediaFields_mimeType { + create: MediaFields_mimeType_Create + read: MediaFields_mimeType_Read + update: MediaFields_mimeType_Update + delete: MediaFields_mimeType_Delete +} + +type MediaFields_mimeType_Create { + permission: Boolean! +} + +type MediaFields_mimeType_Read { + permission: Boolean! +} + +type MediaFields_mimeType_Update { + permission: Boolean! +} + +type MediaFields_mimeType_Delete { + permission: Boolean! +} + +type MediaFields_filesize { + create: MediaFields_filesize_Create + read: MediaFields_filesize_Read + update: MediaFields_filesize_Update + delete: MediaFields_filesize_Delete +} + +type MediaFields_filesize_Create { + permission: Boolean! +} + +type MediaFields_filesize_Read { + permission: Boolean! +} + +type MediaFields_filesize_Update { + permission: Boolean! +} + +type MediaFields_filesize_Delete { + permission: Boolean! +} + +type MediaFields_width { + create: MediaFields_width_Create + read: MediaFields_width_Read + update: MediaFields_width_Update + delete: MediaFields_width_Delete +} + +type MediaFields_width_Create { + permission: Boolean! +} + +type MediaFields_width_Read { + permission: Boolean! +} + +type MediaFields_width_Update { + permission: Boolean! +} + +type MediaFields_width_Delete { + permission: Boolean! +} + +type MediaFields_height { + create: MediaFields_height_Create + read: MediaFields_height_Read + update: MediaFields_height_Update + delete: MediaFields_height_Delete +} + +type MediaFields_height_Create { + permission: Boolean! +} + +type MediaFields_height_Read { + permission: Boolean! +} + +type MediaFields_height_Update { + permission: Boolean! +} + +type MediaFields_height_Delete { + permission: Boolean! +} + +type MediaFields_focalX { + create: MediaFields_focalX_Create + read: MediaFields_focalX_Read + update: MediaFields_focalX_Update + delete: MediaFields_focalX_Delete +} + +type MediaFields_focalX_Create { + permission: Boolean! +} + +type MediaFields_focalX_Read { + permission: Boolean! +} + +type MediaFields_focalX_Update { + permission: Boolean! +} + +type MediaFields_focalX_Delete { + permission: Boolean! +} + +type MediaFields_focalY { + create: MediaFields_focalY_Create + read: MediaFields_focalY_Read + update: MediaFields_focalY_Update + delete: MediaFields_focalY_Delete +} + +type MediaFields_focalY_Create { + permission: Boolean! +} + +type MediaFields_focalY_Read { + permission: Boolean! +} + +type MediaFields_focalY_Update { + permission: Boolean! +} + +type MediaFields_focalY_Delete { + permission: Boolean! +} + +type MediaFields_sizes { + create: MediaFields_sizes_Create + read: MediaFields_sizes_Read + update: MediaFields_sizes_Update + delete: MediaFields_sizes_Delete + fields: MediaFields_sizes_Fields +} + +type MediaFields_sizes_Create { + permission: Boolean! +} + +type MediaFields_sizes_Read { + permission: Boolean! +} + +type MediaFields_sizes_Update { + permission: Boolean! +} + +type MediaFields_sizes_Delete { + permission: Boolean! +} + +type MediaFields_sizes_Fields { + thumbnail: MediaFields_sizes_thumbnail + medium: MediaFields_sizes_medium + large: MediaFields_sizes_large +} + +type MediaFields_sizes_thumbnail { + create: MediaFields_sizes_thumbnail_Create + read: MediaFields_sizes_thumbnail_Read + update: MediaFields_sizes_thumbnail_Update + delete: MediaFields_sizes_thumbnail_Delete + fields: MediaFields_sizes_thumbnail_Fields +} + +type MediaFields_sizes_thumbnail_Create { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_Read { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_Update { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_Delete { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_Fields { + url: MediaFields_sizes_thumbnail_url + width: MediaFields_sizes_thumbnail_width + height: MediaFields_sizes_thumbnail_height + mimeType: MediaFields_sizes_thumbnail_mimeType + filesize: MediaFields_sizes_thumbnail_filesize + filename: MediaFields_sizes_thumbnail_filename +} + +type MediaFields_sizes_thumbnail_url { + create: MediaFields_sizes_thumbnail_url_Create + read: MediaFields_sizes_thumbnail_url_Read + update: MediaFields_sizes_thumbnail_url_Update + delete: MediaFields_sizes_thumbnail_url_Delete +} + +type MediaFields_sizes_thumbnail_url_Create { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_url_Read { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_url_Update { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_url_Delete { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_width { + create: MediaFields_sizes_thumbnail_width_Create + read: MediaFields_sizes_thumbnail_width_Read + update: MediaFields_sizes_thumbnail_width_Update + delete: MediaFields_sizes_thumbnail_width_Delete +} + +type MediaFields_sizes_thumbnail_width_Create { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_width_Read { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_width_Update { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_width_Delete { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_height { + create: MediaFields_sizes_thumbnail_height_Create + read: MediaFields_sizes_thumbnail_height_Read + update: MediaFields_sizes_thumbnail_height_Update + delete: MediaFields_sizes_thumbnail_height_Delete +} + +type MediaFields_sizes_thumbnail_height_Create { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_height_Read { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_height_Update { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_height_Delete { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_mimeType { + create: MediaFields_sizes_thumbnail_mimeType_Create + read: MediaFields_sizes_thumbnail_mimeType_Read + update: MediaFields_sizes_thumbnail_mimeType_Update + delete: MediaFields_sizes_thumbnail_mimeType_Delete +} + +type MediaFields_sizes_thumbnail_mimeType_Create { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_mimeType_Read { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_mimeType_Update { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_mimeType_Delete { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_filesize { + create: MediaFields_sizes_thumbnail_filesize_Create + read: MediaFields_sizes_thumbnail_filesize_Read + update: MediaFields_sizes_thumbnail_filesize_Update + delete: MediaFields_sizes_thumbnail_filesize_Delete +} + +type MediaFields_sizes_thumbnail_filesize_Create { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_filesize_Read { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_filesize_Update { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_filesize_Delete { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_filename { + create: MediaFields_sizes_thumbnail_filename_Create + read: MediaFields_sizes_thumbnail_filename_Read + update: MediaFields_sizes_thumbnail_filename_Update + delete: MediaFields_sizes_thumbnail_filename_Delete +} + +type MediaFields_sizes_thumbnail_filename_Create { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_filename_Read { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_filename_Update { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_filename_Delete { + permission: Boolean! +} + +type MediaFields_sizes_medium { + create: MediaFields_sizes_medium_Create + read: MediaFields_sizes_medium_Read + update: MediaFields_sizes_medium_Update + delete: MediaFields_sizes_medium_Delete + fields: MediaFields_sizes_medium_Fields +} + +type MediaFields_sizes_medium_Create { + permission: Boolean! +} + +type MediaFields_sizes_medium_Read { + permission: Boolean! +} + +type MediaFields_sizes_medium_Update { + permission: Boolean! +} + +type MediaFields_sizes_medium_Delete { + permission: Boolean! +} + +type MediaFields_sizes_medium_Fields { + url: MediaFields_sizes_medium_url + width: MediaFields_sizes_medium_width + height: MediaFields_sizes_medium_height + mimeType: MediaFields_sizes_medium_mimeType + filesize: MediaFields_sizes_medium_filesize + filename: MediaFields_sizes_medium_filename +} + +type MediaFields_sizes_medium_url { + create: MediaFields_sizes_medium_url_Create + read: MediaFields_sizes_medium_url_Read + update: MediaFields_sizes_medium_url_Update + delete: MediaFields_sizes_medium_url_Delete +} + +type MediaFields_sizes_medium_url_Create { + permission: Boolean! +} + +type MediaFields_sizes_medium_url_Read { + permission: Boolean! +} + +type MediaFields_sizes_medium_url_Update { + permission: Boolean! +} + +type MediaFields_sizes_medium_url_Delete { + permission: Boolean! +} + +type MediaFields_sizes_medium_width { + create: MediaFields_sizes_medium_width_Create + read: MediaFields_sizes_medium_width_Read + update: MediaFields_sizes_medium_width_Update + delete: MediaFields_sizes_medium_width_Delete +} + +type MediaFields_sizes_medium_width_Create { + permission: Boolean! +} + +type MediaFields_sizes_medium_width_Read { + permission: Boolean! +} + +type MediaFields_sizes_medium_width_Update { + permission: Boolean! +} + +type MediaFields_sizes_medium_width_Delete { + permission: Boolean! +} + +type MediaFields_sizes_medium_height { + create: MediaFields_sizes_medium_height_Create + read: MediaFields_sizes_medium_height_Read + update: MediaFields_sizes_medium_height_Update + delete: MediaFields_sizes_medium_height_Delete +} + +type MediaFields_sizes_medium_height_Create { + permission: Boolean! +} + +type MediaFields_sizes_medium_height_Read { + permission: Boolean! +} + +type MediaFields_sizes_medium_height_Update { + permission: Boolean! +} + +type MediaFields_sizes_medium_height_Delete { + permission: Boolean! +} + +type MediaFields_sizes_medium_mimeType { + create: MediaFields_sizes_medium_mimeType_Create + read: MediaFields_sizes_medium_mimeType_Read + update: MediaFields_sizes_medium_mimeType_Update + delete: MediaFields_sizes_medium_mimeType_Delete +} + +type MediaFields_sizes_medium_mimeType_Create { + permission: Boolean! +} + +type MediaFields_sizes_medium_mimeType_Read { + permission: Boolean! +} + +type MediaFields_sizes_medium_mimeType_Update { + permission: Boolean! +} + +type MediaFields_sizes_medium_mimeType_Delete { + permission: Boolean! +} + +type MediaFields_sizes_medium_filesize { + create: MediaFields_sizes_medium_filesize_Create + read: MediaFields_sizes_medium_filesize_Read + update: MediaFields_sizes_medium_filesize_Update + delete: MediaFields_sizes_medium_filesize_Delete +} + +type MediaFields_sizes_medium_filesize_Create { + permission: Boolean! +} + +type MediaFields_sizes_medium_filesize_Read { + permission: Boolean! +} + +type MediaFields_sizes_medium_filesize_Update { + permission: Boolean! +} + +type MediaFields_sizes_medium_filesize_Delete { + permission: Boolean! +} + +type MediaFields_sizes_medium_filename { + create: MediaFields_sizes_medium_filename_Create + read: MediaFields_sizes_medium_filename_Read + update: MediaFields_sizes_medium_filename_Update + delete: MediaFields_sizes_medium_filename_Delete +} + +type MediaFields_sizes_medium_filename_Create { + permission: Boolean! +} + +type MediaFields_sizes_medium_filename_Read { + permission: Boolean! +} + +type MediaFields_sizes_medium_filename_Update { + permission: Boolean! +} + +type MediaFields_sizes_medium_filename_Delete { + permission: Boolean! +} + +type MediaFields_sizes_large { + create: MediaFields_sizes_large_Create + read: MediaFields_sizes_large_Read + update: MediaFields_sizes_large_Update + delete: MediaFields_sizes_large_Delete + fields: MediaFields_sizes_large_Fields +} + +type MediaFields_sizes_large_Create { + permission: Boolean! +} + +type MediaFields_sizes_large_Read { + permission: Boolean! +} + +type MediaFields_sizes_large_Update { + permission: Boolean! +} + +type MediaFields_sizes_large_Delete { + permission: Boolean! +} + +type MediaFields_sizes_large_Fields { + url: MediaFields_sizes_large_url + width: MediaFields_sizes_large_width + height: MediaFields_sizes_large_height + mimeType: MediaFields_sizes_large_mimeType + filesize: MediaFields_sizes_large_filesize + filename: MediaFields_sizes_large_filename +} + +type MediaFields_sizes_large_url { + create: MediaFields_sizes_large_url_Create + read: MediaFields_sizes_large_url_Read + update: MediaFields_sizes_large_url_Update + delete: MediaFields_sizes_large_url_Delete +} + +type MediaFields_sizes_large_url_Create { + permission: Boolean! +} + +type MediaFields_sizes_large_url_Read { + permission: Boolean! +} + +type MediaFields_sizes_large_url_Update { + permission: Boolean! +} + +type MediaFields_sizes_large_url_Delete { + permission: Boolean! +} + +type MediaFields_sizes_large_width { + create: MediaFields_sizes_large_width_Create + read: MediaFields_sizes_large_width_Read + update: MediaFields_sizes_large_width_Update + delete: MediaFields_sizes_large_width_Delete +} + +type MediaFields_sizes_large_width_Create { + permission: Boolean! +} + +type MediaFields_sizes_large_width_Read { + permission: Boolean! +} + +type MediaFields_sizes_large_width_Update { + permission: Boolean! +} + +type MediaFields_sizes_large_width_Delete { + permission: Boolean! +} + +type MediaFields_sizes_large_height { + create: MediaFields_sizes_large_height_Create + read: MediaFields_sizes_large_height_Read + update: MediaFields_sizes_large_height_Update + delete: MediaFields_sizes_large_height_Delete +} + +type MediaFields_sizes_large_height_Create { + permission: Boolean! +} + +type MediaFields_sizes_large_height_Read { + permission: Boolean! +} + +type MediaFields_sizes_large_height_Update { + permission: Boolean! +} + +type MediaFields_sizes_large_height_Delete { + permission: Boolean! +} + +type MediaFields_sizes_large_mimeType { + create: MediaFields_sizes_large_mimeType_Create + read: MediaFields_sizes_large_mimeType_Read + update: MediaFields_sizes_large_mimeType_Update + delete: MediaFields_sizes_large_mimeType_Delete +} + +type MediaFields_sizes_large_mimeType_Create { + permission: Boolean! +} + +type MediaFields_sizes_large_mimeType_Read { + permission: Boolean! +} + +type MediaFields_sizes_large_mimeType_Update { + permission: Boolean! +} + +type MediaFields_sizes_large_mimeType_Delete { + permission: Boolean! +} + +type MediaFields_sizes_large_filesize { + create: MediaFields_sizes_large_filesize_Create + read: MediaFields_sizes_large_filesize_Read + update: MediaFields_sizes_large_filesize_Update + delete: MediaFields_sizes_large_filesize_Delete +} + +type MediaFields_sizes_large_filesize_Create { + permission: Boolean! +} + +type MediaFields_sizes_large_filesize_Read { + permission: Boolean! +} + +type MediaFields_sizes_large_filesize_Update { + permission: Boolean! +} + +type MediaFields_sizes_large_filesize_Delete { + permission: Boolean! +} + +type MediaFields_sizes_large_filename { + create: MediaFields_sizes_large_filename_Create + read: MediaFields_sizes_large_filename_Read + update: MediaFields_sizes_large_filename_Update + delete: MediaFields_sizes_large_filename_Delete +} + +type MediaFields_sizes_large_filename_Create { + permission: Boolean! +} + +type MediaFields_sizes_large_filename_Read { + permission: Boolean! +} + +type MediaFields_sizes_large_filename_Update { + permission: Boolean! +} + +type MediaFields_sizes_large_filename_Delete { + permission: Boolean! +} + +type MediaCreateAccess { + permission: Boolean! + where: JSONObject +} + +type MediaReadAccess { + permission: Boolean! + where: JSONObject +} + +type MediaUpdateAccess { + permission: Boolean! + where: JSONObject +} + +type MediaDeleteAccess { permission: Boolean! where: JSONObject } @@ -1395,7 +3496,6 @@ type UsersFields { updatedAt: UsersFields_updatedAt createdAt: UsersFields_createdAt email: UsersFields_email - password: UsersFields_password } type UsersFields_updatedAt { @@ -1467,29 +3567,6 @@ type UsersFields_email_Delete { permission: Boolean! } -type UsersFields_password { - create: UsersFields_password_Create - read: UsersFields_password_Read - update: UsersFields_password_Update - delete: UsersFields_password_Delete -} - -type UsersFields_password_Create { - permission: Boolean! -} - -type UsersFields_password_Read { - permission: Boolean! -} - -type UsersFields_password_Update { - permission: Boolean! -} - -type UsersFields_password_Delete { - permission: Boolean! -} - type UsersCreateAccess { permission: Boolean! where: JSONObject @@ -1515,6 +3592,157 @@ type UsersUnlockAccess { where: JSONObject } +type payload_locked_documentsAccess { + fields: PayloadLockedDocumentsFields + create: PayloadLockedDocumentsCreateAccess + read: PayloadLockedDocumentsReadAccess + update: PayloadLockedDocumentsUpdateAccess + delete: PayloadLockedDocumentsDeleteAccess +} + +type PayloadLockedDocumentsFields { + document: PayloadLockedDocumentsFields_document + globalSlug: PayloadLockedDocumentsFields_globalSlug + user: PayloadLockedDocumentsFields_user + updatedAt: PayloadLockedDocumentsFields_updatedAt + createdAt: PayloadLockedDocumentsFields_createdAt +} + +type PayloadLockedDocumentsFields_document { + create: PayloadLockedDocumentsFields_document_Create + read: PayloadLockedDocumentsFields_document_Read + update: PayloadLockedDocumentsFields_document_Update + delete: PayloadLockedDocumentsFields_document_Delete +} + +type PayloadLockedDocumentsFields_document_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_document_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_document_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_document_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_globalSlug { + create: PayloadLockedDocumentsFields_globalSlug_Create + read: PayloadLockedDocumentsFields_globalSlug_Read + update: PayloadLockedDocumentsFields_globalSlug_Update + delete: PayloadLockedDocumentsFields_globalSlug_Delete +} + +type PayloadLockedDocumentsFields_globalSlug_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_globalSlug_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_globalSlug_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_globalSlug_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_user { + create: PayloadLockedDocumentsFields_user_Create + read: PayloadLockedDocumentsFields_user_Read + update: PayloadLockedDocumentsFields_user_Update + delete: PayloadLockedDocumentsFields_user_Delete +} + +type PayloadLockedDocumentsFields_user_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_user_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_user_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_user_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_updatedAt { + create: PayloadLockedDocumentsFields_updatedAt_Create + read: PayloadLockedDocumentsFields_updatedAt_Read + update: PayloadLockedDocumentsFields_updatedAt_Update + delete: PayloadLockedDocumentsFields_updatedAt_Delete +} + +type PayloadLockedDocumentsFields_updatedAt_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_updatedAt_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_updatedAt_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_updatedAt_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_createdAt { + create: PayloadLockedDocumentsFields_createdAt_Create + read: PayloadLockedDocumentsFields_createdAt_Read + update: PayloadLockedDocumentsFields_createdAt_Update + delete: PayloadLockedDocumentsFields_createdAt_Delete +} + +type PayloadLockedDocumentsFields_createdAt_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_createdAt_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_createdAt_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_createdAt_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsCreateAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsReadAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsUpdateAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsDeleteAccess { + permission: Boolean! + where: JSONObject +} + type payload_preferencesAccess { fields: PayloadPreferencesFields create: PayloadPreferencesCreateAccess @@ -1761,56 +3989,140 @@ type Mutation { createPost(data: mutationPostInput!, draft: Boolean): Post updatePost(id: String!, autosave: Boolean, data: mutationPostUpdateInput!, draft: Boolean): Post deletePost(id: String!): Post - duplicatePost(id: String!): Post - restoreVersionPost(id: String): Post + duplicatePost(id: String!, data: mutationPostInput!): Post + createMedia(data: mutationMediaInput!, draft: Boolean): Media + updateMedia(id: String!, autosave: Boolean, data: mutationMediaUpdateInput!, draft: Boolean): Media + deleteMedia(id: String!): Media + duplicateMedia(id: String!, data: mutationMediaInput!): Media createUser(data: mutationUserInput!, draft: Boolean): User updateUser(id: String!, autosave: Boolean, data: mutationUserUpdateInput!, draft: Boolean): User deleteUser(id: String!): User - refreshTokenUser(token: String): usersRefreshedUser + refreshTokenUser: usersRefreshedUser logoutUser: String unlockUser(email: String!): Boolean! - loginUser(email: String, password: String): usersLoginResult - forgotPasswordUser(disableEmail: Boolean, email: String!, expiration: Int): Boolean! + loginUser(email: String!, password: String): usersLoginResult + forgotPasswordUser(disableEmail: Boolean, expiration: Int, email: String!): Boolean! resetPasswordUser(password: String, token: String): usersResetPassword verifyEmailUser(token: String): Boolean + createPayloadLockedDocument(data: mutationPayloadLockedDocumentInput!, draft: Boolean): PayloadLockedDocument + updatePayloadLockedDocument(id: String!, autosave: Boolean, data: mutationPayloadLockedDocumentUpdateInput!, draft: Boolean): PayloadLockedDocument + deletePayloadLockedDocument(id: String!): PayloadLockedDocument + duplicatePayloadLockedDocument(id: String!, data: mutationPayloadLockedDocumentInput!): PayloadLockedDocument createPayloadPreference(data: mutationPayloadPreferenceInput!, draft: Boolean): PayloadPreference - updatePayloadPreference( - id: String! - autosave: Boolean - data: mutationPayloadPreferenceUpdateInput! - draft: Boolean - ): PayloadPreference + updatePayloadPreference(id: String!, autosave: Boolean, data: mutationPayloadPreferenceUpdateInput!, draft: Boolean): PayloadPreference deletePayloadPreference(id: String!): PayloadPreference - duplicatePayloadPreference(id: String!): PayloadPreference + duplicatePayloadPreference(id: String!, data: mutationPayloadPreferenceInput!): PayloadPreference updateMenu(data: mutationMenuInput!, draft: Boolean): Menu } input mutationPostInput { - text: String - richText: JSON - richText2: JSON + title: String + content: JSON updatedAt: String createdAt: String - _status: Post__status_MutationInput -} - -enum Post__status_MutationInput { - draft - published } input mutationPostUpdateInput { - text: String - richText: JSON - richText2: JSON + title: String + content: JSON updatedAt: String createdAt: String - _status: PostUpdate__status_MutationInput } -enum PostUpdate__status_MutationInput { - draft - published +input mutationMediaInput { + updatedAt: String + createdAt: String + url: String + thumbnailURL: String + filename: String + mimeType: String + filesize: Float + width: Float + height: Float + focalX: Float + focalY: Float + sizes: mutationMedia_SizesInput +} + +input mutationMedia_SizesInput { + thumbnail: mutationMedia_Sizes_ThumbnailInput + medium: mutationMedia_Sizes_MediumInput + large: mutationMedia_Sizes_LargeInput +} + +input mutationMedia_Sizes_ThumbnailInput { + url: String + width: Float + height: Float + mimeType: String + filesize: Float + filename: String +} + +input mutationMedia_Sizes_MediumInput { + url: String + width: Float + height: Float + mimeType: String + filesize: Float + filename: String +} + +input mutationMedia_Sizes_LargeInput { + url: String + width: Float + height: Float + mimeType: String + filesize: Float + filename: String +} + +input mutationMediaUpdateInput { + updatedAt: String + createdAt: String + url: String + thumbnailURL: String + filename: String + mimeType: String + filesize: Float + width: Float + height: Float + focalX: Float + focalY: Float + sizes: mutationMediaUpdate_SizesInput +} + +input mutationMediaUpdate_SizesInput { + thumbnail: mutationMediaUpdate_Sizes_ThumbnailInput + medium: mutationMediaUpdate_Sizes_MediumInput + large: mutationMediaUpdate_Sizes_LargeInput +} + +input mutationMediaUpdate_Sizes_ThumbnailInput { + url: String + width: Float + height: Float + mimeType: String + filesize: Float + filename: String +} + +input mutationMediaUpdate_Sizes_MediumInput { + url: String + width: Float + height: Float + mimeType: String + filesize: Float + filename: String +} + +input mutationMediaUpdate_Sizes_LargeInput { + url: String + width: Float + height: Float + mimeType: String + filesize: Float + filename: String } input mutationUserInput { @@ -1842,6 +4154,7 @@ input mutationUserUpdateInput { type usersRefreshedUser { exp: Int refreshedToken: String + strategy: String user: usersJWT } @@ -1861,6 +4174,62 @@ type usersResetPassword { user: User } +input mutationPayloadLockedDocumentInput { + document: PayloadLockedDocument_DocumentRelationshipInput + globalSlug: String + user: PayloadLockedDocument_UserRelationshipInput + updatedAt: String + createdAt: String +} + +input PayloadLockedDocument_DocumentRelationshipInput { + relationTo: PayloadLockedDocument_DocumentRelationshipInputRelationTo + value: JSON +} + +enum PayloadLockedDocument_DocumentRelationshipInputRelationTo { + posts + media + users +} + +input PayloadLockedDocument_UserRelationshipInput { + relationTo: PayloadLockedDocument_UserRelationshipInputRelationTo + value: JSON +} + +enum PayloadLockedDocument_UserRelationshipInputRelationTo { + users +} + +input mutationPayloadLockedDocumentUpdateInput { + document: PayloadLockedDocumentUpdate_DocumentRelationshipInput + globalSlug: String + user: PayloadLockedDocumentUpdate_UserRelationshipInput + updatedAt: String + createdAt: String +} + +input PayloadLockedDocumentUpdate_DocumentRelationshipInput { + relationTo: PayloadLockedDocumentUpdate_DocumentRelationshipInputRelationTo + value: JSON +} + +enum PayloadLockedDocumentUpdate_DocumentRelationshipInputRelationTo { + posts + media + users +} + +input PayloadLockedDocumentUpdate_UserRelationshipInput { + relationTo: PayloadLockedDocumentUpdate_UserRelationshipInputRelationTo + value: JSON +} + +enum PayloadLockedDocumentUpdate_UserRelationshipInputRelationTo { + users +} + input mutationPayloadPreferenceInput { user: PayloadPreference_UserRelationshipInput key: String @@ -1899,4 +4268,4 @@ input mutationMenuInput { globalText: String updatedAt: String createdAt: String -} +} \ No newline at end of file From 8880d705e32060ceecd25ffad85d989e8cf7fe28 Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Thu, 3 Apr 2025 12:23:14 -0400 Subject: [PATCH 68/77] fix(ui): optimistic rows disappear while form state requests are pending (#11961) When manipulating array and blocks rows on slow networks, rows can sometimes disappear and then reappear as requests in the queue arrive. Consider this scenario: 1. You add a row to form state: this pushes the row in local state optimistically then triggers a long-running form state request containing a single row 2. You add another row to form state: this pushes a second row into local state optimistically then triggers another long-running form state request containing two rows 3. The first form state request returns with a single row in the response and replaces local state (which contained two rows) 4. AT THIS MOMENT IN TIME, THE SECOND ROW DISAPPEARS 5. The second form state request returns with two rows in the response and replaces local state 6. THE UI IS NO LONGER STALE AND BOTH ROWS APPEAR AS EXPECTED The same issue applies when deleting, moving, and duplicating rows. Local state becomes out of sync with the form state response and is ultimately overridden. The issue is that when we merge the result from form state, we do not traverse the rows themselves, and instead take the rows in their entirety. This means that we lose local row state. Instead, we need to compare the results with what is saved to local state and intelligently merge them. --- .../ui/src/forms/Form/mergeServerFormState.ts | 24 ++++++++++++++++--- .../addFieldStatePromise.ts | 2 ++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/ui/src/forms/Form/mergeServerFormState.ts b/packages/ui/src/forms/Form/mergeServerFormState.ts index f86ae1a6f5..af722f67c4 100644 --- a/packages/ui/src/forms/Form/mergeServerFormState.ts +++ b/packages/ui/src/forms/Form/mergeServerFormState.ts @@ -1,8 +1,7 @@ 'use client' -import type { FieldState } from 'payload' +import type { FieldState, FormState } from 'payload' import { dequal } from 'dequal/lite' // lite: no need for Map and Set support -import { type FormState } from 'payload' import { mergeErrorPaths } from './mergeErrorPaths.js' @@ -34,7 +33,6 @@ export const mergeServerFormState = ({ 'valid', 'errorMessage', 'errorPaths', - 'rows', 'customComponents', 'requiresRender', ] @@ -77,6 +75,26 @@ export const mergeServerFormState = ({ } } + /** + * Need to intelligently merge the rows array to ensure no rows are lost or added while the request was pending + * For example, the server response could come back with a row which has been deleted on the client + * Loop over the incoming rows, if it exists in client side form state, merge in any new properties from the server + */ + if (Array.isArray(incomingState[path].rows)) { + incomingState[path].rows.forEach((row) => { + const matchedExistingRowIndex = newFieldState.rows.findIndex( + (existingRow) => existingRow.id === row.id, + ) + + if (matchedExistingRowIndex > -1) { + newFieldState.rows[matchedExistingRowIndex] = { + ...newFieldState.rows[matchedExistingRowIndex], + ...row, + } + } + }) + } + /** * Handle adding all the remaining props that should be updated in the local form state from the server form state */ diff --git a/packages/ui/src/forms/fieldSchemasToFormState/addFieldStatePromise.ts b/packages/ui/src/forms/fieldSchemasToFormState/addFieldStatePromise.ts index c1b17a9f14..6677f6a1d4 100644 --- a/packages/ui/src/forms/fieldSchemasToFormState/addFieldStatePromise.ts +++ b/packages/ui/src/forms/fieldSchemasToFormState/addFieldStatePromise.ts @@ -316,6 +316,7 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom acc.rows.push({ id: row.id, + isLoading: false, }) const previousRows = previousFormState?.[path]?.rows || [] @@ -495,6 +496,7 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom acc.rowMetadata.push({ id: row.id, blockType: row.blockType, + isLoading: false, }) const collapsedRowIDs = preferences?.fields?.[path]?.collapsed From e87521a3762040e7b8be0f53ecc0ce6c9554bc7d Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Thu, 3 Apr 2025 12:27:14 -0400 Subject: [PATCH 69/77] perf(ui): significantly optimize form state component rendering, up to 96% smaller and 75% faster (#11946) Significantly optimizes the component rendering strategy within the form state endpoint by precisely rendering only the fields that require it. This cuts down on server processing and network response sizes when invoking form state requests **that manipulate array and block rows which contain server components**, such as rich text fields, custom row labels, etc. (results listed below). Here's a breakdown of the issue: Previously, when manipulating array and block fields, _all_ rows would render any server components that might exist within them, including rich text fields. This means that subsequent changes to these fields would potentially _re-render_ those same components even if they don't require it. For example, if you have an array field with a rich text field within it, adding the first row would cause the rich text field to render, which is expected. However, when you add a second row, the rich text field within the first row would render again unnecessarily along with the new row. This is especially noticeable for fields with many rows, where every single row processes its server components and returns RSC data. And this does not only affect nested rich text fields, but any custom component defined on the field level, as these are handled in the same way. The reason this was necessary in the first place was to ensure that the server components receive the proper data when they are rendered, such as the row index and the row's data. Changing one of these rows could cause the server component to receive the wrong data if it was not freshly rendered. While this is still a requirement that rows receive up-to-date props, it is no longer necessary to render everything. Here's a breakdown of the actual fix: This change ensures that only the fields that are actually being manipulated will be rendered, rather than all rows. The existing rows will remain in memory on the client, while the newly rendered components will return from the server. For example, if you add a new row to an array field, only the new row will render its server components. To do this, we send the path of the field that is being manipulated to the server. The server can then use this path to determine for itself which fields have already been rendered and which ones need required rendering. ## Results The following results were gathered by booting up the `form-state` test suite and seeding 100 array rows, each containing a rich text field. To invoke a form state request, we navigate to a document within the "posts" collection, then add a new array row to the list. The result is then saved to the file system for comparison. | Test Suite | Collection | Number of Rows | Before | After | Percentage Change | |------|------|---------|--------|--------|--------| | `form-state` | `posts` | 101 | 1.9MB / 266ms | 80KB / 70ms | ~96% smaller / ~75% faster | --------- Co-authored-by: James Co-authored-by: Alessio Gravili --- docs/configuration/collections.mdx | 50 +-- packages/payload/src/admin/forms/Form.ts | 22 +- .../src/features/upload/server/validate.ts | 1 - packages/richtext-lexical/src/index.ts | 4 +- packages/ui/src/fields/Array/index.tsx | 30 +- packages/ui/src/fields/Blocks/index.tsx | 4 +- packages/ui/src/forms/Form/fieldReducer.ts | 73 +---- packages/ui/src/forms/Form/index.tsx | 2 +- .../ui/src/forms/Form/mergeServerFormState.ts | 3 +- .../addFieldStatePromise.ts | 65 ++-- .../forms/fieldSchemasToFormState/index.tsx | 4 + .../fieldSchemasToFormState/iterateFields.ts | 4 + .../fieldSchemasToFormState/renderField.tsx | 291 +++++++++++------- .../forms/fieldSchemasToFormState/types.ts | 3 + packages/ui/src/providers/ListQuery/types.ts | 2 +- packages/ui/src/utilities/buildFormState.ts | 2 + .../migrations/20250328_185055.ts | 2 +- .../collections/Posts/ArrayRowLabel.tsx | 5 + test/form-state/collections/Posts/index.ts | 5 + test/form-state/e2e.spec.ts | 99 ++++-- test/form-state/int.spec.ts | 90 +++++- test/helpers/e2e/assertRequestBody.ts | 25 +- test/helpers/e2e/assertResponseBody.ts | 86 ++++++ test/queues/config.ts | 4 +- test/queues/int.spec.ts | 2 +- tsconfig.base.json | 2 +- 26 files changed, 585 insertions(+), 295 deletions(-) create mode 100644 test/form-state/collections/Posts/ArrayRowLabel.tsx create mode 100644 test/helpers/e2e/assertResponseBody.ts diff --git a/docs/configuration/collections.mdx b/docs/configuration/collections.mdx index 9e804750b9..bbea44a364 100644 --- a/docs/configuration/collections.mdx +++ b/docs/configuration/collections.mdx @@ -60,31 +60,31 @@ export const Posts: CollectionConfig = { The following options are available: -| Option | Description | -| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `admin` | The configuration options for the Admin Panel. [More details](#admin-options). | -| `access` | Provide Access Control functions to define exactly who should be able to do what with Documents in this Collection. [More details](../access-control/collections). | -| `auth` | Specify options if you would like this Collection to feature authentication. [More details](../authentication/overview). | -| `custom` | Extension point for adding custom data (e.g. for plugins) | -| `disableDuplicate` | When true, do not show the "Duplicate" button while editing documents within this Collection and prevent `duplicate` from all APIs. | -| `defaultSort` | Pass a top-level field to sort by default in the Collection List View. Prefix the name of the field with a minus symbol ("-") to sort in descending order. Multiple fields can be specified by using a string array. | -| `dbName` | Custom table or Collection name depending on the Database Adapter. Auto-generated from slug if not defined. | -| `endpoints` | Add custom routes to the REST API. Set to `false` to disable routes. [More details](../rest-api/overview#custom-endpoints). | -| `fields` \* | Array of field types that will determine the structure and functionality of the data stored within this Collection. [More details](../fields/overview). | -| `graphQL` | Manage GraphQL-related properties for this collection. [More](#graphql) | -| `hooks` | Entry point for Hooks. [More details](../hooks/overview#collection-hooks). | -| `orderable` | If true, enables custom ordering for the collection, and documents can be reordered via drag and drop. Uses [fractional indexing](https://observablehq.com/@dgreensp/implementing-fractional-indexing) for efficient reordering. | -| `labels` | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. | -| `enableQueryPresets` | Enable query presets for this Collection. [More details](../query-presets/overview). | -| `lockDocuments` | Enables or disables document locking. By default, document locking is enabled. Set to an object to configure, or set to `false` to disable locking. [More details](../admin/locked-documents). | -| `slug` \* | Unique, URL-friendly string that will act as an identifier for this Collection. | -| `timestamps` | Set to false to disable documents' automatically generated `createdAt` and `updatedAt` timestamps. | -| `typescript` | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. | -| `upload` | Specify options if you would like this Collection to support file uploads. For more, consult the [Uploads](../upload/overview) documentation. | -| `versions` | Set to true to enable default options, or configure with object properties. [More details](../versions/overview#collection-config). | -| `defaultPopulate` | Specify which fields to select when this Collection is populated from another document. [More Details](../queries/select#defaultpopulate-collection-config-property). | -| `indexes` | Define compound indexes for this collection. This can be used to either speed up querying/sorting by 2 or more fields at the same time or to ensure uniqueness between several fields. | -| `forceSelect` | Specify which fields should be selected always, regardless of the `select` query which can be useful that the field exists for access control / hooks | +| Option | Description | +| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `admin` | The configuration options for the Admin Panel. [More details](#admin-options). | +| `access` | Provide Access Control functions to define exactly who should be able to do what with Documents in this Collection. [More details](../access-control/collections). | +| `auth` | Specify options if you would like this Collection to feature authentication. [More details](../authentication/overview). | +| `custom` | Extension point for adding custom data (e.g. for plugins) | +| `disableDuplicate` | When true, do not show the "Duplicate" button while editing documents within this Collection and prevent `duplicate` from all APIs. | +| `defaultSort` | Pass a top-level field to sort by default in the Collection List View. Prefix the name of the field with a minus symbol ("-") to sort in descending order. Multiple fields can be specified by using a string array. | +| `dbName` | Custom table or Collection name depending on the Database Adapter. Auto-generated from slug if not defined. | +| `endpoints` | Add custom routes to the REST API. Set to `false` to disable routes. [More details](../rest-api/overview#custom-endpoints). | +| `fields` \* | Array of field types that will determine the structure and functionality of the data stored within this Collection. [More details](../fields/overview). | +| `graphQL` | Manage GraphQL-related properties for this collection. [More](#graphql) | +| `hooks` | Entry point for Hooks. [More details](../hooks/overview#collection-hooks). | +| `orderable` | If true, enables custom ordering for the collection, and documents can be reordered via drag and drop. Uses [fractional indexing](https://observablehq.com/@dgreensp/implementing-fractional-indexing) for efficient reordering. | +| `labels` | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. | +| `enableQueryPresets` | Enable query presets for this Collection. [More details](../query-presets/overview). | +| `lockDocuments` | Enables or disables document locking. By default, document locking is enabled. Set to an object to configure, or set to `false` to disable locking. [More details](../admin/locked-documents). | +| `slug` \* | Unique, URL-friendly string that will act as an identifier for this Collection. | +| `timestamps` | Set to false to disable documents' automatically generated `createdAt` and `updatedAt` timestamps. | +| `typescript` | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. | +| `upload` | Specify options if you would like this Collection to support file uploads. For more, consult the [Uploads](../upload/overview) documentation. | +| `versions` | Set to true to enable default options, or configure with object properties. [More details](../versions/overview#collection-config). | +| `defaultPopulate` | Specify which fields to select when this Collection is populated from another document. [More Details](../queries/select#defaultpopulate-collection-config-property). | +| `indexes` | Define compound indexes for this collection. This can be used to either speed up querying/sorting by 2 or more fields at the same time or to ensure uniqueness between several fields. | +| `forceSelect` | Specify which fields should be selected always, regardless of the `select` query which can be useful that the field exists for access control / hooks | _\* An asterisk denotes that a property is required._ diff --git a/packages/payload/src/admin/forms/Form.ts b/packages/payload/src/admin/forms/Form.ts index 419087a6ec..88274b70b8 100644 --- a/packages/payload/src/admin/forms/Form.ts +++ b/packages/payload/src/admin/forms/Form.ts @@ -13,8 +13,12 @@ export type Data = { export type Row = { blockType?: string collapsed?: boolean + customComponents?: { + RowLabel?: React.ReactNode + } id: string isLoading?: boolean + lastRenderedPath?: string } export type FilterOptionsResult = { @@ -34,7 +38,6 @@ export type FieldState = { Error?: React.ReactNode Field?: React.ReactNode Label?: React.ReactNode - RowLabels?: React.ReactNode[] } disableFormData?: boolean errorMessage?: string @@ -46,8 +49,16 @@ export type FieldState = { fieldSchema?: Field filterOptions?: FilterOptionsResult initialValue?: unknown + /** + * The path of the field when its custom components were last rendered. + * This is used to denote if a field has been rendered, and if so, + * what path it was rendered under last. + * + * If this path is undefined, or, if it is different + * from the current path of a given field, the field's components will be re-rendered. + */ + lastRenderedPath?: string passesCondition?: boolean - requiresRender?: boolean rows?: Row[] /** * The `serverPropsToIgnore` obj is used to prevent the various properties from being overridden across form state requests. @@ -95,6 +106,13 @@ export type BuildFormStateArgs = { */ language?: keyof SupportedLanguages locale?: string + /** + * If true, will not render RSCs and instead return a simple string in their place. + * This is useful for environments that lack RSC support, such as Jest. + * Form state can still be built, but any server components will be omitted. + * @default false + */ + mockRSCs?: boolean operation?: 'create' | 'update' /* If true, will render field components within their state object diff --git a/packages/richtext-lexical/src/features/upload/server/validate.ts b/packages/richtext-lexical/src/features/upload/server/validate.ts index bbbdbca49e..ac475d1acb 100644 --- a/packages/richtext-lexical/src/features/upload/server/validate.ts +++ b/packages/richtext-lexical/src/features/upload/server/validate.ts @@ -46,7 +46,6 @@ export const uploadValidation = ( const result = await fieldSchemasToFormState({ id, collectionSlug: node.relationTo, - data: node?.fields ?? {}, documentData: data, fields: collection.fields, diff --git a/packages/richtext-lexical/src/index.ts b/packages/richtext-lexical/src/index.ts index 78f6b95551..4e0fd0083d 100644 --- a/packages/richtext-lexical/src/index.ts +++ b/packages/richtext-lexical/src/index.ts @@ -901,12 +901,12 @@ export { HTMLConverterFeature, type HTMLConverterFeatureProps, } from './features/converters/lexicalToHtml_deprecated/index.js' -export { DebugJsxConverterFeature } from './features/debug/jsxConverter/server/index.js' export { convertLexicalToMarkdown } from './features/converters/lexicalToMarkdown/index.js' export { convertMarkdownToLexical } from './features/converters/markdownToLexical/index.js' - export { getPayloadPopulateFn } from './features/converters/utilities/payloadPopulateFn.js' + export { getRestPopulateFn } from './features/converters/utilities/restPopulateFn.js' +export { DebugJsxConverterFeature } from './features/debug/jsxConverter/server/index.js' export { TestRecorderFeature } from './features/debug/testRecorder/server/index.js' export { TreeViewFeature } from './features/debug/treeView/server/index.js' export { EXPERIMENTAL_TableFeature } from './features/experimental_table/server/index.js' diff --git a/packages/ui/src/fields/Array/index.tsx b/packages/ui/src/fields/Array/index.tsx index a230a93c82..5c3730e4c3 100644 --- a/packages/ui/src/fields/Array/index.tsx +++ b/packages/ui/src/fields/Array/index.tsx @@ -110,10 +110,10 @@ export const ArrayFieldComponent: ArrayFieldClientComponent = (props) => { ) const { - customComponents: { AfterInput, BeforeInput, Description, Error, Label, RowLabels } = {}, + customComponents: { AfterInput, BeforeInput, Description, Error, Label } = {}, disabled, errorPaths, - rows: rowsData = [], + rows = [], showError, valid, value, @@ -173,12 +173,12 @@ export const ArrayFieldComponent: ArrayFieldClientComponent = (props) => { (collapsed: boolean) => { const { collapsedIDs, updatedRows } = toggleAllRows({ collapsed, - rows: rowsData, + rows, }) setDocFieldPreferences(path, { collapsed: collapsedIDs }) dispatchFields({ type: 'SET_ALL_ROWS_COLLAPSED', path, updatedRows }) }, - [dispatchFields, path, rowsData, setDocFieldPreferences], + [dispatchFields, path, rows, setDocFieldPreferences], ) const setCollapse = useCallback( @@ -186,22 +186,22 @@ export const ArrayFieldComponent: ArrayFieldClientComponent = (props) => { const { collapsedIDs, updatedRows } = extractRowsAndCollapsedIDs({ collapsed, rowID, - rows: rowsData, + rows, }) dispatchFields({ type: 'SET_ROW_COLLAPSED', path, updatedRows }) setDocFieldPreferences(path, { collapsed: collapsedIDs }) }, - [dispatchFields, path, rowsData, setDocFieldPreferences], + [dispatchFields, path, rows, setDocFieldPreferences], ) - const hasMaxRows = maxRows && rowsData.length >= maxRows + const hasMaxRows = maxRows && rows.length >= maxRows const fieldErrorCount = errorPaths.length const fieldHasErrors = submitted && errorPaths.length > 0 - const showRequired = (readOnly || disabled) && rowsData.length === 0 - const showMinRows = rowsData.length < minRows || (required && rowsData.length === 0) + const showRequired = (readOnly || disabled) && rows.length === 0 + const showMinRows = rows.length < minRows || (required && rows.length === 0) return (
    { )}
    - {rowsData?.length > 0 && ( + {rows?.length > 0 && (