Bläddra i källkod

configure biome for page service

Futa Arai 4 månader sedan
förälder
incheckning
6caac9548c

+ 1 - 0
apps/app/.eslintrc.js

@@ -96,6 +96,7 @@ module.exports = {
     'src/server/service/in-app-notification/**',
     'src/server/service/interfaces/**',
     'src/server/service/normalize-data/**',
+    'src/server/service/page/**',
   ],
   settings: {
     // resolve path aliases by eslint-import-resolver-typescript

+ 37 - 19
apps/app/src/server/service/page/delete-completely-user-home-by-system.integ.ts

@@ -1,5 +1,4 @@
 import type EventEmitter from 'events';
-
 import mongoose from 'mongoose';
 import { vi } from 'vitest';
 import { mock } from 'vitest-mock-extended';
@@ -8,19 +7,21 @@ import { getPageSchema } from '~/server/models/obsolete-page';
 import { configManager } from '~/server/service/config-manager';
 
 import pageModel from '../../models/page';
-
 import { deleteCompletelyUserHomeBySystem } from './delete-completely-user-home-by-system';
 import type { IPageService } from './page-service';
 
 // TODO: use actual user model after ~/server/models/user.js becomes importable in vitest
 // ref: https://github.com/vitest-dev/vitest/issues/846
-const userSchema = new mongoose.Schema({
-  name: { type: String },
-  username: { type: String, required: true, unique: true },
-  email: { type: String, unique: true, sparse: true },
-}, {
-  timestamps: true,
-});
+const userSchema = new mongoose.Schema(
+  {
+    name: { type: String },
+    username: { type: String, required: true, unique: true },
+    email: { type: String, unique: true, sparse: true },
+  },
+  {
+    timestamps: true,
+  },
+);
 const User = mongoose.model('User', userSchema);
 
 describe('delete-completely-user-home-by-system test', () => {
@@ -31,7 +32,7 @@ describe('delete-completely-user-home-by-system test', () => {
   const userId1 = new mongoose.Types.ObjectId();
   const user1HomepageId = new mongoose.Types.ObjectId();
 
-  beforeAll(async() => {
+  beforeAll(async () => {
     // setup page model
     getPageSchema(null);
     pageModel(null);
@@ -45,7 +46,10 @@ describe('delete-completely-user-home-by-system test', () => {
 
     // setup user documents
     const user1 = await User.create({
-      _id: userId1, name: 'user1', username: 'user1', email: 'user1@example.com',
+      _id: userId1,
+      name: 'user1',
+      username: 'user1',
+      email: 'user1@example.com',
     });
 
     // setup page documents
@@ -85,10 +89,16 @@ describe('delete-completely-user-home-by-system test', () => {
 
   describe('deleteCompletelyUserHomeBySystem()', () => {
     // setup
-    const mockUpdateDescendantCountOfAncestors = vi.fn().mockImplementation(() => Promise.resolve());
-    const mockDeleteCompletelyOperation = vi.fn().mockImplementation(() => Promise.resolve());
+    const mockUpdateDescendantCountOfAncestors = vi
+      .fn()
+      .mockImplementation(() => Promise.resolve());
+    const mockDeleteCompletelyOperation = vi
+      .fn()
+      .mockImplementation(() => Promise.resolve());
     const mockPageEvent = mock<EventEmitter>();
-    const mockDeleteMultipleCompletely = vi.fn().mockImplementation(() => Promise.resolve());
+    const mockDeleteMultipleCompletely = vi
+      .fn()
+      .mockImplementation(() => Promise.resolve());
 
     const mockPageService = mock<IPageService>({
       updateDescendantCountOfAncestors: mockUpdateDescendantCountOfAncestors,
@@ -97,10 +107,13 @@ describe('delete-completely-user-home-by-system test', () => {
       deleteMultipleCompletely: mockDeleteMultipleCompletely,
     });
 
-    it('should call used page service functions', async() => {
+    it('should call used page service functions', async () => {
       // when
       const existsUserHomepagePath = '/user/user1';
-      await deleteCompletelyUserHomeBySystem(existsUserHomepagePath, mockPageService);
+      await deleteCompletelyUserHomeBySystem(
+        existsUserHomepagePath,
+        mockPageService,
+      );
 
       // then
       expect(mockUpdateDescendantCountOfAncestors).toHaveBeenCalled();
@@ -109,13 +122,18 @@ describe('delete-completely-user-home-by-system test', () => {
       expect(mockDeleteMultipleCompletely).toHaveBeenCalled();
     });
 
-    it('should throw error if userHomepage is not exists', async() => {
+    it('should throw error if userHomepage is not exists', async () => {
       // when
       const notExistsUserHomepagePath = '/user/not_exists_user';
-      const deleteUserHomepageFunction = deleteCompletelyUserHomeBySystem(notExistsUserHomepagePath, mockPageService);
+      const deleteUserHomepageFunction = deleteCompletelyUserHomeBySystem(
+        notExistsUserHomepagePath,
+        mockPageService,
+      );
 
       // then
-      expect(deleteUserHomepageFunction).rejects.toThrow('user homepage is not found.');
+      expect(deleteUserHomepageFunction).rejects.toThrow(
+        'user homepage is not found.',
+      );
     });
   });
 });

+ 36 - 25
apps/app/src/server/service/page/delete-completely-user-home-by-system.ts

@@ -1,11 +1,10 @@
-import { Writable } from 'stream';
-import { pipeline } from 'stream/promises';
-
-import { getIdForRef } from '@growi/core';
 import type { IPage, Ref } from '@growi/core';
+import { getIdForRef } from '@growi/core';
 import { isUsersHomepage } from '@growi/core/dist/utils/page-path-utils';
 import type { HydratedDocument } from 'mongoose';
 import mongoose from 'mongoose';
+import { Writable } from 'stream';
+import { pipeline } from 'stream/promises';
 
 import type { PageDocument, PageModel } from '~/server/models/page';
 import { createBatchStream } from '~/server/util/batch-stream';
@@ -17,29 +16,33 @@ import { shouldUseV4Process } from './should-use-v4-process';
 
 const logger = loggerFactory('growi:services:page');
 
-
-type IPageUnderV5 = Omit<IPage, 'parent'> & { parent: Ref<IPage> }
+type IPageUnderV5 = Omit<IPage, 'parent'> & { parent: Ref<IPage> };
 
 const _shouldUseV5Process = (page: IPage): page is IPageUnderV5 => {
   return !shouldUseV4Process(page);
 };
 
 /**
-   * @description This function is intended to be used exclusively for forcibly deleting the user homepage by the system.
-   * It should only be called from within the appropriate context and with caution as it performs a system-level operation.
-   *
-   * @param {string} userHomepagePath - The path of the user's homepage.
-   * @returns {Promise<void>} - A Promise that resolves when the deletion is complete.
-   * @throws {Error} - If an error occurs during the deletion process.
-   */
-export const deleteCompletelyUserHomeBySystem = async(userHomepagePath: string, pageService: IPageService): Promise<void> => {
+ * @description This function is intended to be used exclusively for forcibly deleting the user homepage by the system.
+ * It should only be called from within the appropriate context and with caution as it performs a system-level operation.
+ *
+ * @param {string} userHomepagePath - The path of the user's homepage.
+ * @returns {Promise<void>} - A Promise that resolves when the deletion is complete.
+ * @throws {Error} - If an error occurs during the deletion process.
+ */
+export const deleteCompletelyUserHomeBySystem = async (
+  userHomepagePath: string,
+  pageService: IPageService,
+): Promise<void> => {
   if (!isUsersHomepage(userHomepagePath)) {
     const msg = 'input value is not user homepage path.';
     logger.error(msg);
     throw new Error(msg);
   }
 
-  const Page = mongoose.model<HydratedDocument<PageDocument>, PageModel>('Page');
+  const Page = mongoose.model<HydratedDocument<PageDocument>, PageModel>(
+    'Page',
+  );
   const userHomepage = await Page.findByPath(userHomepagePath, true);
 
   if (userHomepage == null) {
@@ -56,8 +59,14 @@ export const deleteCompletelyUserHomeBySystem = async(userHomepagePath: string,
   try {
     if (shouldUseV5Process) {
       // Ensure consistency of ancestors
-      const inc = userHomepage.isEmpty ? -userHomepage.descendantCount : -(userHomepage.descendantCount + 1);
-      await pageService.updateDescendantCountOfAncestors(getIdForRef(userHomepage.parent), inc, true);
+      const inc = userHomepage.isEmpty
+        ? -userHomepage.descendantCount
+        : -(userHomepage.descendantCount + 1);
+      await pageService.updateDescendantCountOfAncestors(
+        getIdForRef(userHomepage.parent),
+        inc,
+        true,
+      );
     }
 
     // Delete the user's homepage
@@ -65,7 +74,9 @@ export const deleteCompletelyUserHomeBySystem = async(userHomepagePath: string,
 
     if (shouldUseV5Process) {
       // Remove leaf empty pages
-      await Page.removeLeafEmptyPagesRecursively(getIdForRef(userHomepage.parent));
+      await Page.removeLeafEmptyPagesRecursively(
+        getIdForRef(userHomepage.parent),
+      );
     }
 
     if (!userHomepage.isEmpty) {
@@ -82,8 +93,7 @@ export const deleteCompletelyUserHomeBySystem = async(userHomepagePath: string,
 
     // Stream processing to delete descendant pages
     // ────────┤ start │─────────
-    const readStream = await builder
-      .query
+    const readStream = await builder.query
       .lean()
       .cursor({ batchSize: BULK_REINDEX_SIZE });
 
@@ -98,8 +108,7 @@ export const deleteCompletelyUserHomeBySystem = async(userHomepagePath: string,
           // Delete multiple pages completely
           await pageService.deleteMultipleCompletely(batch, undefined);
           logger.debug(`Adding pages progressing: (count=${count})`);
-        }
-        catch (err) {
+        } catch (err) {
           logger.error('addAllPages error on add anyway: ', err);
         }
         callback();
@@ -112,9 +121,11 @@ export const deleteCompletelyUserHomeBySystem = async(userHomepagePath: string,
 
     await pipeline(readStream, batchStream, writeStream);
     // ────────┤ end │─────────
-  }
-  catch (err) {
-    logger.error('Error occurred while deleting user homepage and subpages.', err);
+  } catch (err) {
+    logger.error(
+      'Error occurred while deleting user homepage and subpages.',
+      err,
+    );
     throw err;
   }
 };

+ 18 - 20
apps/app/src/server/service/page/index.ts

@@ -1,26 +1,25 @@
-import assert from 'assert';
-import type EventEmitter from 'events';
-import pathlib from 'path';
-import { Readable, Writable } from 'stream';
-import { pipeline } from 'stream/promises';
-
-import {
-  PageStatus, YDocStatus, getIdForRef,
+import {getIdForRef,
   getIdStringForRef,
+  PageStatus, YDocStatus, 
 } from '@growi/core';
-import { PageGrant, isIPageInfoForEntity } from '@growi/core/dist/interfaces';
-import type {
-  Ref, HasObjectId, IUserHasId, IUser,
-  IPage, IGrantedGroup, IRevisionHasId,
-  IPageNotFoundInfo, IPageInfoExt, IPageInfo, IPageInfoForEntity, IPageInfoForOperation,
-  IDataWithRequiredMeta,
+import type {HasObjectId, 
+  IDataWithRequiredMeta,IGrantedGroup, 
+  IPage, IPageInfo, IPageInfoExt, IPageInfoForEntity, IPageInfoForOperation,
+  IPageNotFoundInfo, IRevisionHasId,IUser,IUserHasId, 
+  Ref, 
 } from '@growi/core/dist/interfaces';
+import { isIPageInfoForEntity, PageGrant } from '@growi/core/dist/interfaces';
 import {
   pagePathUtils, pathUtils,
 } from '@growi/core/dist/utils';
+import assert from 'assert';
 import escapeStringRegexp from 'escape-string-regexp';
+import type EventEmitter from 'events';
 import type { Cursor, HydratedDocument } from 'mongoose';
 import mongoose from 'mongoose';
+import pathlib from 'path';
+import { Readable, Writable } from 'stream';
+import { pipeline } from 'stream/promises';
 
 import { Comment } from '~/features/comment/server';
 import type { ExternalUserGroupDocument } from '~/features/external-user-group/server/models/external-user-group';
@@ -37,12 +36,12 @@ import {
 import type { PopulatedGrantedGroup } from '~/interfaces/page-grant';
 import { PageActionStage, PageActionType } from '~/interfaces/page-operation';
 import { PageActionOnGroupDelete } from '~/interfaces/user-group';
-import { SocketEventName, type PageMigrationErrorData, type UpdateDescCountRawData } from '~/interfaces/websocket';
+import { type PageMigrationErrorData, SocketEventName, type UpdateDescCountRawData } from '~/interfaces/websocket';
 import type { CurrentPageYjsData } from '~/interfaces/yjs';
 import type Crowi from '~/server/crowi';
 import type { CreateMethod } from '~/server/models/page';
-import {
-  type PageModel, type PageDocument, pushRevision, PageQueryBuilder,
+import {type PageDocument, 
+  type PageModel, PageQueryBuilder,pushRevision, 
 } from '~/server/models/page';
 import type { PageTagRelationDocument } from '~/server/models/page-tag-relation';
 import PageTagRelation from '~/server/models/page-tag-relation';
@@ -71,7 +70,6 @@ import { configManager } from '../config-manager';
 import type { IPageGrantService } from '../page-grant';
 import { preNotifyService } from '../pre-notify';
 import { getYjsService } from '../yjs';
-
 import { BULK_REINDEX_SIZE, LIMIT_FOR_MULTIPLE_PAGE_OP } from './consts';
 import type { IPageService } from './page-service';
 import { shouldUseV4Process } from './should-use-v4-process';
@@ -3075,7 +3073,7 @@ class PageService implements IPageService {
       }
     }
     finally {
-      await Page.deleteMany({ path: { $regex: new RegExp('growi_check_is_path_index_unique', 'g') } });
+      await Page.deleteMany({ path: { $regex: /growi_check_is_path_index_unique/g } });
     }
 
 
@@ -4360,7 +4358,7 @@ class PageService implements IPageService {
 
     // https://regex101.com/r/KYZWls/1
     // ex. /trash/.*
-    const regexp = new RegExp('^/trash\\/.*$');
+    const regexp = /^\/trash\\/.*$/;
     const queryBuilder = new PageQueryBuilder(Page.find({ path: { $regex: regexp } }), true);
 
     await queryBuilder.addViewerCondition(user, userGroups);

+ 171 - 41
apps/app/src/server/service/page/page-service.ts

@@ -1,11 +1,17 @@
-import type EventEmitter from 'events';
-
 import type {
   HasObjectId,
   IDataWithRequiredMeta,
   IGrantedGroup,
-  IPageInfo, IPageInfoForEntity, IPageNotFoundInfo, IUser, IPageInfoExt, IPage, PageGrant, IUserHasId,
+  IPage,
+  IPageInfo,
+  IPageInfoExt,
+  IPageInfoForEntity,
+  IPageNotFoundInfo,
+  IUser,
+  IUserHasId,
+  PageGrant,
 } from '@growi/core';
+import type EventEmitter from 'events';
 import type { HydratedDocument, Types } from 'mongoose';
 
 import type { ExternalUserGroupDocument } from '~/features/external-user-group/server/models/external-user-group';
@@ -19,59 +25,183 @@ import type { PageOperationDocument } from '~/server/models/page-operation';
 import type { UserGroupDocument } from '~/server/models/user-group';
 
 export interface IPageService {
-  create(path: string, body: string, user: HasObjectId, options: IOptionsForCreate): Promise<HydratedDocument<PageDocument>>,
-  forceCreateBySystem(path: string, body: string, options: IOptionsForCreate): Promise<PageDocument>,
+  create(
+    path: string,
+    body: string,
+    user: HasObjectId,
+    options: IOptionsForCreate,
+  ): Promise<HydratedDocument<PageDocument>>;
+  forceCreateBySystem(
+    path: string,
+    body: string,
+    options: IOptionsForCreate,
+  ): Promise<PageDocument>;
   updatePage(
-    pageData: HydratedDocument<PageDocument>, body: string | null, previousBody: string | null, user: IUser, options: IOptionsForUpdate
-  ): Promise<HydratedDocument<PageDocument>>,
-  updateDescendantCountOfAncestors: (pageId: ObjectIdLike, inc: number, shouldIncludeTarget: boolean) => Promise<void>,
+    pageData: HydratedDocument<PageDocument>,
+    body: string | null,
+    previousBody: string | null,
+    user: IUser,
+    options: IOptionsForUpdate,
+  ): Promise<HydratedDocument<PageDocument>>;
+  updateDescendantCountOfAncestors: (
+    pageId: ObjectIdLike,
+    inc: number,
+    shouldIncludeTarget: boolean,
+  ) => Promise<void>;
   updateGrant(
-    page: HydratedDocument<PageDocument>, user: IUserHasId, grantData: {grant: PageGrant, userRelatedGrantedGroups: IGrantedGroup[]},
-  ): Promise<PageDocument>,
-  deleteCompletelyOperation: (pageIds: ObjectIdLike[], pagePaths: string[]) => Promise<void>,
-  getEventEmitter: () => EventEmitter,
-  deleteMultipleCompletely: (pages: ObjectIdLike[], user: IUser | undefined) => Promise<void>,
+    page: HydratedDocument<PageDocument>,
+    user: IUserHasId,
+    grantData: { grant: PageGrant; userRelatedGrantedGroups: IGrantedGroup[] },
+  ): Promise<PageDocument>;
+  deleteCompletelyOperation: (
+    pageIds: ObjectIdLike[],
+    pagePaths: string[],
+  ) => Promise<void>;
+  getEventEmitter: () => EventEmitter;
+  deleteMultipleCompletely: (
+    pages: ObjectIdLike[],
+    user: IUser | undefined,
+  ) => Promise<void>;
   findPageAndMetaDataByViewer(
-      pageId: string, path: string | null, user?: HydratedDocument<IUser>, isSharedPage?: boolean,
-  ): Promise<IDataWithRequiredMeta<HydratedDocument<PageDocument>, IPageInfoExt> | IDataWithRequiredMeta<null, IPageNotFoundInfo>>
+    pageId: string,
+    path: string | null,
+    user?: HydratedDocument<IUser>,
+    isSharedPage?: boolean,
+  ): Promise<
+    | IDataWithRequiredMeta<HydratedDocument<PageDocument>, IPageInfoExt>
+    | IDataWithRequiredMeta<null, IPageNotFoundInfo>
+  >;
   findPageAndMetaDataByViewer(
-      pageId: string | null, path: string, user?: HydratedDocument<IUser>, isSharedPage?: boolean,
-  ): Promise<IDataWithRequiredMeta<HydratedDocument<PageDocument>, IPageInfoExt> | IDataWithRequiredMeta<null, IPageNotFoundInfo>>
-  resumeRenameSubOperation(renamedPage: PageDocument, pageOp: PageOperationDocument, activity?): Promise<void>
+    pageId: string | null,
+    path: string,
+    user?: HydratedDocument<IUser>,
+    isSharedPage?: boolean,
+  ): Promise<
+    | IDataWithRequiredMeta<HydratedDocument<PageDocument>, IPageInfoExt>
+    | IDataWithRequiredMeta<null, IPageNotFoundInfo>
+  >;
+  resumeRenameSubOperation(
+    renamedPage: PageDocument,
+    pageOp: PageOperationDocument,
+    activity?,
+  ): Promise<void>;
   handlePrivatePagesForGroupsToDelete(
     groupsToDelete: UserGroupDocument[] | ExternalUserGroupDocument[],
     action: PageActionOnGroupDelete,
     transferToUserGroup: IGrantedGroup | undefined,
     user: IUser,
-): Promise<void>
-  shortBodiesMapByPageIds(pageIds?: Types.ObjectId[], user?): Promise<Record<string, string | null>>,
-  constructBasicPageInfo(page: PageDocument, isGuestUser?: boolean): Omit<IPageInfo | IPageInfoForEntity, 'bookmarkCount'>,
-  normalizeAllPublicPages(): Promise<void>,
-  canDelete(page: PageDocument, creatorId: ObjectIdLike | null, operator: any | null, isRecursively: boolean): boolean,
+  ): Promise<void>;
+  shortBodiesMapByPageIds(
+    pageIds?: Types.ObjectId[],
+    user?,
+  ): Promise<Record<string, string | null>>;
+  constructBasicPageInfo(
+    page: PageDocument,
+    isGuestUser?: boolean,
+  ): Omit<IPageInfo | IPageInfoForEntity, 'bookmarkCount'>;
+  normalizeAllPublicPages(): Promise<void>;
+  canDelete(
+    page: PageDocument,
+    creatorId: ObjectIdLike | null,
+    operator: any | null,
+    isRecursively: boolean,
+  ): boolean;
   canDeleteCompletely(
-    page: PageDocument, creatorId: ObjectIdLike | null, operator: any | null, isRecursively: boolean, userRelatedGroups: PopulatedGrantedGroup[]
-  ): boolean,
+    page: PageDocument,
+    creatorId: ObjectIdLike | null,
+    operator: any | null,
+    isRecursively: boolean,
+    userRelatedGroups: PopulatedGrantedGroup[],
+  ): boolean;
   canDeleteCompletelyAsMultiGroupGrantedPage(
-    page: PageDocument, creatorId: ObjectIdLike | null, operator: any | null, userRelatedGroups: PopulatedGrantedGroup[]
-  ): boolean,
-  getYjsData(pageId: string, revisionBody?: string): Promise<CurrentPageYjsData>,
-  updateDescendantCountOfPagesWithPaths(paths: string[]): Promise<void>,
-  revertRecursivelyMainOperation(page, user, options, pageOpId: ObjectIdLike, activity?): Promise<void>,
-  revertDeletedPage(page, user, options, isRecursively: boolean, activityParameters?),
-  deleteCompletelyRecursivelyMainOperation(page, user, options, pageOpId: ObjectIdLike, activity?): Promise<void>,
-  deleteCompletely(page, user, options, isRecursively: boolean, preventEmitting: boolean, activityParameters),
-  deleteRecursivelyMainOperation(page, user, pageOpId: ObjectIdLike, activity?): Promise<void>,
-  deletePage(page, user, options, isRecursively: boolean, activityParameters),
+    page: PageDocument,
+    creatorId: ObjectIdLike | null,
+    operator: any | null,
+    userRelatedGroups: PopulatedGrantedGroup[],
+  ): boolean;
+  getYjsData(
+    pageId: string,
+    revisionBody?: string,
+  ): Promise<CurrentPageYjsData>;
+  updateDescendantCountOfPagesWithPaths(paths: string[]): Promise<void>;
+  revertRecursivelyMainOperation(
+    page,
+    user,
+    options,
+    pageOpId: ObjectIdLike,
+    activity?,
+  ): Promise<void>;
+  revertDeletedPage(
+    page,
+    user,
+    options,
+    isRecursively: boolean,
+    activityParameters?,
+  );
+  deleteCompletelyRecursivelyMainOperation(
+    page,
+    user,
+    options,
+    pageOpId: ObjectIdLike,
+    activity?,
+  ): Promise<void>;
+  deleteCompletely(
+    page,
+    user,
+    options,
+    isRecursively: boolean,
+    preventEmitting: boolean,
+    activityParameters,
+  );
+  deleteRecursivelyMainOperation(
+    page,
+    user,
+    pageOpId: ObjectIdLike,
+    activity?,
+  ): Promise<void>;
+  deletePage(page, user, options, isRecursively: boolean, activityParameters);
   duplicateRecursivelyMainOperation(
     page: PageDocument,
     newPagePath: string,
     user,
     pageOpId: ObjectIdLike,
     onlyDuplicateUserRelatedResources: boolean,
-  ): Promise<void>,
-  duplicate(page: PageDocument, newPagePath: string, user, isRecursively: boolean, onlyDuplicateUserRelatedResources: boolean),
-  renameSubOperation(page, newPagePath: string, user, options, renamedPage, pageOpId: ObjectIdLike, activity?): Promise<void>,
-  renamePage(page: IPage, newPagePath, user, options, activityParameters): Promise<PageDocument | null>,
-  renameMainOperation(page, newPagePath: string, user, options, pageOpId: ObjectIdLike, activity?): Promise<PageDocument | null>,
-  createSubOperation(page, user, options: IOptionsForCreate, pageOpId: ObjectIdLike): Promise<void>,
+  ): Promise<void>;
+  duplicate(
+    page: PageDocument,
+    newPagePath: string,
+    user,
+    isRecursively: boolean,
+    onlyDuplicateUserRelatedResources: boolean,
+  );
+  renameSubOperation(
+    page,
+    newPagePath: string,
+    user,
+    options,
+    renamedPage,
+    pageOpId: ObjectIdLike,
+    activity?,
+  ): Promise<void>;
+  renamePage(
+    page: IPage,
+    newPagePath,
+    user,
+    options,
+    activityParameters,
+  ): Promise<PageDocument | null>;
+  renameMainOperation(
+    page,
+    newPagePath: string,
+    user,
+    options,
+    pageOpId: ObjectIdLike,
+    activity?,
+  ): Promise<PageDocument | null>;
+  createSubOperation(
+    page,
+    user,
+    options: IOptionsForCreate,
+    pageOpId: ObjectIdLike,
+  ): Promise<void>;
 }

+ 3 - 1
apps/app/src/server/service/page/should-use-v4-process.ts

@@ -14,7 +14,9 @@ export const shouldUseV4Process = (page: IPage): boolean => {
   const isRoot = isTopPage(page.path);
   const isPageRestricted = page.grant === Page.GRANT_RESTRICTED;
 
-  const shouldUseV4Process = !isRoot && (!isV5Compatible || !isPageMigrated || isTrashPage || isPageRestricted);
+  const shouldUseV4Process =
+    !isRoot &&
+    (!isV5Compatible || !isPageMigrated || isTrashPage || isPageRestricted);
 
   return shouldUseV4Process;
 };

+ 1 - 2
biome.json

@@ -30,8 +30,7 @@
       "!packages/pdf-converter-client/specs",
       "!apps/app/src/client",
       "!apps/app/src/server/middlewares",
-      "!apps/app/src/server/routes/apiv3/*.js",
-      "!apps/app/src/server/service/page"
+      "!apps/app/src/server/routes/apiv3/*.js"
     ]
   },
   "formatter": {