Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hydro v5 #951

Open
wants to merge 74 commits into
base: master
Choose a base branch
from
Open

Hydro v5 #951

wants to merge 74 commits into from

Conversation

undefined-moe
Copy link
Member

@undefined-moe undefined-moe commented Mar 3, 2025

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a modern, React‑powered user interface for configuration and settings management, featuring real‑time editing and revision history.
    • Added support for Kattis‑style checkers to enhance contest judging.
    • Enhanced translation handling by centralizing functionality within the I18nService.
    • Added new entries to the localization files for improved user experience in multiple languages.
    • Introduced a new ConfigService class for better configuration management.
    • Added a new procPeak property to the SandboxVersion and SandboxResult interfaces for tracking process peaks.
    • Enhanced user notifications related to domain membership status and actions.
    • Added a new message for users when they are kicked from a domain, specifying the domain and the user who performed the action.
  • Improvements

    • Upgraded core components and refactored integrations for increased performance, reliability, and smoother interactions.
    • Streamlined resource management and metrics configuration for a more robust system experience.
    • Enhanced cleanup processes and error handling in various services for better resource management.
    • Simplified the logic for user permissions and domain management within the application.
    • Improved the handling of historical records in the RecordModel class for better data tracking.
    • Refactored the ScoreboardService initialization for better context management.
    • Updated the apply function in the GeoIPService class for streamlined service registration.
    • Adjusted the handling of user roles and permissions to support batch processing in domain management.
    • Enhanced the DiscussionMainHandler class with optimized database query performance through index hints.
    • Updated the blacklist handling to return complete results from operations, improving functionality.
    • Removed deprecated global assignments for various utility functions, enhancing encapsulation and modularity.
    • Improved the handling of user account roles and statuses in localization files, providing clearer feedback for users.

Copy link

coderabbitai bot commented Mar 4, 2025

Walkthrough

The pull request involves comprehensive refactoring across the project. A new .gitattributes file enforces consistent line endings for various file types. Several modules and functions have been updated to improve type safety through generic parameters and stronger context integration, while redundant global assignments have been removed in favor of dependency injection. Dependency versions and package names have been revised across multiple package.json files, and a number of modules have been restructured or refactored—for example, transitioning asynchronous operations, enhancing error handling, and improving resource cleanup. The updates extend to configuration management, with new schema definitions replacing legacy settings, and major changes in the UI layer include the introduction of a new React/Vite package. Linting configurations, build tools, and service registration mechanisms have also been updated to streamline processes and ensure a more modular, maintainable codebase.

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

framework/framework/decorators.ts

Oops! Something went wrong! :(

ESLint: 9.23.0

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@hydrooj/eslint-config' imported from /eslint.config.mjs
at packageResolve (node:internal/modules/esm/resolve:839:9)
at moduleResolve (node:internal/modules/esm/resolve:908:18)
at defaultResolve (node:internal/modules/esm/resolve:1038:11)
at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:557:12)
at ModuleLoader.resolve (node:internal/modules/esm/loader:525:25)
at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:246:38)
at ModuleJob._link (node:internal/modules/esm/module_job:126:49)

framework/framework/server.ts

Oops! Something went wrong! :(

ESLint: 9.23.0

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@hydrooj/eslint-config' imported from /eslint.config.mjs
at packageResolve (node:internal/modules/esm/resolve:839:9)
at moduleResolve (node:internal/modules/esm/resolve:908:18)
at defaultResolve (node:internal/modules/esm/resolve:1038:11)
at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:557:12)
at ModuleLoader.resolve (node:internal/modules/esm/loader:525:25)
at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:246:38)
at ModuleJob._link (node:internal/modules/esm/module_job:126:49)

packages/hydrooj/src/service/server.ts

Oops! Something went wrong! :(

ESLint: 9.23.0

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@hydrooj/eslint-config' imported from /eslint.config.mjs
at packageResolve (node:internal/modules/esm/resolve:839:9)
at moduleResolve (node:internal/modules/esm/resolve:908:18)
at defaultResolve (node:internal/modules/esm/resolve:1038:11)
at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:557:12)
at ModuleLoader.resolve (node:internal/modules/esm/loader:525:25)
at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:246:38)
at ModuleJob._link (node:internal/modules/esm/module_job:126:49)

  • 2 others
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (15)
framework/framework/serializer.ts (1)

3-3: Enhanced type safety with generic parameter.

Adding the generic type parameter <T> to the serializer function improves type safety by allowing the HandlerCommon parameter to be properly typed. This ensures better type checking and IDE support when working with different handler types.

Consider adding a JSDoc comment to explain the purpose of the generic parameter:

+ /**
+  * Creates a serializer function for JSON.stringify with support for specialized handlers
+  * @template T Type parameter for the handler context
+  * @param ignoreSerializeFunction Whether to ignore serialize functions on objects
+  * @param h Optional handler common instance with type context
+  * @returns A replacer function for JSON.stringify
+  */
 export default function serializer<T>(ignoreSerializeFunction = false, h?: HandlerCommon<T>) {
packages/hydrooj/package.json (1)

19-21:

❓ Verification inconclusive

Update to new @cordisjs modularity architecture

The PR introduces dependencies on alpha versions of the modular @cordisjs packages (core, logger, and plugin-timer), replacing the previous monolithic cordis package. This aligns with the broader codebase update to use the namespaced packages.

Since these are alpha versions, let's verify their stability and compatibility:


🏁 Script executed:

#!/bin/bash
# Check the latest versions of these cordis packages and any relevant release notes

echo "Checking the latest versions of cordis packages:"
npm view @cordisjs/core versions --json | jq '.[-5:]'
npm view @cordisjs/logger versions --json | jq '.[-5:]'
npm view @cordisjs/plugin-timer versions --json | jq '.[-5:]'

# Check if there are any github repos with release notes
echo "Looking for related GitHub repositories:"
gh search repos --owner cordisjs --limit 3 --json name,url

Length of output: 612


Modular @cordisjs Dependencies Verified

The PR now correctly adopts the new modular architecture by replacing the monolithic package with the namespaced packages. Verification via npm view confirms that:

  • @cordisjs/core is updated to "4.0.0-alpha.1" (with earlier releases up to "4.0.0-alpha.0").
  • @cordisjs/logger is updated to "1.0.0-alpha.1" (following the previous 0.3.x cycle).
  • @cordisjs/plugin-timer remains at "1.0.0-alpha.0" (the only available version).

Since all these are alpha releases, additional stability and compatibility testing is advised before wider adoption.

framework/framework/decorators.ts (1)

38-40: Enhanced type safety with generic Context

The function signature now uses generics with <T extends Context>, allowing for more specific typing of the handler context. This is a significant improvement to type safety across the framework.

Consider adding a type guard or documentation clarifying how these generic handlers should be implemented. This would be helpful for developers creating custom handlers.

packages/hydrooj/src/loader.ts (1)

142-150: Enhanced asynchronous context initialization

The preload function has been updated to be asynchronous, ensuring proper initialization of the application context with required plugins before continuing execution. This is a good improvement for handling asynchronous operations.

There's a missing semicolon at the end of line 150, which was flagged by static analysis. Fix it to maintain code consistency:

-    })
+    });
🧰 Tools
🪛 GitHub Check: CodeQL

[notice] 150-150: Semicolon insertion
Avoid automated semicolon insertion (90% of all statements in the enclosing function have an explicit semicolon).

packages/hydrooj/src/context.ts (1)

12-13: Fix the TODO comment grammar.
There's a minor typo in the comment: "this is an broken declaration" should be "this is a broken declaration."

-// TODO: this is an broken declaration
+// TODO: this is a broken declaration
framework/framework/server.ts (10)

186-188: Remove usage of any for server renderers.
Casting (this.ctx as any).server.renderers can be replaced with proper type definitions for your server instance to ensure type safety.

-const renderers = Object.values((this.ctx as any).server.renderers as Record<string, Renderer>)
+const renderers = Object.values(this.ctx.server.renderers)
  .filter((r) => r.accept.includes(templateName) || r.asFallback);

246-246: Ensure consistent generics.
ConnectionHandler<C> extends HandlerCommon<C> similarly. If you anticipate a narrower generic type than any C, consider a more constrained approach to avoid confusion in usage sites.


481-483: Address repeated type casting.
You’re using (this.ctx.parallel as any) with a // FIXME: should pass type check. Recommend updating the type definitions to remove reliance on any.


535-536: Similar pattern with this.ctx.serial.
Likewise, you are casting this.ctx.serial as any. Consider refining your context or plugin types for improved type safety.


551-552: Parallel usage in WS handling.
Again, (this.ctx.parallel as any) is used when creating a connection. Try to unify type definitions to avoid these repeated workarounds.


594-594: Emit usage with as any.
Emitting 'connection/close' with (this.ctx.emit as any) also bypasses type checks. Suggest properly defining or augmenting your event emitter.


705-705: Event registration with as any.
this.ctx.on(…) is again cast to any for the callback. Type definitions for the event system can remove the need for such casts.


709-710: Refine handler parameters.
A TODO comment notes this should be typeof Handler<Context> instead of any. Updating it would enhance type safety.


715-715: Ensure typed connection handlers.
Similar to the Route method, switch from any to a well-defined handler type once your framework interface is stable.


720-724: Type the registered layers.
Storing all layers as any is flexible but loses type safety. Consider refining the signature of registerLayer to clarify the shape of each layer.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 221283e and dec3170.

📒 Files selected for processing (34)
  • .gitattributes (1 hunks)
  • framework/framework/decorators.ts (3 hunks)
  • framework/framework/interface.ts (1 hunks)
  • framework/framework/package.json (1 hunks)
  • framework/framework/serializer.ts (1 hunks)
  • framework/framework/server.ts (21 hunks)
  • package.json (1 hunks)
  • packages/hydrooj/package.json (1 hunks)
  • packages/hydrooj/src/context.ts (4 hunks)
  • packages/hydrooj/src/entry/worker.ts (1 hunks)
  • packages/hydrooj/src/handler/judge.ts (1 hunks)
  • packages/hydrooj/src/loader.ts (3 hunks)
  • packages/hydrooj/src/model/contest.ts (1 hunks)
  • packages/hydrooj/src/model/discussion.ts (1 hunks)
  • packages/hydrooj/src/model/document.ts (1 hunks)
  • packages/hydrooj/src/model/domain.ts (1 hunks)
  • packages/hydrooj/src/model/message.ts (1 hunks)
  • packages/hydrooj/src/model/oplog.ts (1 hunks)
  • packages/hydrooj/src/model/problem.ts (1 hunks)
  • packages/hydrooj/src/model/setting.ts (2 hunks)
  • packages/hydrooj/src/model/solution.ts (1 hunks)
  • packages/hydrooj/src/model/system.ts (1 hunks)
  • packages/hydrooj/src/model/task.ts (1 hunks)
  • packages/hydrooj/src/model/token.ts (1 hunks)
  • packages/hydrooj/src/model/user.ts (1 hunks)
  • packages/hydrooj/src/service/bus.ts (4 hunks)
  • packages/hydrooj/src/service/db.ts (1 hunks)
  • packages/hydrooj/src/service/hmr.ts (2 hunks)
  • packages/hydrooj/src/service/monitor.ts (1 hunks)
  • packages/hydrooj/src/service/server.ts (7 hunks)
  • packages/hydrooj/src/ui.ts (1 hunks)
  • packages/onsite-toolkit/index.ts (1 hunks)
  • packages/scoreboard-xcpcio/index.ts (1 hunks)
  • packages/ui-default/package.json (1 hunks)
✅ Files skipped from review due to trivial changes (9)
  • packages/hydrooj/src/model/discussion.ts
  • packages/scoreboard-xcpcio/index.ts
  • packages/hydrooj/src/model/domain.ts
  • packages/ui-default/package.json
  • packages/hydrooj/src/model/system.ts
  • packages/onsite-toolkit/index.ts
  • .gitattributes
  • packages/hydrooj/src/model/setting.ts
  • packages/hydrooj/src/service/monitor.ts
🧰 Additional context used
🪛 GitHub Check: CodeQL
packages/hydrooj/src/loader.ts

[notice] 150-150: Semicolon insertion
Avoid automated semicolon insertion (90% of all statements in the enclosing function have an explicit semicolon).

framework/framework/server.ts

[warning] 676-676: Useless conditional
This use of variable 'perm' always evaluates to false.

🪛 Biome (1.9.4)
packages/hydrooj/src/service/server.ts

[error] 79-79: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)


[error] 119-119: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)

framework/framework/server.ts

[error] 128-128: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 129-129: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (49)
package.json (1)

23-24: Expanded linting coverage to include the framework directory.

The linting script now includes the framework directory, ensuring that all TypeScript and JSX files there are also subject to the same linting rules as the rest of the project. This makes sense given that "framework/*" is already part of the project's workspaces (line 6).

framework/framework/package.json (1)

7-7:

✅ Verification successful

Package dependency updated from "cordis" to "@cordisjs/core".

The peer dependency has been changed from a non-namespaced package to a namespaced one. This change is likely part of a broader migration to using the namespaced version of the package throughout the project.


🏁 Script executed:

#!/bin/bash
# Check if there are any remaining imports or dependencies for the old "cordis" package
echo "Checking for remaining references to the old 'cordis' package..."
grep -r "import.*from.*cordis['\"]" --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" .
grep -r "\"cordis\":" --include="package.json" .

Length of output: 303


I'll run an additional, deeper search to ensure no lingering references to the old "cordis" package exist. This new script searches broadly for any occurrence of the string "cordis" (excluding common vendored directories) to provide a higher-confidence result.

Please run this script and share the output so we can proceed with a high-confidence verification of the update from "cordis" to "@cordisjs/core."


🏁 Script executed:

#!/bin/bash
echo "Performing deep search for any occurrence of 'cordis' (case-insensitive) excluding node_modules, dist, and build directories..."
rg -i "cordis" --glob "!node_modules/*" --glob "!dist/*" --glob "!build/*" .

Length of output: 3784


Dependency migration verified – Namespaced package "@cordisjs/core" correctly in use

The deep search confirms that the dependency update in framework/framework/package.json is correctly applied. We see that all usages now reference @cordisjs/core, and no lingering references to the old non-namespaced "cordis" remain in package dependencies. Minor mentions of "cordis" in comments and documentation are acceptable as they do not affect functionality.

  • Location verified: framework/framework/package.json now correctly includes "@cordisjs/core": "*"
  • Other code references: All module imports across the codebase consistently use the namespaced package.
packages/hydrooj/src/service/db.ts (1)

10-10:

✅ Verification successful

Import style updated from namespace to default import.

The import statement has been changed from a namespace import (import * as bus from './bus') to a default import (import bus from './bus'). This change suggests that the bus module now exports a default value, or has been refactored to do so. This change is consistent with similar changes in other files mentioned in the summary.


🏁 Script executed:

#!/bin/bash
# Check the export style of the bus module
cat packages/hydrooj/src/service/bus.ts | grep -E "export default|module.exports ="

Length of output: 105


Import update verified:
The import change in packages/hydrooj/src/service/db.ts from a namespace import (import * as bus from './bus') to a default import (import bus from './bus') is correct. The module at packages/hydrooj/src/service/bus.ts indeed exports a default value (export default app;), confirming the intended refactor. There are no additional issues to address.

packages/hydrooj/src/model/token.ts (1)

3-3: Import style updated from namespace to default import.

The import statement has been changed from a namespace import (import * as bus from '../service/bus') to a default import (import bus from '../service/bus'). This change is consistent with the project-wide refactoring to use default imports for the bus module.

packages/hydrooj/src/entry/worker.ts (1)

45-49: Context handling enhancement with asynchronous injection

The introduction of an asynchronous context injection mechanism ensures that the server dependency is fully integrated into the context before proceeding with subsequent operations. This is a good practice for proper dependency management.

This change addresses potential race conditions where ctx might not have the fully initialized server dependency when needed by code executed after line 44. The Promise-based approach ensures everything proceeds in the correct order.

packages/hydrooj/src/ui.ts (1)

3-3: Updated import style for bus module

The change from namespace import (import * as bus) to default import (import bus) indicates a refactoring of the module export strategy in the bus service.

This change aligns with modern JavaScript module practices and likely part of a broader effort to standardize import styles across the codebase, as similar changes appear in multiple files.

packages/hydrooj/src/model/contest.ts (1)

12-12: Updated import style for bus module

Changing from namespace import (import * as bus) to default import (import bus) aligns with the project-wide standardization of how the bus service is imported.

This is consistent with similar changes in other files, indicating a systematic refactoring of import statements across the codebase.

packages/hydrooj/src/model/solution.ts (1)

3-3: Updated import style for bus module

The import statement has been changed from namespace import to default import, consistent with other files in the project.

This change is part of a broader refactoring effort to standardize how the bus service is imported throughout the codebase, improving consistency.

packages/hydrooj/src/model/task.ts (1)

9-9: Import change from namespace to default is appropriate.

The change from import * as bus from '../service/bus' to import bus from '../service/bus' aligns with the broader refactoring effort across the codebase to standardize import patterns.

packages/hydrooj/src/model/document.ts (1)

12-12: Import change from namespace to default is appropriate.

The change from import * as bus from '../service/bus' to import bus from '../service/bus' aligns with the broader refactoring effort across the codebase to standardize import patterns.

packages/hydrooj/src/model/message.ts (1)

3-3: Import change from namespace to default is appropriate.

The change from import * as bus from '../service/bus' to import bus from '../service/bus' aligns with the broader refactoring effort across the codebase to standardize import patterns.

packages/hydrooj/src/model/oplog.ts (1)

4-4:

✅ Verification successful

Import style updated for the bus module.

The import has been updated from a namespace import (import * as bus) to a default import (import bus). This change is consistent with the same pattern applied across multiple files in the codebase.


🏁 Script executed:

#!/bin/bash
# Check how bus is exported in the source file
cat packages/hydrooj/src/service/bus.ts | grep -n "export default" || echo "No default export found in bus.ts"

Length of output: 92


Verification complete: The import change for the bus module is correct.

The default import (import bus from '../service/bus';) is now consistent with the export in packages/hydrooj/src/service/bus.ts, where the default export is defined (export default app;). No further changes are needed.

packages/hydrooj/src/model/user.ts (1)

12-12:

✅ Verification successful

Import style updated for the bus module.

The import statement has been changed from a namespace import (import * as bus) to a default import (import bus). This is consistent with the changes made across other files in the codebase and indicates that the bus module is now using a default export pattern.


🏁 Script executed:

#!/bin/bash
# Check if bus is consistently imported as default across the codebase
echo "Files using default import for bus:"
rg "import bus from '../service/bus'" packages/hydrooj/src/

echo -e "\nFiles still using namespace import for bus:"
rg "import \* as bus from '../service/bus'" packages/hydrooj/src/

Length of output: 1254


Import style update verified across the codebase

All files, including packages/hydrooj/src/model/user.ts, now consistently use the default import for the bus module; no namespace import remains.

packages/hydrooj/src/handler/judge.ts (1)

26-26:

✅ Verification successful

Import style updated for the bus module.

The import has been standardized from namespace import (import * as bus) to default import (import bus). This is part of a broader refactoring pattern across the codebase.


🏁 Script executed:

#!/bin/bash
# Check how the bus module is structured and what it exports
cat packages/hydrooj/src/service/bus.ts | head -20

Length of output: 732


I'll run an additional check to verify that the bus.ts module indeed provides a default export as expected.


🏁 Script executed:

rg "export default" packages/hydrooj/src/service/bus.ts

Length of output: 77


Import statement verified: Default export found and used correctly.

The code change from a namespace import to a default import is correct since packages/hydrooj/src/service/bus.ts exports a default export (export default app;). No further modifications are necessary for this update.

packages/hydrooj/src/model/problem.ts (1)

19-19:

✅ Verification successful

Import style updated for the bus module.

The import statement has been updated from a namespace import to a default import. This change is consistent with the same pattern applied across the entire codebase for the bus module.


🏁 Script executed:

#!/bin/bash
# Examine how bus is used in this file to ensure the import change is appropriate
rg -A 1 "bus\.(parallel|emit|broadcast|on)" packages/hydrooj/src/model/problem.ts

Length of output: 1427


Import style update for the bus module verified.
The default import from ../service/bus is being used consistently (e.g., bus.parallel and bus.emit) in the file packages/hydrooj/src/model/problem.ts as confirmed by the grep output. This change aligns with the overall codebase pattern, and no issues remain.

framework/framework/decorators.ts (2)

1-1: Import from new namespaced @cordisjs package

The import has been updated to use the new modular @cordisjs/core package, which is consistent with the dependency changes in package.json.


48-48: Propagated generic type to validate function

The nested validate function properly maintains the generic type parameter from the outer function, ensuring consistent typing throughout the descriptor.

packages/hydrooj/src/loader.ts (2)

169-170: Proper async handling in load function

The load function now properly awaits the completion of preload(), ensuring that all dependencies are initialized before proceeding with the application startup.


207-209: Consistent async handling in CLI loader

The loadCli function now properly awaits the completion of preload(), matching the pattern used in the main load function. This ensures consistent behavior across different entry points.

packages/hydrooj/src/service/hmr.ts (4)

151-151: Simplified plugin tracking in HMR

The pending map type has been changed from Map<string, Plugin.Runtime<Context>> to Map<string, Plugin>, focusing on storing the plugin objects directly rather than their runtime instances. This aligns with the broader changes in the codebase.


164-165: Direct plugin storage and side effect checking

The code now properly stores the plugin object directly and checks its sideEffect property. This is a cleaner approach than handling the runtime.


181-184: Improved reloads map association

The reloads map now correctly associates the plugin with its filename and runtime, matching the updated structure of the pending map.


168-173:

❓ Verification inconclusive

Refactored plugin validation loop

The loop now correctly iterates over plugins and retrieves the runtime separately. The side effect check has been moved to use the plugin object directly.

Let's verify that sideEffect access is consistent throughout the codebase:


🏁 Script executed:

#!/bin/bash
# Check for consistent access patterns to the sideEffect property on plugins

echo "Checking sideEffect property access patterns across the codebase:"
rg --type typescript "sideEffect" -A 1 -B 1

Length of output: 219


Verify SideEffect Access Consistency
The refactored plugin validation loop correctly retrieves the runtime and checks the plugin’s sideEffect property using bracket notation. However, our initial verification script failed due to an unrecognized file type error. Please manually verify that the sideEffect property is accessed consistently across the codebase by running the revised script above.


🏁 Script executed:

#!/bin/bash
echo "Searching sideEffect in TypeScript files (.ts and .tsx):"
rg -g '*.ts' -g '*.tsx' "sideEffect" -A 1 -B 1

Length of output: 854


Plugin Validation Loop Refactor & SideEffect Consistency Check
The refactored plugin validation loop in packages/hydrooj/src/service/hmr.ts (lines 168–173) now iterates over plugins and retrieves the runtime separately while using the simpler check (if (!plugin['sideEffect'])) as intended.

However, our codebase search also revealed another instance in the same file using a more defensive pattern (if (!plugin || !('sideEffect' in plugin) || !plugin['sideEffect'])). Please verify whether this discrepancy is intentional or if the conditions should be unified for consistency.

  • Refactored loop (lines 168–173) correctly uses if (!plugin['sideEffect']).
  • An earlier block in the file uses the additional existence check on plugin and its sideEffect.
  • packages/hydrooj/src/service/api.ts exports sideEffect consistently.
packages/hydrooj/src/service/bus.ts (4)

5-5: Import usage looks good.
Using a type import from the framework is a clean approach, ensuring we don't bring in unnecessary code.


17-18: Interface definition clarity.
Declaring EventMap in a single interface consolidates event definitions and streamlines event-related logic. Ensure that any dynamic or external events are also typed or otherwise handled gracefully to avoid runtime errors.


88-88: Explicit handler type is consistent.
Using Handler<Context> for the oplog/log event is consistent with the generics introduced elsewhere, improving type clarity for event subscribers.


33-33:

❓ Verification inconclusive

Confirm external references to broadcast events.
Switching from keyof ServerEvents to keyof EventMap restricts the valid events that can be broadcast. Please verify and update any external code referencing events outside of EventMap.


🏁 Script executed:

#!/bin/bash
# Verify references to the old 'bus/broadcast' usage to ensure they match the new signature
rg -A 3 "bus/broadcast"

Length of output: 1879


Action: Validate ‘bus/broadcast’ Event Keys Against the Updated EventMap

The change from keyof ServerEvents to keyof EventMap now restricts broadcast events to only those defined in EventMap. Our repository search found the following usages:

  • packages/prom-client/metrics.ts – The event is received as name for incrementing counters.
  • packages/hydrooj/src/model/task.ts – The event is handled with (event, payload, trace).
  • packages/hydrooj/src/context.ts – The event is emitted via ctx.emit.

Please confirm that each of these usages only references event keys present in EventMap. If any external code relies on events outside of this mapping, update either the event references or extend EventMap accordingly.

framework/framework/interface.ts (6)

1-5: Modular approach to known handlers.
Defining KnownHandlers with specific handler entries, such as 'NotFound': NotFoundHandler, simplifies maintenance and ensures type safety. Good job.


7-14: Flexible mapped event types.
Combining template literal types with your MapHandlerEvents and KnownHandlerEvents provides powerful typing for your events. Just be sure that any downstream usage is thoroughly tested to catch any subtle type mismatches.
[approve]


15-17: Generic handler events.
Extending event signatures with <C> allows context-specific event hooks. This pattern is beneficial for large systems requiring specialized context handling.


21-23: Restricting hook types.
Using Exclude<HookType, 'before-operation'> for HookWithMethod is a neat technique to disallow certain hook combinations. This approach prevents accidental usage of hooks in unsupported scenarios.


24-34: Expanded ServerEvents interface.
The extended ServerEvents<C> captures both known handler events and generic handler events, covering a wide range of scenarios. This provides a robust event system while maintaining strong typing.


36-38: Extending third-party modules with generic events.
Declaring Events<C> to extend ServerEvents<C> in @cordisjs/core is a solid pattern. Confirm in your build/compilation steps that the augmentation merges properly and doesn't conflict with other type definitions in the same module.

packages/hydrooj/src/service/server.ts (3)

8-10: Generic imports from the framework.
Switching to HandlerOriginal<Context> and ConnectionHandlerOriginal<Context> aligns with the new typed approach introduced throughout the codebase. This ensures context-aware handlers for both HTTP and WebSocket connections.


33-33: Ensuring generics are fully utilized.
Declaring HandlerCommon<C> is a good step. Confirm that all usage sites either specify <Context> or additional custom contexts as needed, to avoid unintentional any resolution.


135-135: Framework plugin usage.
Replacing the direct import of require('@hydrooj/framework') with WebService is a clean, modular approach. This clarified import fosters better maintainability and avoids bundling the entire framework when only the web service is needed.

packages/hydrooj/src/context.ts (5)

1-3: Imports look good.
These imports from @cordisjs/core, @cordisjs/logger, and @cordisjs/plugin-timer appear consistent with the usage of this.plugin(TimerService); and this.plugin(Logger);. No issues detected here.


29-29: Confirm usage of re-exported entities.
You’re re-exporting Disposable, Plugin, and ScopeStatus from @cordisjs/core. Ensure they’re actually used in this file or other files importing from here, otherwise they might be extraneous.


31-32: Validate the property signature.
Using [Context.events]: EventMap & cordis.Events<Context> is unusual. Verify that Context.events is indeed a valid property or symbol on the cordis.Context. If it's meant to be a Symbol, ensure you have the correct reference to avoid type mismatches.


54-54: Class extension looks coherent.
Defining ApiMixin to extend cordis.Service<Context> is consistent with other services. No immediate issues found.


75-75: Logger plugin usage is fine.
Registering the Logger plugin after TimerService is valid. Ensure your logging configuration is properly initialized so logs appear in the expected format/output.

framework/framework/server.ts (8)

5-5: Imports updated correctly.
Importing Context as CordisContext and Service from @cordisjs/core aligns with the new context structures and type usage.


138-146: Question the usage of .extend({}).
Inside the constructor, this.ctx is being re-assigned to (ctx as any).extend({}). Verify that your ctx is indeed an object or class with an extend method. Otherwise, this can trigger runtime errors if ctx does not meet that contract.


200-200: Class extension is consistent.
Handler<C> extends HandlerCommon<C> with additional methods. Recommend specifying constraints on C if you rely on specific properties from context. Otherwise, good to proceed.


283-283: Explicit CordisContext type.
Using extends Handler<CordisContext> is a valid approach for the NotFoundHandler if you specifically only handle a CordisContext. Looks consistent.


322-322: Generic WebService definition is sound.
Providing <C extends CordisContext = CordisContext> is a flexible default. This should help with type safety across extended contexts.


337-338: Initialize with config and context.
The constructor properly calls super(ctx, 'server') and mixes in server features. No immediate issues detected.


655-680: Useless conditional on perm
Static analysis indicates that if (perm) may always evaluate to false under certain usage because perm appears not to be set by typical flows. This is the same concern flagged in previous reviews or scanning tools.

🧰 Tools
🪛 GitHub Check: CodeQL

[warning] 676-676: Useless conditional
This use of variable 'perm' always evaluates to false.


766-771: Module augmentation for @cordisjs/core.
Augmenting interface Context with server, Route, and others is a standard TypeScript approach. Make sure each property is set or at least defined at runtime to avoid undefined references.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
framework/framework/server.ts (2)

128-129: ⚠️ Potential issue

Fix unsafe declaration merging

The empty interface HandlerCommon<C> followed by a class with the same name causes unsafe declaration merging. The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

-export interface HandlerCommon<C> { } // eslint-disable-line @typescript-eslint/no-unused-vars
+// Use a type alias instead of an empty interface
 export class HandlerCommon<C> {
🧰 Tools
🪛 Biome (1.9.4)

[error] 128-128: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 129-129: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)


655-679: ⚠️ Potential issue

Fix conditional logic in Checker function

The Checker function has been refactored to properly handle permission and privilege checking, but there's an issue in the returned checking function.

The condition on line 676 is flagged by static analysis as always evaluating to false. This is because perm is initialized as undefined and doesn't get properly assigned in some code paths.

 return function check(this: Handler<C>) {
   checker();
-  if (perm) this.checkPerm(perm);
+  if (perm !== undefined) this.checkPerm(perm);
   if (priv) this.checkPriv(priv);
 };
🧰 Tools
🪛 GitHub Check: CodeQL

[warning] 676-676: Useless conditional
This use of variable 'perm' always evaluates to false.

🧹 Nitpick comments (5)
packages/hydrooj/src/plugin-api.ts (1)

56-58: Use explicit side-effect import instead of empty export.
While this approach can load side effects from './handler/contest', it's more conventional to use a side-effect import statement for clarity.

Use this diff to switch to a side-effect import:

- // to load ctx.scoreboard
- export { } from './handler/contest';
+ // to load ctx.scoreboard
+ import './handler/contest';
packages/hydrooj/src/model/user.ts (1)

468-486: Consider adding error handling or logging for index creation.
Although creating these indexes in parallel is fine, you might want to handle or log possible failures to aid debugging.

Example of adding minimal error handling:

 export async function apply() {
   await Promise.all([
     db.ensureIndexes(
       coll,
       { key: { unameLower: 1 }, name: 'uname', unique: true },
       { key: { mailLower: 1 }, name: 'mail', unique: true },
     ).catch(err => console.error('Error ensuring coll indexes:', err)),
     db.ensureIndexes(
       collV,
       { key: { unameLower: 1 }, name: 'uname', unique: true },
       { key: { mailLower: 1 }, name: 'mail', unique: true },
     ).catch(err => console.error('Error ensuring collV indexes:', err)),
     db.ensureIndexes(
       collGroup,
       { key: { domainId: 1, name: 1 }, name: 'name', unique: true },
       { key: { domainId: 1, uids: 1 }, name: 'uid' },
     ).catch(err => console.error('Error ensuring collGroup indexes:', err)),
   ]);
 }
packages/hydrooj/src/model/domain.ts (1)

288-308: Add optional logging to the new apply function.
Invoking ctx.on('domain/delete-cache', ...) is a good pattern. For improved observability, consider logging on domain cache deletion or whenever index creation completes.

 export async function apply(ctx: Context) {
   ctx.on('domain/delete-cache', async (domainId: string) => {
     const ddoc = await DomainModel.get(domainId);
     if (!ddoc) return;
     for (const host of ddoc.hosts || []) {
       cache.delete(`host::${host}`);
     }
     cache.delete(`id::${domainId}`);
+    console.info(`[domain/apply] Cache entries cleared for domain: ${domainId}`);
   });
   await Promise.all([
     db.ensureIndexes(
       coll,
       { key: { lower: 1 }, name: 'lower', unique: true },
     ),
     db.ensureIndexes(
       collUser,
       { key: { domainId: 1, uid: 1 }, name: 'uid', unique: true },
       { key: { domainId: 1, rp: -1, uid: 1 }, name: 'rp', sparse: true },
     ),
   ]);
+  console.info('[domain/apply] Domain indexes ensured successfully');
 }
framework/framework/server.ts (2)

138-146: Proper generic type implementation in HandlerCommon constructor

The constructor now accepts a generic context type parameter, improving type safety. However, there's an unsafe type cast on line 146 that could be improved with a proper type definition.

-        this.ctx = (ctx as any).extend({});
+        // Consider using a more specific type instead of 'any'
+        this.ctx = ctx.extend({});

708-710: Fix TypeScript type annotation for Route method

The Route method currently has a FIXME comment indicating it should use a more specific type rather than any for the RouteHandler parameter.

-  // FIXME: should be typeof Handler<Context> instead of any
-  // eslint-disable-next-line @typescript-eslint/naming-convention
-  public Route(name: string, path: string, RouteHandler: any, ...permPrivChecker) {
+  // eslint-disable-next-line @typescript-eslint/naming-convention
+  public Route(name: string, path: string, RouteHandler: typeof Handler<C>, ...permPrivChecker) {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dec3170 and d72bb20.

📒 Files selected for processing (6)
  • framework/framework/server.ts (21 hunks)
  • packages/hydrooj/src/handler/judge.ts (2 hunks)
  • packages/hydrooj/src/loader.ts (3 hunks)
  • packages/hydrooj/src/model/domain.ts (2 hunks)
  • packages/hydrooj/src/model/user.ts (2 hunks)
  • packages/hydrooj/src/plugin-api.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/hydrooj/src/handler/judge.ts
🧰 Additional context used
🪛 Biome (1.9.4)
framework/framework/server.ts

[error] 128-128: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 129-129: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)

🪛 GitHub Check: CodeQL
framework/framework/server.ts

[warning] 676-676: Useless conditional
This use of variable 'perm' always evaluates to false.

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (9)
packages/hydrooj/src/model/domain.ts (2)

4-4: Importing Context is valid.
This new import correctly aligns with the added apply function’s signature.


6-6: Default import from bus is consistent with other refactors.
Switching from a namespace import to a default import is in line with the broader shift in this update.

packages/hydrooj/src/loader.ts (3)

142-150: Good use of async/await for application initialization

The conversion of preload() to an async function using a Promise-based initialization pattern is a significant improvement. This ensures proper sequencing of the initialization steps and prevents potential race conditions when setting up the application context.


169-170: Properly awaiting preload for sequential execution

Converting the load function to async and awaiting the preload() function ensures the application is properly initialized before proceeding with additional setup steps.


207-209: Appropriate async CLI initialization

The loadCli function correctly uses async/await pattern to ensure proper initialization sequence, matching the changes in the load function.

framework/framework/server.ts (4)

5-5: Updated import to use new package structure

The change from importing Context to importing Context as CordisContext from @cordisjs/core aligns with the package structure changes mentioned in the PR summary.


200-200: Good use of generic defaults in Handler class

Using <C = CordisContext> provides a sensible default while allowing for custom context types when needed, enhancing flexibility without sacrificing type safety.


246-246: Generic type parameter added to ConnectionHandler

The ConnectionHandler class now properly accepts a generic context type, aligning with the other handler classes for type consistency.


766-772: Well-structured module declaration augmentation

The module declaration extends the Context interface to include the server-related properties with proper generic type handling, ensuring type safety when accessing these properties from a context instance.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
packages/hydrooj/src/service/server.ts (2)

79-79: ⚠️ Potential issue

Address unsafe interface-class merge [noUnsafeDeclarationMerging].

The interface Handler (line 76) and class Handler (line 79) share the same name, potentially causing issues with uninitialized interface fields. To avoid confusion and ensure full type checking, consider renaming the interface or incorporating its fields into the class.

-export interface Handler {
-    domain: DomainDoc;
-}
-export class Handler extends HandlerOriginal<Context> {
+interface IHandler {
+    domain: DomainDoc;
+}
+export class Handler extends HandlerOriginal<Context> implements IHandler {
     constructor(_, ctx) {
         super(_, ctx);
         ...
🧰 Tools
🪛 Biome (1.9.4)

[error] 79-79: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)


119-119: ⚠️ Potential issue

Likewise address interface-class merge.

Same issue as above for ConnectionHandler. Interface and class share the same name, leading to potential confusion and partial type checks. Rename or integrate the interface into the class.

-export interface ConnectionHandler {
-    domain: DomainDoc;
-}
-export class ConnectionHandler extends ConnectionHandlerOriginal<Context> {
+interface IConnectionHandler {
+    domain: DomainDoc;
+}
+export class ConnectionHandler extends ConnectionHandlerOriginal<Context> implements IConnectionHandler {
     constructor(_, ctx) {
         super(_, ctx);
         ...
🧰 Tools
🪛 Biome (1.9.4)

[error] 119-119: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)

🧹 Nitpick comments (1)
packages/hydrooj/src/context.ts (1)

75-75: Added LoggerService to the Context constructor.

The addition of LoggerService to the Context constructor ensures that logging capabilities are available throughout the application. This is a good enhancement for observability.

Consider documenting what features the LoggerService provides and how it should be used by developers working on the application.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d72bb20 and f7e635c.

📒 Files selected for processing (2)
  • packages/hydrooj/src/context.ts (4 hunks)
  • packages/hydrooj/src/service/server.ts (8 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
packages/hydrooj/src/service/server.ts

[error] 79-79: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)


[error] 119-119: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (12)
packages/hydrooj/src/service/server.ts (7)

8-10: Import statement updated to support generic typed framework components.

The imports have been updated to use the original Handler and ConnectionHandler with generic typing, and WebService has been added as a new direct import. This supports the generic type improvements throughout the codebase.


33-33: Good type enhancement to the HandlerCommon interface.

Adding the generic type parameter <C> to the HandlerCommon interface improves type safety by making the interface more flexible and allowing it to work with different context types.


80-80: Good simplification of constructor signature.

The constructor signature has been simplified by removing explicit type declarations, as TypeScript can now infer the types from the generic parameter <Context> provided to the parent class.


120-120: Good simplification of constructor signature.

Similar to the Handler class, the constructor signature has been simplified by removing explicit type declarations which are now inferred from the generic parameter.


135-135: Updated to use WebService directly instead of requiring the framework.

The change from require('@hydrooj/framework') to directly using the imported WebService is a good practice as it makes the dependency more explicit and can help with tree-shaking during builds.


222-222: Minor improvement to router URL call.

This change appears to be a slight modification to the method call but maintains the same functionality. It's a minor improvement to the code style.


283-296: Enhanced error handling with new event handlers for HTTP and WebSocket connections.

The addition of event handlers for 'handler/create/http' and 'handler/create/ws' with error checking logic is a good improvement. It ensures that any pending errors are properly thrown and handled early in the request lifecycle.

The implementation properly checks for pendingError in the context and throws it if present, which will trigger the appropriate error handling flow.

packages/hydrooj/src/context.ts (5)

1-3: Updated imports to use dedicated packages instead of a monolithic import.

The import changes from 'cordis' to '@cordisjs/core' and addition of LoggerService and TimerService from their respective packages indicate a move towards a more modular architecture. This is a good practice that can lead to better tree-shaking and more explicit dependencies.


12-13: TODO needs to be addressed for broken declaration.

The comment acknowledges a broken declaration, and the code exports EventMap as Events. This should be prioritized for fixing since it could lead to type-related bugs.

Could you clarify what makes this declaration "broken"? Is it related to:

  1. EventMap compatibility with the rest of the system?
  2. A transition period during refactoring?

Consider either fixing the issue or adding more details about the problem in the TODO comment to help future developers.


29-29: Updated exports to match new import sources.

The exports have been updated to match the new import path from '@cordisjs/core' instead of 'cordis', which is consistent with the import changes at the top of the file.


31-32: Improved type definition for Context interface.

The Context interface has been simplified and improved by:

  1. Removing the Pick dependency
  2. Using EventMap with cordis.Events to properly type the events

This change enhances type safety while making the code more maintainable.


54-54: Enhanced type safety with generic parameter on ApiMixin.

Adding the generic type parameter <Context> to the ApiMixin class improves type safety by ensuring that the service correctly works with the Context type.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
packages/hydrooj/src/service/server.ts (1)

76-78: 🛠️ Refactor suggestion

Address unsafe interface-class merge.

The code has an unsafe interface-class merge issue where interfaces and classes share the same name. This pattern is flagged by TypeScript's linter as it may lead to uninitialized interface fields not being checked by the compiler.

Consider implementing the interface in the class definition instead:

-export class Handler extends HandlerOriginal<Context> {
-  domain: DomainDoc;
-}
+export class Handler extends HandlerOriginal<Context> implements { domain: DomainDoc } {
+  // The domain property is already implemented through inheritance
+}

-export class ConnectionHandler extends ConnectionHandlerOriginal<Context> {
-  domain: DomainDoc;
-}
+export class ConnectionHandler extends ConnectionHandlerOriginal<Context> implements { domain: DomainDoc } {
+  // The domain property is already implemented through inheritance
+}

This approach makes it explicit that the class is implementing these properties and avoids the interface-class merge warning.

Also applies to: 79-81

framework/framework/server.ts (2)

128-129: 🛠️ Refactor suggestion

Resolve unsafe declaration merging.

There's an unsafe declaration merging issue with an empty interface and class sharing the same name. This pattern is flagged by TypeScript's linter as potentially problematic.

Replace the empty interface with a type alias or remove it completely:

-export interface HandlerCommon<C> { } // eslint-disable-line @typescript-eslint/no-unused-vars
-export class HandlerCommon<C> {
+export class HandlerCommon<C> {

Since the interface is empty, there's no need to keep it. If the intention was to allow for module augmentation, consider using a different approach or documentation to indicate this.

🧰 Tools
🪛 Biome (1.9.4)

[error] 128-128: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 129-129: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)


481-483: 🛠️ Refactor suggestion

Address type-checking TODOs/FIXMEs.

Several TODOs/FIXMEs have been added related to type checking issues, particularly with event emission. These should be properly addressed to maintain type safety throughout the codebase.

Instead of using type assertions to any, consider creating proper type definitions for the event handlers:

// Define an interface for events
interface ServerEvents<T> {
  'handler/create': [handler: T, type: 'http' | 'ws'];
  'handler/create/http': [handler: T];
  'handler/create/ws': [handler: T];
  'handler/error': [handler: T, error: Error];
  'handler/error/${string}': [handler: T, error: Error];
  'connection/create': [handler: T];
  'connection/active': [handler: T];
  'connection/close': [handler: T];
}

// Update the Context interface
interface Context {
  // Update methods to use typed events
  parallel<K extends keyof ServerEvents<T>, T>(event: K, ...args: ServerEvents<T>[K]): Promise<void>;
  serial<K extends keyof ServerEvents<T>, T>(event: K, ...args: ServerEvents<T>[K]): Promise<void>;
}

This would allow for proper type checking of event emissions without resorting to any casts.

Also applies to: 535-536, 550-551, 579-582, 593-594, 632-633, 704-705

🧹 Nitpick comments (4)
packages/utils/lib/common.ts (1)

214-214: Improved type safety in sortFiles function signature.

The addition of a generic type parameter T that extends { _id: string } enhances type safety by preserving the full type of the input objects when they're returned. This change ensures that consumers of this function retain all type information about their objects, rather than getting back only objects with the minimal { _id: string } structure.

Consider making the key parameter more type-safe as well by using a mapped type to ensure it's a key of T:

-export function sortFiles<T extends { _id: string }>(files: T[], key?: '_id'): T[];
+export function sortFiles<T extends { _id: string }>(files: T[], key?: keyof T & '_id'): T[];

This would ensure that when a key is provided, it exists on the type T and is specifically the '_id' property.

packages/migrate/index.ts (1)

10-16: Improved function signature to accept and forward multiple arguments

This change enhances the flexibility of the checkLock function by using rest parameters and argument spreading, allowing it to accept an arbitrary number of arguments. The modification improves the function's adaptability for use with various script runners that might require different parameter signatures.

function checkLock(innerCall) {
-   return async (args) => {
+   return async (...args) => {
        const cur = await SystemModel.get('migrate.lock');
        if (cur) throw new SystemError(`migrate lock already exists: ${cur}, possible another migration is running`);
-       return innerCall(args);
+       return innerCall(...args);
    };
}
packages/hydrooj/src/entry/cli.ts (1)

126-130: Introduced asynchronous context modification with server dependency injection

This change adds an important asynchronous step in the application initialization flow, ensuring the server dependency is properly injected into the context before proceeding with the remainder of the startup process. The context is reassigned after the dependency injection to ensure subsequent code uses the updated context.

The pattern used here (creating a new Promise and resolving it with the updated context) is appropriate for ensuring proper sequencing in the initialization process.

While this approach works, consider examining whether this initialization pattern could be standardized across other similar dependency injection flows in the application for consistency. You might also benefit from a more formalized dependency resolution system if similar patterns appear elsewhere.

packages/hydrooj/src/entry/common.ts (1)

45-45: Simplified plugin loading API by removing redundant context parameter

The call to ctx.loader.reloadPlugin has been updated to remove the ctx parameter, which was redundant since the context is already available through the method's object. This change is part of a broader refactoring to simplify the plugin loading mechanism.

The code now passes fewer parameters, making it cleaner, but verify that this pattern is consistently applied across the codebase.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f7e635c and f6bb3b6.

📒 Files selected for processing (16)
  • README.md (1 hunks)
  • framework/eslint-config/package.json (1 hunks)
  • framework/framework/package.json (2 hunks)
  • framework/framework/server.ts (20 hunks)
  • package.json (4 hunks)
  • packages/elastic/package.json (1 hunks)
  • packages/hydrojudge/package.json (1 hunks)
  • packages/hydrooj/package.json (3 hunks)
  • packages/hydrooj/src/entry/cli.ts (1 hunks)
  • packages/hydrooj/src/entry/common.ts (2 hunks)
  • packages/hydrooj/src/entry/worker.ts (2 hunks)
  • packages/hydrooj/src/loader.ts (6 hunks)
  • packages/hydrooj/src/service/server.ts (6 hunks)
  • packages/migrate/index.ts (1 hunks)
  • packages/ui-default/package.json (4 hunks)
  • packages/utils/lib/common.ts (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • packages/elastic/package.json
  • packages/hydrojudge/package.json
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/hydrooj/src/entry/worker.ts
  • package.json
  • framework/framework/package.json
  • packages/hydrooj/src/loader.ts
  • packages/ui-default/package.json
🧰 Additional context used
🪛 Biome (1.9.4)
framework/framework/server.ts

[error] 128-128: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 129-129: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)

🪛 GitHub Check: CodeQL
framework/framework/server.ts

[warning] 676-676: Useless conditional
This use of variable 'perm' always evaluates to false.

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (27)
packages/migrate/index.ts (5)

32-32: Consistent use of rest parameter pattern

This migration script runner is correctly updated to use the spread operator, aligning with the change in the checkLock function.


46-46: Consistent use of rest parameter pattern

This migration script runner is correctly updated to use the spread operator, matching the new implementation of the checkLock function.


57-57: Consistent use of rest parameter pattern

This migration script runner is correctly updated to use the spread operator, matching the new implementation of the checkLock function.


70-70: Consistent use of rest parameter pattern

This migration script runner is correctly updated to use the spread operator, matching the new implementation of the checkLock function.


85-85: Consistent use of rest parameter pattern

This migration script runner is correctly updated to use the spread operator, matching the new implementation of the checkLock function.

packages/hydrooj/src/entry/cli.ts (1)

134-134:

✅ Verification successful

Updated plugin reload method signature

The call to reloadPlugin has been modified to remove the ctx parameter, consistent with changes in the plugin loading mechanism across the codebase. This suggests the method now relies on an internally stored context rather than requiring it to be passed explicitly.


🏁 Script executed:

#!/bin/bash
# Verify how reloadPlugin is defined and used elsewhere in the codebase

# Check the definition of reloadPlugin method to confirm it no longer expects the context parameter
rg -A 5 "reloadPlugin.*?\(" --glob "*.ts" | grep -v "ctx, " || echo "No instances of old-style reloadPlugin calls found"

# Check for any remaining instances of the old method signature that might need updating
rg "reloadPlugin.*?\(ctx," --glob "*.ts" || echo "No remaining instances of old-style method calls found"

Length of output: 2959


Plugin Reload Method Signature Verified as Updated

The usage in packages/hydrooj/src/entry/cli.ts is now aligned with the new method signature—only the plugin key, configuration, and an optional name are passed. Verification across the codebase confirmed that all invocations (in cli.ts, common.ts, and worker.ts) have removed the extraneous context parameter, and the reloadPlugin definition in packages/hydrooj/src/loader.ts reflects this update.

  • The call in cli.ts now correctly uses:
    ctx.loader.reloadPlugin(path.resolve(scriptDir, h), {}, `hydrooj/script/${h.split('.')[0]}`);
  • No occurrences of the old pattern (passing ctx as an argument) were found.
framework/eslint-config/package.json (4)

11-11: Updated De Morgan plugin to latest version

The eslint-plugin-de-morgan has been updated to version 1.2.0, which may include improvements to logical expression handling.


16-16: Updated React Hooks plugin to latest version

The eslint-plugin-react-hooks has been updated to version 5.2.0, which likely includes improvements for detecting React Hooks issues and supporting newer React features.


22-25:

✅ Verification successful

Added TypeScript as an optional dependency

TypeScript has been added as an optional dependency with version ^5.8.2. This is a good practice as it ensures a compatible TypeScript version is available for the ESLint plugins without making it a strict requirement.


🌐 Web query:

Is TypeScript 5.8.2 the latest version, and what are its key features?

💡 Result:

TypeScript 5.8 is the latest stable version as of March 2025, with TypeScript 5.8.2 likely representing a minor patch within this release. This update introduces significant improvements to type safety, module interoperability, and developer tooling. Below are the key features and enhancements:

1. Granular Return Expression Checks

TypeScript 5.8 adds stricter checks for conditional expressions in return statements. Each branch of a return expression is now validated against the function's declared return type, catching errors where mismatched types might otherwise go unnoticed. For example:

declare const cache: Map<any, any>;
function getURL(url: string): URL {
    return cache.has(url) ? cache.get(url) : url; // Error: 'string' not assignable to 'URL'[1][4][10]

2. Improved CommonJS/ESM Interoperability

With Node.js 22+ support under the --module nodenext flag, CommonJS modules can now require() ECMAScript modules (ESM), simplifying library development and eliminating the need for dual publishing. This resolves long-standing compatibility issues between module systems[1][6][10].

3. --erasableSyntaxOnly Flag

This new compiler option enforces syntax that can be fully erased during compilation, ensuring compatibility with Node.js’ experimental TypeScript execution mode. It disallows runtime-impacting TypeScript features like enums, namespaces, and parameter properties in classes[1][5][10].

4. Performance Optimizations

  • Faster program loads/updates: Reduced path normalization overhead and avoided redundant configuration checks (e.g., tsconfig.json validation) improve responsiveness in large projects[8][10].
  • Watch mode/editor efficiency: Updates to files now skip unnecessary revalidation steps when project structure remains unchanged[8][10].

5. Declaration File Improvements

Computed property names in classes are now preserved in declaration files instead of being rewritten as index signatures. This enhances predictability for consumers of .d.ts files[5][10].

6. Module and Library Enhancements

  • --libReplacement flag: Disables automatic lookup for @typescript/lib-* packages, reducing overhead for projects not using custom type libraries[5][10].
  • Import assertion restrictions: The assert keyword for imports is deprecated in favor of with under --module nodenext, aligning with Node.js 22+ standards[10].

7. Deferred Features

A planned feature for conditional return type checking was moved to TypeScript 5.9 due to implementation complexities. However, preparatory work enabled the granular return checks in 5.8[1][4][10].


TypeScript 5.8 focuses on refining type safety, modernizing module workflows, and optimizing tooling performance. Developers can install it via npm install typescript or explore nightly builds for upcoming 5.9 features[1][10].

Citations:


Approved: TypeScript ^5.8.2 is Correctly Configured

The optionalDependencies update in framework/eslint-config/package.json now correctly specifies TypeScript version ^5.8.2. Our verification confirms that TypeScript 5.8 (with patch 5.8.2) is the latest stable release as of March 2025, and it brings useful improvements in type safety, module interoperability, and tooling performance. This optional dependency ensures that ESLint plugins have access to a compatible TypeScript without enforcing a strict requirement.

  • Location: framework/eslint-config/package.json, lines 22-25
  • Snippet:
        },
        "optionalDependencies": {
            "typescript": "^5.8.2"
        }

8-9:

✅ Verification successful

Updated TypeScript ESLint dependencies to latest versions

The TypeScript ESLint plugin and parser have been updated to version 8.26.0, which likely includes bug fixes, new rule sets, and improved TypeScript language support.


🌐 Web query:

What are the major changes in @typescript-eslint/eslint-plugin version 8.26.0 compared to previous versions?

💡 Result:

The @typescript-eslint/eslint-plugin version 8.26.0 introduces several significant changes and enhancements. Here's a breakdown of the major updates:


🚀 Key Features and Enhancements

TypeScript 5.8 Support

  • Full compatibility with TypeScript 5.8, ensuring accurate linting for new syntax and type-checking features[1][2].

Project Service Stabilization

  • The experimental projectService option is now stable, replacing parserOptions.project in many cases. It simplifies configuration and improves performance by leveraging TypeScript's editor-like project management[2][3].
    // Example configuration
    parserOptions: {
      projectService: true, // Automatically finds tsconfig.json
      tsconfigRootDir: import.meta.dirname,
    }

New Rules and Rule Updates

  • Added Rules:
    • no-empty-object-type: Bans the {} type in ambiguous contexts[2].
    • no-require-imports: Replaces the deprecated no-var-requires rule[2][3].
    • no-unsafe-function-type: Flags unsafe Function type usage[2].
    • no-wrapper-object-types: Bans Object, Number, etc., in favor of primitives[2].
  • Enhanced Rules:
    • no-unnecessary-type-parameters: Improved handling of tuples and array parameter locations[1].
    • no-unused-var: Now detects unused variables in declaration files with implicit exports[1].

🩹 Fixes and Optimizations

  • Dependency Updates: Compatibility with ESLint v9 and other tooling improvements[1][4].
  • Scope Manager: Reduced redundant Object.entries calls for type libs, improving performance[1].
  • Rule Fixes:
    • no-invalid-void-type: Reports invalid void types in accessor properties[1].
    • no-unnecessary-type-assertion: Handles unknown types correctly[1].
    • unified-signatures: Ignores overloads with differing JSDoc comments[1].

⚠️ Breaking Changes and Deprecations

  • Deprecated Rules:
    • ban-types was split into more targeted rules (no-empty-object-type, no-unsafe-function-type, etc.)[2][3].
    • no-throw-literal replaced by only-throw-error[3].
  • Configuration Presets Updated:
    • eslint:recommended and recommended-type-checked now include stricter defaults[2][3].
    • Removed rules: ban-types, no-loss-of-precision, no-var-requires[2].

🛠️ Migration Steps

  1. Update Dependencies:
    npm install @typescript-eslint/[email protected] @typescript-eslint/[email protected] --save-dev
  2. Adopt projectService: Replace project: true with projectService: true for faster, more reliable type-aware linting[2][3].
  3. Review Rule Changes: Disable new rules if necessary or adjust configurations for stricter defaults.

For a full list of changes, see the v8.26.0 release notes[1].

Citations:


Updated TypeScript ESLint Dependencies to v8.26.0 – Leveraging TypeScript 5.8 and Enhanced Linting Capabilities

  • The dependency upgrade in framework/eslint-config/package.json now sets both the ESLint plugin and parser to version 8.26.0.
  • This version brings full support for TypeScript 5.8, stable projectService configuration (which simplifies tsconfig.json management), and introduces several new and enhanced rules (e.g., improved handling of empty object types, unsafe function types, and more).
  • The changes ensure better performance, improved configuration defaults, and overall more robust TypeScript linting without any visible removal or replacement in the diff snippet.
packages/hydrooj/src/entry/common.ts (1)

72-72: Simplified plugin loading API by removing redundant context parameter

Similar to the change in the getLoader function, this call to ctx.loader.reloadPlugin has been updated to remove the redundant ctx parameter. This maintains consistency with the plugin loading mechanism changes throughout the codebase.

README.md (2)

125-125: Documentation improvement for installation warning.

Good addition of a warning about shared memory (shm) space size during installation. This is important information for users, especially when deploying in containerized environments where shared memory limitations can cause issues.


127-134: Good documentation of major architectural changes.

The documentation clearly outlines important architectural changes:

  1. Upgrade to cordis@4
  2. Support for multiple renderers
  3. Separation of HMR and Watcher components
  4. Enhanced i18n with interface options
  5. New checker support
  6. Removal of legacy bus calls
  7. Enforced dependency declarations

These notes will be helpful for users upgrading from previous versions.

packages/hydrooj/package.json (2)

19-21: Migration to namespaced cordis packages.

Good transition from the monolithic cordis package to the modular @cordisjs/* packages. This follows modern JavaScript packaging practices and should provide better maintainability and potentially reduced bundle sizes through more granular imports.


22-22: Dependency updates to newer versions.

Keeping dependencies updated is good practice for security and performance. Make sure to test the application thoroughly with these new versions to ensure compatibility.

Also applies to: 28-28, 46-46, 52-52, 67-67

packages/hydrooj/src/service/server.ts (7)

8-10: Improved imports with type-safety.

Good improvement on imports using type imports and adding WebService from the framework. This makes the dependencies clearer and will provide better type checking.


33-33: Enhanced type-safety with generic interface.

Converting HandlerCommon to a generic interface with type parameter <C> improves type safety and flexibility. This allows the interface to adapt to different context types throughout the application.


84-93: Improved plugin architecture.

Great improvement to use WebService directly as a plugin instead of requiring the entire framework module. This follows better dependency injection practices and makes the code more maintainable.


222-245: Well-structured error handling for HTTP handlers.

The addition of the httpHandlerMixin with detailed error handling logic is a good improvement. It properly handles different error types, provides appropriate responses, and includes useful logging.

The special handling for unauthenticated users encountering permission errors by redirecting to the login page is a nice UX touch.


247-255: Consistent error handling for WebSocket connections.

Good addition of error handling for WebSocket connections. The implementation properly logs errors while excluding common errors like NotFoundError when the user is not authenticated, which helps keep logs clean.


262-268: Enhanced template rendering with domain support.

The implementation of domain-specific template rendering is a good improvement. It attempts to load a domain-specific template first (${s[0]}.${args.domainId}.${s[1]}) and falls back to the generic template if not found.


270-283: Improved error handling in handler creation.

The addition of error checking for pending errors in the handler creation process is a good safety feature. This ensures that any errors that occurred during earlier stages of request processing are properly propagated.

framework/framework/server.ts (5)

5-5: Migration to @cordisjs/core.

Good update to import Context as CordisContext from @cordisjs/core instead of using a local Context. This aligns with the package.json changes and moves toward using the namespaced cordis packages.


200-200: Enhanced type safety with generics.

Good improvement to make the Handler, ConnectionHandler, NotFoundHandler, and WebService classes generic. This allows for better type checking and more flexible composition across the application.

Also applies to: 246-246, 283-283, 322-322


655-679: Improved permission and privilege checking logic.

The reworked Checker function is a significant improvement. It properly handles different types of inputs (objects, numbers, bigints) and returns a function that checks permissions and privileges based on the provided arguments. This makes the code more maintainable and reduces duplication.

🧰 Tools
🪛 GitHub Check: CodeQL

[warning] 676-676: Useless conditional
This use of variable 'perm' always evaluates to false.


749-763: Well-structured mixin implementation with effect hooks.

The implementation of the mixin methods using ctx.effect() is excellent. This approach:

  1. Properly registers and unregisters the mixins when components are activated/deactivated
  2. Separates concerns between HTTP and WebSocket handlers
  3. Provides clean warnings when attempting to override existing methods
  4. Uses type-safe generics to ensure compatibility with the target classes

This implementation follows modern React-like patterns for managing side effects and cleanup.

Also applies to: 765-779, 781-794


807-814: Enhanced type declarations for framework integration.

The module augmentation for @cordisjs/core is well implemented. It ensures that the server, Route, Connection, and withHandlerClass properties are properly typed in the extended Context interface, providing proper type checking for users of the framework.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (17)
packages/migrate/scripts/hustoj.ts (2)

291-296: Improved numeric handling with BigInt for large datasets

The change to use BigInt for pagination logic is a good improvement that prevents potential numeric overflow when dealing with large datasets in migration scenarios.

However, be cautious about the conversion between BigInt and Number types in the progress reporting code.

Consider adding a comment explaining why BigInt is used here to help future maintainers understand the rationale:

- const [{ 'count(*)': _rcount }] = await query('SELECT count(*) FROM `solution`');
- const rcount = BigInt(_rcount);
+ // Using BigInt to handle potentially large solution counts that exceed Number.MAX_SAFE_INTEGER
+ const [{ 'count(*)': _rcount }] = await query('SELECT count(*) FROM `solution`');
+ const rcount = BigInt(_rcount);

332-337: Ensure safe conversion from BigInt to Number

When reporting progress, you're converting BigInt values to Number which could lead to precision loss with extremely large values.

Consider adding a safety check before the conversion:

- if (pageId % 10n === 0n) {
-   const progress = Math.round(((Number(pageId) * step) / Number(rcount)) * 100);
-   report({
-     message: `record finished ${Number(pageId * BigInt(step))} / ${Number(rcount)} (${progress}%)`,
-   });
- }
+ if (pageId % 10n === 0n) {
+   // Safe conversion - ensure values don't exceed MAX_SAFE_INTEGER
+   const pageIdNum = pageId <= Number.MAX_SAFE_INTEGER ? Number(pageId) : Infinity;
+   const rcountNum = rcount <= Number.MAX_SAFE_INTEGER ? Number(rcount) : Infinity;
+   const processedNum = (pageId * BigInt(step)) <= Number.MAX_SAFE_INTEGER ? 
+     Number(pageId * BigInt(step)) : Infinity;
+   
+   const progress = Math.round(((pageIdNum * step) / rcountNum) * 100);
+   report({
+     message: `record finished ${processedNum} / ${rcountNum} (${progress}%)`,
+   });
+ }
packages/ui-default/index.ts (1)

77-77: Configuration source updated to use context-specific settings

This change moves from using a static configuration source to a context-specific one, aligning with the broader refactoring toward using the new ConfigService.

Add error handling to ensure the code doesn't break if the config settings are missing:

- const schema = convert(Schema.intersect(this.ctx.config.settings) as any, true);
+ const settings = this.ctx.config?.settings || {};
+ const schema = convert(Schema.intersect(settings) as any, true);
packages/import-qduoj/index.ts (1)

31-37: Improved type safety for optional SPJ field

The change to make spj a union type with Schema.never() increases type safety by explicitly modeling the absence of SPJ information. This is better than just making the field optional.

Consider adding a comment to explain this pattern for clarity:

  spj: Schema.union([
+     // Using Schema.never() to explicitly represent cases where SPJ doesn't exist,
+     // providing better type safety than a simple optional field
      Schema.never(),
      Schema.object({
          language: Schema.string().required(),
          code: Schema.string().required(),
      }),
  ]),
packages/hydrooj/src/entry/worker.ts (2)

41-45: Avoid reassigning ctx.
Reassigning ctx inside a promise may cause confusion. Considering a different variable name can improve clarity.

-    ctx = await new Promise((resolve) => {
+    const updatedCtx = await new Promise((resolve) => {

50-54: Same overshadowing concern.
Similarly, reassigning ctx in another promise can hamper readability. A distinct variable name is preferable.

packages/hydrooj/src/service/db.ts (1)

188-193: Deprecated fallback proxy.
This db proxy depends on a global app reference and could create unexpected behavior if app is unavailable. Consider removing or gating usage more explicitly.

packages/hydrooj/src/service/storage.ts (1)

391-415: Security check for proxy route.
The rewrite logic and proxy usage are fine. However, consider adding security or rate-limiting to avoid exposing files unintentionally.

packages/hydrooj/src/loader.ts (4)

50-50: Consider specifying a more descriptive type for state
Using Record<string, EffectScope> is acceptable. However, static analysis warns against using {} (observed in the subsequent line for public config). If feasible, define a more robust interface or at least a Record<string, unknown> to improve clarity and enforce type safety.


58-62: Handle interval cleanup
You are establishing a repeating check with ctx.setInterval(...) to log plugin states. Consider clearing this interval if the service is disposed or if the app shuts down, to avoid potential memory leaks or calls after the context is no longer valid.


100-108: Returning an empty object if no schema
The logic to return {} for plugins without a schema is convenient but may hide silent misconfigurations. Consider logging a warning or providing a default config to improve debuggability.


147-152: Assigning global.app
Using global.app might introduce maintainability issues. If your codebase standardizes around it, that's acceptable, but stay mindful if multiple modules attempt to modify global.app concurrently.

packages/hydrooj/src/settings.ts (4)

17-20: Type definitions for configurations
Using Schema[] and any might limit type safety. If possible, refine systemConfig to a structured type instead of any to reduce potential runtime errors.


29-39: Error handling for config loading
This function parses YAML, logs on failure, and emits an event on success. Consider providing a fallback to default settings if parsing fails, to prevent partial system functionality.


77-83: Configuration getter
Dot-notation traversal is handy but can fail silently if any subpath is undefined. Consider optional safety checks or default return values for more robust behavior.


85-119: Dynamic config proxy
Providing a Proxy for config updates is powerful but can be harder to debug and can add overhead. Still, this pattern fosters a neat, reactive approach to configuration management.

packages/hydrooj/src/model/setting.ts (1)

82-119: Well-structured schema conversion function

The schemaToSettings function is well implemented with proper error handling for unsupported structures. It correctly processes schema metadata and maps schema types to corresponding setting types.

Consider adding a type guard or assertion for the return value of schemaToSettings to ensure type safety when used in the settings functions:

-function schemaToSettings(schema: Schema<any>) {
+function schemaToSettings(schema: Schema<any>): _Setting[] {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f6bb3b6 and 31b4ed7.

📒 Files selected for processing (18)
  • README.md (1 hunks)
  • packages/hydrooj/src/entry/cli.ts (3 hunks)
  • packages/hydrooj/src/entry/common.ts (2 hunks)
  • packages/hydrooj/src/entry/worker.ts (4 hunks)
  • packages/hydrooj/src/handler/manage.ts (1 hunks)
  • packages/hydrooj/src/handler/misc.ts (1 hunks)
  • packages/hydrooj/src/interface.ts (0 hunks)
  • packages/hydrooj/src/loader.ts (7 hunks)
  • packages/hydrooj/src/model/setting.ts (9 hunks)
  • packages/hydrooj/src/service/db.ts (3 hunks)
  • packages/hydrooj/src/service/server.ts (6 hunks)
  • packages/hydrooj/src/service/storage.ts (7 hunks)
  • packages/hydrooj/src/settings.ts (1 hunks)
  • packages/hydrooj/src/upgrade.ts (2 hunks)
  • packages/hydrooj/src/utils.ts (2 hunks)
  • packages/import-qduoj/index.ts (1 hunks)
  • packages/migrate/scripts/hustoj.ts (2 hunks)
  • packages/ui-default/index.ts (2 hunks)
💤 Files with no reviewable changes (1)
  • packages/hydrooj/src/interface.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/hydrooj/src/entry/common.ts
🧰 Additional context used
🪛 Biome (1.9.4)
packages/hydrooj/src/handler/manage.ts

[error] 198-198: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

packages/hydrooj/src/loader.ts

[error] 51-51: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

🪛 GitHub Check: CodeQL
packages/hydrooj/src/settings.ts

[warning] 51-51: Prototype-polluting assignment
This assignment may alter Object.prototype if a malicious 'proto' string is injected from library input.

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (76)
README.md (1)

125-139: Well-documented changes in the update

Good job documenting all the major changes in this update, especially architectural changes like the upgrade to cordis@4, the removal of global services, and the support for Schemastery in Settings.

These changes provide users with clear information about what to expect in this version.

packages/import-qduoj/index.ts (1)

108-115:

✅ Verification successful

Verify SPJ language check

The current code only handles SPJ in C++. After making spj optional with the union type, ensure this conditional still behaves as expected.


🏁 Script executed:

#!/bin/bash
# Find all places where spj.language is checked to verify consistency
rg "spj.*language" -A 5 -B 5

Length of output: 3257


SPJ language conditional verified

I've confirmed via a repository-wide search that the only check on spj.language in the qduoj import code is on line 108 of packages/import-qduoj/index.ts, where it evaluates if (pdoc.spj?.language === 'C++'). This optional chaining ensures that if spj is undefined (as allowed by the new union type), the condition safely returns false, thereby avoiding any unintended execution of the SPJ-related logic.

Please double-check that supporting only the C++ SPJ is intentional. If additional SPJ languages should be supported in the future, adjustments to this conditional might be necessary.

packages/hydrooj/src/handler/misc.ts (1)

112-112: Improved configuration management approach.

The change to retrieve the file secret from context configuration instead of a static import is a good improvement. This promotes better dependency injection and makes the code more testable and configurable.

packages/hydrooj/src/entry/cli.ts (5)

9-11: Updated imports for service-based architecture.

Good restructuring to support the new service-based approach.


114-116: Improved service initialization with dependency injection.

The refactoring from direct service calls to plugin-based initialization improves modularity and follows better dependency injection practices.


117-122: Enhanced dependency handling with Promise-based injection.

This change ensures that the loader dependency is properly injected before proceeding. This is a good pattern for managing asynchronous dependencies.


133-137: Consistent implementation of Promise-based dependency injection.

Similar to the loader injection, this ensures the server dependency is available before proceeding with addon operations.


141-142: Simplified plugin reloading.

The removal of the ctx parameter from reloadPlugin call simplifies the function signature while maintaining functionality.

packages/hydrooj/src/upgrade.ts (2)

425-435: Centralized configuration management.

The migration from setBuiltinConfig to app.get('config').setConfig aligns with the project's move toward a service-based architecture for configuration management. This makes configuration handling more consistent and maintainable.


704-704: Version marker added.

The comment indicating the start of Hydro v5 provides useful versioning information for future reference.

packages/hydrooj/src/utils.ts (2)

1-2: Added import for enhanced null checking.

Good addition of the isNullable utility from cosmokit for more robust null/undefined checks.


22-29: Improved module export handling logic.

The refactored unwrapExports function is more readable and explicit in handling different cases. The updated structure with individual condition checks improves maintainability and the added comments about ESBuild interoperability provide helpful context.

packages/hydrooj/src/entry/worker.ts (6)

10-11: Smooth import additions.
No issues found here; the new imports for MongoService and ConfigService appear straightforward.


26-26: Verify null or empty string scenarios.
If MongoService.getUrl() returns '' or undefined, ensure if (!url) correctly handles that case.


37-38: Registration order looks fine.
Plugging in MongoService and ConfigService is consistent with the new approach.


46-46: Plugin reload looks correct.
No problems found with reloading the storage service plugin.


69-69: Plugin reload usage.
Reloading the handler plugin is consistent with your pattern.


76-76: No issues found.
The script plugin reload mirrors the handler pattern with no evident problems.

packages/hydrooj/src/handler/manage.ts (4)

186-186: Circumvent direct config usage.
Referencing this.ctx.config.configSource is in line with the new ConfigService; no immediate concerns.


188-188: Verify schema intersection behavior.
Ensure partial or invalid YAML doesn't yield downstream errors, though the try/catch is likely sufficient.


191-191: Publicly exposing schema.
Generating a JSON representation of the intersected schema is a clean approach.


205-205: Saving config seamlessly.
The call to this.ctx.config.saveConfig(config) fits the new config system well.

packages/hydrooj/src/service/db.ts (9)

7-7: New import is consistent.
Bringing in Context and Service aligns well with the updated architecture.


11-11: No concerns with bus import.
Using this default import is a standard approach.


29-33: Typed context extension.
Adding db: MongoService to Context improves type safety and clarity.


35-35: MongoService class hierarchy.
Extending Service is a straightforward design to group DB logic.


39-41: Constructor pattern looks good.
super(ctx, 'db') is consistent with naming for the service.


43-49: Behavior in CI environment.
getUrl() is managing in-memory Mongo for CI. Verify that production builds never set CI inadvertently.


58-59: Service setup method.
Using [Service.setup] neatly triggers the initialization. Looks correct.


64-64: Periodic collection maintenance.
fixExpireAfter() each hour is generally fine, but watch out for performance overhead on large sets.


68-70: Custom collection mapping.
Leveraging collectionMap is a clean solution for flexible naming.

packages/hydrooj/src/service/storage.ts (10)

15-15: Introduction of koa-proxies.
Importing proxy is reasonable for the new approach to file routing.


17-17: nanoid usage is appropriate.
A short, unique secret is a solid approach for config defaults.


18-18: Schemastery import.
Ensures typed validation for storage configuration.


63-65: Check default path logic.
Using process.env.CI plus a fallback is sensible. Confirm environment variables won't break references.


66-96: Comprehensive FileSetting schema.
Good job unifying local and S3 storage definitions via Schema.intersect().


98-99: Exporting Config.
Re-exporting FileSetting under Config is clear enough.


110-111: RemoteStorageService constructor.
Injecting typed config fosters clarity for S3 usage.


307-308: LocalStorageService constructor.
Similarly adopting typed config for local storage is consistent.


383-389: Adaptive storage instantiation.
Falling back to local if type === 'file' is logical. You may want to guard against unknown types.


419-425: Deprecated proxy retained.
Keeping a fallback export is fine but do encourage consumers to use ctx.storage.

packages/hydrooj/src/loader.ts (8)

17-19: Imports of context types are consistent.
These imports appear appropriate, and all the symbols (Context, Service, ScopeStatus, EffectScope) are indeed used in the file.


24-24: Schemastery import usage
Using the schemastery import for configuration schema handling is appropriate. Looks good.


56-56: Dependency injection array
This injection array (['config', 'timer', 'i18n', 'logger']) matches your usage. No issues found.


110-114: reloadPlugin method reuses the plugin object
The method updates the plugin config and optionally overrides plugin.name. Ensure that overwriting plugin.name does not disrupt other references or logging flows. Overall, the approach for retrieving and applying the plugin config is sound.


121-121: Initialize plugin with resolved config
This is a straightforward call to initialize the plugin. Verify that each plugin can properly handle the passed-in config object to avoid unexpected runtime errors.


135-136: Verbose error logging
Logging errors when plugin resolution fails is helpful for debugging. Ensure that err does not contain sensitive information that might be exposed in logs.


172-172: Synchronous loading
Calling await preload() ensures required dependencies and data are fully loaded before proceeding. This improves reliability of the loading process.


211-211: Ensuring CLI preload
Awaiting preload() in loadCli() helps unify the initialization path for CLI usage, maintaining consistency with the main load() method.

packages/hydrooj/src/service/server.ts (6)

7-9: Modular import from @hydrooj/framework
Importing ConnectionHandlerOriginal, HandlerOriginal, and related types from the framework improves clarity and modular design.


31-31: Introducing generic parameter C
Extending HandlerCommon to accept a generic context type fosters greater type flexibility. Ensure that downstream references use the new parameter consistently.


74-74: Generic class extension for Handler
Switching Handler to extend HandlerOriginal<Context> clarifies the expected context type, enhancing type safety.


77-77: Consistent usage of typed Context in ConnectionHandler
Using ConnectionHandlerOriginal<Context> aligns with the approach in Handler, ensuring uniform type handling.


82-82: Registering WebService
Replacing direct framework usage with the WebService plugin helps maintain a modular structure. Verify that prior functionality remains accessible through this plugin integration.


259-260: Early error throw in WS handler
Immediately rejecting if h.context.pendingError is set prevents initiating any incomplete WebSocket operations. This “fail fast” method is beneficial for robust error handling.

packages/hydrooj/src/settings.ts (9)

3-3: Context and Service import
Importing these for the new settings architecture appears consistent with the overall service approach.


8-10: Augmenting the Context interface
Adding config: ConfigService ensures configuration logic is conveniently accessible across the application.


14-15: New ConfigService with DB injection
Deriving from Service while injecting the DB dependency centralizes config logic. This is a cohesive design choice.


21-21: Constructor ensures naming
Using super(ctx, 'config') clearly identifies this service. Maintains consistency with your injection pattern.


25-27: Service setup ensures config loading
Overriding [Service.setup] to invoke loadConfig() ensures early retrieval of settings, aligning with service lifecycle expectations.


55-63: Validation synergy
isPatchValid reuses applyDelta and Schema.intersect to verify patches. Ensure all update flows call this method to avoid bypassing checks.


65-71: Schema intersection before saving
Performing Schema.intersect(this.settings)(config) ensures the config adheres to expected schemas before persistence. Nice defensive measure.


72-75: Granular config updates
Using applyDelta for partial config changes is flexible. Validate that multi-level paths are tested, especially if keys or sub-keys are missing.


120-121: No additional functional changes
These lines appear to close out the class with no further modifications.

packages/hydrooj/src/model/setting.ts (12)

3-3: Package dependency update from 'cordis' to '@cordisjs/core'

This change aligns with the broader project update to use the namespaced @cordisjs/core package instead of the original cordis package.


7-7: Added Schema import from 'schemastery'

The addition of Schema import is necessary to support the new schema-based settings functionality in this file.


74-80: Good implementation of Schemastery namespace declaration

The global declaration for Schemastery namespace properly defines the Meta interface with a family property, which will be used for schema metadata.


121-122: Improved settings function to support Schema objects

The PreferenceSetting function now accepts both _Setting arrays and Schema objects, using the new schemaToSettings function to convert Schema objects to _Setting arrays when needed.


141-142: Improved AccountSetting function to support Schema objects

Similar to PreferenceSetting, the AccountSetting function now supports Schema objects as input.


161-162: Improved DomainUserSetting function to support Schema objects

DomainUserSetting now accepts Schema objects and converts them to _Setting objects appropriately.


177-178: Improved DomainSetting function to support Schema objects

DomainSetting function now handles Schema objects, consistent with the other setting functions.


193-194: Improved SystemSetting function to support Schema objects

SystemSetting now supports Schema objects, completing the consistent pattern across all setting functions.


351-351: Updated module declaration to use '@cordisjs/core'

This change is consistent with the import update at the top of the file, ensuring type compatibility with the new package.


380-380: Added dependency injection specification

The addition of the 'inject' export specifies that the 'db' service is a dependency for this module, making dependencies explicit.


388-388: Improved database access with context-aware approach

Changed from using the global database service to using the context-bound database service, improving modularity and testability.


412-413: Updated model export to include the inject property

This ensures that the dependency requirements are properly exposed in the global model object.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
framework/framework/server.ts (3)

128-129: ⚠️ Potential issue

Fix unsafe declaration merging and empty interface

The empty interface followed by a class with the same name creates unsafe declaration merging in TypeScript. The compiler won't check if properties defined in the interface are initialized in the class.

-export interface HandlerCommon<C> { } // eslint-disable-line @typescript-eslint/no-unused-vars
+// Use a type alias instead if needed, or remove entirely as the class already defines the structure
 
export class HandlerCommon<C> {
🧰 Tools
🪛 Biome (1.9.4)

[error] 128-128: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 129-129: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)


481-483: 🛠️ Refactor suggestion

Create proper type definitions for event handlers

Multiple type casts to any with FIXME comments indicate a need for proper typing of event handlers.

Consider creating a proper event definition interface:

interface HandlerEvents<T> {
  'handler/create': [handler: T, type: 'http' | 'ws'];
  'handler/create/http': [handler: T];
  // Define other event types similarly
}

// Then extend the Context interface to include typed events

676-676: ⚠️ Potential issue

Fix condition that always evaluates to false

The condition if (perm) is flagged by static analysis as always evaluating to false.

The issue might be that perm is initialized as undefined and the type checking logic doesn't properly assign it. Consider checking if perm is being assigned correctly in the loop above:

-                if (perm) this.checkPerm(perm);
+                if (perm !== undefined) this.checkPerm(perm);

Alternatively, initialize perm with a falsy value that's not undefined:

-            let perm: bigint;
+            let perm: bigint | undefined;
🧰 Tools
🪛 GitHub Check: CodeQL

[warning] 676-676: Useless conditional
This use of variable 'perm' always evaluates to false.

🧹 Nitpick comments (3)
framework/framework/server.ts (3)

146-146: Remove explicit any type assertion

Type assertions to any defeat TypeScript's type checking. Consider creating a proper type definition for the context extension method.

-        this.ctx = (ctx as any).extend({});
+        this.ctx = ctx.extend({});

If the extend method isn't properly typed in the context type, consider enhancing the type definition instead of using any.


187-188: Avoid type assertions to any for renderers

Instead of using any, properly type this.ctx.server.renderers.

-        const renderers = Object.values((this.ctx as any).server.renderers as Record<string, Renderer>)
+        const renderers = Object.values(this.ctx.server.renderers as Record<string, Renderer>)

708-710: Address FIXME comment with proper type definition

The FIXME comment indicates a need for proper typing of the Route method parameter.

Define a proper type for RouteHandler instead of using any:

-    // FIXME: should be typeof Handler<Context> instead of any
-    // eslint-disable-next-line @typescript-eslint/naming-convention
-    public Route(name: string, path: string, RouteHandler: any, ...permPrivChecker) {
+    // eslint-disable-next-line @typescript-eslint/naming-convention
+    public Route<T extends CordisContext = C>(name: string, path: string, RouteHandler: typeof Handler<T>, ...permPrivChecker) {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 31b4ed7 and a33826c.

📒 Files selected for processing (6)
  • framework/framework/server.ts (21 hunks)
  • packages/hydrooj/src/entry/cli.ts (3 hunks)
  • packages/hydrooj/src/entry/worker.ts (4 hunks)
  • packages/hydrooj/src/model/setting.ts (10 hunks)
  • packages/hydrooj/src/model/user.ts (3 hunks)
  • packages/hydrooj/src/plugin-api.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/hydrooj/src/plugin-api.ts
🧰 Additional context used
🪛 Biome (1.9.4)
framework/framework/server.ts

[error] 128-128: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 129-129: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)

🪛 GitHub Check: CodeQL
framework/framework/server.ts

[warning] 676-676: Useless conditional
This use of variable 'perm' always evaluates to false.

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (31)
packages/hydrooj/src/model/user.ts (3)

12-12: Updated bus import pattern

The import statement for bus has been changed from namespace import to default import, which aligns with the broader pattern change across the codebase mentioned in the PR summary.


212-214: Added static references to utility functions

Adding static references to existing functions enhances the class interface by making these utilities accessible through the UserModel class directly. This improves code organization and follows good OOP principles.


471-489: Introduced async initialization pattern

The new apply function replaces the previous event listener approach with a more explicit initialization pattern. This is a good architectural improvement that:

  1. Makes the initialization sequence more deterministic
  2. Uses Promise.all for efficient parallel database index creation
  3. Aligns with the asynchronous initialization pattern mentioned in the PR summary

This approach provides better control over the application startup sequence.

packages/hydrooj/src/entry/cli.ts (5)

9-11: Updated imports to support the new service architecture.

The imports have been updated to align with the new architecture, introducing loadOptions, MongoService, and ConfigService. This is part of the broader refactoring to improve dependency management.


114-115: Services now initialized as plugins rather than direct calls.

The direct calls to database initialization and config loading have been replaced with a more modular plugin-based approach. This improves testability and allows for better dependency management.


117-122: Added async context injection for the loader.

This Promise-based pattern ensures that the loader dependency is available before proceeding, which is a more robust approach to handling dependencies. This aligns with the async refactoring across the codebase.


133-137: Added async context injection for the server component.

Similar to the loader injection, this ensures the server component is fully initialized before proceeding with addon loading and other operations that might depend on it.


141-142: Simplified plugin reloading call.

The plugin reloading call has been simplified by removing the explicit ctx parameter, which is now handled internally. This is a cleaner approach that reduces parameter passing.

packages/hydrooj/src/entry/worker.ts (7)

10-11: Updated imports for the new service architecture.

Similar to cli.ts, imports have been updated to support the new plugin-based service architecture with MongoService and ConfigService.


26-30: Improved database URL retrieval with async pattern.

Now uses an async approach to retrieve the MongoDB URL before initializing the setup process if needed. This provides better flow control and error handling.


37-38: Services now initialized as plugins.

Consistent with the changes in cli.ts, database and configuration services are now initialized as plugins, enhancing modularity.


41-48: Added async context injection and improved plugin initialization.

The code now ensures the loader is fully initialized before proceeding and introduces better plugin management. The addition of HMR service with a watch option enhances development capabilities.


50-54: Added async context injection for the server component.

Similar to the loader injection, this ensures proper initialization sequencing for components that depend on the server.


69-70: Simplified plugin reloading for handlers.

Removed unnecessary ctx parameter in the reloadPlugin call, consistent with other similar changes in the codebase.


76-77: Simplified plugin reloading for scripts.

Similar simplification as with handlers, maintaining consistency in the plugin loading approach across the codebase.

packages/hydrooj/src/model/setting.ts (13)

3-8: Updated imports to use namespaced package and added Schema support.

The import from 'cordis' has been updated to '@cordisjs/core', and Schema from 'schemastery' has been added to support the new declarative settings approach.


74-80: Added global declaration for Schemastery namespace.

This extends the global type definitions to include the Schemastery namespace with a Meta interface that includes a 'family' property. This enables type safety when working with schema metadata.


82-119: Added schemaToSettings function for converting Schema to Setting objects.

This utility function enables a more declarative approach to defining settings using Schema objects. It correctly handles various schema types and includes appropriate error handling for unsupported structures.


121-123: Updated PreferenceSetting to support Schema objects.

The function now accepts both _Setting arrays and Schema objects, with conversion handled through the new schemaToSettings function. This provides more flexibility in how settings are defined.


141-143: Updated AccountSetting to support Schema objects.

Similar to PreferenceSetting, this function now supports both traditional setting arrays and schema-based definitions.


161-163: Updated DomainUserSetting to support Schema objects.

Consistent with other setting functions, this now supports schema-based definitions.


177-179: Updated DomainSetting to support Schema objects.

Consistent with other setting functions, this now supports schema-based definitions.


193-195: Updated SystemSetting to support Schema objects.

Consistent with other setting functions, this now supports schema-based definitions.


290-317: Added Schema-based setting definition example.

This showcases the new declarative approach to defining settings using Schema objects. The approach provides better type safety and structure compared to the previous array-based approach.


359-363: Updated module declaration to reference @cordisjs/core.

This aligns with the import change at the top of the file, maintaining consistency in the module references.


388-388: Added inject property to specify database dependency.

This explicitly declares the database dependency, improving clarity around required services.


396-397: Updated database access to use context.

Changed from using the global Hydro service to ctx.db, which is more aligned with the context-based approach used throughout the codebase.


420-421: Added inject property to global model.

Ensures the dependency information is available to the global model, maintaining consistency with the service-based approach.

framework/framework/server.ts (3)

719-725: Nice improvement with effect-based registration

Using ctx.effect() for layer registration is a good pattern as it automatically handles cleanup when the context is disposed.


749-763: Good implementation of handler mixins with proper cleanup

The implementation of mixins using ctx.effect() ensures proper registration and cleanup of prototype modifications, enhancing the maintainability of the codebase.


807-813: Good use of module augmentation for type safety

The module declaration enhances type safety by properly typing the context extensions, ensuring correct types are used throughout the application.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (4)
framework/framework/server.ts (4)

129-130: 🛠️ Refactor suggestion

Fix unsafe declaration merging.

The empty interface HandlerCommon<C> followed by a class with the same name creates an unsafe declaration merging pattern in TypeScript. The linter also flags this as problematic.

Consider using a type alias instead of an empty interface:

-export interface HandlerCommon<C> { } // eslint-disable-line @typescript-eslint/no-unused-vars
+// Use a type alias if you need to augment the class type
+export type HandlerCommonType<C> = HandlerCommon<C>;

export class HandlerCommon<C> {
🧰 Tools
🪛 Biome (1.9.4)

[error] 129-129: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 130-130: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)


487-489: 🛠️ Refactor suggestion

Address type checking TODOs for event emission.

Several type casts to any have been added with FIXME comments for event-related methods.

Create proper type definitions for the event handlers to maintain type safety throughout the codebase:

// Add to your interface file
interface HandlerEvents<T> {
  'handler/create': [handler: T, type: 'http' | 'ws'];
  'handler/create/http': [handler: T];
  // Add other event types
}

// Then update the Context interface to include these typed events

662-686: ⚠️ Potential issue

Fix condition that always evaluates to false.

In the Checker function, the perm variable is being initialized incorrectly, causing the if (perm) condition at line 683 to always evaluate to false.

The issue is that you're using assignment without updating the variable correctly:

 const Checker = (args) => {
-    let perm: bigint;
-    let priv: number;
+    let perm: bigint | undefined;
+    let priv: number | undefined;
     let checker = () => { };
     for (const item of args) {
         if (typeof item === 'object') {
             if (typeof item.call !== 'undefined') {
                 checker = item;
             } else if (typeof item[0] === 'number') {
-                priv = item;
+                priv = item[0];
             } else if (typeof item[0] === 'bigint') {
-                perm = item;
+                perm = item[0];
             }
         } else if (typeof item === 'number') {
             priv = item;
         } else if (typeof item === 'bigint') {
             perm = item;
         }
     }
     return function check(this: Handler<C>) {
         checker();
         if (perm) this.checkPerm(perm);
         if (priv) this.checkPriv(priv);
     };
 };
🧰 Tools
🪛 GitHub Check: CodeQL

[warning] 683-683: Useless conditional
This use of variable 'perm' always evaluates to false.


794-796: ⚠️ Potential issue

Fix wsHandlerMixin implementation.

The wsHandlerMixin method warns about existing properties but doesn't actually assign the new properties, making it ineffective.

All the other mixin methods use _applyMixin which properly assigns properties, but this method doesn't:

public wsHandlerMixin(MixinClass: Partial<ConnectionHandler<C>>) {
-    return this._applyMixin(ConnectionHandler, MixinClass);
+    this._applyMixin(ConnectionHandler, MixinClass);
+    return;
}
🧹 Nitpick comments (1)
framework/framework/server.ts (1)

147-147: Avoid type casting when extending context.

The use of as any when calling .extend() on the context circumvents type checking, which contradicts the PR's goal of improving type safety.

Consider creating a proper type for the context's extend method:

-this.ctx = (ctx as any).extend({});
+this.ctx = ctx.extend({});

Add proper type definitions for the extend method in the CordisContext interface if needed.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a33826c and 209cee9.

📒 Files selected for processing (2)
  • build/prepare.js (1 hunks)
  • framework/framework/server.ts (21 hunks)
✅ Files skipped from review due to trivial changes (1)
  • build/prepare.js
🧰 Additional context used
🪛 Biome (1.9.4)
framework/framework/server.ts

[error] 129-129: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 130-130: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)

🪛 GitHub Check: CodeQL
framework/framework/server.ts

[warning] 683-683: Useless conditional
This use of variable 'perm' always evaluates to false.

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (3)
framework/framework/server.ts (3)

809-816: Good use of TypeScript module augmentation.

The module declaration correctly extends the @cordisjs/core Context interface with the WebService methods using the this type to maintain type relationships.

This is a good pattern for extending external types while preserving type safety and self-referential relationships.


756-778: Great implementation of the _applyMixin method.

The new _applyMixin method is well-designed, featuring:

  1. Type checking for the target
  2. Clean setup and teardown through the effect pattern
  3. Proper warning messages for existing properties
  4. Restoration of original values during cleanup

This represents a significant improvement over the previous implementation.


201-203: Good use of generic defaults.

The Handler class now properly uses generics with default types, improving both flexibility and backward compatibility.

export class Handler<C = CordisContext> extends HandlerCommon<C> {

This approach allows existing code to work without changes while enabling new code to specify custom context types.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (10)
packages/ui-default/locales/zh.yaml (1)

492-493: New Localization Entries for Domain Actions Added
The entries "Join Domain to Create a Discussion: 加入域后创建讨论" and "Join Domain to Submit: 加入域后递交" are newly added. These phrases provide clear instructions to users about the actions required before participating in discussions or submissions within a domain. Please verify that these keys are referenced consistently throughout the UI.

packages/ui-default/templates/partials/problem_sidebar_normal.html (2)

20-22: Enhanced Discussion Creation Prompt
The conditional branch that checks not handler.user._dudoc.join to render the "Join Domain to Create a Discussion" link is a user-friendly enhancement. Ensure that the property _dudoc.join accurately reflects the user’s current domain membership, and that the joinDomain() JavaScript function is implemented to handle the join flow seamlessly.


52-55: Consistent Submission Prompt
For the problem submission section, the template now shows a disabled link prompting users to "Join Domain to Submit" when they are not members. Verify that using a disabled link in this context meets your accessibility standards and that the joinDomain() function is available to guide the user through the joining process.

packages/ui-default/templates/domain_user.html (1)

85-87: User Join Status Indicator
Introducing a conditional check to display “(Not joined yet)” next to a user’s name (when udoc.join is false) provides users with immediate feedback about membership status. Please verify that the styling with the text-orange class meets your interface’s accessibility contrast requirements.

packages/hydrooj/src/model/setting.ts (2)

122-141: Refactor duplicate setting key handling
Now that PreferenceSetting accepts both _Setting objects and Schema objects, consider stronger collision management beyond just logging a warning.


291-319: Role-based validation
For .role('url') or other roles, ensure you have custom validation (if needed) to avoid unexpected user input.

packages/hydrooj/src/handler/home.ts (1)

471-471: Fix the empty object destructuring pattern.

The code uses an empty object destructuring pattern which is flagged by static analysis. Consider using a proper parameter name or remove the destructuring if not needed.

-async get({ }, all: boolean) {
+async get(_: any, all: boolean) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 471-471: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

packages/hydrooj/src/model/domain.ts (1)

136-138: Use Array.isArray() instead of instanceof Array.

The instanceof Array check can be unreliable when dealing with arrays from different frames or contexts. Using Array.isArray() is more reliable.

-if (!(uid instanceof Array)) {
+if (!Array.isArray(uid)) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 138-138: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

packages/hydrooj/src/handler/domain.ts (2)

153-160: Consider using performance-friendly alternatives to delete.

The static analysis tool flags the use of delete u.user which can impact performance. Consider using assignment to undefined instead.

-            delete u.user;
+            u.user = undefined;
🧰 Tools
🪛 Biome (1.9.4)

[error] 158-158: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


338-339: Consider using performance-friendly alternatives to delete.

Similar to the previous comment, the use of delete this.joinSettings can impact performance. Consider using assignment to undefined instead.

-        if (assignedRole !== 'default') delete this.joinSettings;
+        if (assignedRole !== 'default') this.joinSettings = undefined;
🧰 Tools
🪛 Biome (1.9.4)

[error] 338-338: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 706a9a0 and e9c5bf5.

📒 Files selected for processing (14)
  • packages/hydrooj/src/handler/domain.ts (3 hunks)
  • packages/hydrooj/src/handler/home.ts (3 hunks)
  • packages/hydrooj/src/model/domain.ts (8 hunks)
  • packages/hydrooj/src/model/setting.ts (11 hunks)
  • packages/hydrooj/src/model/user.ts (4 hunks)
  • packages/hydrooj/src/service/server.ts (8 hunks)
  • packages/hydrooj/src/upgrade.ts (4 hunks)
  • packages/ui-default/locales/zh.yaml (5 hunks)
  • packages/ui-default/templates/domain_join.html (2 hunks)
  • packages/ui-default/templates/domain_join_applications.html (0 hunks)
  • packages/ui-default/templates/domain_permission.html (0 hunks)
  • packages/ui-default/templates/domain_user.html (2 hunks)
  • packages/ui-default/templates/home_domain.html (1 hunks)
  • packages/ui-default/templates/partials/problem_sidebar_normal.html (2 hunks)
💤 Files with no reviewable changes (2)
  • packages/ui-default/templates/domain_join_applications.html
  • packages/ui-default/templates/domain_permission.html
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/hydrooj/src/model/user.ts
  • packages/hydrooj/src/service/server.ts
🧰 Additional context used
🧬 Code Definitions (3)
packages/hydrooj/src/handler/home.ts (1)
packages/hydrooj/src/interface.ts (1) (1)
  • DomainDoc (307-315)
packages/hydrooj/src/model/domain.ts (3)
packages/hydrooj/src/service/bus.ts (1) (1)
  • apply (97-114)
packages/hydrooj/src/service/db.ts (1) (1)
  • apply (180-183)
packages/hydrooj/src/plugin-api.ts (2) (2)
  • Context (41-41)
  • db (58-58)
packages/hydrooj/src/model/setting.ts (3)
packages/hydrooj/src/interface.ts (1) (1)
  • Setting (46-56)
packages/hydrooj/src/service/db.ts (1) (1)
  • apply (180-183)
packages/hydrooj/src/context.ts (2) (2)
  • Context (31-41)
  • Context (68-77)
🪛 Biome (1.9.4)
packages/hydrooj/src/handler/home.ts

[error] 471-471: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

packages/hydrooj/src/model/domain.ts

[error] 138-138: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

packages/hydrooj/src/handler/domain.ts

[error] 158-158: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 338-338: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (48)
packages/ui-default/locales/zh.yaml (2)

608-608: Added Status Indicator for Unjoined Users
The new entry "Not joined yet: 暂未加入" offers a clear status message for users who have not yet joined a domain. Confirm that this text is used consistently in contexts where a user's join status is displayed.


909-909: New Entry for Domain Ownership Label
The addition of "The domain owner: 域所有者:" enhances clarity by explicitly denoting the ownership of a domain. Ensure that this translation aligns with the design guidelines and is applied wherever domain ownership is presented in the interface.

packages/hydrooj/src/upgrade.ts (4)

39-40: Good addition: MongoDB read preference setting for consistency

Adding the onPrimary constant with readPreference: 'primary' ensures data is read from the primary node, which is important for data consistency during migration operations.


56-56: Linting comment added

The lint directive // oxlint-disable-line no-new-array is properly added to suppress warnings about using the new Array() constructor.


427-428: Configuration management refactored

The change from setBuiltinConfig to app.get('config').setConfig indicates a shift to a more modular approach using dependency injection for configuration management.


706-723: Well-structured migration script for Hydro v5

This migration script properly:

  1. Sets join: true for all users in domains
  2. Configures default _join settings for domains that lack them
  3. Ensures users with ID > 1 are added to the 'system' domain
  4. Uses onPrimary read preference for data consistency

The migration handles both updating existing records and inserting new ones with the upsert option.

packages/ui-default/templates/home_domain.html (1)

40-40: Context Variable Validation for 'role'
The expression {{ role[ddoc._id]|default('default') }} now replaces the previous lookup via dudict. Please ensure that the variable role is reliably provided in the template context and that its structure aligns with the expected data keys (i.e. domain IDs).

packages/ui-default/templates/domain_join.html (4)

8-12: Dynamic Title Rendering Based on Join Settings
The conditional title rendering—choosing between “Join {domain name}” and “You are invited to join {domain name}” based on the presence of joinSettings—is clear and effective. Please confirm that joinSettings is consistently defined in the template context for all scenarios.


18-21: Display of Domain Owner Information
Rendering the domain owner with {{ user.render_inline(domainInfo['owner']) }} provides important context for the user. Just ensure that the helper function properly escapes content to avoid any potential XSS issues.


22-26: Conditional Rendering for Domain Bulletin
The new block that renders the domain bulletin (with markdown filtering) enriches the page content. Verify that the markdown filter is configured securely and does not inadvertently allow unsafe HTML.


40-41: Hidden Input Fields for Navigation
The additions of hidden input fields for target and redirect are useful for maintaining proper navigation after form submission. Ensure that these parameters are validated server-side to prevent open redirect vulnerabilities.

packages/ui-default/templates/domain_user.html (1)

105-107: Consistent User Status in Listings
The similarly applied check for rudoc.join in the second user loop helps maintain a consistent UI. Confirm that the inline rendering of user information alongside the join status message is uniform across the application.

packages/hydrooj/src/model/setting.ts (12)

3-3: Switching to @cordisjs/core for cordis imports
No issues noticed. This change aligns with the updated package references throughout the PR.


7-7: Add schemastery to your project dependencies
This is the same concern raised in a past review. Please confirm that you've included schemastery in either dependencies or devDependencies to avoid runtime errors.


74-81: Global declaration for Schemastery
Declaring Meta<T> within the Schemastery namespace is appropriate, and your optional fields look properly typed.


142-161: Same feedback as PreferenceSetting
Look into more robust collision resolution when combining _Setting and Schema expansions.


162-177: Same feedback as PreferenceSetting
Ensure collisions are handled gracefully, preventing perpetual warnings.


178-193: Same feedback as PreferenceSetting
Domain setting expansions would benefit from a more consistent collision strategy.


194-209: Same feedback as PreferenceSetting
Enhanced collision detection flows are recommended as you introduce schema-based settings.


279-279: New DomainUserSetting field
No functional issues spotted with this addition.


361-365: Augmenting the Context interface
Adding setting to Context neatly integrates the SettingService into the existing framework.


390-390: Dependency injection
Introducing 'db' in inject cleanly hooks up the required database resource for the service.


398-401: Consider fallback or error handling for database interaction
If ctx.db is ever undefined or unavailable, this could raise exceptions. It's good practice to handle potential failures or provide a fallback path.

Would you like me to generate a script to verify ctx.db initialization throughout the lifecycle?


422-423: Exporting inject
Exposing inject in the global Hydro.model.setting object ensures consistency with the injection pattern used in other services.

packages/hydrooj/src/handler/home.ts (8)

184-184: Good extraction of context dependencies.

Extracting the geoip service from context makes the code more maintainable and follows the dependency injection pattern.


192-195: Improved code readability and maintainability.

Using the extracted geoip variable makes the code cleaner and more readable.


205-205: Consistent usage of the extracted dependency.

Good consistency in using the extracted geoip variable throughout the handler.


472-474: Good type definitions for variables.

The new code provides explicit typing with DomainDoc[] for ddocs and Record<string, string> for role, which improves type safety.


475-476: Consider centralizing domain user retrieval logic.

The method domain.getDictUserByDomainId is now using join: true filtering in its implementation, which is why it's used here in the if block. This is a good refactoring, but make sure this change is consistent with all usages of this method.


477-481: Clear variable naming and usage.

Renaming from res to ddocs makes the code more self-documenting about what the variable contains.


483-488: Logical simplification of role assignment.

The code now directly assigns 'root' role for users with PRIV_MANAGE_ALL_DOMAIN privilege, which is cleaner than the previous implementation.


497-497: Simplified response body structure.

The response now directly includes the role mapping rather than including the entire dudict, which is more efficient and cleaner.

packages/hydrooj/src/model/domain.ts (7)

137-137: Good use of conditional spread operator.

Using the spread operator with a conditional is a clean way to optionally include the join property in the update object.


148-148: Improved updateMany operation.

The updateMany operation now applies the same update logic as the single document update, maintaining consistency.


131-132: Added join filtering to user counting.

The countUser method now correctly filters by users who have joined the domain, which is consistent with the overall changes in this PR.


209-209: Enhanced permission check for domain role.

The added condition ensures that users who haven't joined the domain are treated as guests unless they have the VIEW_ALL_DOMAIN privilege, which improves security.


255-255: Consistent join filtering for user queries.

The getDictUserByDomainId method now filters for users who have joined the domain, which is consistent with other changes in this PR.


62-62: Improved user role setting with autojoin.

Setting autojoin to true when adding a domain owner is a logical enhancement to ensure the owner is properly joined to their domain.


288-308: Well-structured context application function.

The new apply function follows a consistent pattern for service registration and initialization. It centralizes event handling and index creation in one place, which is a good practice.

packages/hydrooj/src/handler/domain.ts (9)

105-150: Improved MongoDB aggregation pipeline for user retrieval.

The refactoring to use MongoDB's aggregation pipeline is a significant improvement. It:

  1. More efficiently fetches user data in a single query instead of separate lookups
  2. Properly filters users based on both role and join status
  3. Projects only the necessary fields, reducing data transfer

This is a good optimization for performance and maintainability.


161-163: Simplified rudocs construction.

The code now creates the rudocs object more directly from the filtered users array, which is cleaner and more efficient.


261-261: Broader role inclusion for domain applications.

Changing the filter to only exclude 'guest' (instead of both 'default' and 'guest') makes more roles available for domain join applications, which is likely the intended behavior.


325-340: Enhanced domain join preparation with target parameter.

Adding the target parameter provides more flexibility in the domain join process, allowing users to join domains other than the current one. The role assignment logic is also improved to handle privileged users appropriately.

🧰 Tools
🪛 Biome (1.9.4)

[error] 338-338: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


343-345: Improved parameter handling with defaults.

Adding the target and redirect parameters with sensible defaults improves the flexibility of the API without breaking existing functionality.


347-354: Enhanced domain information for join page.

The code now provides more comprehensive domain information for the join page, improving the user experience.


367-371: Clearer error handling for invitation codes.

The conditional check for the join method and the subsequent validation of the invitation code is now more explicit and easier to follow.


373-376: Improved domain join with conditional role assignment.

Using the spread operator to conditionally include the role setting based on joinSettings is a clean pattern.


379-379: Enhanced redirect handling after joining domain.

The redirect parameter provides more flexibility in the UI flow after joining a domain, and the improved redirect URL includes a notification message for better user feedback.

Comment on lines +83 to +120
function schemaToSettings(schema: Schema<any>) {
const result: _Setting[] = [];
const processNode = (key: string, s: Schema<number> | Schema<string> | Schema<boolean>, defaultFamily = 'setting_basic') => {
if (s.dict) throw new Error('Dict is not supported here');
let flag = (s.meta?.hidden ? FLAG_HIDDEN : 0)
| (s.meta?.disabled ? FLAG_DISABLED : 0);
const type = s.type === 'number' ? 'number'
: s.type === 'boolean' ? 'checkbox'
: s.meta?.role === 'textarea' ? 'textarea' : 'text';
if (s.meta?.role === 'password') flag |= FLAG_SECRET;
const options = {};
for (const item of s.list || []) {
if (item.type !== 'const') throw new Error('List item must be a constant');
options[item.value] = item.meta?.description || item.value;
}
return {
family: s.meta?.family || defaultFamily,
key,
value: s.meta?.default,
name: key,
desc: s.meta?.description,
flag,
subType: '',
type: s.list ? 'select' : type,
range: s.list ? options : null,
} as _Setting;
};
if (!schema.dict) return [];
for (const key in schema.dict) {
const value = schema.dict[key];
if (value.dict) {
for (const subkey in value.dict) {
result.push(processNode(`${key}.${subkey}`, value.dict[subkey], value.meta?.family));
}
} else result.push(processNode(key, value));
}
return result;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Potential coverage gap for complex schemas
Currently, the function handles only a limited subset of data types (string, number, boolean) and single-level nesting. Any deeper or more complex schema structures may not be fully processed.

Would you like help refining the function to recursively handle nested objects and arrays, ensuring complete schema coverage?

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (2)
packages/hydrooj/src/service/server.ts (2)

74-76: ⚠️ Potential issue

Fix the unsafe interface-class merge issue.

The interface Handler and class Handler share the same name, potentially causing issues with uninitialized interface fields. This is a TypeScript anti-pattern flagged by linters.

Apply this change to address the unsafe interface-class merge:

-export class Handler extends HandlerOriginal<Context> {
-    domain: DomainDoc;
-}
+interface IHandler {
+    domain: DomainDoc;
+}
+export class Handler extends HandlerOriginal<Context> implements IHandler {
+    domain: DomainDoc;
+}

77-79: ⚠️ Potential issue

Fix the unsafe interface-class merge for ConnectionHandler.

Same issue as with the Handler class - the interface and class share the same name, leading to potential type checking issues.

Apply this fix:

-export class ConnectionHandler extends ConnectionHandlerOriginal<Context> {
-    domain: DomainDoc;
-}
+interface IConnectionHandler {
+    domain: DomainDoc;
+}
+export class ConnectionHandler extends ConnectionHandlerOriginal<Context> implements IConnectionHandler {
+    domain: DomainDoc;
+}
🧹 Nitpick comments (9)
packages/hydrooj/src/handler/home.ts (1)

471-471: Fix the empty object pattern

The empty object pattern {} is unnecessary when no parameters are being destructured. This also triggered a lint error.

-  async get({ }, all: boolean) {
+  async get(_: unknown, all: boolean) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 471-471: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

packages/hydrooj/src/model/setting.ts (1)

291-291: Consider migrating more settings to the Schema-based approach

The comment on line 320 indicates that the old settings format is being maintained temporarily. For consistency, consider planning the migration of the remaining settings (lines 321-356) to use the Schema-based approach once the new setting UI is ready.

Also applies to: 320-320

packages/hydrooj/src/service/server.ts (2)

109-109: Consider clarifying the reverse order of addons processing.

The code now uses spread with reverse on the addon values. If there's a specific reason for processing addons in reverse order, consider adding a comment explaining this design decision.


200-232: Comprehensive HTTP error handling implementation.

The HTTP handler mixin provides a thorough error handling mechanism with different paths for various error types and user states. This is a good addition that centralizes error handling logic.

Consider adding some additional comments within this complex function to explain the different handling paths, particularly for the redirect logic.

packages/hydrooj/src/upgrade.ts (2)

711-711: Consider batch processing for large collections.

The update operation on potentially large collections might benefit from batch processing to avoid timeouts and reduce memory usage.

// Start Hydro v5
async function _91_92() {
    try {
        await domain.collUser.updateMany({}, { $set: { join: true } });
+       
+       // Process large collections in batches
+       const batchSize = 1000;
+       let processed = 0;
+       
+       while (true) {
+           const result = await domain.coll.updateMany(
+               { 
+                   $or: [{ _join: { $exists: false } }, { _join: { $eq: null } }],
+                   _id: { $gt: lastId }
+               },
+               { $set: { _join: { method: domain.JOIN_METHOD_ALL, role: 'default', expire: null }, _migratedJoin: true } },
+               { limit: batchSize }
+           );
+           
+           if (result.modifiedCount === 0) break;
+           processed += result.modifiedCount;
+           logger.info(`Processed ${processed} documents`);
+       }
-       await domain.coll.updateMany(
-           { $or: [{ _join: { $exists: false } }, { _join: { $eq: null } }] },
-           { $set: { _join: { method: domain.JOIN_METHOD_ALL, role: 'default', expire: null }, _migratedJoin: true } },
-       );
        
        // Rest of the function...
    } catch (error) {
        logger.error(`Migration to Hydro v5 failed: ${error.message}`);
        throw error;
    }
}

713-715: Add logging for migration progress.

Adding logging statements would help track the progress of the migration and aid in troubleshooting if issues occur.

    try {
        await domain.collUser.updateMany({}, { $set: { join: true } });
+       logger.info('Updated all users in collUser with join:true');
        
        await domain.coll.updateMany(
            { $or: [{ _join: { $exists: false } }, { _join: { $eq: null } }] },
            { $set: { _join: { method: domain.JOIN_METHOD_ALL, role: 'default', expire: null }, _migratedJoin: true } },
        );
+       logger.info('Updated domain collection documents with _join field');
        
        const domainUser = await domain.coll.find({ domainId: 'system', join: true }, onPrimary)
            .project({ uid: 1 }).toArray();
+       logger.info(`Found ${domainUser.length} users in system domain with join:true`);
packages/hydrooj/src/model/domain.ts (1)

135-149: Use Array.isArray() for robust checks.
Change:

- if (!(uid instanceof Array)) {
+ if (!Array.isArray(uid)) {

to avoid false negatives for arrays from different contexts.

🧰 Tools
🪛 Biome (1.9.4)

[error] 138-138: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

packages/hydrooj/src/handler/domain.ts (2)

153-160: Consider avoiding the delete operator for performance.
You can set u.user = undefined; instead of using delete u.user;. For example:

- delete u.user;
+ u.user = undefined;
🧰 Tools
🪛 Biome (1.9.4)

[error] 158-158: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


326-340: Domain join preparation logic.
Handles domain retrieval, role assignment, and membership checks. However, consider the same caution about the delete operator:

- delete this.joinSettings;
+ this.joinSettings = undefined;
🧰 Tools
🪛 Biome (1.9.4)

[error] 338-338: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 706a9a0 and e9c5bf5.

📒 Files selected for processing (14)
  • packages/hydrooj/src/handler/domain.ts (3 hunks)
  • packages/hydrooj/src/handler/home.ts (3 hunks)
  • packages/hydrooj/src/model/domain.ts (8 hunks)
  • packages/hydrooj/src/model/setting.ts (11 hunks)
  • packages/hydrooj/src/model/user.ts (4 hunks)
  • packages/hydrooj/src/service/server.ts (8 hunks)
  • packages/hydrooj/src/upgrade.ts (4 hunks)
  • packages/ui-default/locales/zh.yaml (5 hunks)
  • packages/ui-default/templates/domain_join.html (2 hunks)
  • packages/ui-default/templates/domain_join_applications.html (0 hunks)
  • packages/ui-default/templates/domain_permission.html (0 hunks)
  • packages/ui-default/templates/domain_user.html (2 hunks)
  • packages/ui-default/templates/home_domain.html (1 hunks)
  • packages/ui-default/templates/partials/problem_sidebar_normal.html (2 hunks)
💤 Files with no reviewable changes (2)
  • packages/ui-default/templates/domain_join_applications.html
  • packages/ui-default/templates/domain_permission.html
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/hydrooj/src/model/user.ts
🧰 Additional context used
🧬 Code Definitions (3)
packages/hydrooj/src/service/server.ts (1)
framework/framework/server.ts (5) (5)
  • HandlerCommon (129-129)
  • HandlerCommon (130-199)
  • Handler (201-247)
  • ConnectionHandler (249-286)
  • WebService (328-828)
packages/hydrooj/src/model/domain.ts (3)
packages/hydrooj/src/service/bus.ts (1) (1)
  • apply (97-114)
packages/hydrooj/src/service/db.ts (1) (1)
  • apply (180-183)
packages/hydrooj/src/plugin-api.ts (2) (2)
  • Context (41-41)
  • db (58-58)
packages/hydrooj/src/model/setting.ts (5)
packages/hydrooj/src/interface.ts (1) (1)
  • Setting (46-56)
packages/hydrooj/src/service/worker.ts (1) (1)
  • apply (89-92)
packages/hydrooj/src/service/check.ts (1) (1)
  • apply (77-80)
packages/hydrooj/src/service/db.ts (1) (1)
  • apply (180-183)
packages/hydrooj/src/context.ts (2) (2)
  • Context (31-41)
  • Context (68-77)
🪛 Biome (1.9.4)
packages/hydrooj/src/handler/home.ts

[error] 471-471: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

packages/hydrooj/src/model/domain.ts

[error] 138-138: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

packages/hydrooj/src/handler/domain.ts

[error] 158-158: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 338-338: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

🔇 Additional comments (49)
packages/hydrooj/src/handler/home.ts (7)

184-184: Good improvement: Better context handling with dependency injection

The code now explicitly extracts the geoip context from this.ctx.get('geoip') instead of accessing it directly as a property. This aligns with dependency injection patterns and makes the code more maintainable.


192-195: Good refactoring: Using local variable improves readability

Using the local geoip variable instead of repeatedly accessing this.ctx.geoip improves code readability and follows the DRY principle.


205-205: Consistent usage of the extracted geoip variable

This change maintains consistency with the earlier changes, utilizing the local geoip variable.


472-474: Good refactoring: Better type definition and role management

Explicitly typing ddocs as DomainDoc[] and introducing a role object to manage user roles improves type safety and makes the code's intent clearer.


475-481: Improved code structure and readability

The refactored code maintains the same logic but with clearer variable names and data flow. Using ddocs consistently throughout the method improves readability.


483-495: Better role management with explicit role assignment

The code now explicitly assigns roles for each domain, making it easier to understand permission handling. The refactoring from dudict to a dedicated role object improves clarity and maintainability.


497-497: Updated response with explicit role information

The response structure has been improved by including the explicit role object instead of the less descriptive dudict.

packages/hydrooj/src/model/setting.ts (9)

3-3: Update library import for consistency

The import statement has been updated from 'cordis' to '@cordisjs/core', which aligns with the new module declaration on line 361. This change is part of the broader framework update.


7-7: Action Required: Add "schemastery" to project dependencies

The import of Schema from schemastery is appropriate given its usage in the file. However, verification shows that schemastery is not currently listed under either dependencies or devDependencies in your package.json.


74-81: Well-structured type extension for Schema metadata

The global declaration extends the Schemastery namespace with metadata options that enable setting-specific properties like 'family' and 'secret', allowing for better integration with the existing settings system.


83-120: Robust Schema to Settings conversion implementation

The schemaToSettings function effectively bridges the gap between schema-based configuration and the existing settings system. It correctly handles:

  1. Type mapping between Schema types and setting types
  2. Metadata extraction for descriptions and flags
  3. Nested dictionaries with proper key path creation
  4. Error handling for unsupported structures

The error handling for unsupported schema types (line 86 and 95) is particularly well-implemented.


122-123: Clean implementation of Schema support in setting registration functions

The modification to accept both traditional _Setting[] and new Schema<any>[] provides backward compatibility while enabling the new schema-based approach. The flatMap implementation efficiently handles the conversion.

Also applies to: 142-143, 162-163, 178-179, 194-195


291-319: Excellent Schema-based settings definition showcase

This implementation demonstrates a more structured, type-safe way to define settings with:

  1. Hierarchical organization (smtp, server)
  2. Strongly typed properties with validation rules
  3. Default values and descriptions
  4. Specialized input types via the 'role' property

This approach is more maintainable and less error-prone than the traditional approach used elsewhere in the file.


398-398: Improved context-based DB access

Replacing global.Hydro.service.db with ctx.db is a good change that:

  1. Makes database access more predictable through dependency injection
  2. Improves testability by removing global state dependency
  3. Aligns with modern service architecture patterns

This change is consistent with the dependency injection pattern established by the inject array on line 390.


390-390: Properly declared service dependencies

Adding the inject = ['db'] export ensures that the DB service is available before this service initializes, which is necessary for the updated apply function to work correctly.


361-365: Updated module declaration to match new import

The module declaration has been correctly updated to reference '@cordisjs/core' instead of 'cordis', maintaining type consistency with the updated import on line 3.

packages/hydrooj/src/service/server.ts (9)

7-9: Improved importing strategy with explicit names.

The changes to import statements provide more clarity by explicitly importing the original handler classes and the new WebService component. This approach improves readability and makes dependencies more explicit.


31-31: Good addition of generic type parameter.

Adding the generic type parameter <C> to the HandlerCommon interface improves type safety by allowing the interface to work with different context types. This change aligns with modern TypeScript best practices.


82-82: Good use of WebService import instead of require.

Using the imported WebService directly instead of requiring the entire framework is a cleaner approach that follows better module practices and improves maintainability.


149-149: Good explicit conversion to string.

Explicitly calling toString() on the URL result ensures type consistency and prevents potential issues with non-string values.


163-164: Improved translation logic.

The changes to the translation logic provide better handling of language preferences, first checking the user's view language before falling back to accepted languages from the request.


233-248: Well-structured WebSocket error handling.

The WebSocket handler mixin properly handles errors by logging them, sending error information to the client, and cleanly closing the connection. This implementation follows good practices for WebSocket error management.


255-256: Improved context extension approach.

Using extend() to create a new context with the domain is a cleaner approach than direct assignment, promoting immutability and preventing unintended side effects.


257-267: Good addition of HTTP handler creation event.

The HTTP handler creation event includes important checks such as rate limiting and permission verification. The addition of checking for pending errors is a valuable safeguard.


268-270: Proper error checking for WebSocket handlers.

Adding error checking during WebSocket handler creation ensures errors are caught early in the connection lifecycle, improving reliability.

packages/hydrooj/src/upgrade.ts (2)

39-40: Good addition of read preference setting.

Adding the onPrimary constant with a primary read preference ensures that critical database operations will always read from the primary node, avoiding potential stale data issues in replica set configurations.


56-56: Proper linting override for array initialization.

The added comment correctly disables the oxlint rule for this specific line, maintaining code quality while addressing a necessary pattern.

packages/ui-default/locales/zh.yaml (3)

492-493: Translations look consistent.
The newly added strings for creating and submitting after joining a domain are clear.


608-608: Good phrasing for indicating a user has not yet joined.
The translation “暂未加入” accurately conveys the status.


910-910: Proper addition of '域所有者' label.
The newly introduced entry for “The domain owner” helps clarity.

packages/hydrooj/src/model/domain.ts (5)

4-6: Imports look good.
Importing Context and bus is aligned with the new event-based structure.


63-63: Auto-join parameter usage.
Assigning the 'root' role with true for autojoin ensures proper domain owner setup.


131-133: Filter by join: true is correct.
Requiring join: true when counting users matches the updated logic of only considering domain members.


253-255: User domain dictionary retrieval looks good.
No issues with filtering on { uid, join: true }.


288-308: Consolidated event handling and index setup.
This new apply(ctx: Context) function properly manages cache deletion logic and ensures database indexes.

packages/hydrooj/src/handler/domain.ts (4)

105-151: Aggregation pipeline approach.
Using $match and $lookup to retrieve user details is a powerful, centralized solution. The logic to exclude non-joined users or default/guest roles looks coherent.


257-257: Excluding only 'guest' is consistent.
This ensures users with 'default' role remain visible.


345-361: Flexible GET method with redirect support.
This additional parameter set (code, target, redirect) increases the handler’s usefulness without apparent issues.


367-380: Secure domain join process.
Verifies invitation code when needed and updates membership. This logic is clear and straightforward.

packages/ui-default/templates/home_domain.html (1)

40-40: Refactoring Role Retrieval in Template
The new change directly accesses the role using role[ddoc._id]|default('default'), which is clearer and more concise than using an intermediary variable (e.g., dudict). Just ensure that the role variable is always defined and passed to the template context.

packages/ui-default/templates/domain_user.html (2)

85-87: Conditional Indication for Unjoined Users (First Occurrence)
The addition of a conditional block to display a “Not joined yet” message for users (using udoc.join) is clear and improves user feedback. Verify that the styling (e.g., the text-orange class) is consistent with the rest of the UI.


105-107: Conditional Indication for Unjoined Users (Second Occurrence)
Similarly, the change for rendering the inline user representation with an additional “Not joined yet” badge for rudoc cases is well implemented. This helps users quickly identify unjoined statuses.

packages/ui-default/templates/partials/problem_sidebar_normal.html (2)

20-22: Prompting Domain Join for Discussion Creation
The new conditional (using not handler.user._dudoc.join) to prompt the user to join the domain before creating a discussion is a smart UX touch. Ensure that the condition correctly reflects the user’s join status and that the joinDomain() function is well integrated.


52-55: Prompting Domain Join for Problem Submission
Likewise, adding a condition to display a “Join Domain to Submit” option for users lacking domain membership adds useful guidance. Confirm that the disabled styling and active state logic (using {% if page_name == 'problem_submit' %}) behave as intended across various scenarios.

packages/ui-default/templates/domain_join.html (5)

8-12: Dynamic Title Based on Join Settings
Using a conditional to change the title—displaying either “Join {0}” or “You are invited to join {0}” based on the presence of joinSettings—enhances clarity in the user prompt. This dynamic approach helps inform the user accurately about the context of their join action.


16-16: Clear Join Process Description
The updated paragraph now clearly explains that clicking the button will make the user a member of the domain. This explicit description improves usability by setting clear expectations.


18-21: Display of Domain Owner Information
Rendering the domain owner's details with a header adds valuable context, allowing users to quickly verify the domain’s legitimacy. Ensure the output from user.render_inline(domainInfo['owner']) is secure and formatted consistently.


22-26: Rendering Domain Bulletin (Markdown Conversion)
The conditional block for the bulletin now converts its content to markdown, which is useful for rich text formatting. Make sure that the markdown rendering is securely sanitized to mitigate any potential XSS risks if the bulletin content is user-generated.


40-41: Passing Additional Context with Hidden Inputs
Adding hidden inputs for target and redirect ensures that necessary navigation context is preserved during the join process. This approach is effective; just double-check that these values are properly validated on the server side.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/hydrooj/src/handler/domain.ts (2)

153-160: Consider optimizing the object transformation

The code transforms the aggregation results with a property deletion operation that could impact performance.

-const users = dudocs.map((dudoc) => {
-    const u = {
-        ...dudoc,
-        ...dudoc.user,
-    };
-    delete u.user;
-    return u;
-});
+const users = dudocs.map((dudoc) => {
+    const { user: userData, ...rest } = dudoc;
+    return { ...rest, ...userData };
+});

This approach uses object destructuring to create a new object without the user property, avoiding the delete operator that was flagged by static analysis.

🧰 Tools
🪛 Biome (1.9.4)

[error] 158-158: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


338-338: Performance consideration in conditional property deletion

The delete this.joinSettings operation may impact performance as flagged by static analysis.

-if (assignedRole !== 'default') delete this.joinSettings;
+if (assignedRole !== 'default') this.joinSettings = undefined;

Setting to undefined instead of using the delete operator is generally more performant while achieving the same result.

🧰 Tools
🪛 Biome (1.9.4)

[error] 338-338: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e9c5bf5 and 0bd15ca.

📒 Files selected for processing (2)
  • packages/hydrooj/src/handler/domain.ts (3 hunks)
  • packages/ui-default/pages/problem_submit.page.tsx (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
packages/hydrooj/src/handler/domain.ts

[error] 158-158: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 338-338: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

🔇 Additional comments (6)
packages/hydrooj/src/handler/domain.ts (6)

105-150: Complex aggregation pipeline improves user data retrieval

The refactoring of the user retrieval logic using MongoDB's aggregation pipeline is a significant improvement. This approach:

  1. Efficiently filters users based on membership criteria
  2. Uses $lookup to join with the user collection in a single database operation
  3. Projects only necessary fields, reducing data transfer
  4. Properly handles permissions for viewing display names

This implementation is more performant than separate queries and reduces round trips to the database.


261-261: Simplified role filtering logic

The role filtering has been simplified to exclude only the 'guest' role, making the code more maintainable and easier to understand.


344-361: Improved response body with detailed domain information

The get method now returns a more comprehensive response that includes domain details such as name, owner, avatar, and bulletin information. This provides a better user experience by presenting all relevant domain information in one response.


364-380: Enhanced post method with dynamic role assignment

The post method now handles user role assignment more dynamically based on join settings, making the domain join process more flexible. The addition of a redirect parameter also improves navigation flow after joining a domain.


373-376: Clean conditional role assignment

The conditional assignment of the role using the spread operator is a clean and elegant solution:

{
  join: true,
  ...(this.joinSettings ? { role: this.joinSettings.role } : {}),
}

This pattern effectively conditionally adds the role property only when joinSettings is available.


325-340:

✅ Verification successful

Enhanced domain join functionality with target parameter

The addition of the target parameter to the prepare method significantly improves flexibility in the domain join process. This change:

  1. Allows joining a different domain than the current one
  2. Properly checks membership status in the target domain
  3. Correctly handles role assignment based on privileges
  4. Improves error handling with specific error conditions

The implementation is solid and adds valuable functionality to the application.

Consider running this test to ensure all routes using this handler properly pass the target parameter:


🏁 Script executed:

#!/bin/bash
# Check if all routes that use DomainJoinHandler pass target parameter
rg -A 3 -B 3 "Route\(.*?DomainJoinHandler" --glob "*.ts"

Length of output: 827


Domain Join Enhancement Verified

The updated prepare method in the DomainJoinHandler now accepts a target parameter, which enhances domain flexibility by allowing a user to join a domain different from their current one. This update:

  • Enables joining an alternate domain by defaulting to the current domain when no target is provided.
  • Checks the membership status against the passed target domain.
  • Assigns roles based on user privileges, defaulting appropriately unless the user has the management privilege.
  • Improves error scenarios by throwing specific errors when the user is already a member or when joining is forbidden.

A quick search confirms that the DomainJoinHandler is used for the /domain/join endpoint, ensuring that the initialization now correctly supports incoming target parameters.

The implementation is solid and no further changes are required.

🧰 Tools
🪛 Biome (1.9.4)

[error] 338-338: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (10)
packages/elastic/index.ts (3)

111-116: 🛠️ Refactor suggestion

Add error handling to the problem/del event handler.

The event handler doesn't include error handling, which could lead to unhandled promise rejections. Consider adding a try-catch block.

        this.ctx.on('problem/del', async (domainId, docId) => {
+           try {
                await this.client.delete({
                    index: 'problem',
                    id: `${domainId}/${docId}`,
                });
+           } catch (error) {
+               this.ctx.logger.error(`Error deleting problem from index: ${error.message}`);
+           }
        });

104-110: 🛠️ Refactor suggestion

Add error handling to the problem/edit event handler.

The event handler doesn't include error handling, which could lead to unhandled promise rejections. Consider adding a try-catch block.

        this.ctx.on('problem/edit', async (pdoc) => {
+           try {
                await this.client.index({
                    index: 'problem',
                    id: `${pdoc.domainId}/${pdoc.docId}`,
                    document: processDocument(pdoc),
                });
+           } catch (error) {
+               this.ctx.logger.error(`Error updating problem index: ${error.message}`);
+           }
        });

97-103: 🛠️ Refactor suggestion

Add error handling to the problem/add event handler.

The event handler doesn't include error handling, which could lead to unhandled promise rejections. Consider adding a try-catch block.

        this.ctx.on('problem/add', async (doc, docId) => {
+           try {
                await this.client.index({
                    index: 'problem',
                    id: `${doc.domainId}/${docId}`,
                    document: processDocument(doc),
                });
+           } catch (error) {
+               this.ctx.logger.error(`Error indexing problem: ${error.message}`);
+           }
        });
packages/ui-default/backendlib/template.ts (3)

121-121: ⚠️ Potential issue

Avoid using eval if possible.

eval() exposes your application to security risks and performance issues.

Consider refactoring to use safer alternatives such as:

  • Function constructors if you need dynamic code execution
  • JSON.parse for data parsing
  • Template literals for string interpolation
🧰 Tools
🪛 Biome (1.9.4)

[error] 121-121: eval() exposes to security risks and performance issues.

See the MDN web docs for more details.
Refactor the code so that it doesn't need to call eval().

(lint/security/noGlobalEval)


122-128: ⚠️ Potential issue

Security Concern: Limit Global Exposure in Template Engine

Exposing complete global objects (Date, Object, String, process, global) to templates creates significant security risks like prototype pollution, remote code execution, and information disclosure.

Replace with limited, controlled interfaces:

-    this.addGlobal('Date', Date);
-    this.addGlobal('Object', Object);
-    this.addGlobal('String', String);
-    this.addGlobal('Array', Array);
-    this.addGlobal('Math', Math);
-    this.addGlobal('process', process);
-    this.addGlobal('global', global);
+    // Provide limited date functionality
+    this.addGlobal('Date', {
+      now: Date.now,
+      parse: Date.parse,
+      format: (date) => new Date(date).toLocaleString(),
+    });
+    // Provide safer Math operations
+    this.addGlobal('Math', {
+      abs: Math.abs,
+      ceil: Math.ceil,
+      floor: Math.floor,
+      max: Math.max,
+      min: Math.min,
+      round: Math.round,
+    });
+    // Safe string utilities
+    this.addGlobal('stringUtils', {
+      trim: (s) => String(s).trim(),
+      toLowerCase: (s) => String(s).toLowerCase(),
+      toUpperCase: (s) => String(s).toUpperCase(),
+    });

221-242: 🛠️ Refactor suggestion

Add timeout handling to prevent long-running renders

While there's logging for slow renders (>5000ms), there's no timeout mechanism to prevent extremely long-running renders from blocking the server.

Add a timeout mechanism:

   const render = (name: string, state: any) => new Promise<string>((resolve, reject) => {
     const start = Date.now();
+    const renderTimeout = setTimeout(() => {
+      reject(new Error(`Render timeout for template ${name}`));
+    }, 10000); // 10 seconds timeout
+    
     env.render(name, {
       page_name: name.split('.')[0],
       ...state,
       formatJudgeTexts: (texts) => texts.map((text) => {
         if (typeof text === 'string') return text;
         return state._(text.message).format(...text.params || []) + ((process.env.DEV && text.stack) ? `\n${text.stack}` : '');
       }).join('\n'),
       datetimeSpan: (arg0, arg1, arg2) => misc.datetimeSpan(arg0, arg1, arg2, state.handler.user?.timeZone),
       ctx: state.handler?.ctx,
       perm: PERM,
       PRIV,
       STATUS,
       UiContext: state.handler?.UiContext || {},
     }, (err, res) => {
+      clearTimeout(renderTimeout);
       const end = Date.now();
       if (end - start > 5000) console.error(`Render of ${name} took ${end - start}ms`);
       if (err) reject(err);
       else resolve(res || '');
     });
   });
packages/ui-default/index.ts (1)

56-56: ⚠️ Potential issue

Remove the empty object pattern.

Static analysis flags { } as an unexpected empty pattern. Consider removing it as it doesn't serve any purpose.

-  async get({ }, legacy = false, nohint = false) {
+  async get(legacy = false, nohint = false) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 56-56: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

packages/hydrooj/src/settings.ts (1)

159-169: ⚠️ Potential issue

Silent failure in Proxy setter could hide errors.

The set trap doesn't await the asynchronous setConfig operation, potentially hiding database write failures.

set(self, p: string | symbol, newValue: any) {
-   that.setConfig(path.concat(p).join(','), newValue);
-   return true;
+   // Since this is a Proxy trap, we can't make it async directly
+   // but we can capture and log errors
+   that.setConfig(path.concat(p).join(','), newValue)
+     .catch(err => {
+       logger.error('Failed to set config property:', path.concat(p).join(','), err.message);
+     });
+   return true;
},

A better long-term solution would be to redesign the proxy pattern to properly handle asynchronous operations.

build/prepare.js (1)

163-167: ⚠️ Potential issue

Potential file system race condition
tryUpdate logic may fail if the file is altered between existence check and write. Consider a try-catch for robust error handling.

-    const current = fs.existsSync(location) ? fs.readFileSync(location, 'utf-8') : '';
-    const expected = ...
-    if (expected !== current) fs.writeFileSync(location, expected);
+    try {
+        const current = fs.readFileSync(location, 'utf-8');
+        const expected = ...
+        ...
+    } catch (err) {
+        ...
+    }
🧰 Tools
🪛 GitHub Check: CodeQL

[failure] 166-166: Potential file system race condition
The file may have changed since it was checked.

framework/framework/server.ts (1)

139-141: 🛠️ Refactor suggestion

Avoid empty interface merging
Defining HandlerCommon<C> as both interface and class can lead to unsafe declaration merging.

-export interface HandlerCommon<C> { } // ...
-export class HandlerCommon<C> {
+// Remove empty interface or convert it to a type alias
+export class HandlerCommon<C> {
🧰 Tools
🪛 Biome (1.9.4)

[error] 139-139: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 140-140: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)

🧹 Nitpick comments (20)
.github/workflows/build.yml (1)

62-69: Clarify Parallel Task Invocation in “Build And Lint” Step
The updated command on line 66 now runs:

parallel --tty -j+0 yarn ::: lint:ci build build:ui:production:webpack test

This change omits the previously used lint:ui:ci task and instead runs lint:ci, build, build:ui:production:webpack, and test in parallel when UI-related files have changed or when the UI package version differs. Please verify that this removal of lint:ui:ci is intentional and that its functionality is now correctly addressed (either merged into lint:ci or handled elsewhere). Additionally, ensure that the new command order aligns with your CI expectations and that no required lint checks on UI code are inadvertently skipped.

packages/hydrooj/src/handler/misc.ts (2)

110-110: Consider using a more standard parameter pattern instead of an empty object

The empty object pattern { } is flagged by static analysis as unconventional. While it works, it reduces readability and may confuse developers.

Instead of an empty object, consider using one of these alternatives:

- async get({ }, target: string, filename = '', expire: number, secret: string) {
+ async get(_: unknown, target: string, filename = '', expire: number, secret: string) {

Or if the first parameter is intentionally being removed:

- async get({ }, target: string, filename = '', expire: number, secret: string) {
+ async get(target: string, filename = '', expire: number, secret: string) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 110-110: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)


124-124: Consider using a more standard parameter pattern instead of an empty object

Similar to line 110, the empty object pattern { } is flagged by static analysis as unconventional. It reduces readability and may confuse other developers.

Instead of an empty object, consider:

- async get({ }, uid: number) {
+ async get(_: unknown, uid: number) {

Or if the first parameter is intentionally being removed:

- async get({ }, uid: number) {
+ async get(uid: number) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 124-124: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

packages/hydrooj/src/model/setting.ts (1)

290-318: Excellent schema-based approach for system settings

This implementation showcases the power of the new Schema-based approach, providing strong typing, validation, and metadata for system settings. The organization by functional groups (smtp, server) makes the code more maintainable and self-documenting.

Consider adding validation for email format to the smtp.from and smtp.user fields using regex patterns to ensure valid email addresses are provided.

eslint.config.mjs (2)

1-2: Consider limiting or scoping these disabled rules.
Disabling max-len and @typescript-eslint/naming-convention globally may hide potential readability and naming issues across the entire codebase. If these rules are only problematic in certain directories or files, consider disabling them more selectively.


107-109: Address the FIXME comment.
The 'template-curly-spacing' rule is commented out due to a known parser bug. Let me know if you’d like further help in resolving or tracking this in a new issue.

packages/elastic/index.ts (1)

29-29: Remove console.log statement.

The console.log statement should be removed or replaced with proper logging using the context's logger.

-        console.log('elastic-search', config);
+        this.ctx.logger.info('Initializing elastic-search service', { url: config.url });
packages/utils/lib/utils.ts (2)

15-28: Consider additional configuration options for logging.

While this factory-based setup is flexible, you might want to parameterize options like showDiff, timestamp, and levels to better adapt to different environments (test, production, etc.).


33-34: Check the cast approach when exporting Logger.

Casting createLogger to Logger via as any as Logger might limit type safety. Consider a more direct factory pattern or a safer type assertion if possible.

packages/hydrooj/src/service/db.ts (1)

35-41: Extending the Service class for MongoService.

This constructor approach neatly initializes service properties. Ensure that any error handling (e.g., invalid config) is also addressed in case the MongoService fails to initialize.

packages/hydrooj/src/loader.ts (1)

49-49: Consider replacing empty object type with a more specific type

Don't use {} as a type. It means "any non-nullable value" and could lead to unexpected behavior. Consider defining a more specific type for the config property.

- public config: {};
+ public config: Record<string, unknown>;
🧰 Tools
🪛 Biome (1.9.4)

[error] 49-49: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

packages/hydrooj/src/model/record.ts (2)

213-216: Consider removing return await.
Returning a Promise directly vs. using await here generally performs the same. Removing await could reduce minor overhead.


235-264: Risk of partial operations in reset.
Multiple asynchronous calls in a single Promise.all may lead to inconsistent state if an operation fails midway. Consolidating or using transactions could help prevent partial updates/inserts/deletions.

packages/ui-default/backendlib/template.ts (1)

46-46: Use optional chaining to simplify null check

The code can be simplified using optional chaining.

-  if ((obj || {})._original) obj = obj._original;
+  if (obj?._original) obj = obj._original;
🧰 Tools
🪛 Biome (1.9.4)

[error] 46-46: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

packages/hydrooj/src/handler/domain.ts (1)

104-160: Enhanced user query with MongoDB aggregation pipeline.

The implementation has been completely refactored to use MongoDB's aggregation framework, which provides significant improvements.

Benefits of this change:

  1. Reduces database round-trips by joining user data in a single query
  2. Uses projection to only retrieve needed fields for better performance
  3. Properly filters users based on role and domain membership
  4. Adds proper structure to the returned data with nested user information

The code could be further improved by extracting the aggregation pipeline to a reusable function:

async get({ domainId }, format = 'default') {
+   const getUserAggregation = (domainId) => [
+       {
+           $match: {
+               role: {
+                   $nin: ['default', 'guest'],
+                   $ne: null,
+               },
+               domainId,
+           },
+       },
+       // ... rest of the pipeline
+   ];

    const [dudocs, roles] = await Promise.all([
-       domain.collUser.aggregate([/* ... */]).toArray(),
+       domain.collUser.aggregate(getUserAggregation(domainId)).toArray(),
        domain.getRoles(domainId),
    ]);
    // ...
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 155-155: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

framework/framework/server.ts (5)

484-492: Refactor handleHttp
Utilizing forkContextWithScope(savedContext) ensures a sub-scope for each request.
Likewise, parallel event calls 'handler/create' & 'handler/create/http' are typed as any. Consider stronger type-safety if possible.


536-537: Ignore TS for steps
The // @ts-ignore approach for handler/ calls may hide type issues. Evaluate a typed approach if possible.


684-708: Checker function
Dynamically collects perm or priv from arguments. The approach is flexible but might be hard to maintain.

Consider using a more structured method of providing permission/priv options.


744-748: Debug code
Commented-out debug lines. If not needed, consider removing.


787-810: Mixin system
Applying mixins dynamically with disposal is advanced. This design might further benefit from strong type constraints.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0bd15ca and f8ed636.

📒 Files selected for processing (94)
  • .eslintrc.yaml (0 hunks)
  • .github/workflows/build.yml (1 hunks)
  • build/prepare.js (5 hunks)
  • eslint.config.mjs (1 hunks)
  • framework/eslint-config/base.mjs (1 hunks)
  • framework/eslint-config/base.yaml (0 hunks)
  • framework/eslint-config/package.json (1 hunks)
  • framework/eslint-config/react.yaml (0 hunks)
  • framework/eslint-config/typescript.js (0 hunks)
  • framework/framework/error.ts (0 hunks)
  • framework/framework/server.ts (22 hunks)
  • package.json (2 hunks)
  • packages/elastic/index.ts (2 hunks)
  • packages/hydrojudge/src/cases.ts (0 hunks)
  • packages/hydrojudge/src/checkers.ts (4 hunks)
  • packages/hydrojudge/src/daemon.ts (0 hunks)
  • packages/hydrojudge/src/hosts/hydro.ts (0 hunks)
  • packages/hydrojudge/src/hosts/vj4.ts (1 hunks)
  • packages/hydrojudge/src/judge/hack.ts (4 hunks)
  • packages/hydrooj/package.json (3 hunks)
  • packages/hydrooj/src/commands/install.ts (1 hunks)
  • packages/hydrooj/src/entry/cli.ts (2 hunks)
  • packages/hydrooj/src/entry/common.ts (2 hunks)
  • packages/hydrooj/src/entry/setup.ts (0 hunks)
  • packages/hydrooj/src/entry/worker.ts (3 hunks)
  • packages/hydrooj/src/handler/contest.ts (0 hunks)
  • packages/hydrooj/src/handler/domain.ts (3 hunks)
  • packages/hydrooj/src/handler/misc.ts (3 hunks)
  • packages/hydrooj/src/handler/problem.ts (1 hunks)
  • packages/hydrooj/src/interface.ts (6 hunks)
  • packages/hydrooj/src/loader.ts (6 hunks)
  • packages/hydrooj/src/model/blacklist.ts (1 hunks)
  • packages/hydrooj/src/model/contest.ts (7 hunks)
  • packages/hydrooj/src/model/document.ts (11 hunks)
  • packages/hydrooj/src/model/domain.ts (9 hunks)
  • packages/hydrooj/src/model/message.ts (3 hunks)
  • packages/hydrooj/src/model/oauth.ts (1 hunks)
  • packages/hydrooj/src/model/opcount.ts (1 hunks)
  • packages/hydrooj/src/model/problem.ts (1 hunks)
  • packages/hydrooj/src/model/record.ts (8 hunks)
  • packages/hydrooj/src/model/schedule.ts (2 hunks)
  • packages/hydrooj/src/model/setting.ts (11 hunks)
  • packages/hydrooj/src/model/storage.ts (6 hunks)
  • packages/hydrooj/src/model/system.ts (3 hunks)
  • packages/hydrooj/src/model/task.ts (3 hunks)
  • packages/hydrooj/src/model/token.ts (2 hunks)
  • packages/hydrooj/src/model/user.ts (8 hunks)
  • packages/hydrooj/src/plugin-api.ts (2 hunks)
  • packages/hydrooj/src/script/problemStat.ts (0 hunks)
  • packages/hydrooj/src/script/storageUsage.ts (0 hunks)
  • packages/hydrooj/src/service/bus.ts (5 hunks)
  • packages/hydrooj/src/service/db.ts (3 hunks)
  • packages/hydrooj/src/service/worker.ts (2 hunks)
  • packages/hydrooj/src/settings.ts (1 hunks)
  • packages/hydrooj/src/ui.ts (1 hunks)
  • packages/migrate/package.json (1 hunks)
  • packages/onlyoffice/frontend/office.page.ts (0 hunks)
  • packages/onsite-toolkit/frontend/resolver.page.tsx (2 hunks)
  • packages/ui-default/.eslintignore (0 hunks)
  • packages/ui-default/.eslintrc.js (0 hunks)
  • packages/ui-default/api.ts (0 hunks)
  • packages/ui-default/backendlib/builder.ts (4 hunks)
  • packages/ui-default/backendlib/markdown-it-imsize.ts (1 hunks)
  • packages/ui-default/backendlib/markdown-it-media.ts (0 hunks)
  • packages/ui-default/backendlib/misc.ts (1 hunks)
  • packages/ui-default/backendlib/template.ts (3 hunks)
  • packages/ui-default/build/config/webpack.ts (1 hunks)
  • packages/ui-default/build/main.ts (1 hunks)
  • packages/ui-default/components/autocomplete/components/AutoComplete.tsx (3 hunks)
  • packages/ui-default/components/autocomplete/components/UserSelectAutoComplete.tsx (1 hunks)
  • packages/ui-default/components/calendar/index.js (2 hunks)
  • packages/ui-default/components/message/worker.ts (1 hunks)
  • packages/ui-default/components/problemconfig/ProblemConfigEditor.tsx (1 hunks)
  • packages/ui-default/components/problemconfig/ProblemConfigTree.tsx (1 hunks)
  • packages/ui-default/components/problemconfig/reducer/config.ts (1 hunks)
  • packages/ui-default/components/problemconfig/tree/AddTestcase.tsx (1 hunks)
  • packages/ui-default/components/problemconfig/tree/SubtaskSettings.tsx (1 hunks)
  • packages/ui-default/components/problemconfig/tree/Testcase.tsx (1 hunks)
  • packages/ui-default/components/scratchpad/DataInputComponent.jsx (0 hunks)
  • packages/ui-default/components/scratchpad/ScratchpadToolbarContainer.jsx (0 hunks)
  • packages/ui-default/index.ts (6 hunks)
  • packages/ui-default/package.json (5 hunks)
  • packages/ui-next/package.json (1 hunks)
  • packages/ui-next/src/App.tsx (1 hunks)
  • packages/utils/lib/locate-pm2.ts (1 hunks)
  • packages/utils/lib/utils.ts (1 hunks)
  • packages/utils/package.json (2 hunks)
  • packages/vjudge/src/index.ts (3 hunks)
  • packages/vjudge/src/providers/codeforces.ts (0 hunks)
  • packages/vjudge/src/providers/hduoj.ts (0 hunks)
  • packages/vjudge/src/providers/poj.ts (0 hunks)
  • packages/vjudge/src/providers/spoj.ts (0 hunks)
  • packages/vjudge/src/providers/uoj.ts (0 hunks)
  • packages/vjudge/src/providers/yacs.ts (0 hunks)
💤 Files with no reviewable changes (25)
  • packages/ui-default/.eslintignore
  • packages/ui-default/components/scratchpad/ScratchpadToolbarContainer.jsx
  • packages/hydrooj/src/script/storageUsage.ts
  • packages/ui-default/backendlib/markdown-it-media.ts
  • packages/hydrooj/src/entry/setup.ts
  • packages/hydrojudge/src/cases.ts
  • packages/vjudge/src/providers/hduoj.ts
  • packages/vjudge/src/providers/spoj.ts
  • packages/hydrojudge/src/daemon.ts
  • packages/hydrooj/src/script/problemStat.ts
  • packages/hydrojudge/src/hosts/hydro.ts
  • packages/onlyoffice/frontend/office.page.ts
  • packages/vjudge/src/providers/poj.ts
  • framework/framework/error.ts
  • framework/eslint-config/react.yaml
  • packages/vjudge/src/providers/yacs.ts
  • packages/vjudge/src/providers/codeforces.ts
  • packages/vjudge/src/providers/uoj.ts
  • packages/ui-default/api.ts
  • packages/ui-default/components/scratchpad/DataInputComponent.jsx
  • packages/ui-default/.eslintrc.js
  • .eslintrc.yaml
  • packages/hydrooj/src/handler/contest.ts
  • framework/eslint-config/base.yaml
  • framework/eslint-config/typescript.js
✅ Files skipped from review due to trivial changes (14)
  • packages/ui-default/components/problemconfig/tree/Testcase.tsx
  • packages/ui-default/components/problemconfig/reducer/config.ts
  • packages/utils/lib/locate-pm2.ts
  • packages/ui-default/build/config/webpack.ts
  • packages/ui-default/backendlib/markdown-it-imsize.ts
  • packages/hydrojudge/src/hosts/vj4.ts
  • packages/ui-default/components/problemconfig/ProblemConfigEditor.tsx
  • packages/ui-default/backendlib/misc.ts
  • packages/ui-default/components/message/worker.ts
  • packages/ui-default/components/problemconfig/tree/AddTestcase.tsx
  • packages/ui-default/build/main.ts
  • packages/ui-default/components/problemconfig/ProblemConfigTree.tsx
  • packages/ui-default/components/problemconfig/tree/SubtaskSettings.tsx
  • packages/ui-default/components/calendar/index.js
🚧 Files skipped from review as they are similar to previous changes (27)
  • packages/ui-next/src/App.tsx
  • packages/hydrooj/src/model/token.ts
  • packages/hydrooj/src/ui.ts
  • packages/hydrojudge/src/judge/hack.ts
  • packages/ui-next/package.json
  • packages/hydrooj/src/model/message.ts
  • packages/hydrooj/src/entry/cli.ts
  • packages/ui-default/components/autocomplete/components/UserSelectAutoComplete.tsx
  • packages/hydrooj/src/model/system.ts
  • packages/hydrooj/src/model/problem.ts
  • packages/hydrooj/src/model/contest.ts
  • packages/hydrooj/src/handler/problem.ts
  • packages/hydrooj/src/commands/install.ts
  • packages/ui-default/backendlib/builder.ts
  • packages/hydrooj/src/model/storage.ts
  • packages/ui-default/components/autocomplete/components/AutoComplete.tsx
  • packages/utils/package.json
  • packages/onsite-toolkit/frontend/resolver.page.tsx
  • packages/migrate/package.json
  • packages/hydrooj/src/plugin-api.ts
  • packages/vjudge/src/index.ts
  • packages/hydrooj/src/model/user.ts
  • packages/hydrooj/src/model/task.ts
  • packages/hydrooj/src/service/bus.ts
  • package.json
  • packages/hydrooj/package.json
  • packages/ui-default/package.json
🧰 Additional context used
🧬 Code Definitions (14)
packages/hydrooj/src/entry/worker.ts (4)
packages/hydrooj/src/service/db.ts (1) (1)
  • MongoService (35-180)
packages/hydrooj/src/options.ts (1) (1)
  • load (24-37)
packages/hydrooj/src/entry/setup.ts (1) (1)
  • load (9-38)
packages/hydrooj/src/settings.ts (1) (1)
  • ConfigService (14-172)
packages/hydrooj/src/service/db.ts (1)
packages/hydrooj/src/options.ts (1) (1)
  • load (24-37)
packages/hydrooj/src/model/record.ts (8)
packages/hydrooj/src/model/schedule.ts (1) (1)
  • apply (62-101)
packages/hydrooj/src/service/api.ts (1) (1)
  • apply (217-220)
packages/hydrooj/src/model/document.ts (1) (1)
  • apply (413-447)
packages/hydrooj/src/model/task.ts (1) (1)
  • apply (145-191)
packages/hydrooj/src/model/user.ts (1) (1)
  • apply (477-495)
packages/hydrooj/src/model/blacklist.ts (1) (1)
  • apply (34-40)
packages/hydrooj/src/model/opcount.ts (1) (1)
  • apply (23-27)
packages/hydrooj/src/model/message.ts (1) (1)
  • apply (88-94)
packages/hydrooj/src/interface.ts (1)
packages/common/types.ts (1) (1)
  • RecordJudgeInfo (84-96)
packages/elastic/index.ts (4)
packages/hydrooj/src/plugin-api.ts (2) (2)
  • Service (41-41)
  • Context (41-41)
packages/hydrooj/src/settings.ts (1) (1)
  • Context (30-34)
packages/hydrooj/src/interface.ts (1) (1)
  • ProblemSearch (619-619)
packages/hydrooj/src/model/problem.ts (1) (1)
  • ProblemModel (74-675)
packages/hydrooj/src/settings.ts (4)
packages/ui-default/backendlib/template.ts (1) (1)
  • Context (254-275)
packages/elastic/index.ts (1) (1)
  • Context (95-125)
packages/vjudge/src/index.ts (1) (1)
  • Context (191-196)
packages/hydrooj/src/service/db.ts (1) (1)
  • Context (58-66)
packages/ui-default/backendlib/template.ts (3)
packages/hydrooj/src/plugin-api.ts (2) (2)
  • Service (41-41)
  • Context (41-41)
packages/ui-default/api.ts (3) (3)
  • Service (5-5)
  • ctx (5-5)
  • Context (5-5)
packages/hydrooj/src/model/builtin.ts (2) (2)
  • PERM (9-102)
  • PRIV (240-267)
packages/hydrooj/src/model/setting.ts (5)
packages/hydrooj/src/interface.ts (1) (1)
  • Setting (46-56)
packages/hydrooj/src/service/check.ts (1) (1)
  • apply (77-80)
packages/hydrooj/src/service/layers/user.ts (1) (1)
  • ctx (5-18)
packages/hydrooj/src/context.ts (2) (2)
  • Context (31-41)
  • Context (68-77)
packages/hydrooj/src/service/db.ts (1) (1)
  • Context (58-66)
framework/framework/server.ts (4)
packages/hydrooj/src/service/layers/user.ts (1) (1)
  • ctx (5-18)
packages/hydrooj/src/plugin-api.ts (3) (3)
  • Handler (40-40)
  • Service (41-41)
  • Context (41-41)
framework/framework/interface.ts (1) (1)
  • KnownHandlers (3-5)
packages/hydrooj/src/context.ts (2) (2)
  • Context (31-41)
  • Context (68-77)
packages/hydrooj/src/loader.ts (1)
packages/hydrooj/src/context.ts (3) (3)
  • EffectScope (27-27)
  • Context (31-41)
  • Context (68-77)
packages/hydrooj/src/entry/common.ts (4)
packages/ui-default/api.ts (2) (2)
  • ctx (5-5)
  • Context (5-5)
packages/hydrooj/src/plugin-api.ts (1) (1)
  • Context (41-41)
packages/hydrooj/src/context.ts (2) (2)
  • Context (31-41)
  • Context (68-77)
packages/hydrooj/src/utils.ts (1) (1)
  • unwrapExports (21-29)
packages/hydrooj/src/model/document.ts (7)
packages/hydrooj/src/model/user.ts (1) (1)
  • coll (22-22)
packages/hydrooj/src/model/oplog.ts (1) (1)
  • coll (8-8)
packages/hydrooj/src/model/discussion.ts (1) (1)
  • coll (43-43)
packages/hydrooj/src/model/problem.ts (1) (1)
  • incStatus (431-436)
packages/hydrooj/src/model/token.ts (1) (1)
  • update (53-71)
packages/hydrooj/src/model/record.ts (1) (1)
  • update (195-219)
packages/hydrooj/src/service/monitor.ts (1) (1)
  • update (76-89)
packages/hydrooj/src/model/domain.ts (4)
packages/hydrooj/src/interface.ts (1) (1)
  • DomainDoc (306-314)
packages/hydrooj/src/service/bus.ts (1) (1)
  • apply (96-113)
packages/hydrooj/src/plugin-api.ts (2) (2)
  • Context (41-41)
  • db (58-58)
packages/hydrooj/src/service/db.ts (1) (1)
  • Context (58-66)
packages/ui-default/index.ts (1)
packages/ui-default/backendlib/template.ts (1) (1)
  • TemplateService (161-276)
🪛 Biome (1.9.4)
packages/ui-default/backendlib/template.ts

[error] 46-46: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 121-121: eval() exposes to security risks and performance issues.

See the MDN web docs for more details.
Refactor the code so that it doesn't need to call eval().

(lint/security/noGlobalEval)

framework/framework/server.ts

[error] 139-139: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 140-140: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)

packages/hydrooj/src/loader.ts

[error] 49-49: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

packages/hydrooj/src/handler/domain.ts

[error] 155-155: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 335-335: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

packages/hydrooj/src/handler/misc.ts

[error] 110-110: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)


[error] 124-124: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

packages/hydrooj/src/model/document.ts

[error] 223-223: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

packages/hydrooj/src/model/domain.ts

[error] 138-138: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

packages/ui-default/index.ts

[error] 56-56: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

🪛 GitHub Check: CodeQL
build/prepare.js

[failure] 166-166: Potential file system race condition
The file may have changed since it was checked.

🔇 Additional comments (150)
packages/hydrooj/src/handler/misc.ts (1)

112-112: Verify fallback behavior for storage validation

The new validation logic uses optional chaining (?.) which could lead to undefined behavior if the storage provider or its isLinkValid method is not available.

Ensure that there's proper fallback behavior or error handling if this.ctx.get('storage') returns null or if isLinkValid is not implemented by the storage provider.

packages/hydrooj/src/model/setting.ts (8)

3-3: Updated dependencies and added Schemastery schema support

The dependency update from 'cordis' to '@cordisjs/core' and the addition of the Schemastery schema library improve the codebase architecture by providing stronger typing and schema validation capabilities.

The import of Schema from schemastery was previously flagged as missing from your project dependencies. Please verify it has been added:

#!/bin/bash
# Check if schemastery is properly listed in dependencies
cd packages/hydrooj && cat package.json | jq '.dependencies.schemastery, .devDependencies.schemastery'

Also applies to: 7-7


73-80: Well-structured namespace declaration for Schemastery metadata

The global namespace declaration for Schemastery adds type support for the schema metadata, particularly the 'family' and 'secret' properties that will be used in the settings system.


82-119: Robust schema conversion implementation but with coverage limitations

The schemaToSettings function effectively transforms Schema objects into _Setting arrays, providing a bridge between the new schema-based approach and the existing settings system. The error handling for unsupported structures (like Dict and non-constant list items) is appropriate.

Consider enhancing the function to handle deeper nested objects and more complex schema structures. Currently, it only supports one level of nesting (through the value.dict check) and limited data types. Adding support for arrays, nested objects beyond one level, and additional schema types would make this function more robust.


121-122: Enhanced type safety and schema support in setting functions

The updates to the setting functions (PreferenceSetting, AccountSetting, DomainUserSetting, DomainSetting, SystemSetting) now accept both traditional _Setting arrays and Schema objects, making the transition to schema-based definitions smoother while maintaining backward compatibility.

Also applies to: 141-142, 161-162, 177-178, 193-194


359-359: Updated module declaration to reflect package name change

This correctly updates the module declaration to match the new package name '@cordisjs/core', ensuring type definitions are properly associated.


388-388: Added dependency injection for database access

The addition of the inject = ['db'] export properly declares the database dependency, which is a good practice for dependency management.


395-395: Improved context-aware database access

The change from using the global database service to context-based DB access (ctx.db) improves testability and aligns with modern dependency injection practices.


419-420: Added inject property to global model

The addition of the inject property to the global Hydro model ensures proper dependency registration.

eslint.config.mjs (6)

8-15: Verify why certain files are fully ignored.
The current globalIgnores includes .d.ts files, which could prevent type definitions from being linted. Make sure you actually want to skip linting those, as they can benefit from basic checks.


19-21: ecmaVersion 5 may be restrictive.
You might miss out on newer JavaScript features. If your codebase doesn’t need to target ES5 specifically, consider bumping this version to ES6 or higher.


32-32: Confirm necessity of '.vue' extension.
The config includes .vue in the resolver, but there was no mention of Vue in the summary. Verify if .vue files are actually in use.


60-86: Inconsistent ECMAScript versions across configurations.
Here, ecmaVersion is set to 2020, whereas the top-level config is set to ES5. Ensure that this dual setup is intentional and won’t cause confusing lint behaviors.


104-105: Double-check disabled ESLint rules.
'github/array-foreach' and '@typescript-eslint/no-invalid-this' are fully disabled. Verify if you need these rules for improved code quality standards.


110-114: Align indentation rule settings.
The first block sets '@stylistic/indent' with { SwitchCase: 1 }, while the last block omits this. Confirm if this difference in switch-case indentation style is intentional across different file patterns.

Also applies to: 147-148

packages/elastic/index.ts (4)

34-34: Add proper type annotation for the opts parameter.

The opts parameter is missing a type annotation. Consider defining an interface for the options or using a more specific type to improve type safety.

-    async problemSearch(domainId: string, q: string, opts): ReturnType<ProblemSearch> {
+    async problemSearch(domainId: string, q: string, opts: { limit?: number; skip?: number }): ReturnType<ProblemSearch> {

72-72: Add proper type annotations for the run method parameters.

The parameters in the run method lack proper type annotations, which reduces type safety. Consider defining interfaces for these parameters.

-    async run({ domainId }, report) {
+    async run({ domainId }: { domainId?: string }, report: (status: { message: string }) => void) {

117-123: Handle potential errors in script execution.

The script registration doesn't include error handling for the run method when used as a callback. Consider wrapping it in a try-catch or using a higher-order function to catch and handle errors appropriately.

-            this.run.bind(this),
+            async (...args) => {
+                try {
+                    return await this.run.bind(this)(...args);
+                } catch (error) {
+                    this.ctx.logger.error(`Error in ensureElasticSearch script: ${error.message}`);
+                    throw error;
+                }
+            },

20-126: Overall good refactoring to class-based architecture.

The refactoring from global functions to a class-based approach with proper dependency injection and configuration management is a significant improvement. The code is now more maintainable, testable, and adheres to better OOP principles. The service properly encapsulates the Elasticsearch functionality and follows a consistent pattern with other services in the codebase.

packages/hydrooj/src/model/oauth.ts (1)

18-18: Confirm the updated return value.

Previously, findOneAndUpdate would place the updated document in res.value. Changing the return to res?.uid might reference the overall result rather than the actual updated document. Please verify that res?.uid is indeed the correct property for the updated uid.

packages/utils/lib/utils.ts (2)

10-10: New import from 'reggol' is introduced.

Importing types and classes from reggol looks okay. No immediate issues spotted.


29-31: Good approach for creating named loggers.

The createLogger function is straightforward and promotes consistent logging usage across modules.

packages/hydrooj/src/service/db.ts (6)

7-11: Revising imports to integrate Context and Service.

The switch to a context-based service injection aligns with the new modular design. All references to bus look correct, but ensure that bus usage is consistent with the rest of the codebase.


29-33: Context augmentation confirmed.

Augmenting Context to include db: MongoService is consistent with the new pattern. Make sure all other services that depend on db are updated accordingly.


43-49: Dynamic MongoDB URL generation.

Using mongodb-memory-server in CI improves test reliability. Verify that it doesn’t inadvertently run in non-CI environments. If fallback logic is needed, confirm that opts from load() always yields a valid URL or null.


58-65: Generator-based initialization.

Yielding a cleanup function fits well with a lifecycle-based approach. Ensure that your service orchestrator consistently calls this generator and properly invokes the returned cleanup for graceful shutdown.


69-70: Prefix and collectionMap usage.

This logic correctly remaps collection names. Double-check if prefix includes trailing dots or other edge cases, and confirm that collectionMap is always updated if prefix changes.


183-189: Proxying the db export.

Wrapping the service with a proxy referencing app.get('db') can obscure debugging if app is not set or is changed late in startup. Confirm that all code paths reliably set app before calling any db methods.

packages/hydrooj/src/interface.ts (6)

2-2: Added import for ParsedAuthenticatorData.

This import broadens type coverage for authentication details. Nothing problematic here.


7-8: Extended usage of RecordJudgeInfo.

Exporting RecordJudgeInfo from @hydrooj/common/types is consistent with shared definitions. The reference seems properly aligned.


83-83: Refined authenticatorExtensionResults type.

Switching to ParsedAuthenticatorData['extensionsData'] ensures accurate typing. Be sure any code referencing AuthenticationExtensionsAuthenticatorOutputs is updated accordingly.


226-229: New RecordHistoryDoc interface.

Extending RecordJudgeInfo and adding _id/rid is a clear way to store historical record data. Confirm that existing code or migrations account for this new structure.


637-637: Restored or updated problemSearch definition.

This indicates a shift back to a module-based search function rather than a global reference; confirm that all consumers of problemSearch point here instead of any deprecated global or direct references.


663-663: Switched addons to a record structure.

Changing addons from an array to a Record<string, string> might impact code expecting array semantics. Verify that all array-style accesses have been migrated to the new record-based approach.

packages/hydrooj/src/loader.ts (14)

15-17: Updated imports for enhanced type safety

The import statement now includes additional types from the context module, including Context, Service, ScopeStatus, and EffectScope. This improves type safety when working with these entities.


22-22: Added Schema import for config validation

This import is necessary for the new resolveConfig method which uses schema validation.


48-48: Enhanced type safety for state property

The state property now has a more specific type definition using Record<string, EffectScope> instead of a generic object type, improving type safety and code clarity.


54-55: Added static inject property for dependency injection

This property explicitly declares the dependencies needed by the Loader service, making the dependency injection mechanism more transparent.


56-57: Updated constructor to use Context parameter

The constructor now takes a ctx parameter rather than relying on global state, improving encapsulation and testability.


59-60: Updated event handler to use ctx directly

The event handler now uses the provided ctx parameter instead of accessing a global context, enhancing code clarity and maintainability.


98-107: Added async resolveConfig method for schema-based configuration

This new method provides a structured approach to resolving plugin configurations using Schema validation. It handles both scoped and non-scoped configurations, and includes migration support.


109-117: Updated reloadPlugin to use async/await pattern

The reloadPlugin method has been updated to be async and now uses the new resolveConfig method. It has a cleaner approach to handling the plugin configuration.


121-121: Simplified plugin application by directly using ctx.plugin

The method now directly uses this.ctx.plugin rather than relying on a parent context, improving code clarity and reducing dependencies.


135-136: Improved error logging in resolvePlugin

Error logging has been enhanced to provide more context when a plugin fails to resolve, which should aid in debugging.


147-152: Converted preload to async function with Promise-based initialization

The preload function has been updated to use async/await syntax, with a Promise to ensure global.app is properly initialized before proceeding. This enables better control flow and error handling.


161-161: Make sure the semicolon is consistently applied

Ensure consistent use of semicolons to avoid potential issues with automatic semicolon insertion.

- global.addons[name] = modulePath
+ global.addons[name] = modulePath;

170-171: Updated load function to use async/await syntax

The load function has been updated to properly await the completion of the preload function, ensuring that initialization is complete before proceeding.


208-210: Updated loadCli function to use async/await syntax

The loadCli function has been updated to properly await the completion of the preload function, ensuring that initialization is complete before proceeding with CLI operations.

packages/hydrojudge/src/checkers.ts (4)

12-12: Added code property to CheckConfig interface

Added a new code property of type CopyInFile to the CheckConfig interface, allowing user code to be passed to checkers. This enhancement enables checkers to access and potentially validate against the submitted code.


179-180: Updated syzoj checker documentation

Documentation for the syzoj checker has been updated to reflect that the code property is now supported, removing the "(not impl)" notation.


190-190: Implemented code property in syzoj checker

The syzoj checker now properly implements the code property, allowing it to access the user's submitted code during the checking process.


206-206: Added user_code mapping in testlib checker

The testlib checker now maps the config.code to user_code in its sandbox configuration, enabling testlib checkers to access the submitted code.

packages/hydrooj/src/model/opcount.ts (1)

16-16: Updated property access to match MongoDB driver response structure

The return statement has been modified to access opcount directly from the response object, rather than from a nested value property. This change aligns with MongoDB driver's behavior when using returnDocument: 'after' option.

packages/hydrooj/src/model/blacklist.ts (1)

16-21: Simplified return pattern for database operation

The method now directly returns the result of findOneAndUpdate without unnecessary intermediate variable assignment. This simplifies the code and aligns with the pattern used in other model methods.

packages/hydrooj/src/model/record.ts (3)

2-2: Using sum from lodash is appropriate.
Your addition of sum is consistent with the usage in this file.


23-23: New collHistory collection looks good.
Well-defined collection name and consistent naming scheme. Index creation for collHistory is included, so no immediate concerns.


283-328: Verify indexing needs for collHistory.
Currently, only { rid: 1, _id: -1 } is indexed. If domain-based queries on historical records become necessary, consider including a domainId field and index.

packages/hydrooj/src/entry/worker.ts (13)

9-10: Imports of MongoService and ConfigService acknowledged.
No conflicts identified.


12-12: Adds setting to the destructured imports.
This supports the subsequent usage of the settings plugin.


24-25: Conditionally running setup for missing MongoDB URL.
Neat approach to streamline local onboarding.


31-33: Plugin registration for locale, MongoService, and ConfigService.
Good modular approach for loading services.


37-41: Asynchronous injection of loader and config.
No issues found.


43-46: Reloading plugins in parallel.
Consistent with Hydro's modular plugin system.


48-50: Chaining additional context injection.
Continues the pattern used above.


52-52: Invoking api.apply directly.
Straightforward approach; no concerns.


60-65: Applying settings via setting(pending, fail, require('../model/setting')).
Maintains consistent plugin flow.


69-69: Reloading handlers in a loop.
Clean approach to ensuring handler updates.


75-76: Reloading scripts similarly.
Consistent usage with other reload patterns.


92-92: Copying addon assets into static directory.
No flags here; safe to skip additional commentary.


97-102: Inject server and listen.
Proper placement of server startup logic.

packages/hydrooj/src/model/schedule.ts (2)

7-7: Importing WorkerService type is fine.
Matches usage patterns in this file.


18-24: Verify usage of res from findOneAndDelete.
MongoDB’s findOneAndDelete typically stores the document in res.value, which may be null when no record is found. Relying on res directly might introduce logic errors.

framework/eslint-config/base.mjs (2)

1-14: Initial ESLint config setup is valid.
Imports are properly declared and FlatCompat usage is straightforward.


15-483: Comprehensive ruleset aligns with best practices.
Your approach extends multiple rule sets, merges them properly, and configures advanced TypeScript rules. No major conflicts or redundancy noted.

packages/hydrooj/src/service/worker.ts (2)

12-12:

❓ Verification inconclusive

Export style changed: Consider updating all imports

The class export has been changed from named export to default export, which will require updates to any imports of this service throughout the codebase.

Run this script to find usages that need to be updated:


🏁 Script executed:

#!/bin/bash
# Find all imports of WorkerService that might need updating
echo "Checking for imports that need updating..."
rg "import.*WorkerService.*from '.*service/worker'" --type ts

Length of output: 255


Action Required: Update Import in Model Schedule

The script found one import in packages/hydrooj/src/model/schedule.ts:

  • import type WorkerService from '../service/worker';

Since the service now uses a default export, the type-import here might not be ideal if it’s later used as a runtime value. Please verify if this import is solely for type purposes. If a runtime instantiation is performed, update the import to a value import (i.e. remove the type keyword):

- import type WorkerService from '../service/worker';
+ import WorkerService from '../service/worker';

If the usage is exclusively for type checking, no changes are needed.


32-38:

❓ Verification inconclusive

DB result handling changed: potential breaking change

The function now directly checks and returns res instead of res.value, which indicates a change in the database layer response format. This could break code that expects the old structure.

Let's check if there are any other places in the codebase that might be expecting the old structure:


🏁 Script executed:

#!/bin/bash
# Search for other places using findOneAndDelete and expecting .value
rg "findOneAndDelete.*\.value" --type ts

Length of output: 42


Action Required: Verify DB Result Format Dependency

The updated code in packages/hydrooj/src/service/worker.ts (lines 32–38) now directly returns res instead of using res.value. Our automated search for usages of patterns like findOneAndDelete expecting a .value (e.g., via the command rg "findOneAndDelete.*\.value" --type ts) did not locate any such references. However, since the search produced no output—which might be due to limitations in the inference—we need manual verification to ensure that no part of the codebase still depends on the old structure.

Please confirm that:

  • Any modules or services handling database responses are updated to work with the complete result object (res).
  • There are no residual expectations of a .value property elsewhere in the application.
packages/ui-default/backendlib/template.ts (2)

25-34: Good implementation of file traversal

The recursive getFiles function effectively handles directory traversal and correctly normalizes path separators for cross-platform compatibility.


161-275: Well-structured TemplateService with dependency injection

The TemplateService class follows good service-oriented design principles with clear separation of concerns, proper initialization, and error handling. The use of static injection points and context registration improves maintainability.

framework/eslint-config/package.json (2)

7-21:

❓ Verification inconclusive

Dependency updates: Review for compatibility

Several dependencies have been updated to newer versions, including major version upgrades. Ensure these are compatible with your codebase.


🏁 Script executed:

#!/bin/bash
# Check for any peer dependency warnings or errors
npm ls --depth=0

Length of output: 8122


Action Required: Manually Verify ESLint Dependency Compatibility

The dependency updates in framework/eslint-config/package.json (e.g., updates to @typescript-eslint/*, eslint-config-airbnb, etc.) look intentional. However, the npm ls --depth=0 output reveals several unmet dependency errors related to the monorepo’s local packages, which may be obscuring any subtle compatibility problems.

Before merging, please ensure that:

  • The updated ESLint plugins, parser, and related packages work seamlessly with the overall codebase.
  • There are no new peer dependency issues or runtime conflicts when the monorepo’s linked packages are fully installed.
  • An end-to-end linting and integration test is performed to confirm that these dependency updates behave as expected in context.

5-5:

❓ Verification inconclusive

Main entry point changed: Update dependent packages

The main entry has changed from react.yaml to base.mjs, which may require updates in packages that import this config.


🏁 Script executed:

#!/bin/bash
# Find packages that might need updates due to the changed entry point
echo "Checking for packages using the old entry point..."
rg -l "require.*@hydrooj/eslint-config/react" --type js

Length of output: 168


Action Required: Confirm External Dependency Updates for New Main Entry

The update in framework/eslint-config/package.json changes the package’s main entry from react.yaml to base.mjs. Our initial script search for references matching the old entry did not return any local hits. However, because the automated output was inconclusive, please manually verify that no external packages or documentation still depend on the legacy react.yaml entry.

  • File Affected: framework/eslint-config/package.json (line 5)
  • Verification Needed: Check for any dependent code, documentation, or configuration (possibly external to this repository) that references @hydrooj/eslint-config/react or the string react.yaml.
packages/ui-default/index.ts (3)

77-77: System settings reference updated

The change from SystemSettings to this.ctx.config.settings aligns with the broader refactoring to use context-based configuration.


3-4: Good architecture change: Service dependency injection

Replacing the direct import with proper service injection via ctx.plugin(TemplateService) improves modularity and testability.

Also applies to: 167-167


25-25: Improved type safety with explicit type annotations

Adding explicit type annotation for the sections array enhances code reliability and IDE support.

packages/hydrooj/src/settings.ts (1)

55-67: Security improvement needed for prototype pollution prevention.

The applyDelta method includes a blacklist check for dangerous property names, but the implementation in line 65 could still be vulnerable to prototype pollution through other attack vectors.

While the blacklist approach in line 57 helps prevent common prototype pollution attacks, consider implementing a more comprehensive solution:

applyDelta(source: any, key: string, value: any) {
    const path = key.split('.');
    if (path.some((i) => ConfigService.blacklist.includes(i))) return false;
    const t = path.pop();
    const root = JSON.parse(JSON.stringify(source));
    let cursor = root;
    for (const p of path) {
        cursor[p] ??= {};
+       // Additional safety check for properties with __proto__ in them
+       if (Object.prototype.hasOwnProperty.call(cursor, p) && 
+           typeof cursor[p] !== 'object') return false;
        cursor = cursor[p];
    }
+   // Prevent setting properties that might lead to prototype pollution
+   if (t && (t === '__proto__' || t === 'constructor' || t === 'prototype')) return false;
    cursor[t] = value;
    return root;
}
packages/hydrooj/src/model/domain.ts (3)

213-213: Logical change to domain user role authorization.

Line 213 introduces a new condition requiring join: true for users without the PRIV_VIEW_ALL_DOMAIN privilege to access domains with roles other than 'guest'.

This change improves access control by ensuring users can only access domains they've explicitly joined or have appropriate privileges for.


258-260: Query modification to only return users who have joined the domain.

The getDictUserByDomainId method now filters for users with join: true, ensuring only active domain members are returned.

This change ensures consistency with the join-based access control model being implemented throughout the codebase.


292-312: Well-structured event handling with proper Context integration.

The new apply function properly integrates with the context system for event handling and database initialization.

The function correctly:

  1. Sets up a domain cache invalidation event handler
  2. Ensures necessary database indexes are created
  3. Follows the service pattern using the Context parameter

This aligns with the broader refactoring effort toward better context-based dependency injection throughout the application.

packages/hydrooj/src/entry/common.ts (3)

24-45: Simplified loader system with improved type safety.

The function signature has changed from accepting an array of strings to a record mapping, and the loader now properly uses the Context parameter.

The new implementation:

  1. Uses Object.entries() for cleaner iteration over the mapping
  2. Correctly passes the plugin name during reloading
  3. Properly integrates with the context system for logging

This aligns with the broader refactoring of the application toward better type safety and context-based dependency injection.


60-81: Improved locale loading with better type safety.

The function signature has changed to accept a Record instead of an array, and uses Object.values() for iteration.

The change maintains functionality while providing better type safety and integration with the new module loading patterns.


83-122: Consistent refactoring of settings loader.

Similar to other loader functions, this has been updated to use a Record parameter and Object.values() for iteration.

The implementation maintains the same functionality while adhering to the new loading patterns established throughout the codebase.

packages/hydrooj/src/handler/domain.ts (4)

258-258: Improved role filtering in domain join applications.

The code now only excludes the 'guest' role instead of both 'default' and 'guest', simplifying role management.

This change allows the 'default' role to be offered as a join option, which is more flexible and consistent with the domain access model.


322-337: Enhanced domain join preparation with target parameter.

The prepare method now supports joining a different domain than the current context through the target parameter.

This change adds flexibility to the domain join process and properly handles authorization checks, ensuring users can only join domains they're allowed to access.

🧰 Tools
🪛 Biome (1.9.4)

[error] 335-335: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


339-358: Improved domain join page with detailed domain information.

The get method now includes comprehensive domain information in the response, enhancing the user experience.

The added domain information provides users with more context when joining a domain, including owner details, avatar, and bulletin information when available.


369-376: Flexible role assignment during domain join.

The post method now conditionally assigns the role from join settings, improving the domain onboarding flow.

This implementation correctly:

  1. Sets the join: true flag to mark the user as an explicit member
  2. Only assigns a role if join settings specify one
  3. Properly redirects to the target domain homepage with success notification
packages/hydrooj/src/model/document.ts (18)

12-12: Switching to default import for bus
No concerns. This adoption of default import from the bus module is consistent.


18-18: Refine type definitions
Using Exclude<ArrayKeys<O, P>, symbol> is a solid approach to isolate valid string-based keys. No issues found.


23-33: Enhance TypeScript inference with as const
Declaring constants with as const fosters better type inference. Good improvement over explicit type assignments.


112-112: Return statements
Returning await coll.findOneAndUpdate(...) is consistent with your approach.
No immediate issues.


152-152: Same pattern of returning from findOneAndUpdate()
Maintaining consistency across the codebase. Looks good.


162-162: Refactoring incAndSet
No issues with the await coll.findOneAndUpdate(...); consider verifying null results.


211-211: Pull subdocuments
No concerns. The code is aligned with the other findOneAndUpdate usage.


224-224: Return statement for deleteSub
Consistent usage of findOneAndUpdate.


253-253: Setting subdocument
Returning the updated document. No issues found.


267-267: Add to set operation
Checking your usage of $addToSet is consistent. All good.


279-279: Define getStatus function
No issues. This new function to retrieve status from collStatus is straightforward.


293-293: Returning doc.value and generated ID
This is a convenient approach to pass both the updated doc snapshot and the newly created _id.


329-329: Conditional status update
No immediate issues with calling findOneAndUpdate. Validate usage results if needed.


359-359: Capped increment
Ensuring the usage of $inc with boundary checks is beneficial. Approved.


370-370: Increment status
No concerns. The logic is consistent with the rest of the doc.


386-386: Fallback with res ||=
This approach to set res from findOneAndUpdate if it’s falsy is a neat pattern.


398-398: Initialize revision
Returning the updated doc from collStatus is consistent.


411-411: Set revision
Approach looks good. Potentially verify doc not null.

build/prepare.js (10)

18-22: Update TS compiler options
Switching target to 'es2022', lib to ['es2022'], module to 'preserve', and moduleResolution to 'bundler' is beneficial for advanced features. No concerns.


37-37: Add reference to tsconfig.ui-next.json
No issues. This helps unify the build config.


78-78: Exclude directories
Filtering out 'ui-default' and 'ui-next' is consistent with the new architecture.


83-87: Add excludes for UI default
Excluding 'packages/ui-default/index.ts', 'backendlib/builder.ts', 'misc.ts', 'template.ts', 'markdown.js'.
No immediate concerns.


100-121: Enhanced UIConfig
Adopting react-jsx, bundler mode, noEmit, and other TS checks improves the build. Looks consistent.


123-155: Add UINextConfig
Creating a separate config for ui-next fosters modular development. Looks good.


197-197: Patch invocation
No issues with tryUpdate usage on tsconfig.json.


199-210: Iterate modules
This block ensures dynamic TS config creation for each package. Good approach.


219-219: Generate default index
Writing a fallback module.exports is a neat convenience for Node resolution.


223-225: Update root TS config
Applying UIConfig, UINextConfig, and the main config systematically. Looks correct.

framework/framework/server.ts (28)

5-5: Use of CordisContext & Service
Importing Context as CordisContext from @cordisjs/core for extended type usage is a good design choice.


22-22: KnownHandlers type import
No immediate issues with referencing KnownHandlers.


44-53: Introducing forkContextWithScope
Creating a scoped plugin context fosters better disposal. This pattern is beneficial for lifecycle management.


149-149: Constructor receives typed context
Passing C for the second constructor param is consistent with generic usage.


197-198: Renderer selection
Filtering valid renderers by extension or fallback. Good approach to combine.


210-211: Extended Handler
Handler<C = CordisContext> extends HandlerCommon<C> clarifies general usage. This is a consistent pattern.


258-259: ConnectionHandler
Similarly extends HandlerCommon<C>. Good use of generics.


337-337: Generic WebService
Allowing C extends CordisContext for better type coverage. Approved.


351-351: Expose Handler
Exposing HandlerCommon, Handler, ConnectionHandler as class properties ensures consistent usage.


450-450: 404 fallback
Calling handleHttp with NotFoundHandler is a straightforward approach to handle unknown routes.


478-478: Log success
Neat usage of logger.success to display listening address.


564-569: Refactor handleWS
Creating a sub scope again is consistent, with the same event pattern 'connection/create'.


599-611: Cleanup routine
Encapsulating the disposal logic in clean() is robust. Good approach.


635-637: Tracking heartbeats
Using pong event to refresh lastHeartbeat. No issues.


642-644: Reply to ping
Sending 'pong' on 'ping' keeps the connection active.


646-646: Close invalid connection
If JSON parse fails, forcibly close. Straightforward approach.


649-649: message?.() usage
Optional chaining is concise, re-check for null or undefined if needed.


712-714: Shadow context
Conditionally retrieving parent context from Symbol.for('cordis.shadow'). No immediate issues.


716-716: Route binding
Passing the Checker(permPrivChecker) to handleHttp for route-based perms is consistent.


719-722: WebSocket route
Similarly passing handleWS for a new route ensures parallel approach for WS. Good job.


734-739: withHandlerClass
Allows dynamic usage of the registry. The fallback logic with .on('handler/register/<name>') is clever.


754-754: Connection method
Mirrors Route method with handleWS. No issues.


757-763: registerLayer
Applying effect to add or remove layers is a neat pattern.


812-816: applyMixin
Your approach is consistent with the rest of the dynamic architecture. Approved.


818-820: handlerMixin
Applying partial or functional mixins to HandlerCommon. No issues found.


822-824: httpHandlerMixin
Same pattern for HTTP handlers.


826-827: wsHandlerMixin
Assigning properties from partial mixins for WS. Straightforward approach.


841-847: Augment @cordisjs/core Context
Declaring server, Route, Connection, withHandlerClass on the Cordis Context interface for better integration.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (6)
build/prepare.js (1)

163-167: ⚠️ Potential issue

Fix potential file system race condition

The tryUpdate function has a potential race condition between checking if a file exists and reading it. If the file is deleted between these operations, it could cause errors.

Consider using a try-catch approach instead:

const tryUpdate = (location, content) => {
-    const current = fs.existsSync(location) ? fs.readFileSync(location, 'utf-8') : '';
+    let current = '';
+    try {
+        current = fs.readFileSync(location, 'utf-8');
+    } catch (err) {
+        // File doesn't exist or cannot be read
+    }
    const expected = typeof content === 'string' ? content : JSON.stringify(content, null, 2);
    if (expected !== current) fs.writeFileSync(location, expected);
};
🧰 Tools
🪛 GitHub Check: CodeQL

[failure] 166-166: Potential file system race condition
The file may have changed since it was checked.

packages/hydrooj/src/settings.ts (1)

164-167: 🛠️ Refactor suggestion

Fire-and-forget in Proxy setter may swallow DB write errors

The set trap in the proxy does not await that.setConfig(...), which can result in silent failures if the database call rejects.

Consider making the proxy setter async or otherwise surfacing error handling:

- set(self, p: string | symbol, newValue: any) {
-   that.setConfig(path.concat(p).join(','), newValue);
-   return true;
- },
+ async set(self, p: string | symbol, newValue: any) {
+   try {
+     await that.setConfig(path.concat(p).join(','), newValue);
+   } catch (err) {
+     logger.error('Failed to set config property:', err.message);
+     return false;
+   }
+   return true;
+ },
packages/ui-default/index.ts (1)

56-56: ⚠️ Potential issue

Remove the empty object pattern.

The empty object pattern { } is unnecessary and flagged by static analysis. This parameter doesn't serve any purpose and should be removed.

-  async get({ }, legacy = false, nohint = false) {
+  async get(legacy = false, nohint = false) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 56-56: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

framework/framework/server.ts (3)

139-140: ⚠️ Potential issue

Address unsafe declaration merging in HandlerCommon

Declaring both export interface HandlerCommon<C> (empty) and export class HandlerCommon<C> under the same name can lead to unsafe declaration merging in TypeScript, as flagged by the linter.

Consider removing or renaming the empty interface, or using a type alias if you need to augment the class's shape:

-export interface HandlerCommon<C> { } // eslint-disable-line @typescript-eslint/no-unused-vars
+// Consider removing or a type alias if needed:
+// type HandlerCommonProps<C> = {}

export class HandlerCommon<C> {
  // ...
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 139-139: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 140-140: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)


498-501: ⚠️ Potential issue

Address FIXME comments for type checking

Multiple locations use type assertions to any with FIXME comments about passing type checks. These should be properly typed rather than bypassing TypeScript's type system.

Create proper type definitions for the event handlers to avoid type assertions:

// In your interfaces file:
interface HandlerEvents<T> {
  'handler/create': [handler: T, type: 'http' | 'ws'];
  'handler/create/http': [handler: T];
  'handler/create/ws': [handler: T];
  'handler/error': [handler: T, error: Error];
  'connection/create': [handler: T];
  'connection/active': [handler: T];
  'connection/close': [handler: T];
}

// Then update your context interface to include these typed events
interface C extends CordisContext {
  parallel<E extends keyof HandlerEvents<T>, T>(event: E, ...args: HandlerEvents<T>[E]): Promise<void>;
  serial<E extends keyof HandlerEvents<T>, T>(event: E, ...args: HandlerEvents<T>[E]): Promise<void>;
}

Also applies to: 536-537, 551-554, 568-570, 603-605, 655-657, 739-741


676-709: ⚠️ Potential issue

Improved checker function with better variable handling

The inline definition of the Checker function within the register method improves encapsulation and code organization. However, there's a potential issue with the condition in line 705.

The condition if (perm) at line 705 is flagged by static analysis as always evaluating to false. Investigate why perm is not being properly set or detected in this context:

-                if (perm) this.checkPerm(perm);
+                if (perm !== undefined && perm !== null) this.checkPerm(perm);
🧹 Nitpick comments (19)
eslint.config.mjs (2)

40-40: Unify or justify different @typescript-eslint/no-invalid-this values.

The rule is set to 1 (warning) under one config block and disabled (0) under another. If this is to allow different behaviors in distinct parts of the code, that’s fine. Otherwise, consider applying a single, consistent rule value to avoid confusion.

Also applies to: 105-105


42-52: Consolidate or differentiate repeated simple-import-sort/imports rules.

You have two different grouping configurations for simple-import-sort/imports. If they’re meant for separate contexts, keep them. Otherwise, merging or clarifying their usage can prevent collisions or confusion.

Also applies to: 121-135

framework/eslint-config/base.mjs (2)

64-83: Check multiline comma usage.

The rule '@stylistic/comma-dangle' is set to 'always-multiline', which is fine for readability but can feel strict in smaller code snippets. If it’s a team preference, no issue. Otherwise, consider making it optional.


401-401: github/array-foreach: usage caution.

Setting 'github/array-foreach': 1 to warn can help devs avoid potential side effects of array forEach. Ensure your team is aware of the reasons behind this setting, like potential performance or using more explicit loops.

framework/eslint-config/package.json (1)

24-25: ESLint peer dependency requires version >= 9.

Bumping the peer dependency might break older setups. Ensure contributing developers have ESLint 9+ installed, or provide instructions to upgrade.

.github/workflows/build.yml (1)

26-26: Note on Deprecated set-output Usage
The command on line 26 uses the now-deprecated ::set-output syntax. Consider updating this step to use the recommended $GITHUB_OUTPUT approach. For example:

-      run: echo "::set-output name=dir::$(yarn config get cacheFolder)"
+      run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT

This update will help future-proof the workflow against breaking changes in GitHub Actions.

🧰 Tools
🪛 actionlint (1.7.4)

26-26: workflow command "set-output" was deprecated. use echo "{name}={value}" >> $GITHUB_OUTPUT instead: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions

(deprecated-commands)

packages/ui-default/backendlib/template.ts (4)

25-34: Consider adding robust error handling or concurrency.

While this recursive file reader works, adding try-catch blocks or concurrency could help avoid potential I/O bottlenecks or crashes if an error occurs (e.g., permission issues, missing directories).


36-42: Switch to asynchronous operations if performance is critical.

Currently, fs.existsSync is a synchronous check. Switching to an async check, or at least handling potential errors, can improve performance and resiliency under heavy loads.


44-56: Use optional chaining in lookup.

Instead of (obj || {})._original, consider leveraging optional chaining (obj?._original) to reduce verbosity and guard against null or undefined values more cleanly.

🧰 Tools
🪛 Biome (1.9.4)

[error] 46-46: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


59-59: Enhance type safety for the constructor.

constructor(Loader: any) could be strengthened by introducing a proper type/interface for Loader to improve maintainability and catch potential errors at compile time.

packages/utils/lib/utils.ts (1)

33-35: Type safety concerns with Logger type casting

The type declaration and export statement use type casting (as any as Logger) which may reduce type safety. Consider implementing a proper constructor signature that matches the declared type without needing the unsafe casting.

-export type Logger = Reggol & { new(name: string): Reggol & Logger };
-export const Logger = createLogger as any as Logger;
+export type Logger = Reggol;
+export const Logger = createLogger;

Alternatively, if the constructor signature is required for backward compatibility, consider implementing a proper factory class that satisfies both the function call and constructor patterns.

packages/hydrooj/src/service/db.ts (1)

182-189: Added backward compatibility proxy with deprecation notice

The implementation of a proxy object with a deprecation notice provides backward compatibility while encouraging migration to the context-based approach. Consider adding a timeline for when this compatibility layer will be removed.

You might want to add a more visible deprecation warning that appears at runtime:

/** @deprecated use ctx.db instead */
const db = new Proxy({} as MongoService, {
    get(target, prop) {
+       console.warn('Warning: Direct db access is deprecated. Use ctx.db instead.');
        return app.get('db')?.[prop];
    },
});
packages/hydrooj/src/handler/misc.ts (2)

110-110: Empty object pattern used as parameter

The domainId parameter has been replaced with an empty object pattern. This is flagged by static analysis as potentially problematic. Consider using a more descriptive parameter structure or a proper options object with named properties.

-async get({ }, target: string, filename = '', expire: number, secret: string) {
+async get(_: Record<string, never>, target: string, filename = '', expire: number, secret: string) {

Or if this is part of a broader refactoring to use destructuring:

-async get({ }, target: string, filename = '', expire: number, secret: string) {
+async get({}: { domainId?: string }, target: string, filename = '', expire: number, secret: string) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 110-110: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)


124-124: Empty object pattern used as parameter

Similar to line 110, the domainId parameter has been replaced with an empty object pattern, which is flagged by static analysis. Consider using a more meaningful parameter structure.

-async get({ }, uid: number) {
+async get(_: Record<string, never>, uid: number) {

Or if this is part of a broader refactoring to use destructuring:

-async get({ }, uid: number) {
+async get({}: { domainId?: string }, uid: number) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 124-124: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

packages/ui-default/index.ts (1)

119-119: Added explicit typing for better code readability.

Adding the any[] type annotation to res improves code clarity, though consider using a more specific type than any if possible.

packages/hydrooj/src/loader.ts (1)

49-49: Improve type safety by using a more specific type.

Don't use {} as a type as it means "any non-nullable value". Prefer explicitly defining the object shape or use a more specific type.

-    public config: {};
+    public config: Record<string, unknown>;
🧰 Tools
🪛 Biome (1.9.4)

[error] 49-49: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

packages/hydrooj/src/model/domain.ts (1)

138-138: Use Array.isArray() for more reliable type checking.

Replace instanceof Array with Array.isArray() as it's more reliable, especially with arrays from different execution contexts.

-        if (!(uid instanceof Array)) {
+        if (!Array.isArray(uid)) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 138-138: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

packages/hydrooj/src/handler/domain.ts (2)

155-155: Consider using undefined assignment instead of delete operator

The delete operator can have performance implications in JavaScript. Consider using undefined assignment instead.

-            delete u.user;
+            u.user = undefined;
🧰 Tools
🪛 Biome (1.9.4)

[error] 155-155: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


335-335: Consider using undefined assignment instead of delete operator

Similar to the earlier issue, using the delete operator can impact performance. Consider using undefined assignment instead.

-        else if (!this.joinSettings) throw new DomainJoinForbiddenError(target);
+        if (assignedRole !== 'default') this.joinSettings = undefined;
+        else if (!this.joinSettings) throw new DomainJoinForbiddenError(target);
🧰 Tools
🪛 Biome (1.9.4)

[error] 335-335: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0bd15ca and f8ed636.

📒 Files selected for processing (94)
  • .eslintrc.yaml (0 hunks)
  • .github/workflows/build.yml (1 hunks)
  • build/prepare.js (5 hunks)
  • eslint.config.mjs (1 hunks)
  • framework/eslint-config/base.mjs (1 hunks)
  • framework/eslint-config/base.yaml (0 hunks)
  • framework/eslint-config/package.json (1 hunks)
  • framework/eslint-config/react.yaml (0 hunks)
  • framework/eslint-config/typescript.js (0 hunks)
  • framework/framework/error.ts (0 hunks)
  • framework/framework/server.ts (22 hunks)
  • package.json (2 hunks)
  • packages/elastic/index.ts (2 hunks)
  • packages/hydrojudge/src/cases.ts (0 hunks)
  • packages/hydrojudge/src/checkers.ts (4 hunks)
  • packages/hydrojudge/src/daemon.ts (0 hunks)
  • packages/hydrojudge/src/hosts/hydro.ts (0 hunks)
  • packages/hydrojudge/src/hosts/vj4.ts (1 hunks)
  • packages/hydrojudge/src/judge/hack.ts (4 hunks)
  • packages/hydrooj/package.json (3 hunks)
  • packages/hydrooj/src/commands/install.ts (1 hunks)
  • packages/hydrooj/src/entry/cli.ts (2 hunks)
  • packages/hydrooj/src/entry/common.ts (2 hunks)
  • packages/hydrooj/src/entry/setup.ts (0 hunks)
  • packages/hydrooj/src/entry/worker.ts (3 hunks)
  • packages/hydrooj/src/handler/contest.ts (0 hunks)
  • packages/hydrooj/src/handler/domain.ts (3 hunks)
  • packages/hydrooj/src/handler/misc.ts (3 hunks)
  • packages/hydrooj/src/handler/problem.ts (1 hunks)
  • packages/hydrooj/src/interface.ts (6 hunks)
  • packages/hydrooj/src/loader.ts (6 hunks)
  • packages/hydrooj/src/model/blacklist.ts (1 hunks)
  • packages/hydrooj/src/model/contest.ts (7 hunks)
  • packages/hydrooj/src/model/document.ts (11 hunks)
  • packages/hydrooj/src/model/domain.ts (9 hunks)
  • packages/hydrooj/src/model/message.ts (3 hunks)
  • packages/hydrooj/src/model/oauth.ts (1 hunks)
  • packages/hydrooj/src/model/opcount.ts (1 hunks)
  • packages/hydrooj/src/model/problem.ts (1 hunks)
  • packages/hydrooj/src/model/record.ts (8 hunks)
  • packages/hydrooj/src/model/schedule.ts (2 hunks)
  • packages/hydrooj/src/model/setting.ts (11 hunks)
  • packages/hydrooj/src/model/storage.ts (6 hunks)
  • packages/hydrooj/src/model/system.ts (3 hunks)
  • packages/hydrooj/src/model/task.ts (3 hunks)
  • packages/hydrooj/src/model/token.ts (2 hunks)
  • packages/hydrooj/src/model/user.ts (8 hunks)
  • packages/hydrooj/src/plugin-api.ts (2 hunks)
  • packages/hydrooj/src/script/problemStat.ts (0 hunks)
  • packages/hydrooj/src/script/storageUsage.ts (0 hunks)
  • packages/hydrooj/src/service/bus.ts (5 hunks)
  • packages/hydrooj/src/service/db.ts (3 hunks)
  • packages/hydrooj/src/service/worker.ts (2 hunks)
  • packages/hydrooj/src/settings.ts (1 hunks)
  • packages/hydrooj/src/ui.ts (1 hunks)
  • packages/migrate/package.json (1 hunks)
  • packages/onlyoffice/frontend/office.page.ts (0 hunks)
  • packages/onsite-toolkit/frontend/resolver.page.tsx (2 hunks)
  • packages/ui-default/.eslintignore (0 hunks)
  • packages/ui-default/.eslintrc.js (0 hunks)
  • packages/ui-default/api.ts (0 hunks)
  • packages/ui-default/backendlib/builder.ts (4 hunks)
  • packages/ui-default/backendlib/markdown-it-imsize.ts (1 hunks)
  • packages/ui-default/backendlib/markdown-it-media.ts (0 hunks)
  • packages/ui-default/backendlib/misc.ts (1 hunks)
  • packages/ui-default/backendlib/template.ts (3 hunks)
  • packages/ui-default/build/config/webpack.ts (1 hunks)
  • packages/ui-default/build/main.ts (1 hunks)
  • packages/ui-default/components/autocomplete/components/AutoComplete.tsx (3 hunks)
  • packages/ui-default/components/autocomplete/components/UserSelectAutoComplete.tsx (1 hunks)
  • packages/ui-default/components/calendar/index.js (2 hunks)
  • packages/ui-default/components/message/worker.ts (1 hunks)
  • packages/ui-default/components/problemconfig/ProblemConfigEditor.tsx (1 hunks)
  • packages/ui-default/components/problemconfig/ProblemConfigTree.tsx (1 hunks)
  • packages/ui-default/components/problemconfig/reducer/config.ts (1 hunks)
  • packages/ui-default/components/problemconfig/tree/AddTestcase.tsx (1 hunks)
  • packages/ui-default/components/problemconfig/tree/SubtaskSettings.tsx (1 hunks)
  • packages/ui-default/components/problemconfig/tree/Testcase.tsx (1 hunks)
  • packages/ui-default/components/scratchpad/DataInputComponent.jsx (0 hunks)
  • packages/ui-default/components/scratchpad/ScratchpadToolbarContainer.jsx (0 hunks)
  • packages/ui-default/index.ts (6 hunks)
  • packages/ui-default/package.json (5 hunks)
  • packages/ui-next/package.json (1 hunks)
  • packages/ui-next/src/App.tsx (1 hunks)
  • packages/utils/lib/locate-pm2.ts (1 hunks)
  • packages/utils/lib/utils.ts (1 hunks)
  • packages/utils/package.json (2 hunks)
  • packages/vjudge/src/index.ts (3 hunks)
  • packages/vjudge/src/providers/codeforces.ts (0 hunks)
  • packages/vjudge/src/providers/hduoj.ts (0 hunks)
  • packages/vjudge/src/providers/poj.ts (0 hunks)
  • packages/vjudge/src/providers/spoj.ts (0 hunks)
  • packages/vjudge/src/providers/uoj.ts (0 hunks)
  • packages/vjudge/src/providers/yacs.ts (0 hunks)
💤 Files with no reviewable changes (25)
  • packages/hydrooj/src/script/problemStat.ts
  • packages/hydrojudge/src/daemon.ts
  • packages/ui-default/.eslintignore
  • packages/ui-default/api.ts
  • packages/ui-default/components/scratchpad/DataInputComponent.jsx
  • packages/ui-default/backendlib/markdown-it-media.ts
  • packages/hydrooj/src/entry/setup.ts
  • packages/hydrojudge/src/hosts/hydro.ts
  • packages/vjudge/src/providers/poj.ts
  • packages/hydrojudge/src/cases.ts
  • packages/ui-default/components/scratchpad/ScratchpadToolbarContainer.jsx
  • packages/vjudge/src/providers/yacs.ts
  • packages/vjudge/src/providers/spoj.ts
  • packages/vjudge/src/providers/hduoj.ts
  • packages/hydrooj/src/script/storageUsage.ts
  • framework/eslint-config/typescript.js
  • packages/onlyoffice/frontend/office.page.ts
  • packages/vjudge/src/providers/uoj.ts
  • packages/vjudge/src/providers/codeforces.ts
  • framework/eslint-config/base.yaml
  • packages/hydrooj/src/handler/contest.ts
  • framework/eslint-config/react.yaml
  • framework/framework/error.ts
  • .eslintrc.yaml
  • packages/ui-default/.eslintrc.js
✅ Files skipped from review due to trivial changes (14)
  • packages/ui-default/components/message/worker.ts
  • packages/ui-default/components/problemconfig/reducer/config.ts
  • packages/ui-default/components/problemconfig/ProblemConfigEditor.tsx
  • packages/utils/lib/locate-pm2.ts
  • packages/ui-default/build/config/webpack.ts
  • packages/ui-default/build/main.ts
  • packages/ui-default/components/problemconfig/tree/AddTestcase.tsx
  • packages/ui-default/components/problemconfig/tree/Testcase.tsx
  • packages/ui-default/backendlib/misc.ts
  • packages/ui-default/backendlib/markdown-it-imsize.ts
  • packages/hydrojudge/src/hosts/vj4.ts
  • packages/ui-default/components/calendar/index.js
  • packages/ui-default/components/problemconfig/tree/SubtaskSettings.tsx
  • packages/ui-default/components/problemconfig/ProblemConfigTree.tsx
🚧 Files skipped from review as they are similar to previous changes (25)
  • packages/ui-next/src/App.tsx
  • packages/migrate/package.json
  • packages/hydrooj/src/ui.ts
  • packages/hydrooj/src/model/storage.ts
  • packages/hydrooj/src/handler/problem.ts
  • packages/ui-default/components/autocomplete/components/UserSelectAutoComplete.tsx
  • packages/hydrooj/src/model/message.ts
  • packages/ui-next/package.json
  • packages/hydrooj/src/model/system.ts
  • packages/hydrooj/src/model/token.ts
  • packages/hydrojudge/src/checkers.ts
  • packages/hydrojudge/src/judge/hack.ts
  • packages/ui-default/components/autocomplete/components/AutoComplete.tsx
  • packages/onsite-toolkit/frontend/resolver.page.tsx
  • packages/ui-default/backendlib/builder.ts
  • packages/hydrooj/src/entry/cli.ts
  • packages/hydrooj/src/model/problem.ts
  • packages/hydrooj/src/model/contest.ts
  • packages/utils/package.json
  • packages/hydrooj/src/commands/install.ts
  • packages/hydrooj/src/plugin-api.ts
  • packages/hydrooj/src/model/user.ts
  • packages/vjudge/src/index.ts
  • package.json
  • packages/ui-default/package.json
🧰 Additional context used
🧬 Code Definitions (12)
packages/hydrooj/src/entry/worker.ts (2)
packages/hydrooj/src/service/db.ts (1) (1)
  • MongoService (35-180)
packages/hydrooj/src/settings.ts (1) (1)
  • ConfigService (14-172)
packages/hydrooj/src/model/record.ts (2)
packages/hydrooj/src/model/document.ts (1) (1)
  • apply (413-447)
packages/hydrooj/src/model/task.ts (1) (1)
  • apply (145-191)
packages/hydrooj/src/service/db.ts (1)
packages/hydrooj/src/options.ts (1) (1)
  • load (24-37)
packages/hydrooj/src/service/bus.ts (6)
packages/hydrooj/src/context.ts (3) (3)
  • EventMap (13-13)
  • Context (31-41)
  • Context (68-77)
packages/hydrooj/src/plugin-api.ts (3) (3)
  • EventMap (57-57)
  • Handler (40-40)
  • Context (41-41)
framework/framework/interface.ts (1) (1)
  • VoidReturn (19-19)
packages/hydrooj/src/service/server.ts (1) (1)
  • Handler (74-76)
packages/ui-default/backendlib/template.ts (1) (1)
  • Context (254-275)
packages/ui-default/context.ts (2) (2)
  • Context (8-11)
  • Context (13-13)
packages/ui-default/backendlib/template.ts (3)
packages/hydrooj/src/plugin-api.ts (2) (2)
  • Service (41-41)
  • Context (41-41)
packages/ui-default/api.ts (3) (3)
  • Service (5-5)
  • ctx (5-5)
  • Context (5-5)
packages/hydrooj/src/model/builtin.ts (2) (2)
  • PERM (9-102)
  • PRIV (240-267)
packages/hydrooj/src/model/domain.ts (4)
packages/hydrooj/src/interface.ts (1) (1)
  • DomainDoc (306-314)
packages/hydrooj/src/service/bus.ts (1) (1)
  • apply (96-113)
packages/hydrooj/src/plugin-api.ts (2) (2)
  • Context (41-41)
  • db (58-58)
packages/hydrooj/src/service/db.ts (1) (1)
  • Context (58-66)
packages/hydrooj/src/model/setting.ts (4)
packages/hydrooj/src/interface.ts (1) (1)
  • Setting (46-56)
packages/hydrooj/src/service/check.ts (1) (1)
  • apply (77-80)
packages/hydrooj/src/context.ts (2) (2)
  • Context (31-41)
  • Context (68-77)
packages/hydrooj/src/service/db.ts (1) (1)
  • Context (58-66)
packages/hydrooj/src/interface.ts (1)
packages/common/types.ts (1) (1)
  • RecordJudgeInfo (84-96)
packages/hydrooj/src/entry/common.ts (4)
packages/ui-default/api.ts (2) (2)
  • ctx (5-5)
  • Context (5-5)
packages/hydrooj/src/plugin-api.ts (1) (1)
  • Context (41-41)
packages/hydrooj/src/context.ts (2) (2)
  • Context (31-41)
  • Context (68-77)
packages/hydrooj/src/utils.ts (1) (1)
  • unwrapExports (21-29)
packages/elastic/index.ts (4)
packages/hydrooj/src/plugin-api.ts (2) (2)
  • Service (41-41)
  • Context (41-41)
packages/hydrooj/src/settings.ts (1) (1)
  • Context (30-34)
packages/hydrooj/src/interface.ts (1) (1)
  • ProblemSearch (619-619)
packages/hydrooj/src/model/problem.ts (1) (1)
  • ProblemModel (74-675)
framework/framework/server.ts (8)
packages/ui-default/context.ts (4) (4)
  • ctx (18-18)
  • Service (16-17)
  • Context (8-11)
  • Context (13-13)
packages/hydrooj/src/service/layers/base.ts (1) (1)
  • ctx (20-72)
packages/hydrooj/src/service/layers/user.ts (1) (1)
  • ctx (5-18)
packages/hydrooj/src/service/layers/domain.ts (1) (1)
  • ctx (6-35)
packages/hydrooj/src/service/server.ts (2) (2)
  • HandlerCommon (31-39)
  • Handler (74-76)
packages/hydrooj/src/plugin-api.ts (4) (4)
  • HandlerCommon (7-7)
  • Handler (40-40)
  • Service (41-41)
  • Context (41-41)
framework/framework/interface.ts (1) (1)
  • KnownHandlers (3-5)
packages/hydrooj/src/context.ts (2) (2)
  • Context (31-41)
  • Context (68-77)
packages/hydrooj/src/model/document.ts (7)
packages/hydrooj/src/model/user.ts (1) (1)
  • coll (22-22)
packages/hydrooj/src/model/oplog.ts (1) (1)
  • coll (8-8)
packages/hydrooj/src/model/discussion.ts (1) (1)
  • coll (43-43)
packages/hydrooj/src/model/problem.ts (1) (1)
  • incStatus (431-436)
packages/hydrooj/src/model/token.ts (1) (1)
  • update (53-71)
packages/hydrooj/src/model/record.ts (1) (1)
  • update (195-219)
packages/hydrooj/src/service/monitor.ts (1) (1)
  • update (76-89)
🪛 Biome (1.9.4)
packages/hydrooj/src/handler/misc.ts

[error] 110-110: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)


[error] 124-124: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

packages/ui-default/backendlib/template.ts

[error] 46-46: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 121-121: eval() exposes to security risks and performance issues.

See the MDN web docs for more details.
Refactor the code so that it doesn't need to call eval().

(lint/security/noGlobalEval)

packages/hydrooj/src/model/domain.ts

[error] 138-138: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

packages/hydrooj/src/loader.ts

[error] 49-49: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

framework/framework/server.ts

[error] 139-139: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 140-140: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)

packages/hydrooj/src/handler/domain.ts

[error] 155-155: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 335-335: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

packages/hydrooj/src/model/document.ts

[error] 223-223: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

packages/ui-default/index.ts

[error] 56-56: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

🪛 GitHub Check: CodeQL
build/prepare.js

[failure] 166-166: Potential file system race condition
The file may have changed since it was checked.

🔇 Additional comments (125)
eslint.config.mjs (2)

19-21: Confirm the intended ECMAScript version.

Here, ecmaVersion is set to 5, but in the second block (lines 75-76), it’s set to 2020. If you’re expecting modern syntax features, please verify that this dual setting is intentional and doesn’t lead to contradictory linting outcomes.


110-114: Two-space indentation looks consistent.

Using two spaces across your project is a popular and readable convention. Great job keeping it consistent in this block.

framework/eslint-config/base.mjs (2)

243-249: Consistent use of quotes and semicolons.

Enforcing single quotes via '@stylistic/quotes' and requiring semicolons through '@stylistic/semi' ensures consistency across the codebase. This is a solid style choice.


279-343: Thorough naming-convention rules.

Your @typescript-eslint/naming-convention configuration is quite detailed, covering many selectors and patterns. This level of specificity can help keep a large, fast-moving codebase consistent.

framework/eslint-config/package.json (2)

5-5: Entry point updated.

Changing "main" from a YAML file to "base.mjs" aligns with your new JavaScript-based configuration approach. This is a straightforward improvement.


7-21: Verify compatibility of new dependencies.

Several new or upgraded ESLint plugins (@eslint-react/eslint-plugin, @eslint/compat, @eslint/eslintrc, @stylistic/eslint-plugin, etc.) may come with new rules or behaviors. Confirm they integrate well with pre-existing settings.

.github/workflows/build.yml (1)

66-66:

❓ Verification inconclusive

Updated Parallel Build Command
The change on line 66 removes the separate lint:ui:ci task in favor of running lint:ci, build, build:ui:production:webpack, and test in parallel when UI changes are detected (or the package version differs). Please verify that this adjustment aligns with the intended linting strategy for UI components and that no essential UI-specific linting is inadvertently skipped.


I'll run a shell script to verify that references to the removed lint:ui:ci task are indeed gone from the repository and to check that the remaining linting commands (specifically lint:ci) are correctly defined (for example, in the package.json file). This will help confirm that the updated parallel build command is in line with the intended linting strategy without accidentally skipping essential UI linting.

Please run these scripts and share the outputs to confirm the intended changes before finalizing the review comment.


🏁 Script executed:

#!/bin/bash
# Verify that references to "lint:ui:ci" have been removed from the repository.
echo "Searching for references to 'lint:ui:ci' in repository:"
rg "lint:ui:ci" -n .

# Check package.json for lint command definitions.
echo "Searching for 'lint:ci' in package.json:"
rg '"lint:ci":' package.json -n .

echo "Searching for 'lint:ui:ci' in package.json:"
rg '"lint:ui:ci":' package.json -n .

Length of output: 738


UI Linting Strategy Verification
The updated parallel build command on line 66 consolidates tasks by running lint:ci, build, build:ui:production:webpack, and test concurrently while removing the separate lint:ui:ci task. Our verification confirms that no references to lint:ui:ci exist in the repository and that lint:ci is defined in package.json. However, please ensure that the consolidated lint:ci adequately covers UI-specific linting checks so that no essential UI quality controls are missed.

  • Action Items:
    • Double-check that lint:ci now includes or does not omit critical linting for UI components.
    • Confirm that the parallel execution strategy aligns with your overall build and testing requirements.
packages/ui-default/backendlib/template.ts (9)

1-1: Imports look good.

These import statements are clear and organized, and they accurately reflect the required modules for this file.

Also applies to: 5-5, 7-7


119-129: Usage of eval is a known security risk.
This concern was previously raised. Reassess if eval is truly necessary, as it can open severe security vulnerabilities.

🧰 Tools
🪛 Biome (1.9.4)

[error] 121-121: eval() exposes to security risks and performance issues.

See the MDN web docs for more details.
Refactor the code so that it doesn't need to call eval().

(lint/security/noGlobalEval)


130-157: Exposing global objects in templates poses security risks.
This issue has been discussed previously. Consider limiting which objects and methods are available in the template environment to reduce the attack surface.


161-182: Handler creation logic appears sound.

The approach to customizing renderHTML based on domainId in the registry is well-structured. No immediate concerns.


183-215: Loader class handles template source resolution well.

The fallback to this.registry[templateName] and usage of .source references looks robust, especially in DEV mode where no-cache is enforced.


217-220: Sensible template existence checks.

Adding globals findSubModule and templateExists provides clarity on registry usage.


221-242: Consider implementing a real render timeout.
This recommendation was made in prior feedback—relying on logging slow renders can still block the server if rendering stalls for an extended time. A timeout could reject or abort rendering after a threshold.


244-252: Renderer registration

Registering “ui-default” as a fallback renderer is straightforward. The code is concise and ties neatly into the render promise.


254-275: Initialization logic is well-structured.

Templates are iterated from global.addons, read, and stored in this.registry with a safeguard in a try-catch block. This is a clean, maintainable approach.

packages/elastic/index.ts (8)

4-4: Imports are correct.

No issues found with these imports; they match the usage within the file.


20-24: Configuration schema is well-defined.

The Config object captures essential properties (url, indexSize) and defaults, providing clarity and type constraints.


26-26: Client property initialization is clear.

Defining client at the class level adds clarity to how Elasticsearch will be accessed.


28-32: Avoid logging full config in production environments.

console.log('elastic-search', config); may inadvertently expose secrets if config holds sensitive info (e.g., credentials). Consider masking or removing logs in production.


33-70: Search logic looks consistent.

The query with simple_query_string and domain-based post_filter is thorough. The fallback insertion of direct problem references is a good user-friendly touch.


34-34: Add proper type annotation for the “opts” parameter.

This was mentioned previously, ensuring opts has a well-defined structure (e.g., { limit?: number; skip?: number }) can help with clarity and reduce errors.


72-93: Refine the type definitions for the run method’s parameters.

Previously flagged. Adding explicit types for the destructured object and the report callback would enhance clarity.


95-125: Initialization method is solid.

Registering event listeners for problem changes and reindexing is logical. The usage of addScript to re-index is a convenient approach for admins.

packages/hydrooj/src/model/setting.ts (11)

3-3: Imports from @cordisjs/core and schemastery look appropriate.

Ensure schemastery is properly declared in your package dependencies to avoid any runtime import issues.

Also applies to: 7-7


73-81: Global declaration usage is clear.

Attaching family and secret to Schemastery’s meta interface can be helpful when generating specialized settings.


82-119: Potential coverage gap for nested or complex schemas.

Similar feedback was given before. The current logic does not handle deeper nested structures or arrays beyond simple cases.


121-160: User-facing setting registration.

Dynamically flattening Schema<any> or _Setting[] ensures flexibility. This code systematically merges them into the global arrays.


161-192: Domain-specific setting registration appears consistent.

No obvious issues; code merges domain and domain-user settings into dedicated arrays with minimal overhead.


193-210: System-level settings extended with schema or arrays.

Adopts the same pattern as preferences, account, and domain settings, maintaining consistency.


278-278: “join” setting usage.

This numeric “join” setting is hidden and disabled, indicating it’s used internally. Looks consistent with other hidden/disabled settings.


291-319: Schema-based system settings provide a robust example.

Using .extra('family', 'setting_smtp' or 'setting_server') effectively categorizes these settings, aiding organization.


359-359: Module augmentation for @cordisjs/core.

This extension allows the setting property to be typed on Context. The approach is standard.


388-388: Dependency injection for DB.

Exporting inject = ['db'] is consistent with the framework’s pattern, cleanly declaring the required dependencies.


395-395: Additional check for existing records.

Retrieving the current entry before creating a new setting avoids overwriting user changes. The fallback logic is straightforward.

packages/hydrooj/package.json (4)

3-3: Major version increment to 5.0.0-alpha.0

This represents a significant update marking the transition to Hydro v5. Ensure that all breaking changes are properly documented and that migration guides are available for users upgrading from v4.


19-21: Migrating from cordis to @cordisjs packages

The removal of the cordis dependency and addition of multiple @cordisjs/* packages represents a significant architectural change. This modular approach likely provides better separation of concerns and more flexibility.


22-22: Dependency updates across multiple packages

Multiple dependencies have been updated to newer versions, which may include bug fixes, performance improvements, and possibly API changes. These updates are generally good practice to maintain security and take advantage of improvements.

Also applies to: 28-28, 36-36, 46-46, 52-52, 55-55, 58-58, 67-67


44-44:

❓ Verification inconclusive

Major MongoDB version upgrade (5.x to 6.x)

The upgrade from MongoDB 5.9.2 to 6.15.0 is a major version change that may include breaking changes. Ensure all database interactions have been thoroughly tested with the new version.


🏁 Script executed:

#!/bin/bash
# Check for MongoDB driver version-specific API usage that might need updates
echo "Searching for MongoDB-specific API usage that might need updates:"
rg "db\.(collection|createCollection|createIndex|ensureIndex|dropIndex|dropCollection)" --type ts

Length of output: 10073


Attention: Verify MongoDB Driver Compatibility

The upgrade to MongoDB 6.15.0 introduces potential breaking changes that could affect our widespread use of MongoDB API calls. In particular, note the following:

  • Legacy Methods: Multiple files (e.g., in packages/hydrooj/src/upgrade.ts, packages/hydrooj/src/handler/status.ts, packages/hydrooj/src/model/document.ts, and packages/hydrooj/src/model/user.ts) use methods like ensureIndexes and initializeUnorderedBulkOp. Verify that these custom or legacy wrappers remain compatible with MongoDB 6.x APIs.
  • Bulk and Collection Operations: Since many modules rely on db.collection() and various bulk operations, ensure that all database interactions (including index creation, updating, and deletion) work as expected under the new driver version.

Please thoroughly test all database interactions and review any deprecated or modified API behaviors to prevent runtime issues.

build/prepare.js (7)

18-22: Updated JavaScript/TypeScript target and module settings

The changes to target (es2022), lib, module (preserve), and moduleResolution (bundler) settings reflect modernized build configuration. This enables the use of newer JavaScript features and better aligns with current bundling practices. The change from 'node' to 'bundler' moduleResolution is significant and matches the industry trend toward more sophisticated module bundling.


37-37: Added support for new UI-Next package

The addition of references to 'tsconfig.ui-next.json' and the new UINextConfig object suggests the introduction of a new UI package, likely using newer React patterns or an alternative framework. This separation allows for gradual migration or A/B testing of the new UI alongside the existing one.

Also applies to: 123-161


100-100: React JSX Transform Update

Changing from 'react' to 'react-jsx' enables the new JSX transform from React 17+, which no longer requires explicitly importing React in every component file. This aligns with modern React development practices.


103-120: Enhanced compiler options for modern web development

The additional compiler options such as useDefineForClassFields, moduleDetection, and various linting settings enhance type safety and code quality. The bundler mode settings are particularly relevant for modern web applications that use build tools like Vite or Webpack.


197-197: Improved file write operations

Using the new tryUpdate function for file operations reduces unnecessary writes by only updating files when their content has changed. This optimization can significantly improve build performance, especially in large projects with many configuration files.

Also applies to: 211-211, 219-219, 223-225


78-78: Simplified module filtering logic

The updated filtering logic for modules is more concise while maintaining the same functionality. It uses the some method to check if any of the exclusion patterns match, which is a more idiomatic JavaScript approach.


189-189: Added skipLibCheck option to pluginsConfig

The addition of skipLibCheck: true can improve build performance by skipping type checking of declaration files in dependencies. This is particularly useful for large projects with many dependencies, but be aware that it may hide type errors from third-party libraries.

packages/hydrooj/src/model/oauth.ts (1)

18-18: Updated database result access pattern

The change from res.value?.uid to res?.uid suggests an update in the MongoDB driver's return value structure or a change in how findOneAndUpdate is configured. This is consistent with MongoDB 6.x behavior when using the returnDocument: 'after' option.

Ensure this pattern is updated consistently across all database operations in the codebase. The MongoDB driver upgrade (from 5.x to 6.x) likely changes how results are structured.

packages/hydrooj/src/model/opcount.ts (1)

16-16: Updated database result access pattern

Similar to the change in oauth.ts, this updates how the result from MongoDB operations is accessed. The pattern has changed from res.value.opcount to res.opcount, which is consistent with MongoDB 6.x behavior.

This confirms a systematic update throughout the codebase to accommodate changes in the MongoDB driver API.

packages/hydrooj/src/model/blacklist.ts (1)

16-20:

❓ Verification inconclusive

API change: add method now returns the full MongoDB response.

The method now directly returns the result of findOneAndUpdate instead of just returning res.value. This change might affect code that expects only the document value rather than the full response object.


🏁 Script executed:

#!/bin/bash
# Search for usages of BlackListModel.add to check if any code relies on the return value
rg "BlackListModel\.add" --type ts

Length of output: 36


Action: Verify consumers of BlackListModel.add for correct handling of the full MongoDB response

The add method in packages/hydrooj/src/model/blacklist.ts now returns the entire response from MongoDB rather than just the document (i.e., it returns the value of findOneAndUpdate without extracting .value). This change may impact any consumers that expect only the updated document.

  • Please double-check that none of the consumers expect just the document value (as they might have been written to work with res.value previously).
  • Even though our initial search for direct usages of BlackListModel.add returned no results, a manual verification is recommended to ensure there are no indirect dependencies.
packages/hydrooj/src/model/record.ts (6)

23-23: Good addition of record history collection.

Adding a dedicated collection for record history is a good practice for maintaining the history of record changes.


236-237: Replace instanceof Array with Array.isArray().

Using instanceof Array may return false for array-like objects and arrays from different execution contexts. This can lead to unexpected behavior.

-const rids = rid instanceof Array ? rid : [rid];
+const rids = Array.isArray(rid) ? rid : [rid];

250-262: Well-implemented record history preservation.

The implementation correctly fetches records before deletion, extracts relevant fields using pick from lodash, and stores them in the history collection with a new ObjectId.


283-283: Changed apply to be async.

The function signature has been updated to make apply asynchronous. This is appropriate since it now handles async operations like database index creation.


324-327: Added proper index for the new collHistory collection.

A suitable index has been added for the new collection, which will optimize queries filtering by rid and sorting by _id.


212-217:

❓ Verification inconclusive

API change: update method now returns the full MongoDB response.

The method now directly returns the result of findOneAndUpdate instead of an intermediate variable. This change might affect code that expects a specific return value structure.


🏁 Script executed:

#!/bin/bash
# Search for usages of RecordModel.update to check if any code relies on the return value structure
rg "RecordModel\.update.*await" --type ts

Length of output: 43


I'll run a follow-up shell script to search for any occurrences of the RecordModel.update( pattern in the codebase to verify if there are any usages that could be impacted by the API change.


🏁 Script executed:

#!/bin/bash
rg "RecordModel\.update\(" --type ts

Length of output: 226


Attention: Verify Consumers of the Updated API Return Type

The RecordModel.update method in packages/hydrooj/src/model/record.ts now directly returns the full MongoDB response from findOneAndUpdate instead of an intermediate variable. This change could affect code that expects just the updated document. Notably, our search found calls to RecordModel.update in both:

  • packages/hydrooj/src/model/record.ts (line 212, where it calls return RecordModel.update(domainId, rid, upd);)
  • packages/hydrooj/src/upgrade.ts (usage within an upgrade operation)

Please verify these usages to ensure they handle the full MongoDB response correctly. Adjust the consuming code if expectations about the returned structure have changed.

packages/hydrooj/src/model/schedule.ts (2)

7-7: Import statement updated to match export type.

The import has been changed to match the default export pattern of the WorkerService. This ensures type consistency.


18-25:

❓ Verification inconclusive

API change: Direct MongoDB response object usage.

The code now uses the MongoDB response object directly instead of accessing the .value property. This simplifies the code but changes the function's return behavior.

-if (res.value) {
-    logger.debug('%o', res.value);
-    if (res.value.interval) {
-        const executeAfter = moment(res.value.executeAfter).add(...res.value.interval).toDate();
-        await coll.insertOne({ ...res.value, executeAfter });
-    }
-    return res.value;
+if (res) {
+    logger.debug('%o', res);
+    if (res.interval) {
+        const executeAfter = moment(res.executeAfter).add(...res.interval).toDate();
+        await coll.insertOne({ ...res, executeAfter });
+    }
+    return res;

🏁 Script executed:

#!/bin/bash
# Search for usages of ScheduleModel.getFirst to check if any code relies on the return value structure
rg "ScheduleModel\.getFirst|getFirst" --type ts

Length of output: 603


API Change: Verify Consumers for Direct MongoDB Response Usage

  • The code now directly returns the MongoDB response object (i.e., res) instead of extracting res.value. This simplifies the code, but it changes the function's return behavior.
  • Please confirm that all consumers of ScheduleModel.getFirst (for example, in packages/hydrooj/src/service/worker.ts and packages/hydrooj/src/model/task.ts) have been evaluated to ensure they correctly handle the full response object, rather than expecting just the document data.
packages/hydrooj/src/entry/worker.ts (4)

9-10: Improved service imports using named imports.

The code now imports specific service classes rather than the entire module, improving code clarity and potentially reducing bundle size.


24-34: Enhanced database initialization with dependency injection.

The worker now uses the MongoService.getUrl() method to get the database URL asynchronously and registers services as plugins. This is a cleaner approach than direct database initialization.


36-52: Improved dependency management with Promise-based injection.

The code now uses Promises to ensure dependencies are properly initialized before proceeding, enhancing the reliability of the startup sequence.


92-102: Streamlined server startup with dependency injection.

Server initialization is now handled through dependency injection, making the code more maintainable and testable. The previous imperative approach has been replaced with a more declarative pattern.

packages/utils/lib/utils.ts (3)

10-10: Import statement updated to include factory pattern components

This change updates the import statement to include Exporter and Factory from 'reggol', and renames the imported Logger to Reggol. This prepares for the implementation of a factory pattern for logger creation.


15-27: Added factory pattern for logger configuration

The implementation of a factory pattern for logger creation improves modularity and allows for centralized configuration. The factory is configured with specific display settings (showDiff, showTime, label formatting) and a timestamp.


29-31: Added createLogger function for consistent logger instances

This function encapsulates logger creation logic, promoting consistent logger instantiation throughout the application.

packages/hydrooj/src/service/db.ts (7)

7-7: Enhanced service integration with Context import

Importing the Context and Service classes allows for proper dependency injection and service registration.


11-11: Simplified bus import

Changed from namespace import to default import, matching the updated export pattern of the bus module.


29-33: Added proper Context type extension

This module declaration properly extends the Context interface to include the database service, enhancing type safety throughout the application.


35-41: Improved service architecture with inheritance

The MongoService now extends the Service base class and properly registers itself with the context, following the dependency injection pattern.


43-56: Extracted MongoDB URL resolution to static method

The getUrl static method encapsulates the logic for obtaining the MongoDB connection URL, including special handling for CI environments. This improves code organization and reusability.


58-66: Enhanced lifecycle management with Context.init

Replaced the start method with an async generator that yields a cleanup function, allowing for proper resource management during application lifecycle. The interval setting has been updated to use the context instead of direct setTimeout.


69-71: Improved configuration handling

Collection names now properly respect the configuration settings, including prefix and collection mapping, providing more flexibility for database configuration.

packages/hydrooj/src/model/task.ts (4)

9-9: Updated bus import pattern

Changed from namespace import to default import, aligning with the updated export pattern.


22-25: Simplified database result handling

The database result structure has been simplified, so the code now directly uses the result object instead of accessing a specific property. This change aligns with updates to the database service.


184-184: Updated event logging to match new result structure

Event logging now uses the simplified result object structure.


186-186: Updated event handling condition

The await condition now checks for the presence of the result directly rather than accessing the value property, matching the updated database response structure.

packages/hydrooj/src/handler/misc.ts (2)

17-17: Updated import for sortFiles utility

Import statement refined to specifically import only the required sortFiles function.


112-112: Enhanced security with dynamic link validation

Replaced static secret validation with a dynamic context-based validation through the storage service. This improves security by delegating validation to the appropriate service and removing hardcoded validation logic.

packages/hydrooj/src/service/worker.ts (1)

12-12:

❓ Verification inconclusive

Updated class export to use default export

The class declaration has been changed from a named export to a default export. This is a breaking change that requires updating import statements throughout the codebase.


🏁 Script executed:

#!/bin/bash
# Find all imports of WorkerService to verify they've been updated to use default import

rg "import.*WorkerService.*from ['|\"].*worker" --type=ts

Length of output: 152


Action: Verify All Default Import Usages for WorkerService

I confirmed that in packages/hydrooj/src/model/schedule.ts the WorkerService import is now using a default import (via a type-only import:

import type WorkerService from '../service/worker';
```) which is consistent with the change in *packages/hydrooj/src/service/worker.ts*. Please double-check that there are no remaining named import statements (e.g., using curly braces) anywhere else in the codebase—especially for runtime usages—as this change to a default export is breaking.

</details>
<details>
<summary>packages/hydrooj/src/service/bus.ts (4)</summary>

`4-4`: **Updated import to use explicit type import**

The import statement now explicitly imports only the `Handler` type from the framework package, which improves code clarity.

---

`17-17`: **Simplified EventMap interface definition**

The `EventMap` interface no longer extends `KnownHandlerEvents`, which reduces coupling and simplifies the event handling structure.

---

`87-87`: **Improved type safety for oplog/log event handler**

The `oplog/log` event's handler type has been refined to specify `Handler<Context>` instead of a generic `Handler`, providing better type safety and context specificity.

---

`32-32`: <details>
<summary>✅ Verification successful</summary>

**Refined bus/broadcast event type signature**

The type signature for the `bus/broadcast` event has been updated to only reference `keyof EventMap` instead of also including `keyof ServerEvents`. This change simplifies the event type system.

---

🏁 Script executed:

```shell
#!/bin/bash
# Check for potential type errors in bus/broadcast event calls
# Look for any usage of bus/broadcast with events that might not be in EventMap

rg "bus/broadcast.*" --type=ts -A 1 -B 1

Length of output: 1671


Verified: Bus Broadcast Event Signature Update is Consistent Across the Codebase

The refinement to use only keyof EventMap for the bus/broadcast event is consistent with its usages across the repository. The search output confirms that all relevant call sites pass the appropriate parameters according to the updated signature, and there is no evidence of type conflicts or misusage introduced by removing keyof ServerEvents.

packages/hydrooj/src/interface.ts (3)

2-2: Updated import for WebAuthn types

The import statement has been updated to include ParsedAuthenticatorData from the SimpleWebAuthn server helpers, supporting the improved type definition for authenticator extensions.


83-83: Enhanced type precision for authenticator extensions

The authenticatorExtensionResults property type has been changed from AuthenticationExtensionsAuthenticatorOutputs to ParsedAuthenticatorData['extensionsData'], providing more accurate typing.


226-229: Added RecordHistoryDoc interface for record history tracking

A new interface for historical record documents has been added, extending RecordJudgeInfo with identifiers. This interface is properly referenced in the database collections type definitions.

packages/hydrooj/src/settings.ts (3)

14-172: Introduced ConfigService class for improved configuration management

The new ConfigService class encapsulates all configuration-related functionality, replacing previous standalone functions and global variables. This change aligns with the broader refactoring to reduce global assignments and improve modularity.

This is a significant architectural improvement that:

  1. Enhances encapsulation of configuration data
  2. Provides structured methods for configuration operations
  3. Implements schema validation for configuration values
  4. Includes blacklisting to prevent prototype pollution
  5. Supports configuration migration between formats

153-171: Improved logic in getAccess function

Line 159 now correctly checks if currentValue is falsy, addressing a previous issue where it would return the entire config object instead of the specific value.


55-67:

❓ Verification inconclusive

Potential prototype pollution concern in applyDelta

While the code includes blacklist checks to prevent prototype pollution, the assignment at line 65 could still be vulnerable if malicious property names make it past the check.

Even though there's a blacklist check at line 57, consider implementing additional safeguards or using a specialized library like lodash.set to safely apply property updates.


🏁 Script executed:

#!/bin/bash
# Check if the prototype pollution issue has been addressed elsewhere
rg "__proto__" --type=ts
rg "hasOwnProperty" --type=ts

Length of output: 153


Action Required: Revisit Prototype Pollution Safeguards

  • The function applyDelta (packages/hydrooj/src/settings.ts, lines 55–67) already checks for blacklisted keys ('__proto__', 'prototype', and 'constructor') across the entire property path. However, the assignment at line 65 is executed after the check, which means that if a malicious key slips through a potential gap (e.g., via a non-exact string bypass or other edge cases), the update could still trigger prototype pollution.
  • Although the blacklist exists—as confirmed by the grep result—we currently do not see additional checks (e.g., using hasOwnProperty or a trusted library), which might further reduce risk.
  • Recommendation: Reassess whether relying solely on the blacklist is sufficient. Consider incorporating extra safeguards, such as employing a secure property update method (for example, using lodash.set or a similar utility) to perform the deep update safely.
packages/ui-default/index.ts (4)

77-77: Good refactoring to use context-based configuration.

Switching from SystemSettings to this.ctx.config.settings improves dependency management by using the context-provided configuration.


3-7: Good architectural improvements to imports and dependencies.

Removing the direct SystemSettings import and adding TemplateService as a proper injectable service improves the architecture and modularity of the code.


25-25: Improved type safety with explicit type annotation.

Adding an explicit type for the sections array enhances code readability and type safety.


167-167: Good transition to plugin-based architecture.

Using ctx.plugin(TemplateService) instead of requiring the module directly improves dependency management and follows a better architectural pattern.

packages/hydrooj/src/loader.ts (6)

147-153: Good conversion to async for improved control flow.

Converting preload to an async function enhances error handling and provides better control over the initialization sequence. Using await for promises is a solid improvement.


98-107: Well-structured configuration management.

Adding the resolveConfig method as part of the class provides better encapsulation and a more consistent API. The use of Schema for configuration management is a good practice.


109-126: Improved plugin reload mechanism.

The updated reloadPlugin method simplifies the API and provides better error handling. Using this.ctx.plugin directly is cleaner than the previous approach.


15-17: Improved import structure for better type safety.

The structured imports from context.ts improve code readability and type checking capabilities.


170-172: Good async/await pattern adoption.

Making load and loadCli functions async and awaiting preload ensures proper sequencing of initialization steps, which is especially important for application startup.

Also applies to: 208-211


59-86: Improved event listener implementation.

The event listener now consistently uses ctx instead of mixing global access patterns, which improves code maintainability and testability.

packages/hydrooj/src/model/domain.ts (6)

136-137: Good enhancement to support user auto-joining.

Adding the autojoin parameter with a default value preserves backward compatibility while extending functionality. The conditional spread operator usage is clean and efficient.


292-312: Excellent restructuring with apply pattern.

The new apply function centralizes event handling and database index setup, improving the organization of initialization code. This pattern makes the code more maintainable and testable.


131-132: Improved query filtering with join condition.

Adding the join: true condition to queries ensures only users who have actually joined the domain are counted or returned, which is more accurate.


104-108: Simplified return value for better API consistency.

Directly returning the result from the database operation simplifies the API and makes it more consistent with other methods.


119-120: Cleaner return statement for field value.

Directly returning the updated field value makes the API more intuitive and easier to use.


259-259: Improved query filtering for domain users.

Adding join: true to the query ensures only users who have actually joined domains are returned, providing more accurate results.

packages/hydrooj/src/entry/common.ts (6)

24-25: Improved type safety with more specific type definitions.

Simplifying the LoadTask type and using Record<string, string> for the pending parameter provides better type safety and self-documentation.


26-30: Enhanced iteration with object entries.

Changing from array iteration to Object.entries and renaming variables improves code readability and makes the relationship between keys and values clearer.


32-32: Simplified plugin loading API.

The updated API call to ctx.loader.reloadPlugin with simplified parameters makes the code more maintainable and aligns with the updated Loader implementation.


56-56: Consistent plugin loading approach.

Using the same simplified reloadPlugin API in builtinModel ensures consistency across the codebase.


60-61: Improved parameter typing in locale function.

Changing the pending parameter to Record<string, string> and using Object.values for iteration provides better type safety and aligns with the overall refactoring.


83-90: Consistent parameter typing in setting function.

Similar to the locale function, the setting function now uses consistent parameter typing, which improves the overall code quality.

packages/hydrooj/src/handler/domain.ts (5)

105-147: Good optimization by using MongoDB aggregation pipeline

The refactoring of the query to use an aggregation pipeline is a significant improvement. This approach allows for more efficient data retrieval by filtering users and joining with the user collection in a single database operation, reducing the need for additional queries.


258-258: Simplified role filtering logic

The filtering logic has been optimized to only exclude the 'guest' role instead of both 'default' and 'guest'. This makes the role management process more flexible by allowing users with the 'default' role to be displayed.


322-337: Enhanced flexibility with target parameter

Adding the target parameter to the prepare method enhances flexibility by allowing operations on a different domain than the current one. The implementation correctly checks if the user is already a member of the target domain and retrieves roles based on the specified target domain document.

🧰 Tools
🪛 Biome (1.9.4)

[error] 335-335: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


340-357: Improved domain join GET handler with target parameter

The get method has been enhanced to accept target and redirect parameters, which improves flexibility when handling domain join requests. The response body now includes detailed domain information, providing a better user experience.


361-376: Dynamic role assignment in domain join POST handler

The post method now includes the target and redirect parameters, improving the redirect functionality and making the user role assignment more dynamic based on the target domain's join settings.

packages/hydrooj/src/model/document.ts (4)

12-12: Updated import syntax for bus module

Changed from importing all exports to importing the default export, which aligns with modern ES module practices and indicates that bus is likely exported as a default export in the source module.


23-33: Enhanced type safety with const assertions

Changing from explicit type annotations to using TypeScript's as const assertion enhances type safety and provides better inference for const objects. This change also makes the code more maintainable by ensuring the type is derived from the value automatically.


112-117: Simplified return statements for database operations

Functions have been streamlined by directly returning the result of database operations rather than storing them in intermediate variables. This makes the code more concise and easier to follow without affecting functionality.

Also applies to: 152-157, 163-168, 211-217, 224-230, 255-265, 271-277, 301-311, 328-333, 358-363, 369-374, 397-402


385-391: Improved null handling with nullish coalescing assignment

The use of the nullish coalescing assignment operator (||=) is a modern JavaScript feature that simplifies the code and makes it more readable. Good improvement!

framework/framework/server.ts (6)

5-5: Updated import to use CordisContext

Renaming the imported Context to CordisContext helps clarify the source of the context type and avoids potential naming conflicts with local context implementations.


44-52: New async function for context scope management

The forkContextWithScope function is a good addition that provides a clean way to create and manage context scopes with automatic cleanup using the Symbol.asyncDispose pattern. This helps prevent memory leaks and ensures proper resource management.


210-212: Enhanced type safety with generic parameters

The addition of generic type parameters to Handler, ConnectionHandler, NotFoundHandler, and WebService classes significantly improves type safety across the framework. This allows for better integration with varying context types while maintaining core functionality.

Also applies to: 258-260, 297-297, 337-352


478-478: Improved server startup logging

Using the logger.success method with a template string is a small but good improvement that makes the server startup message more visible and informative.


487-612: Improved HTTP and WebSocket request handling

The refactoring of the handleHttp and handleWS methods with proper context scoping and cleanup operations enhances resource management and error handling. The use of using with the new forkContextWithScope ensures resources are properly disposed of.


841-848: Improved type declarations with module augmentation

The module augmentation for @cordisjs/core enhances type safety by properly typing the methods added to the Context interface. This ensures that TypeScript can correctly check the usage of these methods throughout the codebase.

Comment on lines +26 to +27
"optionalDependencies": {
"typescript": "^5.8.2"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Optional typescript dependency.

Bundling typescript as optional may lead to confusion if linting TypeScript files is a core usage scenario. If you expect TS usage across all teams, consider making it a direct or peer dependency instead.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (8)
packages/ui-default/backendlib/template.ts (2)

120-128: ⚠️ Potential issue

Avoid using eval and exposing global objects.

Using eval() and exposing JavaScript's global objects like Date, Object, String, etc. to templates can introduce significant security risks including remote code execution, prototype pollution, and information disclosure.

🧰 Tools
🪛 Biome (1.9.4)

[error] 121-121: eval() exposes to security risks and performance issues.

See the MDN web docs for more details.
Refactor the code so that it doesn't need to call eval().

(lint/security/noGlobalEval)


221-242: 🛠️ Refactor suggestion

Add timeout handling to prevent long-running renders.

While there's logging for slow renders (>5000ms), there's no actual timeout mechanism to prevent extremely long-running renders from blocking the server.

packages/elastic/index.ts (2)

97-116: 🛠️ Refactor suggestion

Add error handling to event handlers

The event handlers in the Context.init method don't include error handling, which could lead to unhandled promise rejections if operations fail.

        this.ctx.on('problem/add', async (doc, docId) => {
+           try {
                await this.client.index({
                    index: 'problem',
                    id: `${doc.domainId}/${docId}`,
                    document: processDocument(doc),
                });
+           } catch (error) {
+               this.ctx.logger.error(`Error indexing problem: ${error.message}`);
+           }
        });

Apply similar error handling to the other event handlers as well.


122-123: 🛠️ Refactor suggestion

Add error handling to script execution

The script registration doesn't include error handling for the run method when used as a callback.

-            this.run.bind(this),
+            async (...args) => {
+                try {
+                    return await this.run.bind(this)(...args);
+                } catch (error) {
+                    this.ctx.logger.error(`Error in ensureElasticSearch script: ${error.message}`);
+                    throw error;
+                }
+            },
packages/hydrooj/src/settings.ts (1)

55-67: ⚠️ Potential issue

Potential prototype pollution still possible in applyDelta

While the code checks for blacklisted properties, the assignment at line 65 (cursor[t] = value) could still be vulnerable to prototype pollution if t contains malicious values that bypass the blacklist check.

Consider using a safer property assignment method:

- cursor[t] = value;
+ Object.defineProperty(cursor, t, { 
+   value,
+   writable: true,
+   enumerable: true,
+   configurable: true 
+ });

Or use an established library like Lodash's _.set() which has protection against prototype pollution.

framework/framework/server.ts (3)

139-140: 🛠️ Refactor suggestion

Fix unsafe declaration merging.

Declaring both an interface and a class with the same name can lead to unsafe declaration merging in TypeScript. The linter correctly flags this pattern.

-export interface HandlerCommon<C> { } // eslint-disable-line @typescript-eslint/no-unused-vars
+// Consider removing or using a type alias if needed:
+// type HandlerCommonProps<C> = {}

export class HandlerCommon<C> {
  // ...
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 139-139: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 140-140: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)


498-501: 🛠️ Refactor suggestion

Address FIXME comments for type checking.

Multiple locations use type assertions to any with FIXME comments about passing type checks. These should be properly typed rather than bypassing TypeScript's type system.

Create proper type definitions for the event handlers to avoid type assertions:

// In your interfaces file:
interface HandlerEvents<T> {
  'handler/create': [handler: T, type: 'http' | 'ws'];
  'handler/create/http': [handler: T];
  'handler/create/ws': [handler: T];
  'handler/error': [handler: T, error: Error];
  'connection/create': [handler: T];
  'connection/active': [handler: T];
  'connection/close': [handler: T];
}

// Then update your context interface to include these typed events
interface C extends CordisContext {
  parallel<E extends keyof HandlerEvents<T>, T>(event: E, ...args: HandlerEvents<T>[E]): Promise<void>;
  serial<E extends keyof HandlerEvents<T>, T>(event: E, ...args: HandlerEvents<T>[E]): Promise<void>;
}

Also applies to: 537-538, 552-554, 569-570, 604-605, 616-618, 656-657


676-678: ⚠️ Potential issue

Fix condition that always evaluates to false.

The static analysis tool flags that the condition if (perm) at line 705 always evaluates to false, indicating a potential logic error in the function.

In the check function, the condition appears to not work as intended. Verify the initialization and type of the perm variable to ensure it can properly evaluate to true when permissions exist:

 return function check(this: Handler<C>) {
   checker();
-  if (perm) this.checkPerm(perm);
+  // Fix the condition to properly check for permissions
+  if (perm !== undefined && perm !== null) this.checkPerm(perm);
   if (priv) this.checkPriv(priv);
 };

Also applies to: 705-705

🧹 Nitpick comments (23)
.github/workflows/build.yml (2)

64-69: Parallel Execution Command Update: Verify UI Linting Coverage

The updated parallel command (line 66) now runs the tasks lint:ci, build, build:ui:production:webpack, and test—thereby omitting the previously included lint:ui:ci step. Please confirm that UI-specific linting is either no longer required or is covered by another mechanism to ensure overall code quality remains intact.


64-64: UI Iconfont Build Step: Confirm Expected Behavior

The yarn build:ui:iconfont command (line 64) runs when UI-related files have changed. Verify that this step correctly generates the icon fonts and that its output integrates as expected with the downstream UI build and production processes.

packages/ui-default/backendlib/template.ts (4)

46-46: Enhance code safety with optional chaining.

The current code checks for obj being undefined or null, but still accesses obj._original directly. Use optional chaining to make this access safer.

-  if ((obj || {})._original) obj = obj._original;
+  if (obj?._original) obj = obj._original;
🧰 Tools
🪛 Biome (1.9.4)

[error] 46-46: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


25-34: Optimize file discovery for large directory structures.

The recursive getFiles function could become inefficient for large directory structures. Consider adding pagination or limiting the depth of recursion for better performance.

-async function getFiles(folder: string, base = ''): Promise<string[]> {
+async function getFiles(folder: string, base = '', maxDepth = 10): Promise<string[]> {
  const files: string[] = [];
  const f = await fs.readdir(folder);
  for (const i of f) {
    if ((await fs.stat(path.join(folder, i))).isDirectory()) {
+      // Skip recursion if we've reached maximum depth
+      if (maxDepth <= 0) continue;
-      files.push(...await getFiles(path.join(folder, i), path.join(base, i)));
+      files.push(...await getFiles(path.join(folder, i), path.join(base, i), maxDepth - 1));
    } else files.push(path.join(base, i));
  }
  return files.map((item) => item.replace(/\\/gmi, '/'));
}

36-42: Improve error message in file location function.

The locateFile function returns null without any context on why the file wasn't found. Consider returning a more descriptive error or adding logging.

function locateFile(basePath: string, filenames: string[]) {
  for (const i of filenames) {
    const p = path.resolve(basePath, i);
    if (fs.existsSync(p)) return p;
  }
+ // Log which files were attempted
+ console.debug(`Could not locate any of the following files in ${basePath}:`, filenames);
  return null;
}

254-275: Consider adding graceful template fallback.

When templates fail to load, the current code logs errors and injects a notification, but there's no fallback mechanism. Consider implementing a default template system that can be used when custom templates fail.

Would you like me to suggest a fallback implementation that ensures the system remains functional even when templates fail to load?

packages/hydrooj/src/model/oauth.ts (1)

12-19: Consider adding type annotations and improved error handling.

The set method would benefit from explicit return type annotations and error handling. Since res?.uid could return undefined when no document is created or when the returned document structure is unexpected, it would be more consistent to return null like the get method does.

-    static async set(_id: string, uid: number) {
+    static async set(_id: string, uid: number): Promise<number | null> {
         const res = await coll.findOneAndUpdate(
             { _id },
             { $set: { uid } },
             { upsert: true, returnDocument: 'after' },
         );
-        return res?.uid;
+        return res?.uid || null;
     }
packages/elastic/index.ts (1)

30-30: Remove debugging console.log

There's a console.log statement that should be replaced with proper logging using the service's logger.

-        console.log('elastic-search', config);
+        this.logger.debug('Initializing elastic-search service', config);
packages/hydrooj/src/handler/domain.ts (2)

150-157: Performance concern with delete operator

Using the delete operator on u.user might impact performance. Consider using object destructuring with rest parameters instead.

-            const u = {
-                ...dudoc,
-                ...dudoc.user,
-            };
-            delete u.user;
-            return u;
+            const { user: userData, ...rest } = dudoc;
+            return { ...rest, ...userData };
🧰 Tools
🪛 Biome (1.9.4)

[error] 155-155: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


334-336: Simplify conditional logic for joinSettings

The conditional logic for setting joinSettings could be simplified for better readability.

-        if (assignedRole !== 'default') delete this.joinSettings;
-        else if (!this.joinSettings) throw new DomainJoinForbiddenError(target);
+        if (assignedRole !== 'default') {
+            this.joinSettings = undefined;
+        } else if (!this.joinSettings) {
+            throw new DomainJoinForbiddenError(target);
+        }
🧰 Tools
🪛 Biome (1.9.4)

[error] 335-335: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

packages/hydrooj/src/model/blacklist.ts (1)

16-20: Function simplified by removing intermediate variable.

The add method has been simplified to directly return the result of findOneAndUpdate instead of storing it in a temporary variable and returning res.value. This changes the return type from Promise<{ value: any }> to Promise<any>.

Consider documenting this return type change in JSDoc to ensure consumers of this API are aware of the change:

@ArgMethod
+ /**
+  * Add an entry to the blacklist.
+  * @returns The complete result object from the findOneAndUpdate operation
+  */
static async add(id: string, expire?: Date | number) {
eslint.config.mjs (4)

1-2: Check the necessity of disabling rules globally.

Disabling max-len and @typescript-eslint/naming-convention at the file level may be too broad. Instead, consider selectively disabling or customizing these rules to accommodate specific project needs.


8-15: Refine ignore patterns if needed.

The provided ignore patterns may skip linting for files that should remain under lint coverage (e.g., transpiled .js files in certain directories). Confirm that they accurately target only unneeded files.


39-53: Evaluate warning vs. error levels.

@typescript-eslint/no-invalid-this is set to a warning. Decide if upgrading to an error level better suits your codebase, reducing potential runtime issues.


138-149: Extend or unify UI config if desired.

The UI config block is narrower, which might lead to inconsistent lint rules. Consider extending the base config or ensuring partial coverage is intentional.

framework/eslint-config/base.mjs (3)

30-43: Ensure correct TypeScript path resolution.

Your 'import/resolver' includes .mjs and .ts among others. Confirm that TypeScript path aliases and resolution logic are fully satisfied.


54-63: Confirm required TypeScript settings.

@typescript-eslint/parser is specified, but ensure the TS version meets or exceeds the minimum needed for new language features.


455-482: Defer checks to TSC.

Turning off many base rules for .ts files is common when letting the TypeScript compiler handle them. Ensure tsconfig.json enforces stricter checks as needed.

packages/hydrooj/src/settings.ts (1)

164-169: Fire-and-forget pattern in Proxy setter

The set method doesn't await the setConfig call, which could lead to silent failures if the database update fails.

Consider making the proxy setter handle async operations properly:

- set(self, p: string | symbol, newValue: any) {
-   that.setConfig(path.concat(p).join(','), newValue);
-   return true;
- },
+ set(self, p: string | symbol, newValue: any) {
+   // Return true immediately but trigger the async update
+   that.setConfig(path.concat(p).join(','), newValue)
+     .catch((err) => that.ctx.logger.error('Failed to set config:', err));
+   return true;
+ },
packages/hydrooj/src/model/domain.ts (1)

138-138: Use Array.isArray() instead of instanceof Array

Using instanceof Array can return false for arrays from other execution contexts or for array-like objects. This could lead to unexpected behavior.

- if (!(uid instanceof Array)) {
+ if (!Array.isArray(uid)) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 138-138: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

packages/hydrooj/src/loader.ts (1)

49-49: Avoid using {} as a type

Using {} as a type means "any non-nullable value" which is too loose and can lead to type safety issues.

- public config: {};
+ public config: Record<string, unknown>;
🧰 Tools
🪛 Biome (1.9.4)

[error] 49-49: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

packages/hydrooj/src/model/document.ts (1)

223-223: Use Array.isArray() instead of instanceof Array.

The instanceof Array check can return false for array-like objects and arrays from other execution contexts, making it less reliable for type checking.

-    subId = (subId instanceof Array) ? subId : [subId];
+    subId = Array.isArray(subId) ? subId : [subId];
🧰 Tools
🪛 Biome (1.9.4)

[error] 223-223: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

framework/framework/server.ts (1)

744-749: Fix the type signature for Route handlers.

The route handler type has been improved, but there are commented out console.log statements that should be removed.

public Route(name: string, path: string, RouteHandler: typeof Handler<C>, ...permPrivChecker) {
-    // if (name === 'contest_scoreboard') {
-    //     console.log('+++', this.ctx);
-    //     console.log(this.ctx.scoreboard);
-    // }
    return this.register('route', name, path, RouteHandler, ...permPrivChecker);
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0bd15ca and f8ed636.

📒 Files selected for processing (94)
  • .eslintrc.yaml (0 hunks)
  • .github/workflows/build.yml (1 hunks)
  • build/prepare.js (5 hunks)
  • eslint.config.mjs (1 hunks)
  • framework/eslint-config/base.mjs (1 hunks)
  • framework/eslint-config/base.yaml (0 hunks)
  • framework/eslint-config/package.json (1 hunks)
  • framework/eslint-config/react.yaml (0 hunks)
  • framework/eslint-config/typescript.js (0 hunks)
  • framework/framework/error.ts (0 hunks)
  • framework/framework/server.ts (22 hunks)
  • package.json (2 hunks)
  • packages/elastic/index.ts (2 hunks)
  • packages/hydrojudge/src/cases.ts (0 hunks)
  • packages/hydrojudge/src/checkers.ts (4 hunks)
  • packages/hydrojudge/src/daemon.ts (0 hunks)
  • packages/hydrojudge/src/hosts/hydro.ts (0 hunks)
  • packages/hydrojudge/src/hosts/vj4.ts (1 hunks)
  • packages/hydrojudge/src/judge/hack.ts (4 hunks)
  • packages/hydrooj/package.json (3 hunks)
  • packages/hydrooj/src/commands/install.ts (1 hunks)
  • packages/hydrooj/src/entry/cli.ts (2 hunks)
  • packages/hydrooj/src/entry/common.ts (2 hunks)
  • packages/hydrooj/src/entry/setup.ts (0 hunks)
  • packages/hydrooj/src/entry/worker.ts (3 hunks)
  • packages/hydrooj/src/handler/contest.ts (0 hunks)
  • packages/hydrooj/src/handler/domain.ts (3 hunks)
  • packages/hydrooj/src/handler/misc.ts (3 hunks)
  • packages/hydrooj/src/handler/problem.ts (1 hunks)
  • packages/hydrooj/src/interface.ts (6 hunks)
  • packages/hydrooj/src/loader.ts (6 hunks)
  • packages/hydrooj/src/model/blacklist.ts (1 hunks)
  • packages/hydrooj/src/model/contest.ts (7 hunks)
  • packages/hydrooj/src/model/document.ts (11 hunks)
  • packages/hydrooj/src/model/domain.ts (9 hunks)
  • packages/hydrooj/src/model/message.ts (3 hunks)
  • packages/hydrooj/src/model/oauth.ts (1 hunks)
  • packages/hydrooj/src/model/opcount.ts (1 hunks)
  • packages/hydrooj/src/model/problem.ts (1 hunks)
  • packages/hydrooj/src/model/record.ts (8 hunks)
  • packages/hydrooj/src/model/schedule.ts (2 hunks)
  • packages/hydrooj/src/model/setting.ts (11 hunks)
  • packages/hydrooj/src/model/storage.ts (6 hunks)
  • packages/hydrooj/src/model/system.ts (3 hunks)
  • packages/hydrooj/src/model/task.ts (3 hunks)
  • packages/hydrooj/src/model/token.ts (2 hunks)
  • packages/hydrooj/src/model/user.ts (8 hunks)
  • packages/hydrooj/src/plugin-api.ts (2 hunks)
  • packages/hydrooj/src/script/problemStat.ts (0 hunks)
  • packages/hydrooj/src/script/storageUsage.ts (0 hunks)
  • packages/hydrooj/src/service/bus.ts (5 hunks)
  • packages/hydrooj/src/service/db.ts (3 hunks)
  • packages/hydrooj/src/service/worker.ts (2 hunks)
  • packages/hydrooj/src/settings.ts (1 hunks)
  • packages/hydrooj/src/ui.ts (1 hunks)
  • packages/migrate/package.json (1 hunks)
  • packages/onlyoffice/frontend/office.page.ts (0 hunks)
  • packages/onsite-toolkit/frontend/resolver.page.tsx (2 hunks)
  • packages/ui-default/.eslintignore (0 hunks)
  • packages/ui-default/.eslintrc.js (0 hunks)
  • packages/ui-default/api.ts (0 hunks)
  • packages/ui-default/backendlib/builder.ts (4 hunks)
  • packages/ui-default/backendlib/markdown-it-imsize.ts (1 hunks)
  • packages/ui-default/backendlib/markdown-it-media.ts (0 hunks)
  • packages/ui-default/backendlib/misc.ts (1 hunks)
  • packages/ui-default/backendlib/template.ts (3 hunks)
  • packages/ui-default/build/config/webpack.ts (1 hunks)
  • packages/ui-default/build/main.ts (1 hunks)
  • packages/ui-default/components/autocomplete/components/AutoComplete.tsx (3 hunks)
  • packages/ui-default/components/autocomplete/components/UserSelectAutoComplete.tsx (1 hunks)
  • packages/ui-default/components/calendar/index.js (2 hunks)
  • packages/ui-default/components/message/worker.ts (1 hunks)
  • packages/ui-default/components/problemconfig/ProblemConfigEditor.tsx (1 hunks)
  • packages/ui-default/components/problemconfig/ProblemConfigTree.tsx (1 hunks)
  • packages/ui-default/components/problemconfig/reducer/config.ts (1 hunks)
  • packages/ui-default/components/problemconfig/tree/AddTestcase.tsx (1 hunks)
  • packages/ui-default/components/problemconfig/tree/SubtaskSettings.tsx (1 hunks)
  • packages/ui-default/components/problemconfig/tree/Testcase.tsx (1 hunks)
  • packages/ui-default/components/scratchpad/DataInputComponent.jsx (0 hunks)
  • packages/ui-default/components/scratchpad/ScratchpadToolbarContainer.jsx (0 hunks)
  • packages/ui-default/index.ts (6 hunks)
  • packages/ui-default/package.json (5 hunks)
  • packages/ui-next/package.json (1 hunks)
  • packages/ui-next/src/App.tsx (1 hunks)
  • packages/utils/lib/locate-pm2.ts (1 hunks)
  • packages/utils/lib/utils.ts (1 hunks)
  • packages/utils/package.json (2 hunks)
  • packages/vjudge/src/index.ts (3 hunks)
  • packages/vjudge/src/providers/codeforces.ts (0 hunks)
  • packages/vjudge/src/providers/hduoj.ts (0 hunks)
  • packages/vjudge/src/providers/poj.ts (0 hunks)
  • packages/vjudge/src/providers/spoj.ts (0 hunks)
  • packages/vjudge/src/providers/uoj.ts (0 hunks)
  • packages/vjudge/src/providers/yacs.ts (0 hunks)
💤 Files with no reviewable changes (25)
  • packages/ui-default/components/scratchpad/ScratchpadToolbarContainer.jsx
  • packages/hydrooj/src/script/storageUsage.ts
  • packages/ui-default/backendlib/markdown-it-media.ts
  • framework/eslint-config/base.yaml
  • packages/vjudge/src/providers/uoj.ts
  • packages/vjudge/src/providers/yacs.ts
  • packages/hydrojudge/src/hosts/hydro.ts
  • packages/ui-default/.eslintignore
  • packages/hydrojudge/src/cases.ts
  • packages/onlyoffice/frontend/office.page.ts
  • framework/eslint-config/react.yaml
  • packages/ui-default/api.ts
  • framework/framework/error.ts
  • packages/ui-default/components/scratchpad/DataInputComponent.jsx
  • packages/vjudge/src/providers/codeforces.ts
  • packages/hydrooj/src/script/problemStat.ts
  • packages/vjudge/src/providers/hduoj.ts
  • packages/vjudge/src/providers/poj.ts
  • packages/hydrooj/src/entry/setup.ts
  • packages/hydrojudge/src/daemon.ts
  • framework/eslint-config/typescript.js
  • packages/vjudge/src/providers/spoj.ts
  • packages/hydrooj/src/handler/contest.ts
  • packages/ui-default/.eslintrc.js
  • .eslintrc.yaml
✅ Files skipped from review due to trivial changes (14)
  • packages/ui-default/components/problemconfig/ProblemConfigEditor.tsx
  • packages/ui-default/components/problemconfig/ProblemConfigTree.tsx
  • packages/ui-default/build/main.ts
  • packages/ui-default/components/problemconfig/reducer/config.ts
  • packages/ui-default/build/config/webpack.ts
  • packages/ui-default/backendlib/markdown-it-imsize.ts
  • packages/ui-default/components/problemconfig/tree/Testcase.tsx
  • packages/ui-default/components/calendar/index.js
  • packages/ui-default/backendlib/misc.ts
  • packages/hydrojudge/src/hosts/vj4.ts
  • packages/ui-default/components/message/worker.ts
  • packages/ui-default/components/problemconfig/tree/AddTestcase.tsx
  • packages/ui-default/components/problemconfig/tree/SubtaskSettings.tsx
  • packages/utils/lib/locate-pm2.ts
🚧 Files skipped from review as they are similar to previous changes (28)
  • packages/ui-next/package.json
  • packages/hydrooj/src/ui.ts
  • packages/hydrooj/src/model/message.ts
  • packages/hydrooj/src/model/token.ts
  • packages/hydrojudge/src/judge/hack.ts
  • packages/ui-default/components/autocomplete/components/UserSelectAutoComplete.tsx
  • packages/onsite-toolkit/frontend/resolver.page.tsx
  • packages/hydrooj/src/handler/problem.ts
  • packages/hydrooj/src/model/contest.ts
  • packages/hydrooj/src/commands/install.ts
  • packages/utils/package.json
  • packages/hydrooj/src/model/problem.ts
  • packages/migrate/package.json
  • packages/ui-default/backendlib/builder.ts
  • packages/ui-default/components/autocomplete/components/AutoComplete.tsx
  • packages/hydrooj/src/model/system.ts
  • packages/hydrooj/src/model/storage.ts
  • packages/ui-next/src/App.tsx
  • packages/hydrooj/src/plugin-api.ts
  • packages/hydrooj/src/entry/cli.ts
  • packages/hydrooj/src/service/bus.ts
  • packages/vjudge/src/index.ts
  • packages/hydrooj/src/model/user.ts
  • packages/hydrooj/package.json
  • packages/hydrooj/src/model/task.ts
  • packages/hydrooj/src/entry/common.ts
  • package.json
  • packages/ui-default/package.json
🧰 Additional context used
🧬 Code Definitions (11)
packages/hydrooj/src/model/record.ts (10)
packages/hydrooj/src/model/schedule.ts (1) (1)
  • apply (62-101)
packages/hydrooj/src/handler/record.ts (1) (1)
  • apply (458-463)
packages/hydrooj/src/handler/user.ts (1) (1)
  • apply (506-580)
packages/hydrooj/src/handler/problem.ts (1) (1)
  • apply (1020-1097)
packages/hydrooj/src/model/document.ts (1) (1)
  • apply (413-447)
packages/hydrooj/src/model/task.ts (1) (1)
  • apply (145-191)
packages/hydrooj/src/model/user.ts (1) (1)
  • apply (477-495)
packages/hydrooj/src/model/blacklist.ts (1) (1)
  • apply (34-40)
packages/hydrooj/src/model/message.ts (1) (1)
  • apply (88-94)
packages/hydrooj/src/model/storage.ts (1) (1)
  • apply (181-211)
packages/hydrooj/src/entry/worker.ts (4)
packages/hydrooj/src/service/db.ts (1) (1)
  • MongoService (35-180)
packages/hydrooj/src/options.ts (1) (1)
  • load (24-37)
packages/hydrooj/src/entry/setup.ts (1) (1)
  • load (9-38)
packages/hydrooj/src/settings.ts (1) (1)
  • ConfigService (14-172)
packages/ui-default/backendlib/template.ts (3)
packages/hydrooj/src/plugin-api.ts (2) (2)
  • Service (41-41)
  • Context (41-41)
packages/ui-default/api.ts (3) (3)
  • Service (5-5)
  • ctx (5-5)
  • Context (5-5)
packages/hydrooj/src/model/builtin.ts (2) (2)
  • PERM (9-102)
  • PRIV (240-267)
packages/hydrooj/src/service/db.ts (1)
packages/hydrooj/src/options.ts (1) (1)
  • load (24-37)
packages/hydrooj/src/interface.ts (1)
packages/common/types.ts (1) (1)
  • RecordJudgeInfo (84-96)
packages/hydrooj/src/settings.ts (4)
packages/ui-default/backendlib/template.ts (1) (1)
  • Context (254-275)
packages/elastic/index.ts (1) (1)
  • Context (95-125)
packages/vjudge/src/index.ts (1) (1)
  • Context (191-196)
packages/hydrooj/src/service/db.ts (1) (1)
  • Context (58-66)
packages/hydrooj/src/model/setting.ts (3)
packages/hydrooj/src/service/check.ts (1) (1)
  • apply (77-80)
packages/hydrooj/src/context.ts (2) (2)
  • Context (31-41)
  • Context (68-77)
packages/hydrooj/src/service/db.ts (1) (1)
  • Context (58-66)
framework/framework/server.ts (7)
packages/ui-default/context.ts (4) (4)
  • ctx (18-18)
  • Service (16-17)
  • Context (8-11)
  • Context (13-13)
packages/hydrooj/src/service/layers/base.ts (1) (1)
  • ctx (20-72)
packages/hydrooj/src/service/layers/user.ts (1) (1)
  • ctx (5-18)
packages/hydrooj/src/service/server.ts (2) (2)
  • HandlerCommon (31-39)
  • Handler (74-76)
packages/hydrooj/src/plugin-api.ts (4) (4)
  • HandlerCommon (7-7)
  • Handler (40-40)
  • Service (41-41)
  • Context (41-41)
framework/framework/interface.ts (1) (1)
  • KnownHandlers (3-5)
packages/hydrooj/src/context.ts (2) (2)
  • Context (31-41)
  • Context (68-77)
packages/hydrooj/src/model/document.ts (7)
packages/hydrooj/src/model/user.ts (1) (1)
  • coll (22-22)
packages/hydrooj/src/model/oplog.ts (1) (1)
  • coll (8-8)
packages/hydrooj/src/model/discussion.ts (1) (1)
  • coll (43-43)
packages/hydrooj/src/model/problem.ts (1) (1)
  • incStatus (431-436)
packages/hydrooj/src/model/token.ts (1) (1)
  • update (53-71)
packages/hydrooj/src/model/record.ts (1) (1)
  • update (195-219)
packages/hydrooj/src/service/monitor.ts (1) (1)
  • update (76-89)
packages/hydrooj/src/model/domain.ts (4)
packages/hydrooj/src/interface.ts (1) (1)
  • DomainDoc (306-314)
packages/hydrooj/src/service/bus.ts (1) (1)
  • apply (96-113)
packages/hydrooj/src/plugin-api.ts (2) (2)
  • Context (41-41)
  • db (58-58)
packages/hydrooj/src/service/db.ts (1) (1)
  • Context (58-66)
packages/ui-default/index.ts (1)
packages/ui-default/backendlib/template.ts (1) (1)
  • TemplateService (161-276)
🪛 Biome (1.9.4)
packages/ui-default/backendlib/template.ts

[error] 46-46: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 121-121: eval() exposes to security risks and performance issues.

See the MDN web docs for more details.
Refactor the code so that it doesn't need to call eval().

(lint/security/noGlobalEval)

packages/hydrooj/src/loader.ts

[error] 49-49: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

framework/framework/server.ts

[error] 139-139: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 140-140: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)

packages/hydrooj/src/handler/domain.ts

[error] 155-155: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 335-335: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

packages/hydrooj/src/handler/misc.ts

[error] 110-110: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)


[error] 124-124: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

packages/hydrooj/src/model/document.ts

[error] 223-223: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

packages/hydrooj/src/model/domain.ts

[error] 138-138: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

packages/ui-default/index.ts

[error] 56-56: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

🪛 GitHub Check: CodeQL
build/prepare.js

[failure] 166-166: Potential file system race condition
The file may have changed since it was checked.

🔇 Additional comments (113)
build/prepare.js (8)

18-22: TypeScript configuration modernization looks good

Upgrading to ES2022 with bundler-oriented module configuration is a sensible choice for the project. These changes align with modern development practices and enable newer JavaScript features like class fields and top-level await.


37-37: UI-Next reference added correctly

Adding the reference to the new UI-Next TypeScript configuration aligns with the introduction of the new UI package later in this file.


78-78: Module filtering improvement

The updated filtering logic elegantly excludes both UI packages using a more concise approach.


83-120: React JSX Transform Update – Address Unnecessary React Imports

The build configuration now uses the new react-jsx transform (React 17+), which means explicit import React from 'react' statements are generally no longer required for JSX to work. The enhanced configuration also includes improved bundler mode settings and stronger linting rules.


123-161: New UI-Next TypeScript configuration properly structured

The configuration for the new UI-Next package is well-structured with appropriate compiler options, including strict type checking and modern module settings. The path aliasing with @/* will provide a clean import structure for the new React/Vite package.


163-167: Fix potential file system race condition

The tryUpdate function has a potential race condition between checking if a file exists and reading it. If the file is deleted between these operations, it could cause errors.

🧰 Tools
🪛 GitHub Check: CodeQL

[failure] 166-166: Potential file system race condition
The file may have changed since it was checked.


189-190: Skip type checking declaration files for performance

Adding skipLibCheck: true is a good performance optimization that avoids type checking declaration files (*.d.ts) in node_modules, which can significantly speed up compilation.


197-225: Improved file writing logic with optimization

Replacing direct file writes with the tryUpdate function is a good optimization that only writes files when their content has changed. This reduces unnecessary disk operations during development and builds.

packages/ui-default/index.ts (5)

56-56: Remove the empty object pattern.

Static analysis flags { } as an unexpected empty pattern. Consider removing it as it doesn't serve any purpose.

-  async get({ }, legacy = false, nohint = false) {
+  async get(legacy = false, nohint = false) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 56-56: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)


25-25: Good type definition improvement.

Adding explicit type annotation for the sections array enhances code clarity and type safety. This is a positive change.


77-77: Improve configuration management.

Using this.ctx.config.settings instead of the global SystemSettings is a good architectural change that enhances modularity and testability.


119-119: Enhanced type clarity.

Adding the explicit type annotation for res as any[] improves code readability and maintainability.


167-167: Good integration of the new TemplateService.

The integration of the new TemplateService using ctx.plugin() properly follows the service-oriented architecture pattern, enhancing modularity.

packages/hydrooj/src/model/oauth.ts (1)

18-18:

❓ Verification inconclusive

Verify MongoDB return value structure.

The change from res.value?.uid to res?.uid assumes a different structure from the MongoDB findOneAndUpdate operation. This might be correct if you're using a newer MongoDB driver version or if your DB adapter normalizes results, but it's worth verifying that this change aligns with the actual structure returned by your MongoDB implementation.


🏁 Script executed:

#!/bin/bash
# Check if other MongoDB operations in the codebase follow the same pattern
echo "Checking for other findOneAndUpdate usage patterns in the codebase:"
rg "findOneAndUpdate" -A 3 --glob "*.ts" | grep -E "res\.value|res\?" | head -n 15

echo "Checking if there's a MongoDB client configuration or wrapper:"
fd "db\.ts|mongo\.ts" --type f --exec cat {} \; | grep -A 10 -B 10 "findOneAndUpdate"

Length of output: 454


MongoDB Return Structure Verification Needed

The change from using res.value?.uid to res?.uid suggests an assumption that the MongoDB driver (or a custom adapter) now returns the document directly rather than wrapping it in a { value: ... } object. Our automated search did not uncover any additional usage patterns or configuration files that clarify this change in behavior. To proceed safely, please manually verify the following:

  • Driver/Adapter Version: Check the mongodb driver version in packages/hydrooj/package.json (or the relevant package manifest) to confirm that its documentation supports returning the document directly.
  • Expected Return Structure: Consult the MongoDB driver documentation (or verify through runtime tests) to confirm whether findOneAndUpdate now returns the updated document directly rather than as res.value.
  • Code Consistency: Ensure that any dependent code has been reviewed for consistency with this change, especially if other parts of the codebase reference properties like value.

Please double-check these points to ensure that the change is valid for your project's environment.

packages/hydrooj/src/handler/misc.ts (3)

17-17: Added the sortFiles import from utils.

The addition of sortFiles import is used appropriately in the FilesHandler class on line 38.


131-137: Ensure routes are updated if method signatures have changed.

With the changes to the method signatures in StorageHandler and SwitchAccountHandler, verify that the routes defined in the apply function are still passing the correct parameters.

Check if any of the route handlers need updates to match the new parameter structure, particularly for StorageHandler and SwitchAccountHandler routes.


112-112:

❓ Verification inconclusive

Verify the security of the new validation approach.

The validation logic has been changed to use a context-based approach with this.ctx.get('storage')?.isLinkValid?. This is a significant change in how security validation is performed.

Make sure that:

  1. The isLinkValid method is properly implemented in the storage context
  2. It provides the same or better level of security as the previous approach
  3. All edge cases are handled correctly

🏁 Script executed:

#!/bin/bash
# Check if the isLinkValid method is properly implemented
rg "isLinkValid" --type ts

Length of output: 341


Action: Confirm the security and consistency of the isLinkValid implementation in storage

The search output confirms that the isLinkValid method is defined in the storage context (in packages/hydrooj/src/service/storage.ts). However, two similar definitions (one with an unused parameter _: string and another with link: string) were found. As this change modifies the validation approach by relying on this.ctx.get('storage')?.isLinkValid, please ensure the following:

  • Correct Implementation in Use: Verify that the intended isLinkValid implementation is used (and any duplicate or placeholder version is removed or clearly segregated).
  • Robust Security Measures: Ensure that the chosen implementation performs all necessary security checks—such as sanitizing inputs, verifying expiration and secret validity—to maintain or improve upon the previous security level.
  • Comprehensive Edge Case Handling: Confirm that all potential edge cases (e.g., missing, malformed, or unexpected input parameters) are properly managed and that optional chaining (?.) does not inadvertently bypass validation.

Please review the internal implementation details in packages/hydrooj/src/service/storage.ts and confirm that the above points are addressed.

packages/hydrooj/src/model/opcount.ts (1)

16-16:

✅ Verification successful

Data structure access pattern has changed

The return statement has been updated to access opcount directly from the res object instead of from res.value.opcount. This suggests a breaking change in the MongoDB driver response structure or an adaptation to a recent MongoDB update.

I recommend verifying that this change aligns with the version of MongoDB driver being used:


🏁 Script executed:

#!/bin/bash
# Check MongoDB driver version and documentation about findOneAndUpdate return structure
grep -r "mongodb" --include="package.json" . | grep version

Length of output: 57


I'll run a new shell script to search for any explicit references to the MongoDB dependency in all package.json files. This should help us determine the driver version in use (if specified):

Once we have this output, we can verify whether the change in data access (from res.value.opcount to res.opcount) aligns with the documented behavior of the MongoDB driver version in use. Please share the result of this script execution or verify it manually.


🏁 Script executed:

#!/bin/bash
# Search all package.json files for the "mongodb" dependency reference and its version
find . -type f -name "package.json" -exec grep -H '"mongodb":' {} \;

Length of output: 510


Verified: MongoDB Driver Structure Change Consistent with v6.15.0

The updated return statement now accesses opcount directly from the res object. Our verification confirmed that the project uses MongoDB driver version ^6.15.0 (as seen in the package.json files), which aligns with this new response structure. No further action is needed here, but please ensure that any other parts of the code interfacing with the driver follow the updated data structure consistently.

packages/hydrojudge/src/checkers.ts (4)

12-12: Good addition to enhance checker capabilities

Adding the code property to the CheckConfig interface allows checkers to access the submitted code, enabling more sophisticated validation strategies.


179-180: Documentation updated to reflect implemented feature

The comment has been updated to remove "(not impl)" for the code property, correctly reflecting that the feature is now implemented.


190-190: Implementation of code property in syzoj checker

The checker now uses config.code directly, allowing access to the submitted code. This matches the interface update and enhances the checker's capabilities.


206-206: Added code access to testlib checker

The testlib checker now includes user_code: config.code in its copyIn configuration, ensuring the submitted code is available for more thorough validation.

packages/utils/lib/utils.ts (4)

10-10: Enhanced logger import for more modularity

The import has been expanded to include Exporter and Factory from 'reggol', enabling a more configurable logging system.


15-27: Improved logger configuration with factory pattern

This change implements a factory pattern for logger creation with detailed configuration options. The new approach provides better encapsulation and customization of logging behavior.


29-31: Added logger factory function for consistency

The createLogger function provides a clean interface for creating new logger instances, ensuring consistent logger configuration throughout the application.


33-35: Updated Logger export with appropriate type casting

The export statement has been modified to use the new factory-based approach while maintaining backward compatibility through type casting.

packages/hydrooj/src/service/db.ts (9)

7-7: Updated imports to use context and service base class

Importing the Context and Service from the context module aligns with the new context-based architecture.


11-11: Simplified bus import

Changed from namespace import to default import for the bus service, which is a cleaner approach if only using the default export.


29-34: Added MongoDB service to Context interface

This module declaration extends the Context interface to include the database service, enabling type-safe access to the MongoDB service through the context.


35-35: MongoService now extends Service base class

The MongoDB service now properly extends the Service base class, following a more consistent inheritance pattern for services.


39-41: Updated constructor to use Context and proper initialization

The constructor now accepts a Context parameter and calls the parent class constructor with appropriate parameters, enabling proper integration with the context system.


43-56: Added static method for URL generation

The getUrl static method encapsulates the logic for generating the MongoDB connection URL, supporting CI environments with an in-memory MongoDB server and configuration from loaded options.


58-66: Replaced start method with async generator for proper lifecycle management

The method has been updated to an async generator using [Context.init] symbol, which better integrates with the context lifecycle management and yields a cleanup function for proper resource disposal.


69-70: Improved collection name handling with configuration

The collection method now uses configuration properties for prefix and collection mapping, allowing more flexible collection naming strategies.


182-189: Added backward compatibility with a deprecation notice

A proxy object is used to maintain backward compatibility while encouraging migration to the context-based approach with a deprecation notice.

packages/hydrooj/src/interface.ts (5)

226-229: Good addition of RecordHistoryDoc interface with proper extension

The new RecordHistoryDoc interface correctly extends RecordJudgeInfo and adds the essential tracking fields (_id and rid) needed for the record history functionality. This provides good type safety for historical record tracking.


83-83: Type improvement for authenticator extensions

Changing the type from AuthenticationExtensionsAuthenticatorOutputs to ParsedAuthenticatorData['extensionsData'] provides better alignment with the underlying library types and improves type safety.


637-637: Properly moved problemSearch to ModuleInterfaces

The problemSearch property has been moved to the ModuleInterfaces as recommended in previous reviews, which aligns with the refactoring to reduce global assignments and encapsulate functionality within the module system.


663-663: Improved addons data structure

Changing addons from an array to a Record<string, string> improves lookup performance and allows associating metadata with each addon. Make sure all code that previously accessed addons as an array has been updated.


552-552: Proper database collection definition for record history

Good job registering the record.history collection with the RecordHistoryDoc type in the database collections. This ensures type safety when accessing this collection throughout the application.

packages/elastic/index.ts (3)

20-32: Good refactoring to service-based architecture

The refactoring of ElasticSearch functionality into a proper service class with configuration schema is a great improvement over the previous global function approach. This enhances maintainability and modularity.


34-34: Add proper type annotation for the opts parameter

The opts parameter is missing a type annotation. Consider defining an interface for the options or using a more specific type to improve type safety.

-    async problemSearch(domainId: string, q: string, opts): ReturnType<ProblemSearch> {
+    async problemSearch(domainId: string, q: string, opts: { limit?: number; skip?: number }): ReturnType<ProblemSearch> {

72-72: Add proper type annotations for the run method parameters

The parameters in the run method lack proper type annotations, which reduces type safety. Consider defining interfaces for these parameters.

-    async run({ domainId }, report) {
+    async run({ domainId }: { domainId?: string }, report: (status: { message: string }) => void) {
packages/hydrooj/src/model/setting.ts (6)

7-7: Action Required: Add "schemastery" to project dependencies

The import of Schema from schemastery is appropriate given its usage in the file. However, according to a previous verification, schemastery is not currently listed in your project dependencies.

#!/bin/bash
# Check if schemastery is in dependencies
grep -r "schemastery" package.json

73-80: Good addition of Schemastery namespace declaration

The global declaration for the Schemastery namespace provides proper typing for schema metadata, which enhances type safety when working with schemas.


82-119: Potential coverage gap for complex schemas

The schemaToSettings function handles only basic data types (string, number, boolean) and single-level nesting. More complex schema structures like arrays, tuples, or deeply nested objects might not be fully processed.

Consider enhancing the function to handle more complex schema types and deeper nesting levels:

function schemaToSettings(schema: Schema<any>) {
    const result: _Setting[] = [];
-    const processNode = (key: string, s: Schema<number> | Schema<string> | Schema<boolean>, defaultFamily = 'setting_basic') => {
+    const processNode = (key: string, s: Schema<any>, defaultFamily = 'setting_basic') => {
        if (s.dict) throw new Error('Dict is not supported here');
+       // Handle array type
+       if (s.array) {
+           return {
+               family: s.meta?.family || defaultFamily,
+               key,
+               value: s.meta?.default || [],
+               name: key,
+               desc: s.meta?.description,
+               flag: (s.meta?.hidden ? FLAG_HIDDEN : 0) | (s.meta?.disabled ? FLAG_DISABLED : 0),
+               subType: 'json',
+               type: 'json',
+               range: null,
+           } as _Setting;
+       }
        // Rest of the function...

290-318: Excellent use of schema-based configuration

The Schema-based system settings provide a more robust and typed approach to configuration. This is a great improvement over the string-based approach, providing better validation and documentation of settings.


388-388: Good service dependency declaration

Adding the inject property properly declares the dependencies required by the setting service, which is important for the dependency injection system to work correctly.


121-143: Good enhancement to support both Schema and raw settings

The modification to handle both Schema objects and raw _Setting objects improves flexibility while maintaining backward compatibility. The flatMap approach is an elegant way to handle the conversion.

packages/hydrooj/src/handler/domain.ts (5)

105-147: Improved DomainUserHandler with aggregation pipeline

Replacing direct MongoDB queries with an aggregation pipeline is a good improvement that:

  1. Efficiently filters users by role in a single query
  2. Uses $lookup to join with the user collection for better data access
  3. Applies proper field projection to include only necessary data

This approach is more efficient and maintainable than separate queries and manual joining.


258-258: Simplified role filtering logic

Good improvement to only exclude the 'guest' role rather than both 'default' and 'guest'. This allows for more flexible role management where users with the 'default' role can still be shown in the interface.


322-337: Enhanced DomainJoinHandler with target parameter

The addition of a target parameter to prepare makes the handler more flexible, allowing users to join a different domain than the current one. This is a good improvement for cross-domain functionality.

🧰 Tools
🪛 Biome (1.9.4)

[error] 335-335: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


340-358: Improved DomainJoinHandler.get with additional parameters

Adding target and redirect parameters to the get method enhances the flexibility of the domain join process, allowing for better navigation flows. The inclusion of more domain information in the response body also improves the user experience.


361-376: Improved DomainJoinHandler.post with better role assignment

The post method now properly handles the target parameter and conditionally sets the role based on joinSettings, which is a more robust approach to role assignment during domain joining.

packages/hydrooj/src/model/record.ts (7)

2-2: Added lodash's pick utility for history implementation.

Good addition - pick is the appropriate utility for extracting specific fields for the new history feature.


23-23: Added new static collection for storing record history.

Great addition for record history tracking, which enables auditing and system debugging.


212-217: Function simplified by returning findOneAndUpdate result directly.

Similar to other model changes, this eliminates an intermediate variable for a cleaner implementation.


236-236: Fixed instance check for arrays.

Replaced instanceof Array with the more reliable Array.isArray() method, which works correctly across different execution contexts.


250-262: Implemented record history preservation.

The implementation correctly fetches records before deletion, extracts relevant fields using pick, and stores them in the history collection. This enables valuable historical tracking of record changes.

The implementation is well-designed, preserving only the essential fields needed for history tracking.


283-283: Made apply function async for proper promise handling.

Changed the apply function to be async to better support async operations within it.


307-328: Added appropriate indexes to the new collHistory collection.

The implementation adds proper indexing for the new collHistory collection, which is essential for performance as this collection grows.

The index on { rid: 1, _id: -1 } supports efficient queries for record history by record ID and chronological order.

packages/hydrooj/src/model/schedule.ts (2)

7-7: Changed import statement for WorkerService.

Modified from importing WorkerService as a type to importing it as a default export with a type annotation.

This change aligns with how the WorkerService is likely exported from its module.


18-25: Simplified result handling in getFirst method.

The code now works directly with the returned document from findOneAndDelete instead of accessing it through a nested .value property, making the code cleaner and more direct.

This change is likely part of a broader standardization of how database operation results are handled across the application.

packages/hydrooj/src/entry/worker.ts (5)

9-10: Updated imports for dependency injection pattern.

Added imports for MongoService and ConfigService to support the new dependency injection approach.


24-34: Improved database initialization with async URL retrieval.

The implementation now:

  1. Asynchronously retrieves the MongoDB URL
  2. Handles the setup process if URL is not found
  3. Applies plugins for MongoDB and Config services

This is a more robust initialization process compared to the previous implementation.


36-52: Implemented proper dependency injection pattern.

Added structured dependency injection using promises and context injection to ensure dependencies are loaded in the correct order before continuing initialization.

This approach makes the code more maintainable and ensures that services are properly initialized before they're used.


61-65: Added additional dependency injection for worker and settings.

Similar to the previous injection pattern, this ensures worker and settings services are properly initialized.


96-102: Improved server initialization with dependency injection.

Server initialization and listening now use the dependency injection pattern, which:

  1. Ensures the server is properly initialized before listening
  2. Provides better organization of startup sequence
  3. Makes the code more testable
eslint.config.mjs (2)

16-37: Confirm React ESLint config alignment.

You're extending from a custom React config (@hydrooj/eslint-config). Ensure it addresses your project’s React-specific requirements and does not conflict with other ESLint rules.


55-86: Check parser features consistency.

The ecmaVersion aligns with 2020 in this block. If newer JavaScript features appear in other parts of the code, ensure the global config matches.

framework/eslint-config/base.mjs (5)

1-14: Imports and compatibility look fine.

No immediate concerns with these imports. The FlatCompat usage is straightforward and appears well-integrated.


15-21: Validate ignore patterns.

Ignoring .git is typically inconsequential. However, confirm it does not mask checks for submodules or hidden files that might contain relevant lintable code.


22-28: Check overlapping style guides.

Extending both airbnb-base and airbnb/hooks in conjunction with additional plugins can create conflicting rules. Confirm that no conflicts remain unresolved.


45-52: Cross-check plugin compatibility.

Using @stylistic/eslint-plugin, @eslint-react/eslint-plugin, etc., is beneficial. Verify versions are up to date for smooth interoperability.


64-453: Review extended rule overrides.

Disabling certain defaults in favor of @stylistic/* may omit essential checks (e.g., no-extra-parens). Confirm you do not lose coverage on critical lint rules.

packages/hydrooj/src/service/worker.ts (2)

12-12: Switching to default export may break imports.

Renaming or converting WorkerService to a default export can cause issues for modules importing it by name. Verify references are updated.


32-38: Validate res structure from findOneAndDelete.

Returning res instead of res.value might break downstream usage if other parts of the code rely on the old property. Confirm that this updated return aligns with consumption patterns.

framework/eslint-config/package.json (5)

5-5: Main entry point changed from YAML to JavaScript module

The main entry point has been changed from react.yaml to base.mjs, which indicates a shift to JavaScript modules for ESLint configuration. This aligns with current best practices for ESLint 9 configuration.


7-12: Added new ESLint 9 compatible plugins and updated dependencies

The addition of @eslint-react/eslint-plugin, @eslint/compat, and @eslint/eslintrc along with updated TypeScript ESLint packages indicates proper preparation for ESLint 9 compatibility. The TypeScript ESLint plugins have been updated to the latest versions (8.27.0).


14-21: Updated plugin versions and added new utility plugins

The updates to plugin versions and addition of new utility plugins like eslint-plugin-de-morgan and updates to eslint-plugin-simple-import-sort will improve linting capabilities.


26-27: Added TypeScript as an optional dependency

Adding TypeScript as an optional dependency with a specific version requirement (^5.8.2) improves type checking capabilities while keeping it optional for non-TypeScript projects.


24-24:

❓ Verification inconclusive

Upgraded ESLint peer dependency to version 9+

The peer dependency for ESLint has been updated from ">= 8" to ">= 9", which is a major version change. Make sure all dependent packages are compatible with ESLint 9.


🏁 Script executed:

#!/bin/bash
# Check for any packages that might have incompatibility with ESLint 9
fd -e json package.json --exec grep -l "eslint.*\":" {} \; | xargs grep -l "\"eslint\""

Length of output: 143


ESLint 9+ Upgrade – Verify Dependent Package Compatibility

The ESLint peer dependency in framework/eslint-config/package.json is now updated to "eslint": ">= 9". A quick search across the repository confirms that only two files reference ESLint: the top-level package.json and framework/eslint-config/package.json. Please double-check that the ESLint version specified in the top-level package.json is also aligned with version 9 requirements, ensuring that all dependent packages remain compatible with ESLint 9.

  • Action Items:
    • Confirm that any ESLint reference in the top-level package.json does not conflict with the upgrade.
    • Validate that all packages relying on ESLint are compatible with version 9.
packages/hydrooj/src/settings.ts (5)

8-12: Added ConfigService to Context module declaration

The module declaration extends the Context interface with the ConfigService, ensuring proper type safety when accessing the config service throughout the application.


14-24: New ConfigService class with proper dependency injection

The new ConfigService class properly extends Service, declares its dependencies with static inject, and uses proper class encapsulation for configuration state. The blacklist is appropriately defined to prevent prototype pollution.


30-34: Improved Context initialization with database integration

The Context.init method properly initializes the configuration by fetching from the database and loading initial values before calling loadConfig().


69-77: Well-implemented schema validation in isPatchValid

The isPatchValid method correctly creates a temporary configuration object with the changes and validates it against the schema before applying it to the actual config, preventing invalid configurations.


159-159: Fixed null check in getAccess function

The function now correctly checks if currentValue is both not an object and not null, fixing a potential issue where null values might be incorrectly handled.

packages/hydrooj/src/model/domain.ts (4)

136-137: Enhanced setUserRole with autojoin parameter

The setUserRole method now includes an autojoin parameter defaulting to false, which conditionally includes a join property in the update operation, improving flexibility.


130-132: Added join criteria to countUser queries

The countUser method now includes a join: true property in its queries, ensuring only joined users are counted, which aligns with the domain membership model.


258-260: Added join criteria to getDictUserByDomainId query

The getDictUserByDomainId method now adds join: true to its query, ensuring only domains where the user has joined are returned, which aligns with the domain membership model.


292-312: New apply function properly encapsulates initialization logic

The new apply function centralizes domain model initialization, setting up the cache deletion event listener and ensuring database indexes. This follows the service pattern seen in other files, making initialization more consistent and modular.

This approach aligns with the service initialization pattern seen in other modules (like DB service, Template service) where the Context.init lifecycle hook is used for setup. Good refactoring.

packages/hydrooj/src/loader.ts (8)

15-17: Updated imports for Context-related types

The import statement now includes more specific imports from './context', making dependencies clearer and improving code readability.


48-48: Public state property with improved type definition

The state property is now better typed with Record<string, EffectScope>, but the next line has a potential issue.


54-57: Improved dependency injection with static inject

The Loader class now properly declares its dependencies with static inject and uses a more appropriate constructor parameter name (ctx instead of app).


98-107: Enhanced resolveConfig method with schema handling

The new resolveConfig method properly handles configuration scopes and schema validation, with good error handling and fallback behavior. It also integrates with the new config service for migration and request handling.


109-126: Simplified reloadPlugin with async/await pattern

The reloadPlugin method has been updated to use async/await and integrates with the new resolveConfig method, improving error handling and making the code more maintainable.


147-168: Improved preload function with proper async handling

The preload function now uses async/await with a Promise-based approach to reliably initialize the global app, ensuring dependencies are properly injected before continuing.


170-206: Updated load function to use await for preload

The load function now properly awaits the preload function, ensuring initialization completes before continuing with the application startup sequence.


208-213: Updated loadCli function to use await for preload

Similar to the load function, loadCli now properly awaits the preload function, ensuring initialization completes before executing CLI commands.

packages/hydrooj/src/model/document.ts (5)

12-12: Updated import style for the bus module.

The import style has been updated from namespace import to default import, which is consistent with modern JavaScript practices and indicates that the bus module now exports a default.


18-18: Added utility type to exclude symbol keys.

Good addition of the NormalArrayKeys utility type that excludes symbol keys from array keys, which helps improve type safety when dealing with array properties.


23-33: Enhanced type safety with as const assertions.

The constants have been updated to use TypeScript's as const assertion instead of explicit type annotations. This is a beneficial change that enhances type safety by ensuring the constants are treated as literal types, allowing for better type inference in TypeScript.


112-117: Simplified return statements for database operations.

The functions now directly return the results of database operations instead of storing them in intermediate variables. This reduces unnecessary variable declarations and makes the code more concise.

Also applies to: 152-157, 163-168, 211-217, 224-230, 255-265, 271-277, 301-311, 327-336, 358-374, 385-391, 397-402


385-391: Improved code with nullish assignment operator.

The function has been refactored to use the newer ||= nullish assignment operator, which is a cleaner and more concise way to handle conditional assignment.

framework/framework/server.ts (9)

5-5: Updated import to use CordisContext.

The import has been updated to use CordisContext instead of Context, indicating a shift in the underlying framework or a rename to avoid conflicts with other Context classes.


44-52: Added utility function for context scoping.

This new utility function provides a clean way to create isolated context scopes with proper resource cleanup through the async disposable pattern, which is a modern approach to resource management.


210-211: Improved class hierarchy with generics.

The Handler classes now use generic type parameters for better type safety, allowing them to work with different context types. The static kHandler property also provides a cleaner way to identify handler types.

Also applies to: 258-260, 297-300


337-352: Enhanced WebService with generic context support.

The WebService class now accepts a generic context type, improving type safety and allowing for more flexible context handling throughout the application.


487-488: Improved resource management with scoped contexts.

Using the new forkContextWithScope utility ensures proper resource cleanup when handlers are no longer needed. This prevents potential memory leaks and resource exhaustion.

Also applies to: 566-568


599-612: Enhanced error handling and resource cleanup.

The refactored cleanup logic in handleWS provides more robust error handling and ensures all resources are properly released, regardless of how the connection is terminated.


787-810: Added robust mixin implementation.

The new _applyMixin method provides a clean and reliable way to extend class prototypes, with proper cleanup on disposal. This allows for more flexible composition of functionality.


812-828: Introduced type-safe mixin application methods.

The new mixin application methods (applyMixin, handlerMixin, httpHandlerMixin, wsHandlerMixin) provide a consistent and type-safe way to extend handler classes with additional functionality.

The implementation of wsHandlerMixin now correctly applies the mixins to the prototype, fixing the issue where it would previously only warn about existing properties.


841-848: Enhanced type definitions with module augmentation.

The module augmentation for the Context interface ensures that TypeScript properly recognizes the server-related properties and methods, improving type safety throughout the application.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🔭 Outside diff range comments (1)
packages/hydrooj/src/model/domain.ts (1)

136-153: ⚠️ Potential issue

Use Array.isArray check
Replacing uid instanceof Array with Array.isArray(uid) avoids issues with arrays from different contexts.

- if (!(uid instanceof Array)) {
+ if (!Array.isArray(uid)) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 138-138: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

♻️ Duplicate comments (6)
packages/hydrooj/src/interface.ts (1)

637-637: ⚠️ Potential issue

ProblemSearch moved to ModuleInterfaces

The problemSearch property is correctly added to ModuleInterfaces, but there's still a duplicate global property definition that needs to be removed.

Remove the line with the global problemSearch property to fully encapsulate problemSearch within the module system, as mentioned in previous review comments.

build/prepare.js (1)

163-167: ⚠️ Potential issue

Fix potential file system race condition

The tryUpdate function has a potential race condition between checking if a file exists and reading it. If the file is deleted between these operations, it could cause errors.

Apply this fix to handle the race condition more safely:

const tryUpdate = (location, content) => {
-    const current = fs.existsSync(location) ? fs.readFileSync(location, 'utf-8') : '';
+    let current = '';
+    try {
+        current = fs.readFileSync(location, 'utf-8');
+    } catch (err) {
+        // File doesn't exist or cannot be read
+    }
    const expected = typeof content === 'string' ? content : JSON.stringify(content, null, 2);
    if (expected !== current) fs.writeFileSync(location, expected);
};
🧰 Tools
🪛 GitHub Check: CodeQL

[failure] 166-166: Potential file system race condition
The file may have changed since it was checked.

packages/ui-default/backendlib/template.ts (2)

121-121: ⚠️ Potential issue

Security risk: Use of eval() in template engine.

The use of eval() exposes the application to security risks including code injection vulnerabilities. Attackers could potentially execute arbitrary code if they can influence template content.

Replace eval with a safer alternative such as a sandboxed evaluation library or a restricted expression parser. Consider using a library like vm with proper sandboxing or implementing a custom expression evaluator with limited capabilities.

🧰 Tools
🪛 Biome (1.9.4)

[error] 121-121: eval() exposes to security risks and performance issues.

See the MDN web docs for more details.
Refactor the code so that it doesn't need to call eval().

(lint/security/noGlobalEval)


122-138: ⚠️ Potential issue

Security concern: Exposing global objects to templates.

Exposing complete global objects (Date, Object, String, etc.) in the template environment creates a significant attack surface for template injection attacks. This allows template authors to access potentially dangerous methods or properties.

Consider limiting exposure to only needed functionality rather than the entire global objects. For example, expose only specific methods from Date rather than the entire Date constructor.

framework/framework/server.ts (2)

139-140: ⚠️ Potential issue

Remove unsafe interface-class declaration merging.

The empty interface HandlerCommon<C> is unsafely merged with the class of the same name. This pattern is flagged by TypeScript as problematic because properties defined in the interface aren't checked for initialization in the class.

-export interface HandlerCommon<C> { } // eslint-disable-line @typescript-eslint/no-unused-vars
+// Remove empty interface and only keep the class definition
 export class HandlerCommon<C> {
🧰 Tools
🪛 Biome (1.9.4)

[error] 139-139: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 140-140: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)


684-708: ⚠️ Potential issue

Fix condition that always evaluates to false.

The condition if (perm) in the check function at line 705 is likely not working as intended. This was flagged in previous reviews as a condition that always evaluates to false.

 public check(this: Handler<C>) {
     checker();
-    if (perm) this.checkPerm(perm);
+    if (perm !== undefined && perm !== null) this.checkPerm(perm);
     if (priv) this.checkPriv(priv);
 }
🧹 Nitpick comments (18)
.github/workflows/build.yml (1)

65-67: Streamline the Build and Lint Command

The updated command now omits the lint:ui:ci step, which simplifies the workflow and potentially reduces redundant linting. Please verify that this removal does not skip any critical linting on the UI code that was previously covered.

-          parallel --tty -j+0 yarn ::: lint:ci lint:ui:ci build build:ui:production:webpack test
+          parallel --tty -j+0 yarn ::: lint:ci build build:ui:production:webpack test
packages/hydrooj/src/handler/misc.ts (2)

110-110: Replace empty object pattern with proper parameter skipping

The empty object pattern { } is flagged by the linter and doesn't follow TypeScript best practices for ignoring parameters.

Consider using one of these alternatives instead:

- async get({ }, target: string, filename = '', expire: number, secret: string) {
+ async get(_: any, target: string, filename = '', expire: number, secret: string) {

or

- async get({ }, target: string, filename = '', expire: number, secret: string) {
+ async get(_domainId: unknown, target: string, filename = '', expire: number, secret: string) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 110-110: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)


124-124: Replace empty object pattern with proper parameter skipping

Similar to line 110, the empty object pattern { } is flagged by the linter and should be replaced with a proper parameter naming convention.

- async get({ }, uid: number) {
+ async get(_: any, uid: number) {

or

- async get({ }, uid: number) {
+ async get(_domainId: unknown, uid: number) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 124-124: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

packages/hydrooj/src/model/setting.ts (1)

82-119: Enhance schemaToSettings function to handle more complex schemas

The new schemaToSettings function converts Schema objects to _Setting objects, which is a good approach for supporting the schema-based configuration. However, the function currently handles only a limited subset of data types (string, number, boolean) and single-level nesting. More complex schema structures might not be fully processed.

Consider enhancing the function to handle:

  1. More complex nested structures (beyond one level)
  2. Arrays and other data types
  3. More robust error handling for unsupported types
function schemaToSettings(schema: Schema<any>) {
    const result: _Setting[] = [];
-    const processNode = (key: string, s: Schema<number> | Schema<string> | Schema<boolean>, defaultFamily = 'setting_basic') => {
+    const processNode = (key: string, s: Schema<any>, defaultFamily = 'setting_basic') => {
        if (s.dict) throw new Error('Dict is not supported here');
        let flag = (s.meta?.hidden ? FLAG_HIDDEN : 0)
            | (s.meta?.disabled ? FLAG_DISABLED : 0);
        const type = s.type === 'number' ? 'number'
            : s.type === 'boolean' ? 'checkbox'
+               : s.type === 'array' ? 'json'
                : s.meta?.role === 'textarea' ? 'textarea' : 'text';
        if (s.meta?.role === 'password') flag |= FLAG_SECRET;
        const options = {};
        for (const item of s.list || []) {
            if (item.type !== 'const') throw new Error('List item must be a constant');
            options[item.value] = item.meta?.description || item.value;
        }
        return {
            family: s.meta?.family || defaultFamily,
            key,
            value: s.meta?.default,
            name: key,
            desc: s.meta?.description,
            flag,
            subType: '',
            type: s.list ? 'select' : type,
            range: s.list ? options : null,
        } as _Setting;
    };
    if (!schema.dict) return [];
    for (const key in schema.dict) {
        const value = schema.dict[key];
        if (value.dict) {
            for (const subkey in value.dict) {
                result.push(processNode(`${key}.${subkey}`, value.dict[subkey], value.meta?.family));
            }
+        } else if (value.type === 'array') {
+            // Handle array type
+            result.push(processNode(key, value));
        } else result.push(processNode(key, value));
    }
    return result;
}
eslint.config.mjs (2)

1-2: Remove or refine these global rule disables.

Disabling max-len and @typescript-eslint/naming-convention at the top level can reduce code clarity and consistency across the project. Consider selectively allowing exceptions only where needed rather than disabling both rules entirely.


19-21: Evaluate ECMAScript version compatibility.

The configuration sets ecmaVersion: 5, but also specifies sourceType: "module". If you plan to leverage modern ES features, you may wish to increase ecmaVersion beyond 5 for more accurate linting and better alignment with current JavaScript capabilities.

framework/eslint-config/base.mjs (4)

200-206: Consider enforcing the “no-magic-numbers” rule.

By disabling @typescript-eslint/no-magic-numbers, your code may accumulate “magic” constants scattered throughout. Enabling this rule can help maintain clarity and reduce the risk of hardcoded values introducing bugs.


366-366: Review the max line length.

Currently, 'max-len': ['warn', 150] can still lead to unwieldy lines. Consider lowering it for better readability and to prevent large amounts of horizontal scrolling, especially on smaller screens.


377-377: Caution with async operations in loops.

no-await-in-loop is set to warn. While occasionally necessary, awaiting within a loop can degrade performance if parallelization is possible. Ensure you have considered alternatives (e.g., Promise.all) for tasks that can run concurrently.


430-430: Check react-hooks/exhaustive-deps usage.

This rule is completely disabled, which might hide potential useEffect dependency errors in React components. Consider at least warning developers about incomplete dependency arrays to avoid subtle state management bugs.

framework/eslint-config/package.json (1)

7-21: Ensure plugin version compatibility.

Multiple new plugins and upgraded versions (e.g., @eslint-react/eslint-plugin, @eslint/compat, @stylistic/eslint-plugin, etc.) may have peer constraints. Confirm that these versions interoperate correctly, especially for React 18 and modern TypeScript usage.

packages/elastic/index.ts (2)

26-32: Avoid using console.log in production
Use a dedicated logger instead of console.log to ensure consistent log formatting and better log management.

- console.log('elastic-search', config);
+ this.ctx.logger.info('Initializing Elasticsearch with config: %j', config);

80-92: Consider using bulk indexing for performance
Instead of indexing documents one by one, consider using Elasticsearch's bulk API to improve performance when indexing a large number of documents.

packages/hydrooj/src/settings.ts (2)

14-25: Strengthen the prototype pollution safeguard
Although you maintain a list of blacklisted properties (__proto__, prototype, and constructor), consider using a more complete library or approach to mitigate prototype pollution comprehensively.


86-107: Potential performance improvement
Consider storing partial migration updates to batch them instead of updating the database individually for each node.

packages/hydrooj/src/model/domain.ts (1)

292-312: Unified event and index management
This function cleanly centralizes cache invalidation and index creation. Consider logging any index creation errors for troubleshooting.

packages/ui-default/index.ts (1)

119-119: Added explicit type definition for better clarity.

The res variable has been explicitly typed as any[], which improves code readability. Consider using a more specific type than any if possible for better type safety.

-    const res: any[] = [];
+    const res: Array<string> = [];
packages/hydrooj/src/handler/domain.ts (1)

150-160: Restructured user data processing for better organization.

The code now maps and transforms the aggregation results to create a cleaner structure, removing nested objects and organizing data more logically. However, there's a potential performance issue with the use of the delete operator.

-            delete u.user;
+            u.user = undefined;
🧰 Tools
🪛 Biome (1.9.4)

[error] 155-155: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0bd15ca and f8ed636.

📒 Files selected for processing (94)
  • .eslintrc.yaml (0 hunks)
  • .github/workflows/build.yml (1 hunks)
  • build/prepare.js (5 hunks)
  • eslint.config.mjs (1 hunks)
  • framework/eslint-config/base.mjs (1 hunks)
  • framework/eslint-config/base.yaml (0 hunks)
  • framework/eslint-config/package.json (1 hunks)
  • framework/eslint-config/react.yaml (0 hunks)
  • framework/eslint-config/typescript.js (0 hunks)
  • framework/framework/error.ts (0 hunks)
  • framework/framework/server.ts (22 hunks)
  • package.json (2 hunks)
  • packages/elastic/index.ts (2 hunks)
  • packages/hydrojudge/src/cases.ts (0 hunks)
  • packages/hydrojudge/src/checkers.ts (4 hunks)
  • packages/hydrojudge/src/daemon.ts (0 hunks)
  • packages/hydrojudge/src/hosts/hydro.ts (0 hunks)
  • packages/hydrojudge/src/hosts/vj4.ts (1 hunks)
  • packages/hydrojudge/src/judge/hack.ts (4 hunks)
  • packages/hydrooj/package.json (3 hunks)
  • packages/hydrooj/src/commands/install.ts (1 hunks)
  • packages/hydrooj/src/entry/cli.ts (2 hunks)
  • packages/hydrooj/src/entry/common.ts (2 hunks)
  • packages/hydrooj/src/entry/setup.ts (0 hunks)
  • packages/hydrooj/src/entry/worker.ts (3 hunks)
  • packages/hydrooj/src/handler/contest.ts (0 hunks)
  • packages/hydrooj/src/handler/domain.ts (3 hunks)
  • packages/hydrooj/src/handler/misc.ts (3 hunks)
  • packages/hydrooj/src/handler/problem.ts (1 hunks)
  • packages/hydrooj/src/interface.ts (6 hunks)
  • packages/hydrooj/src/loader.ts (6 hunks)
  • packages/hydrooj/src/model/blacklist.ts (1 hunks)
  • packages/hydrooj/src/model/contest.ts (7 hunks)
  • packages/hydrooj/src/model/document.ts (11 hunks)
  • packages/hydrooj/src/model/domain.ts (9 hunks)
  • packages/hydrooj/src/model/message.ts (3 hunks)
  • packages/hydrooj/src/model/oauth.ts (1 hunks)
  • packages/hydrooj/src/model/opcount.ts (1 hunks)
  • packages/hydrooj/src/model/problem.ts (1 hunks)
  • packages/hydrooj/src/model/record.ts (8 hunks)
  • packages/hydrooj/src/model/schedule.ts (2 hunks)
  • packages/hydrooj/src/model/setting.ts (11 hunks)
  • packages/hydrooj/src/model/storage.ts (6 hunks)
  • packages/hydrooj/src/model/system.ts (3 hunks)
  • packages/hydrooj/src/model/task.ts (3 hunks)
  • packages/hydrooj/src/model/token.ts (2 hunks)
  • packages/hydrooj/src/model/user.ts (8 hunks)
  • packages/hydrooj/src/plugin-api.ts (2 hunks)
  • packages/hydrooj/src/script/problemStat.ts (0 hunks)
  • packages/hydrooj/src/script/storageUsage.ts (0 hunks)
  • packages/hydrooj/src/service/bus.ts (5 hunks)
  • packages/hydrooj/src/service/db.ts (3 hunks)
  • packages/hydrooj/src/service/worker.ts (2 hunks)
  • packages/hydrooj/src/settings.ts (1 hunks)
  • packages/hydrooj/src/ui.ts (1 hunks)
  • packages/migrate/package.json (1 hunks)
  • packages/onlyoffice/frontend/office.page.ts (0 hunks)
  • packages/onsite-toolkit/frontend/resolver.page.tsx (2 hunks)
  • packages/ui-default/.eslintignore (0 hunks)
  • packages/ui-default/.eslintrc.js (0 hunks)
  • packages/ui-default/api.ts (0 hunks)
  • packages/ui-default/backendlib/builder.ts (4 hunks)
  • packages/ui-default/backendlib/markdown-it-imsize.ts (1 hunks)
  • packages/ui-default/backendlib/markdown-it-media.ts (0 hunks)
  • packages/ui-default/backendlib/misc.ts (1 hunks)
  • packages/ui-default/backendlib/template.ts (3 hunks)
  • packages/ui-default/build/config/webpack.ts (1 hunks)
  • packages/ui-default/build/main.ts (1 hunks)
  • packages/ui-default/components/autocomplete/components/AutoComplete.tsx (3 hunks)
  • packages/ui-default/components/autocomplete/components/UserSelectAutoComplete.tsx (1 hunks)
  • packages/ui-default/components/calendar/index.js (2 hunks)
  • packages/ui-default/components/message/worker.ts (1 hunks)
  • packages/ui-default/components/problemconfig/ProblemConfigEditor.tsx (1 hunks)
  • packages/ui-default/components/problemconfig/ProblemConfigTree.tsx (1 hunks)
  • packages/ui-default/components/problemconfig/reducer/config.ts (1 hunks)
  • packages/ui-default/components/problemconfig/tree/AddTestcase.tsx (1 hunks)
  • packages/ui-default/components/problemconfig/tree/SubtaskSettings.tsx (1 hunks)
  • packages/ui-default/components/problemconfig/tree/Testcase.tsx (1 hunks)
  • packages/ui-default/components/scratchpad/DataInputComponent.jsx (0 hunks)
  • packages/ui-default/components/scratchpad/ScratchpadToolbarContainer.jsx (0 hunks)
  • packages/ui-default/index.ts (6 hunks)
  • packages/ui-default/package.json (5 hunks)
  • packages/ui-next/package.json (1 hunks)
  • packages/ui-next/src/App.tsx (1 hunks)
  • packages/utils/lib/locate-pm2.ts (1 hunks)
  • packages/utils/lib/utils.ts (1 hunks)
  • packages/utils/package.json (2 hunks)
  • packages/vjudge/src/index.ts (3 hunks)
  • packages/vjudge/src/providers/codeforces.ts (0 hunks)
  • packages/vjudge/src/providers/hduoj.ts (0 hunks)
  • packages/vjudge/src/providers/poj.ts (0 hunks)
  • packages/vjudge/src/providers/spoj.ts (0 hunks)
  • packages/vjudge/src/providers/uoj.ts (0 hunks)
  • packages/vjudge/src/providers/yacs.ts (0 hunks)
💤 Files with no reviewable changes (25)
  • packages/ui-default/components/scratchpad/DataInputComponent.jsx
  • packages/vjudge/src/providers/yacs.ts
  • packages/vjudge/src/providers/hduoj.ts
  • packages/ui-default/api.ts
  • packages/hydrooj/src/script/problemStat.ts
  • packages/onlyoffice/frontend/office.page.ts
  • packages/hydrojudge/src/daemon.ts
  • framework/eslint-config/react.yaml
  • packages/hydrojudge/src/hosts/hydro.ts
  • packages/hydrojudge/src/cases.ts
  • packages/ui-default/components/scratchpad/ScratchpadToolbarContainer.jsx
  • packages/ui-default/backendlib/markdown-it-media.ts
  • packages/ui-default/.eslintignore
  • packages/vjudge/src/providers/spoj.ts
  • framework/framework/error.ts
  • packages/vjudge/src/providers/uoj.ts
  • packages/hydrooj/src/script/storageUsage.ts
  • packages/hydrooj/src/handler/contest.ts
  • packages/hydrooj/src/entry/setup.ts
  • packages/vjudge/src/providers/codeforces.ts
  • framework/eslint-config/typescript.js
  • packages/vjudge/src/providers/poj.ts
  • packages/ui-default/.eslintrc.js
  • framework/eslint-config/base.yaml
  • .eslintrc.yaml
✅ Files skipped from review due to trivial changes (14)
  • packages/ui-default/components/problemconfig/tree/SubtaskSettings.tsx
  • packages/ui-default/components/problemconfig/ProblemConfigEditor.tsx
  • packages/ui-default/components/message/worker.ts
  • packages/ui-default/components/problemconfig/tree/Testcase.tsx
  • packages/ui-default/backendlib/misc.ts
  • packages/ui-default/build/main.ts
  • packages/ui-default/build/config/webpack.ts
  • packages/ui-default/components/problemconfig/reducer/config.ts
  • packages/ui-default/components/problemconfig/ProblemConfigTree.tsx
  • packages/ui-default/backendlib/markdown-it-imsize.ts
  • packages/utils/lib/locate-pm2.ts
  • packages/ui-default/components/calendar/index.js
  • packages/ui-default/components/problemconfig/tree/AddTestcase.tsx
  • packages/hydrojudge/src/hosts/vj4.ts
🚧 Files skipped from review as they are similar to previous changes (24)
  • packages/ui-next/src/App.tsx
  • packages/hydrojudge/src/checkers.ts
  • packages/hydrooj/src/model/message.ts
  • packages/hydrooj/src/entry/cli.ts
  • packages/ui-next/package.json
  • packages/onsite-toolkit/frontend/resolver.page.tsx
  • packages/migrate/package.json
  • packages/ui-default/components/autocomplete/components/UserSelectAutoComplete.tsx
  • packages/hydrooj/src/model/system.ts
  • packages/hydrooj/src/model/token.ts
  • packages/hydrooj/src/model/storage.ts
  • packages/ui-default/components/autocomplete/components/AutoComplete.tsx
  • packages/hydrojudge/src/judge/hack.ts
  • packages/utils/package.json
  • packages/hydrooj/src/model/problem.ts
  • packages/hydrooj/src/ui.ts
  • packages/hydrooj/src/commands/install.ts
  • packages/hydrooj/src/handler/problem.ts
  • package.json
  • packages/vjudge/src/index.ts
  • packages/hydrooj/src/plugin-api.ts
  • packages/hydrooj/src/model/user.ts
  • packages/ui-default/backendlib/builder.ts
  • packages/ui-default/package.json
🧰 Additional context used
🧬 Code Definitions (13)
packages/hydrooj/src/model/record.ts (2)
packages/hydrooj/src/model/document.ts (1) (1)
  • apply (413-447)
packages/hydrooj/src/model/task.ts (1) (1)
  • apply (145-191)
packages/ui-default/backendlib/template.ts (3)
packages/hydrooj/src/plugin-api.ts (2) (2)
  • Service (41-41)
  • Context (41-41)
packages/ui-default/api.ts (3) (3)
  • Service (5-5)
  • ctx (5-5)
  • Context (5-5)
packages/hydrooj/src/model/builtin.ts (2) (2)
  • PERM (9-102)
  • PRIV (240-267)
packages/hydrooj/src/service/db.ts (1)
packages/hydrooj/src/options.ts (1) (1)
  • load (24-37)
packages/hydrooj/src/loader.ts (5)
packages/hydrooj/src/context.ts (3) (3)
  • EffectScope (27-27)
  • Context (31-41)
  • Context (68-77)
packages/ui-default/api.ts (2) (2)
  • ctx (5-5)
  • Context (5-5)
packages/hydrooj/src/plugin-api.ts (1) (1)
  • Context (41-41)
packages/hydrooj/src/lib/i18n.ts (1) (1)
  • name (56-56)
packages/hydrooj/src/options.ts (1) (1)
  • getAddons (39-42)
packages/elastic/index.ts (4)
packages/hydrooj/src/plugin-api.ts (2) (2)
  • Service (41-41)
  • Context (41-41)
packages/hydrooj/src/settings.ts (1) (1)
  • Context (30-34)
packages/hydrooj/src/interface.ts (1) (1)
  • ProblemSearch (619-619)
packages/hydrooj/src/model/problem.ts (1) (1)
  • ProblemModel (74-675)
packages/hydrooj/src/settings.ts (4)
packages/ui-default/backendlib/template.ts (1) (1)
  • Context (254-275)
packages/elastic/index.ts (1) (1)
  • Context (95-125)
packages/vjudge/src/index.ts (1) (1)
  • Context (191-196)
packages/hydrooj/src/service/db.ts (1) (1)
  • Context (58-66)
packages/hydrooj/src/service/bus.ts (6)
packages/hydrooj/src/context.ts (3) (3)
  • EventMap (13-13)
  • Context (31-41)
  • Context (68-77)
packages/hydrooj/src/plugin-api.ts (3) (3)
  • EventMap (57-57)
  • Handler (40-40)
  • Context (41-41)
framework/framework/interface.ts (1) (1)
  • VoidReturn (19-19)
packages/hydrooj/src/service/server.ts (1) (1)
  • Handler (74-76)
packages/hydrooj/src/service/db.ts (1) (1)
  • Context (58-66)
packages/ui-default/context.ts (2) (2)
  • Context (8-11)
  • Context (13-13)
packages/hydrooj/src/model/domain.ts (4)
packages/hydrooj/src/interface.ts (1) (1)
  • DomainDoc (306-314)
packages/hydrooj/src/service/bus.ts (1) (1)
  • apply (96-113)
packages/hydrooj/src/plugin-api.ts (2) (2)
  • Context (41-41)
  • db (58-58)
packages/hydrooj/src/service/db.ts (1) (1)
  • Context (58-66)
packages/hydrooj/src/interface.ts (1)
packages/common/types.ts (1) (1)
  • RecordJudgeInfo (84-96)
packages/hydrooj/src/model/setting.ts (5)
packages/hydrooj/src/interface.ts (1) (1)
  • Setting (46-56)
packages/hydrooj/src/service/check.ts (1) (1)
  • apply (77-80)
packages/hydrooj/src/service/layers/user.ts (1) (1)
  • ctx (5-18)
packages/hydrooj/src/context.ts (2) (2)
  • Context (31-41)
  • Context (68-77)
packages/hydrooj/src/service/db.ts (1) (1)
  • Context (58-66)
packages/hydrooj/src/entry/common.ts (4)
packages/ui-default/api.ts (2) (2)
  • ctx (5-5)
  • Context (5-5)
packages/ui-default/context.ts (3) (3)
  • ctx (18-18)
  • Context (8-11)
  • Context (13-13)
packages/hydrooj/src/plugin-api.ts (1) (1)
  • Context (41-41)
packages/hydrooj/src/utils.ts (1) (1)
  • unwrapExports (21-29)
framework/framework/server.ts (4)
packages/ui-default/context.ts (3) (3)
  • ctx (18-18)
  • Context (8-11)
  • Context (13-13)
packages/hydrooj/src/service/layers/base.ts (1) (1)
  • ctx (20-72)
packages/hydrooj/src/service/layers/user.ts (1) (1)
  • ctx (5-18)
framework/framework/interface.ts (1) (1)
  • KnownHandlers (3-5)
packages/hydrooj/src/model/document.ts (7)
packages/hydrooj/src/model/user.ts (1) (1)
  • coll (22-22)
packages/hydrooj/src/model/oplog.ts (1) (1)
  • coll (8-8)
packages/hydrooj/src/model/discussion.ts (1) (1)
  • coll (43-43)
packages/hydrooj/src/model/problem.ts (1) (1)
  • incStatus (431-436)
packages/hydrooj/src/model/token.ts (1) (1)
  • update (53-71)
packages/hydrooj/src/model/record.ts (1) (1)
  • update (195-219)
packages/hydrooj/src/service/monitor.ts (1) (1)
  • update (76-89)
🪛 Biome (1.9.4)
packages/ui-default/backendlib/template.ts

[error] 46-46: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 121-121: eval() exposes to security risks and performance issues.

See the MDN web docs for more details.
Refactor the code so that it doesn't need to call eval().

(lint/security/noGlobalEval)

packages/hydrooj/src/loader.ts

[error] 49-49: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

packages/hydrooj/src/handler/misc.ts

[error] 110-110: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)


[error] 124-124: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

packages/hydrooj/src/model/domain.ts

[error] 138-138: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

framework/framework/server.ts

[error] 139-139: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 140-140: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)

packages/hydrooj/src/handler/domain.ts

[error] 155-155: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 335-335: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

packages/hydrooj/src/model/document.ts

[error] 223-223: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

packages/ui-default/index.ts

[error] 56-56: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

🪛 GitHub Check: CodeQL
build/prepare.js

[failure] 166-166: Potential file system race condition
The file may have changed since it was checked.

🔇 Additional comments (148)
packages/hydrooj/src/handler/misc.ts (2)

17-17: Added import reflects implementation details

The newly imported sortFiles function from '../utils' is correctly used in the FilesHandler.get() method at line 38.


111-112: Enhanced security with context-based link validation

The secret validation logic has been improved to use a dynamic context-based approach via this.ctx.get('storage')?.isLinkValid?, rather than a static calculation. This is a good architectural change that allows for more flexible security validation implementations.

Ensure the storage service properly implements the isLinkValid method with appropriate security measures.

packages/hydrooj/src/interface.ts (6)

2-2: Import for ParsedAuthenticatorData added

This import is correctly added to support the updated type definition for authenticatorExtensionResults on line 83.


7-7: RecordJudgeInfo import correctly added

The RecordJudgeInfo import is now included to support the new RecordHistoryDoc interface definition. This change provides proper type safety.


83-83: Type definition updated for Authenticator interface

The authenticatorExtensionResults property's type has been changed from AuthenticationExtensionsAuthenticatorOutputs to ParsedAuthenticatorData['extensionsData'], which provides more specificity and better type alignment with the library.


226-229: New RecordHistoryDoc interface added

The new interface extends RecordJudgeInfo and adds ObjectId properties for tracking record history. This is aligned with the addition to the Collections interface on line 552 and provides proper typing for the record history collection.


552-552: New record.history collection added to Collections interface

This addition properly registers the record.history collection in the database schema, using the newly defined RecordHistoryDoc interface.


663-663: Changed addons from array to Record structure

The type of the global addons variable has been changed from string[] to Record<string, string>, which improves lookup performance and allows associating metadata with each addon.

Make sure all code that previously accessed addons as an array has been updated. In particular:

  • Check arrays accesses like addons[i]
  • Check loops like for (const i of addons)
  • Check methods like addons.forEach

Run this script to verify:

#!/bin/bash
# Find all places in the codebase where addons is accessed as an array
rg "addons\[" --type=ts
rg "\.forEach\(.*addons" --type=ts
rg "for.*of.*addons" --type=ts
build/prepare.js (8)

18-22: Modernized TypeScript configuration for ES2022 and bundler mode

The compiler options have been updated to use newer JavaScript features (ES2022) and a different module resolution strategy ('bundler'). These changes align with modern development practices and will allow using newer JavaScript features.


37-37: New UI-next reference added

The addition of the 'tsconfig.ui-next.json' reference indicates support for a new UI package, which is consistent with the later addition of the UINextConfig.


78-78: Improved filter condition for modules

The filter condition has been updated to exclude both 'ui-default' and 'ui-next' directories using a more concise approach with some().


83-87: Additional file exclusions for UI-default

These specific file exclusions suggest a reorganization of the UI package structure, possibly moving functionality to the new UI-next package or refactoring the codebase.


100-120: Updated React JSX transform and bundler configuration

The JSX transform has been updated from 'react' to 'react-jsx', which uses React 17's new JSX transform. This change, along with the bundler mode options and additional linting rules, modernizes the build configuration.


123-161: New UI-next TypeScript configuration

A comprehensive configuration for the new UI-next package has been added with appropriate settings for a modern React application, including strict type checking and path aliases.


189-189: Added skipLibCheck to plugins configuration

Adding skipLibCheck: true to the plugins configuration will improve build performance by skipping type checking of declaration files in dependencies.


197-225: Optimized file updates with tryUpdate function

The script now uses the new tryUpdate function consistently throughout the file to only write configuration files when their content has changed. This improves performance by avoiding unnecessary file writes.

packages/hydrooj/src/model/setting.ts (9)

3-3: Update import path from cordis to @cordisjs/core

The import path has been updated from 'cordis' to '@cordisjs/core', which reflects a framework upgrade. This change appears consistent with the module declaration update on line 359.


7-7: Action Required: Add "schemastery" to project dependencies

The import of Schema from schemastery is appropriate given its usage in the file. However, our verification shows that schemastery is not currently listed under either dependencies or devDependencies in your package.json (both returned null). To ensure best practices and avoid potential runtime errors, please add schemastery as a dependency in your project.

#!/bin/bash
# Verify if schemastery is included in the package dependencies
cat packages/hydrooj/package.json | jq '.dependencies.schemastery, .devDependencies.schemastery'

73-80: Added type declaration for Schemastery namespace

Good addition of the global namespace declaration for Schemastery with the Meta interface. This provides proper type information for the schema metadata used throughout the file.


121-122: Enhanced setting functions to accept Schema objects

Good refactoring of setting functions to accept either traditional _Setting arrays or new Schema objects. This provides flexibility while maintaining backward compatibility with existing code.

The use of flatMap to process the settings is clean and efficient. This change makes it easier to define settings with the new Schema-based approach.

Also applies to: 141-142, 161-162, 177-178, 193-194


290-318: Well-implemented Schema-based setting definitions

The new Schema-based approach for defining system settings is a good improvement over the previous approach. It provides better type safety, structure, and self-documentation through the schema metadata.

This implementation serves as a good example for how other settings can be migrated to use the Schema-based approach in the future.


359-359: Updated module declaration path

The module declaration has been updated from 'cordis' to '@cordisjs/core', which is consistent with the import change on line 3.


388-388: Added dependency injection for db

Good practice adding explicit dependency injection for the database dependency. This makes the dependencies clearer and easier to manage.


395-395: Switched to context-based db access

Good change from using the global database reference (global.Hydro.service.db) to using the context-based reference (ctx.db). This improves modularity and testability by making the database dependency explicit.


419-420: Added inject to the exported model

Properly exported the inject constant in the global model, maintaining consistency with the dependency injection pattern introduced earlier.

packages/utils/lib/utils.ts (6)

10-10: Updated import structure for logger implementation

The import statement has been modified to bring in Exporter, Factory, and rename Logger to Reggol from the 'reggol' package. This aligns with the new factory-based approach to logger creation.


15-16: Factory implementation for logger creation

Introducing a factory pattern for logger creation is a good design choice that improves modularity and configurability.


17-27: Centralized logger configuration

The implementation properly configures the logger with specific settings like time format, label width, and appropriate log levels based on the environment. This is more maintainable than directly manipulating logger properties.


29-31: Added logger creation function

The createLogger function encapsulates the factory usage, which is a good abstraction that simplifies logger creation throughout the codebase.


35-35: Export statement preserved

Preserving the moment export is appropriate since it wasn't targeted for refactoring.


33-34:

❓ Verification inconclusive

Verify the circular type definition and type assertion

The Logger type definition appears circular (it references itself), and the export uses a double type assertion (as any as Logger), which bypasses TypeScript's type checking.

While this may work as intended, consider if a cleaner type structure could be implemented to avoid potential type-related issues.


🏁 Script executed:

#!/bin/bash
# Search for usages of Logger to ensure this type definition works correctly
echo "Checking Logger usage patterns..."
rg "new Logger\(" --type ts
rg "Logger\(" --type ts
rg "import.*Logger.*from.*utils" --type ts

Length of output: 8671


Action: Revisit the Logger type definition for potential refactoring

The usage of Logger across the codebase (e.g., via expressions like new Logger(...)) confirms that its current structure is working as intended. However, note that:

  • The type definition is self-referential—Logger extends Reggol and includes a constructor signature that returns a Reggol & Logger. While this pattern enables the factory behavior, it is inherently circular.
  • The export uses a double type assertion (as any as Logger), which bypasses TypeScript’s type checking and may obscure potential type mismatches.

Although these approaches function currently, consider whether you can refactor to a cleaner type structure. For instance, explicitly separating the instance type from its constructor signature (or properly typing createLogger) might improve type safety and maintainability.

packages/hydrooj/src/loader.ts (13)

15-17: Improved imports from context module

The import has been updated to include more specific entities from the context module: Context, Service, ScopeStatus, and EffectScope. This change improves type safety by explicitly importing the required types.


22-22: Added Schema import for configuration handling

The import of the Schema library from 'schemastery' was added to support the new schema-based configuration resolution implemented in the resolveConfig method.


48-48: Enhanced type safety for state property

The state property type has been properly defined as Record<string, EffectScope> using the imported EffectScope type, improving type safety.


54-55: Explicit dependency declaration

The static inject property now explicitly declares all required dependencies: 'config', 'timer', 'i18n', and 'logger'. This is good practice for dependency injection and makes the dependencies clearer.


56-57: Updated constructor to use Context parameter

The constructor now takes a ctx parameter of type Context instead of app, and passes both the context and service name to the superclass constructor. This aligns with the dependency injection pattern and makes the service name explicit.


59-60: Updated event listener to use ctx directly

The event listener for 'app/started' now uses ctx directly and provides an async callback for the interval function. This is consistent with the constructor changes and properly handles asynchronous operations.


98-107: Added schema-based configuration resolution

The new async resolveConfig method properly implements schema-based configuration resolution using the Schema library. It creates a schema request based on the provided configScope, attempts to migrate the configuration, and returns the appropriate config object.

This implementation is more robust than the previous approach and provides better validation for configurations.


109-117: Improved plugin reloading with async support

The reloadPlugin method has been updated to be async and now takes a configScope parameter. It uses the new resolveConfig method to retrieve the plugin configuration and properly handles the plugin application through this.ctx.plugin.

The template string for logging has been updated to conditionally include the configScope information, which improves log readability.


135-136: Enhanced error logging

Error logging in the resolvePlugin method has been improved to provide more detailed error information, which will be helpful for debugging plugin resolution issues.


147-152: Async preload function with proper dependency injection

The preload function has been updated to be async and now initializes global.app by awaiting a promise that resolves after injecting the necessary dependencies. This ensures that the app is fully initialized before proceeding.


161-161: Updated global addons assignment

The assignment to global.addons has been simplified but maintains the same functionality.


170-171: Proper awaiting of preload function

The load function now properly awaits the preload function, ensuring that all initialization is complete before proceeding with the rest of the loading process.


208-210: Consistent async handling in loadCli

The loadCli function now also awaits the preload function, maintaining consistency with the load function and ensuring proper initialization before CLI operations.

eslint.config.mjs (2)

42-52: Good practice using simple-import-sort/imports.

This plugin effectively enforces a standardized import order. Ensure developers are aware of this sorting convention and consider adding an auto-fix script or CI check to maintain consistent import sorting across the codebase.


110-120: Confirm the correctness of disabled rules.

Options like 'function-paren-newline': 'off', 'no-lonely-if': 'off', and 'no-await-in-loop': 'off' can hide potential readability or performance pitfalls. If any of these rules is relevant to your codebase (e.g., avoiding blocking awaits in loops), you may want to re-enable them or enforce them with a warning level for better maintainer awareness.

framework/eslint-config/package.json (2)

5-5: Validate new main entry.

Switching "main": "base.mjs" is sensible if you intend to load this ESLint configuration by default. Verify that all references and import paths that relied on the old react.yaml entry are updated to avoid broken references.


26-27:

❓ Verification inconclusive

Confirm TypeScript 5.8.2 stability.

You’ve introduced "typescript": "^5.8.2" as an optional dependency. If the codebase relies on features unique to that version, ensure your CI pipeline covers TypeScript 5.8.2–specific tests. For a deeper review:


🏁 Script executed:

#!/bin/bash
# Attempting to verify if TypeScript 5.8.2 is compatible with the rest of the codebase.
# We'll parse any references to "typescript" in the repository and see if conflicting versions exist.

fd -t f --exec rg "typescript" {}

Length of output: 4873


Confirm TypeScript 5.8.2 Compatibility in CI

Your package now lists "typescript": "^5.8.2" as an optional dependency. The repository output shows multiple references using version strings like ^5.8.2, ~5.8.2, and even an explicit "5.8.2", which appear consistent. However, it's not clear whether the CI pipeline is set up to exercise tests that specifically target TypeScript 5.8.2 features. Please ensure that:

  • The CI configuration explicitly covers scenarios where TypeScript 5.8.2–specific behavior is exercised.
  • No conflicting version constraints exist elsewhere that might inadvertently pull a different TypeScript release.

Reviewing the CI settings for TypeScript-related tests will help safeguard stability.

packages/hydrooj/src/model/opcount.ts (1)

16-16: MongoDB driver result access pattern updated

This change updates how the operation count is accessed from MongoDB's findOneAndUpdate result. The code now directly accesses res.opcount instead of the previous res.value.opcount, aligning with newer MongoDB driver versions (4.x+) where documents are returned directly rather than nested in a value property.

packages/hydrooj/src/model/task.ts (3)

9-9: Updated bus import to use default import

The import statement has been changed from namespace import to default import, aligning with module refactoring across the codebase.


22-24: Updated MongoDB result handling pattern

The code now checks res directly instead of res.value, matching the updated MongoDB driver pattern. This change ensures consistency with other model files and newer MongoDB driver behavior.


184-186: Updated event handling logic

The event logging and handling has been simplified to directly check res instead of res.value. This maintains consistent MongoDB result handling across the codebase.

packages/hydrooj/src/model/oauth.ts (1)

18-18: MongoDB result access pattern updated

Changed from accessing res.value?.uid to directly accessing res?.uid, aligning with the MongoDB driver update pattern seen across the codebase. This ensures consistent handling of database operation results.

packages/hydrooj/src/model/blacklist.ts (1)

16-21: Simplified return statement for MongoDB operation

The method now directly returns the result of the database operation instead of storing it in an intermediate variable and returning res.value. This change is consistent with the updated MongoDB driver result handling pattern throughout the codebase.

packages/hydrooj/src/model/record.ts (5)

2-2: Added lodash.pick for record history implementation.

The pick function from lodash is imported to selectively extract specific fields from record documents before storing them in the history collection. This is a good practice for optimizing storage by keeping only the essential data in history records.


23-23: New collection for record history tracking.

Adding a static collHistory collection to store historical versions of records is a good design for maintaining an audit trail of changes. This enables features like viewing previous submissions or tracking record modifications.


235-237: Replaced instanceof Array with Array.isArray().

This is an important safety improvement. Array.isArray() is the preferred method as it correctly detects arrays from different execution contexts, while instanceof Array may return false for array-like objects or arrays from different contexts.


250-264: Implemented record history preservation.

Good implementation of record history preservation that fetches records before deletion, extracts relevant fields using pick(), and stores them in the history collection with a new ObjectId. This approach ensures that important record data is preserved even after resets or rejudges.


283-283: Updated apply function to async and added index for record history.

The function has been correctly updated to be asynchronous, and proper indexes have been created for the new collHistory collection to optimize query performance. The index on { rid: 1, _id: -1 } will efficiently support queries filtering by record ID and sorting by insertion time.

Also applies to: 307-327

packages/hydrooj/src/model/contest.ts (4)

12-12: Changed bus import to default import.

Switched from namespace import (import * as bus) to default import (import bus), which indicates the module has been refactored to use a default export pattern. This is part of the broader codebase modernization effort.


292-294: Improved object immutability with spread operator.

Using the spread operator to create shallow copies of objects instead of direct assignment prevents unintended modifications to the original objects. This is a good practice for maintaining immutability and avoiding side effects.


360-360: Enhanced tsddict condition to account for locked contests.

The condition for determining tsddict now includes a check for whether the contest is locked, which improves the logic for handling contest states. This ensures correct display of contest details based on the current state.


388-388: Added optional chaining for timestamps.

The code now uses optional chaining for startAt and beginAt, ensuring that the code safely handles cases where these properties might be undefined. This improves robustness and prevents potential runtime errors.

Also applies to: 405-406

packages/ui-default/backendlib/template.ts (6)

25-42: Added async file utilities for template management.

The new getFiles and locateFile functions provide better file handling capabilities with async/await patterns. The getFiles function recursively collects files from directories, while locateFile efficiently finds files from a list of possible filenames. These utilities improve the file discovery and management process.


44-57: Enhanced Nunjucks runtime with improved member lookup.

The custom implementation of memberLookup adds support for original function references and proper handling of undefined/null objects. This improves the template engine's ability to access object properties and methods safely.

🧰 Tools
🪛 Biome (1.9.4)

[error] 46-46: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


161-177: Good implementation of service-oriented architecture.

The new TemplateService class follows good service-oriented design practices with dependency injection and proper event handling. The static inject property clearly defines dependencies, and the constructor properly sets up event handlers for template rendering.


183-218: Well-designed custom Loader implementation.

The Loader class efficiently handles template resolution with fallback mechanisms. It first checks the registry for cached templates and then checks the filesystem in development mode. The error handling is appropriate with clear error messages when templates cannot be found.


221-252: Missing timeout handling in render function.

The render function logs slow renders (>5000ms) but lacks a timeout mechanism to prevent long-running renders from blocking the server.

Add a timeout mechanism to prevent extremely long-running renders:

   const render = (name: string, state: any) => new Promise<string>((resolve, reject) => {
     const start = Date.now();
+    const renderTimeout = setTimeout(() => {
+      reject(new Error(`Render timeout for template ${name}`));
+    }, 10000); // 10 seconds timeout
+    
     env.render(name, {
       page_name: name.split('.')[0],
       ...state,
       formatJudgeTexts: (texts) => texts.map((text) => {
         if (typeof text === 'string') return text;
         return state._(text.message).format(...text.params || []) + ((process.env.DEV && text.stack) ? `\n${text.stack}` : '');
       }).join('\n'),
       datetimeSpan: (arg0, arg1, arg2) => misc.datetimeSpan(arg0, arg1, arg2, state.handler.user?.timeZone),
       ctx: state.handler?.ctx,
       perm: PERM,
       PRIV,
       STATUS,
       UiContext: state.handler?.UiContext || {},
     }, (err, res) => {
+      clearTimeout(renderTimeout);
       const end = Date.now();
       if (end - start > 5000) console.error(`Render of ${name} took ${end - start}ms`);
       if (err) reject(err);
       else resolve(res || '');
     });
   });

254-275: Good error handling for template initialization.

The [Context.init] method properly handles template loading with good error handling. It notifies users of template loading failures, which improves user experience and helps with debugging. The use of a logger for both successful and failed operations provides good visibility into the initialization process.

packages/hydrooj/src/entry/worker.ts (5)

9-10: Improved service imports with specific service classes.

Using explicit imports of MongoService and ConfigService instead of importing entire modules improves code readability and can lead to better tree-shaking by bundlers.


24-34: Enhanced database initialization with async/await pattern.

The refactored code uses an async/await pattern to get the MongoDB URL and initialize services. This is a better approach than the previous synchronous loading, as it allows for proper error handling and ensures that components are initialized in the correct order.


36-51: Improved dependency management with Promise-based injection.

Using Promises with the dependency injection system ensures that required dependencies are fully loaded before proceeding. This prevents issues where code might try to use services that aren't fully initialized.


61-76: Consistent use of dependency injection pattern.

The consistent application of the dependency injection pattern throughout the initialization process improves code maintainability and ensures proper service lifecycle management. The approach of waiting for dependencies to be available before proceeding with initialization is good practice.


96-102: Streamlined server startup with dependency injection.

The server startup process is now managed through the dependency injection system, which provides a cleaner and more maintainable approach compared to direct function calls. The proper sequencing of events (listenapp/listenapp/ready) ensures that all components are properly initialized.

packages/hydrooj/src/service/db.ts (7)

7-7: Good job updating imports for better clarity and organization.

The change from importing bus as a namespace to a default import aligns with modern ES module practices and improves code readability.


29-33: Excellent type enhancement to Context interface.

Adding db: MongoService property to the Context interface improves type safety and makes database dependencies explicit throughout the application.


35-41: Good restructuring with dependency injection pattern.

The change to extend Service and accept a Context parameter in the constructor follows proper dependency injection patterns, making the code more testable and modular.


43-56: Well-implemented static method for URL resolution.

The static getUrl method nicely encapsulates the logic for retrieving the MongoDB connection URL, with special handling for CI environments using in-memory MongoDB.


58-66: Excellent use of generator functions for resource management.

The async generator method with [Context.init] that yields a cleanup function is a great pattern for resource management. The client.close() callback ensures proper cleanup when the service is shut down.


69-70: Good refactoring of collection method.

Using the config properties for prefix and collection mapping provides more flexibility in how collections are named and accessed.


182-189: Appropriate use of deprecation pattern with proxy.

The deprecated proxy object provides backward compatibility while guiding users to use the new context-based approach. This is a good transitional pattern.

packages/hydrooj/src/model/schedule.ts (2)

7-7: Good update to import type from default export.

Updated import statement for WorkerService reflects the change to a default export in the worker.ts file.


18-25: Simplified result handling logic.

The updated code directly uses the result object rather than accessing through .value property, which aligns with the updated MongoDB driver response format.

packages/hydrooj/src/service/worker.ts (2)

12-12: Good conversion to default export.

Converting to a default export simplifies imports and is consistent with the module pattern being adopted across the codebase.


32-39: Consistent result handling with schedule.ts.

The result handling has been updated consistently with the changes in schedule.ts, properly accessing properties directly from the result object.

packages/hydrooj/src/service/bus.ts (5)

4-5: Improved type import for better type safety.

Importing the Handler type from framework package improves type consistency across the codebase.


17-17: Simplified EventMap interface definition.

Removing extension from KnownHandlerEvents simplifies the event typing system and makes it more maintainable.


32-32: Enhanced type safety for broadcast event.

Updating the 'bus/broadcast' event type to reference only 'keyof EventMap' improves type checking when broadcasting events.


87-87: Improved handler type specificity.

Specifying 'Handler' for the oplog/log event handler type ensures handlers have the appropriate context access.


115-116: Simplified export structure.

Exporting only the app simplifies the module interface and aligns with the single responsibility principle.

packages/elastic/index.ts (5)

4-4: No immediate concerns.
The import statement is correct and helps define the necessary types needed for the service.


20-25: Configuration schema is well-defined
This helps ensure consistent usage of the url and indexSize properties across the service.


34-69: Add explicit type annotations for the opts parameter
Explicit type annotations for the opts parameter will enhance type safety and code readability.


72-79: Add proper type annotation for the run method parameters
Consider specifying types for domainId and report to enhance readability and ensure type safety.


95-125: Add error handling for event-driven operations
Consider wrapping each of these event callbacks in a try-catch to handle potential exceptions, preventing unhandled promise rejections.

packages/hydrooj/src/settings.ts (13)

3-3: Import statements are fine.
No issues with the new import.


8-10: Context augmentation seems correct
This ensures that config is accessible on Context.


26-29: No concerns
Constructor is straightforward.


30-34: Ensure config documents exist
If there's no 'config' document, handle the case gracefully. Currently, your code logs an error but won't break the flow, which is good.


36-38: Valid usage of schema intersection
Ensures the system config is validated against all registered settings.


40-53: Robust error handling
The try-catch block ensures you handle parsing errors gracefully.


55-67: Double-check deep object merges
The logic here clones the source and modifies the path. For more complex merges, be sure this approach does not inadvertently override nested properties.


69-77: Leverage set-level validations
This approach is fine, but consider referencing any additional constraints (e.g., type constraints or custom validation logic).


79-84: Effective approach to persist & reload config
This helps ensure the config changes are validated and persisted consistently.


109-112: Sequential migration chain is well-handled
Ensures migrations don't overlap and cause inconsistent states.


114-123: Defensive checks look good
Rejecting blacklisted paths helps prevent prototype pollution.


125-128: Method is straightforward
Combines applyDelta and saveConfig for easy property updates.


130-171: Surface DB write errors in the Proxy setter
Consider an asynchronous approach or error handling to ensure DB write errors are not silently ignored.

packages/hydrooj/src/model/domain.ts (5)

4-4: Import of Context
No issues with adding the new import.


6-6: No issue with bus import
This is consistent with other references to bus in the file.


62-62: Ensuring owners are assigned root role by default
This is a reasonable approach for domain creation.


130-133: Filtering by join: true
This ensures only actively joined domain users are counted.


257-259: Using join: true
This logic ensures only domain entries with joined status are retrieved.

packages/hydrooj/src/entry/common.ts (4)

25-45: API migration from array to Record improves type safety.

The getLoader function has been refactored to:

  1. Remove the dontLoad parameter
  2. Change pending from an array of strings to a Record of string key-value pairs
  3. Update iteration logic to use Object.entries instead of directly iterating over the array

These changes improve type safety and clarity in how plugins are loaded and referenced.


56-57: Simplified reloadPlugin call signature.

The call to ctx.loader.reloadPlugin has been updated to remove the empty object parameter, which aligns with the similar change in the loader function. This simplifies the API surface.


60-81: Updated locale function to use Record instead of array.

The locale function has been updated to accept a Record instead of an array for the pending parameter, and iteration has been updated to use Object.values. This is consistent with the changes to the getLoader function.


83-122: Updated setting function to use Record instead of array.

The setting function has been updated similar to locale, accepting a Record instead of an array for the pending parameter and updating iteration to use Object.values. This maintains consistency across the codebase.

packages/ui-default/index.ts (5)

3-4: Dependency replacement for better modularity.

The import of SystemSettings has been removed in favor of using context-based settings, and a new import for TemplateService has been added. This change improves modularity by leveraging dependency injection.

Also applies to: 7-7


25-25: Added explicit type for improved type safety.

The sections variable now has an explicit type definition, enhancing code readability and type safety.


56-56: Remove the empty object pattern.

Static analysis flags { } as an unexpected empty pattern. Consider removing it as it doesn't serve any purpose.

-  async get({ }, legacy = false, nohint = false) {
+  async get(legacy = false, nohint = false) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 56-56: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)


77-78: Updated schema generation to use context-based settings.

The schema is now generated using this.ctx.config.settings instead of the previously imported SystemSettings, which aligns with the dependency changes and context-based architecture.


167-168: Replaced dynamic import with direct service reference.

The dynamic import of the template module has been replaced with direct use of TemplateService, which improves code readability and performance.

packages/hydrooj/package.json (3)

3-3: Major version bump for Hydro v5.

The version has been updated from 4.19.1 to 5.0.0-alpha.0, indicating a major version change with breaking API changes. This aligns with the PR title "Hydro v5".


19-21: Migrated from monolithic to modular dependencies.

Replaced cordis dependency with more modular @cordisjs/* packages:

  • @cordisjs/core
  • @cordisjs/logger
  • @cordisjs/plugin-timer

This promotes better architecture by using more granular, focused packages.


22-58:

✅ Verification successful

Updated multiple dependency versions.

Multiple dependencies have been updated to newer versions, which may include bug fixes, performance improvements, and new features. Note that some versions are alpha/beta releases, which is consistent with the package itself being marked as alpha.


🏁 Script executed:

#!/bin/bash
# Check for any potentially incompatible dependency updates
echo "Checking graphql-scalars update from <1.24.2:"
npm view graphql-scalars@^1.24.2 version

echo -e "\nChecking mongodb update from <6.15.0:"
npm view mongodb@^6.15.0 version

echo -e "\nChecking nanoid update from <5.1.5:"
npm view nanoid@^5.1.5 version

echo -e "\nChecking superagent update from <10.2.0:"
npm view superagent@^10.2.0 version

Length of output: 559


Dependency Updates Verified

  • The dependency versions in packages/hydrooj/package.json have been successfully updated.
  • Verification confirms that:
    • graphql-scalars is now at 1.24.2
    • mongodb is now at 6.15.0
    • nanoid is now at 5.1.5
    • superagent is now at 10.2.0
  • These updates align with expectations, and the note regarding alpha/beta releases remains applicable given the package's alpha status.
packages/hydrooj/src/handler/domain.ts (5)

105-147: Refactored to use MongoDB aggregation pipeline for more efficient queries.

The user retrieval logic has been improved with an aggregation pipeline that:

  1. Filters users by role (excluding 'default' and 'guest')
  2. Joins with user collection to retrieve essential user data (username, avatar)
  3. Projects only necessary fields

This approach is more efficient than separate queries and reduces the amount of data transferred.


258-258: Simplified role filtering logic.

The filter has been updated to exclude only the 'guest' role, rather than both 'default' and 'guest'. This allows users with the 'default' role to be considered in role assignments.


322-337: Enhanced domain join preparation with target parameter.

The prepare method has been updated to:

  1. Accept a target parameter, making it more flexible
  2. Check if the user is already a member of the domain
  3. Retrieve roles based on the specified target domain
  4. Determine assigned role based on user privileges

This improves flexibility and makes the domain joining process more robust.

🧰 Tools
🪛 Biome (1.9.4)

[error] 335-335: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


339-358: Improved domain join flow with redirect support.

The get method now:

  1. Accepts target and redirect parameters for more flexible navigation
  2. Includes detailed domain information in the response
  3. Improves the user experience by providing more context about the domain being joined

This enhances usability and provides a clearer joining experience.


360-377: Enhanced post-join behavior with flexible targeting and redirection.

The post method has been updated to:

  1. Support joining a specific target domain rather than just the current domain
  2. Conditionally assign roles based on join settings
  3. Redirect to a specified URL after successful join

This provides a more configurable and user-friendly domain joining workflow.

packages/hydrooj/src/model/document.ts (6)

12-12: Default import used instead of namespace import.

The import statement has been changed from import * as bus from '../service/bus' to import bus from '../service/bus'. This suggests that the bus module now exports a default value instead of multiple named exports.


18-18: New type utility added to exclude symbol keys.

The NormalArrayKeys<O, P = any> type utility has been introduced to exclude symbol keys from array keys, enhancing type safety when working with array properties.


23-33: Enhanced type safety with const assertions.

The constant declarations have been updated to use TypeScript's as const assertion instead of explicit type annotations. This change ensures that the constants are treated as literal types, providing better type inference and type safety throughout the codebase.


112-117: Code simplified by directly returning promise.

The function now directly returns the result of the database operation instead of using an intermediate variable. This is a good simplification without changing behavior.


152-157: Consistently returning database operation promises directly.

Multiple methods in the file have been updated to directly return database operation promises instead of using intermediate variables. This pattern is applied consistently throughout the file, making the code more concise and easier to read.

Also applies to: 163-168, 211-217, 224-230, 255-265, 301-311, 328-333, 358-363, 369-374, 385-392, 397-402, 410-411


385-392: Improved conditional assignment with nullish assignment operator.

The code now uses the nullish assignment operator (||=) instead of a separate conditional block, which is a more concise way to handle the fallback case while maintaining the same behavior.

framework/framework/server.ts (12)

5-5: Updated import to use CordisContext.

The import has been changed from Context to CordisContext from the @cordisjs/core package, indicating a shift in the underlying framework architecture.


44-52: Added utility for context isolation and lifecycle management.

The new forkContextWithScope function creates an isolated context with its own lifecycle, which enhances the ability to manage resources and handle cleanup properly. The function uses the newer Symbol.asyncDispose feature for asynchronous resource management.


140-141: Enhanced type safety with generic context type parameters.

The handler classes and service now use generic type parameters for context, which allows for more flexible context handling while maintaining type safety. The static handler identifier is also consistently initialized.

Also applies to: 210-212, 258-260, 297-300, 337-338, 352-353

🧰 Tools
🪛 Biome (1.9.4)

[error] 140-140: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)


487-489: Using structured binding and resource management with 'using' declaration.

The code now uses the using declaration with await forkContextWithScope to ensure proper resource cleanup through the Symbol.asyncDispose interface, which is a safer way to manage asynchronous resources.


491-492: More robust handler name detection.

The handler name detection now uses Object.hasOwn and proper type checking to safely access the handler identifier, improving reliability when working with prototype chains.


599-613: Improved connection cleanup logic.

The connection cleanup logic has been significantly improved with better error handling, resource cleanup, and state management. The function now checks for the closed state to prevent multiple cleanup attempts and properly handles various cleanup scenarios.


635-653: Enhanced WebSocket message handling.

The WebSocket message handling has been improved with better error handling and proper JSON parsing with error recovery. The code now properly handles ping/pong messages and ensures that connection state is maintained.


744-750: Updated type signature for Route handlers.

The Route method now correctly specifies that RouteHandler should be of type typeof Handler<C> instead of any, improving type safety for route registration.


753-755: Updated type signature for Connection handlers.

The Connection method now correctly specifies that RouteHandler should be of type typeof ConnectionHandler<C> instead of any, improving type safety for WebSocket connection handlers.


787-810: Added robust mixin application utility.

The new _applyMixin method provides a more structured approach to extending handler functionalities with proper lifecycle management. It correctly handles property existence checks, restoration of original values on cleanup, and warning about potential conflicts.


812-828: Added specialized mixin methods for different handler types.

The new specialized mixin methods (applyMixin, handlerMixin, httpHandlerMixin, wsHandlerMixin) provide type-safe ways to extend different handler types, enhancing the extensibility of the framework.

However, the implementation for wsHandlerMixin previously had an issue where it wasn't actually assigning properties. Verify that this is now correctly using the _applyMixin method which properly assigns properties.


841-848: Updated module declaration with proper generic types.

The module declaration has been updated to reflect the generic context type used throughout the file, ensuring that type safety is maintained when extending the Context interface.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (8)
build/prepare.js (1)

163-167: ⚠️ Potential issue

Fix potential file system race condition

The tryUpdate function has a potential race condition between checking if a file exists and reading it. If the file is deleted between these operations, it could cause errors.

Consider using a try-catch approach instead:

const tryUpdate = (location, content) => {
-    const current = fs.existsSync(location) ? fs.readFileSync(location, 'utf-8') : '';
+    let current = '';
+    try {
+        current = fs.readFileSync(location, 'utf-8');
+    } catch (err) {
+        // File doesn't exist or cannot be read
+    }
    const expected = typeof content === 'string' ? content : JSON.stringify(content, null, 2);
    if (expected !== current) fs.writeFileSync(location, expected);
};
🧰 Tools
🪛 GitHub Check: CodeQL

[failure] 166-166: Potential file system race condition
The file may have changed since it was checked.

framework/framework/server.ts (2)

139-140: ⚠️ Potential issue

Fix unsafe declaration merging.

The empty interface HandlerCommon<C> followed by a class with the same name creates unsafe declaration merging, which TypeScript doesn't fully validate. This pattern is flagged by static analysis tools.

Either remove the empty interface or convert it to a type alias:

-export interface HandlerCommon<C> { } // eslint-disable-line @typescript-eslint/no-unused-vars
+// Use a type alias if you need to extend the class externally
+export type HandlerCommonProps<C> = {};

export class HandlerCommon<C> {
🧰 Tools
🪛 Biome (1.9.4)

[error] 139-139: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 140-140: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)


705-705: ⚠️ Potential issue

Fix condition that always evaluates to false.

Static analysis indicates the if (perm) condition always evaluates to false.

Verify the initialization of perm in the Checker function:

 return function check(this: Handler<C>) {
     checker();
-    if (perm) this.checkPerm(perm);
+    if (perm !== undefined) this.checkPerm(perm);
     if (priv) this.checkPriv(priv);
 };
packages/hydrooj/src/handler/misc.ts (1)

124-124: ⚠️ Potential issue

Address the empty object pattern in parameter list.

Similar to the previous instance, the empty object pattern in the parameter list should be addressed to improve code clarity and avoid static analysis warnings.

🧰 Tools
🪛 Biome (1.9.4)

[error] 124-124: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

packages/elastic/index.ts (2)

34-34: ⚠️ Potential issue

Add proper type annotation for the opts parameter.

The opts parameter is missing a type annotation. Without proper typing, this reduces type safety and makes the code more prone to errors.

Consider defining an interface or using a more specific type:

-async problemSearch(domainId: string, q: string, opts): ReturnType<ProblemSearch> {
+async problemSearch(domainId: string, q: string, opts: { limit?: number; skip?: number }): ReturnType<ProblemSearch> {

72-72: ⚠️ Potential issue

Add proper type annotations for the run method parameters.

The parameters in the run method lack proper type annotations, which reduces type safety and makes the code more difficult to understand and maintain.

packages/hydrooj/src/settings.ts (2)

55-67: ⚠️ Potential issue

Potential prototype pollution risk persists

While you've implemented a blacklist check on line 57, there's still a potential prototype pollution risk at line 65 when setting cursor[t] = value. The blacklist approach helps but static analysis tools still flag this as a risk.

Consider using a safer approach with a specialized library like lodash's _.set() or implementing additional checks:

-    cursor[t] = value;
+    if (Object.prototype.hasOwnProperty.call(cursor, t) || !Object.prototype.hasOwnProperty.call(Object.prototype, t)) {
+        cursor[t] = value;
+    }

164-167: ⚠️ Potential issue

Fire-and-forget in Proxy setter still exists

The set trap is not awaiting the async setConfig method, which means errors in the database operation will be silently ignored.

- set(self, p: string | symbol, newValue: any) {
-     that.setConfig(path.concat(p).join(','), newValue);
-     return true;
- },
+ async set(self, p: string | symbol, newValue: any) {
+     try {
+         await that.setConfig(path.concat(p).join(','), newValue);
+         return true;
+     } catch (err) {
+         console.error('Failed to update config:', err);
+         return false;
+     }
+ },
🧹 Nitpick comments (11)
packages/utils/lib/utils.ts (2)

15-27: Consider addressing potential issues in logger factory configuration

The factory pattern implementation is a good improvement for logger management, but there are a couple of concerns:

  1. The timestamp is set using Date.now() which will be evaluated once when the module loads, creating a static timestamp rather than a dynamic one.
  2. There's a magic number in factory.exporters.get(1) - is this intentional? The exporter was just added, so normally it would be at index 0.
factory.addExporter(new Exporter.Console({
    showDiff: false,
    showTime: 'dd hh:mm:ss',
    label: {
        align: 'right',
        width: 9,
        margin: 1,
    },
-    timestamp: Date.now(),
+    timestamp: () => Date.now(), // Make timestamp dynamic if that's the intention
}));
-factory.exporters.get(1).levels = { default: process.env.DEV ? 3 : 2 };
+// Get the exporter by reference or use an explicit index with a comment explaining why index 1
+const consoleExporter = factory.exporters.get(factory.exporters.size - 1); // Get the exporter we just added
+consoleExporter.levels = { default: process.env.DEV ? 3 : 2 };

33-34: Consider avoiding the use of any type assertion

The type definition for Logger is well structured to support both instance methods and constructor usage. However, the double type assertion with any bypasses TypeScript's type checking, which could hide potential type errors.

export type Logger = Reggol & { new(name: string): Reggol & Logger };
-export const Logger = createLogger as any as Logger;
+// Consider a more type-safe approach if possible
+export const Logger = createLogger as unknown as Logger;

Using unknown instead of any requires an explicit type check before using the value, which can help catch potential type errors. If this cast is necessary due to TypeScript limitations, consider adding a comment explaining why.

packages/hydrooj/src/handler/domain.ts (2)

150-157: Consider performance impact of the delete operator

The delete operator at line 155 may have a small performance impact. While functionally correct, consider an alternative approach for better performance.

  const users = dudocs.map((dudoc) => {
-    const u = {
-      ...dudoc,
-      ...dudoc.user,
-    };
-    delete u.user;
-    return u;
+    const { user: userData, ...rest } = dudoc;
+    return { ...rest, ...userData };
  });
🧰 Tools
🪛 Biome (1.9.4)

[error] 155-155: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


335-335: Consider performance impact of the delete operator

Similar to the earlier instance, the delete operator may have a performance impact. Consider using conditional assignment instead.

-  if (assignedRole !== 'default') delete this.joinSettings;
+  if (assignedRole !== 'default') this.joinSettings = undefined;
🧰 Tools
🪛 Biome (1.9.4)

[error] 335-335: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

packages/ui-default/backendlib/template.ts (3)

46-47: Use optional chaining for cleaner code.

The current null check could be simplified with optional chaining for better readability.

-if ((obj || {})._original) obj = obj._original;
+if (obj?._original) obj = obj._original;
🧰 Tools
🪛 Biome (1.9.4)

[error] 46-46: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


25-34: Consider optimizing file search for large directories

The getFiles function recursively scans directories which can be inefficient for large directory structures. Consider implementing a more efficient approach using streams or by limiting recursion depth.

async function getFiles(folder: string, base = ''): Promise<string[]> {
  const files: string[] = [];
  const f = await fs.readdir(folder);
+  // Consider adding a depth limit to prevent excessive recursion
+  const MAX_DEPTH = 10;
+  const currentDepth = base.split('/').length;
+  
+  if (currentDepth > MAX_DEPTH) {
+    console.warn(`Maximum directory depth reached at ${folder}`);
+    return files;
+  }
  
  for (const i of f) {
    if ((await fs.stat(path.join(folder, i))).isDirectory()) {
      files.push(...await getFiles(path.join(folder, i), path.join(base, i)));
    } else files.push(path.join(base, i));
  }
  return files.map((item) => item.replace(/\\/gmi, '/'));
}

164-165: Add explicit type for registry property

The registry property should have a more explicit type definition to improve code maintainability and type safety.

-  registry: Record<string, string> = {};
+  registry: Record<string, string | undefined> = {};
packages/hydrooj/src/model/document.ts (1)

223-223: Use Array.isArray() instead of instanceof Array.

instanceof Array can return false for arrays from different execution contexts and for array-like objects. Array.isArray() is more reliable.

-    subId = (subId instanceof Array) ? subId : [subId];
+    subId = Array.isArray(subId) ? subId : [subId];
🧰 Tools
🪛 Biome (1.9.4)

[error] 223-223: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

packages/hydrooj/src/loader.ts (2)

48-49: Type improvement needed for config property

While you've properly typed the state property with Record<string, EffectScope>, the config property uses an empty object type {}, which is considered a bad practice.

- public config: {};
+ public config: Record<string, any>;
🧰 Tools
🪛 Biome (1.9.4)

[error] 49-49: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)


128-141: Use Array.isArray() for better compatibility

The use of instanceof Array on line 138 can lead to false negatives with arrays from different contexts.

- this.cache[name] ||= require.resolve(name);
+ this.cache[name] = this.cache[name] || require.resolve(name);

This ensures compatibility with older JavaScript environments that may not support the ||= operator.

packages/hydrooj/src/model/domain.ts (1)

138-138: Replace instanceof Array with Array.isArray()

Using instanceof Array can lead to false negatives when dealing with arrays from different JavaScript contexts.

- if (!(uid instanceof Array)) {
+ if (!Array.isArray(uid)) {

This ensures proper array detection across all JavaScript contexts.

🧰 Tools
🪛 Biome (1.9.4)

[error] 138-138: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0bd15ca and f8ed636.

📒 Files selected for processing (94)
  • .eslintrc.yaml (0 hunks)
  • .github/workflows/build.yml (1 hunks)
  • build/prepare.js (5 hunks)
  • eslint.config.mjs (1 hunks)
  • framework/eslint-config/base.mjs (1 hunks)
  • framework/eslint-config/base.yaml (0 hunks)
  • framework/eslint-config/package.json (1 hunks)
  • framework/eslint-config/react.yaml (0 hunks)
  • framework/eslint-config/typescript.js (0 hunks)
  • framework/framework/error.ts (0 hunks)
  • framework/framework/server.ts (22 hunks)
  • package.json (2 hunks)
  • packages/elastic/index.ts (2 hunks)
  • packages/hydrojudge/src/cases.ts (0 hunks)
  • packages/hydrojudge/src/checkers.ts (4 hunks)
  • packages/hydrojudge/src/daemon.ts (0 hunks)
  • packages/hydrojudge/src/hosts/hydro.ts (0 hunks)
  • packages/hydrojudge/src/hosts/vj4.ts (1 hunks)
  • packages/hydrojudge/src/judge/hack.ts (4 hunks)
  • packages/hydrooj/package.json (3 hunks)
  • packages/hydrooj/src/commands/install.ts (1 hunks)
  • packages/hydrooj/src/entry/cli.ts (2 hunks)
  • packages/hydrooj/src/entry/common.ts (2 hunks)
  • packages/hydrooj/src/entry/setup.ts (0 hunks)
  • packages/hydrooj/src/entry/worker.ts (3 hunks)
  • packages/hydrooj/src/handler/contest.ts (0 hunks)
  • packages/hydrooj/src/handler/domain.ts (3 hunks)
  • packages/hydrooj/src/handler/misc.ts (3 hunks)
  • packages/hydrooj/src/handler/problem.ts (1 hunks)
  • packages/hydrooj/src/interface.ts (6 hunks)
  • packages/hydrooj/src/loader.ts (6 hunks)
  • packages/hydrooj/src/model/blacklist.ts (1 hunks)
  • packages/hydrooj/src/model/contest.ts (7 hunks)
  • packages/hydrooj/src/model/document.ts (11 hunks)
  • packages/hydrooj/src/model/domain.ts (9 hunks)
  • packages/hydrooj/src/model/message.ts (3 hunks)
  • packages/hydrooj/src/model/oauth.ts (1 hunks)
  • packages/hydrooj/src/model/opcount.ts (1 hunks)
  • packages/hydrooj/src/model/problem.ts (1 hunks)
  • packages/hydrooj/src/model/record.ts (8 hunks)
  • packages/hydrooj/src/model/schedule.ts (2 hunks)
  • packages/hydrooj/src/model/setting.ts (11 hunks)
  • packages/hydrooj/src/model/storage.ts (6 hunks)
  • packages/hydrooj/src/model/system.ts (3 hunks)
  • packages/hydrooj/src/model/task.ts (3 hunks)
  • packages/hydrooj/src/model/token.ts (2 hunks)
  • packages/hydrooj/src/model/user.ts (8 hunks)
  • packages/hydrooj/src/plugin-api.ts (2 hunks)
  • packages/hydrooj/src/script/problemStat.ts (0 hunks)
  • packages/hydrooj/src/script/storageUsage.ts (0 hunks)
  • packages/hydrooj/src/service/bus.ts (5 hunks)
  • packages/hydrooj/src/service/db.ts (3 hunks)
  • packages/hydrooj/src/service/worker.ts (2 hunks)
  • packages/hydrooj/src/settings.ts (1 hunks)
  • packages/hydrooj/src/ui.ts (1 hunks)
  • packages/migrate/package.json (1 hunks)
  • packages/onlyoffice/frontend/office.page.ts (0 hunks)
  • packages/onsite-toolkit/frontend/resolver.page.tsx (2 hunks)
  • packages/ui-default/.eslintignore (0 hunks)
  • packages/ui-default/.eslintrc.js (0 hunks)
  • packages/ui-default/api.ts (0 hunks)
  • packages/ui-default/backendlib/builder.ts (4 hunks)
  • packages/ui-default/backendlib/markdown-it-imsize.ts (1 hunks)
  • packages/ui-default/backendlib/markdown-it-media.ts (0 hunks)
  • packages/ui-default/backendlib/misc.ts (1 hunks)
  • packages/ui-default/backendlib/template.ts (3 hunks)
  • packages/ui-default/build/config/webpack.ts (1 hunks)
  • packages/ui-default/build/main.ts (1 hunks)
  • packages/ui-default/components/autocomplete/components/AutoComplete.tsx (3 hunks)
  • packages/ui-default/components/autocomplete/components/UserSelectAutoComplete.tsx (1 hunks)
  • packages/ui-default/components/calendar/index.js (2 hunks)
  • packages/ui-default/components/message/worker.ts (1 hunks)
  • packages/ui-default/components/problemconfig/ProblemConfigEditor.tsx (1 hunks)
  • packages/ui-default/components/problemconfig/ProblemConfigTree.tsx (1 hunks)
  • packages/ui-default/components/problemconfig/reducer/config.ts (1 hunks)
  • packages/ui-default/components/problemconfig/tree/AddTestcase.tsx (1 hunks)
  • packages/ui-default/components/problemconfig/tree/SubtaskSettings.tsx (1 hunks)
  • packages/ui-default/components/problemconfig/tree/Testcase.tsx (1 hunks)
  • packages/ui-default/components/scratchpad/DataInputComponent.jsx (0 hunks)
  • packages/ui-default/components/scratchpad/ScratchpadToolbarContainer.jsx (0 hunks)
  • packages/ui-default/index.ts (6 hunks)
  • packages/ui-default/package.json (5 hunks)
  • packages/ui-next/package.json (1 hunks)
  • packages/ui-next/src/App.tsx (1 hunks)
  • packages/utils/lib/locate-pm2.ts (1 hunks)
  • packages/utils/lib/utils.ts (1 hunks)
  • packages/utils/package.json (2 hunks)
  • packages/vjudge/src/index.ts (3 hunks)
  • packages/vjudge/src/providers/codeforces.ts (0 hunks)
  • packages/vjudge/src/providers/hduoj.ts (0 hunks)
  • packages/vjudge/src/providers/poj.ts (0 hunks)
  • packages/vjudge/src/providers/spoj.ts (0 hunks)
  • packages/vjudge/src/providers/uoj.ts (0 hunks)
  • packages/vjudge/src/providers/yacs.ts (0 hunks)
💤 Files with no reviewable changes (25)
  • packages/ui-default/api.ts
  • packages/hydrooj/src/script/storageUsage.ts
  • packages/ui-default/backendlib/markdown-it-media.ts
  • framework/framework/error.ts
  • packages/hydrooj/src/entry/setup.ts
  • packages/hydrojudge/src/cases.ts
  • packages/hydrojudge/src/daemon.ts
  • packages/ui-default/components/scratchpad/DataInputComponent.jsx
  • packages/ui-default/components/scratchpad/ScratchpadToolbarContainer.jsx
  • packages/hydrooj/src/script/problemStat.ts
  • packages/vjudge/src/providers/poj.ts
  • packages/hydrojudge/src/hosts/hydro.ts
  • packages/vjudge/src/providers/codeforces.ts
  • packages/vjudge/src/providers/hduoj.ts
  • packages/ui-default/.eslintignore
  • packages/onlyoffice/frontend/office.page.ts
  • packages/hydrooj/src/handler/contest.ts
  • framework/eslint-config/typescript.js
  • .eslintrc.yaml
  • framework/eslint-config/react.yaml
  • packages/vjudge/src/providers/yacs.ts
  • packages/vjudge/src/providers/uoj.ts
  • framework/eslint-config/base.yaml
  • packages/vjudge/src/providers/spoj.ts
  • packages/ui-default/.eslintrc.js
✅ Files skipped from review due to trivial changes (14)
  • packages/ui-default/components/problemconfig/tree/SubtaskSettings.tsx
  • packages/ui-default/components/problemconfig/reducer/config.ts
  • packages/ui-default/components/problemconfig/tree/Testcase.tsx
  • packages/ui-default/components/problemconfig/ProblemConfigTree.tsx
  • packages/ui-default/components/problemconfig/tree/AddTestcase.tsx
  • packages/ui-default/backendlib/misc.ts
  • packages/ui-default/backendlib/markdown-it-imsize.ts
  • packages/utils/lib/locate-pm2.ts
  • packages/ui-default/components/problemconfig/ProblemConfigEditor.tsx
  • packages/ui-default/build/config/webpack.ts
  • packages/ui-default/components/message/worker.ts
  • packages/ui-default/components/calendar/index.js
  • packages/ui-default/build/main.ts
  • packages/hydrojudge/src/hosts/vj4.ts
🚧 Files skipped from review as they are similar to previous changes (27)
  • packages/ui-next/src/App.tsx
  • packages/hydrojudge/src/judge/hack.ts
  • packages/hydrooj/src/ui.ts
  • packages/onsite-toolkit/frontend/resolver.page.tsx
  • packages/hydrojudge/src/checkers.ts
  • packages/ui-default/components/autocomplete/components/UserSelectAutoComplete.tsx
  • packages/hydrooj/src/model/user.ts
  • packages/hydrooj/src/service/bus.ts
  • packages/ui-next/package.json
  • packages/migrate/package.json
  • packages/hydrooj/src/model/token.ts
  • packages/hydrooj/src/model/contest.ts
  • packages/hydrooj/src/entry/worker.ts
  • packages/ui-default/components/autocomplete/components/AutoComplete.tsx
  • packages/hydrooj/src/model/message.ts
  • packages/ui-default/backendlib/builder.ts
  • packages/hydrooj/src/model/storage.ts
  • packages/utils/package.json
  • packages/hydrooj/src/handler/problem.ts
  • packages/hydrooj/src/model/problem.ts
  • packages/hydrooj/src/plugin-api.ts
  • packages/vjudge/src/index.ts
  • packages/hydrooj/src/model/system.ts
  • packages/hydrooj/src/commands/install.ts
  • packages/hydrooj/src/model/task.ts
  • package.json
  • packages/ui-default/package.json
🧰 Additional context used
🧬 Code Definitions (11)
packages/hydrooj/src/service/db.ts (3)
packages/hydrooj/src/entry/cli.ts (1) (1)
  • load (105-141)
packages/hydrooj/src/loader.ts (1) (1)
  • load (170-206)
packages/hydrooj/src/options.ts (1) (1)
  • load (24-37)
packages/ui-default/backendlib/template.ts (3)
packages/hydrooj/src/plugin-api.ts (2) (2)
  • Service (41-41)
  • Context (41-41)
packages/ui-default/api.ts (3) (3)
  • Service (5-5)
  • ctx (5-5)
  • Context (5-5)
packages/hydrooj/src/model/builtin.ts (2) (2)
  • PERM (9-102)
  • PRIV (240-267)
packages/hydrooj/src/model/record.ts (2)
packages/hydrooj/src/model/document.ts (1) (1)
  • apply (413-447)
packages/hydrooj/src/model/task.ts (1) (1)
  • apply (145-191)
packages/hydrooj/src/entry/common.ts (4)
packages/ui-default/api.ts (2) (2)
  • ctx (5-5)
  • Context (5-5)
packages/hydrooj/src/plugin-api.ts (1) (1)
  • Context (41-41)
packages/hydrooj/src/context.ts (2) (2)
  • Context (31-41)
  • Context (68-77)
packages/hydrooj/src/utils.ts (1) (1)
  • unwrapExports (21-29)
packages/elastic/index.ts (4)
packages/hydrooj/src/plugin-api.ts (2) (2)
  • Service (41-41)
  • Context (41-41)
packages/hydrooj/src/settings.ts (1) (1)
  • Context (30-34)
packages/hydrooj/src/interface.ts (1) (1)
  • ProblemSearch (619-619)
packages/hydrooj/src/model/problem.ts (1) (1)
  • ProblemModel (74-675)
packages/hydrooj/src/interface.ts (1)
packages/common/types.ts (1) (1)
  • RecordJudgeInfo (84-96)
packages/hydrooj/src/settings.ts (4)
packages/ui-default/backendlib/template.ts (1) (1)
  • Context (254-275)
packages/elastic/index.ts (1) (1)
  • Context (95-125)
packages/vjudge/src/index.ts (1) (1)
  • Context (191-196)
packages/hydrooj/src/service/db.ts (1) (1)
  • Context (58-66)
packages/hydrooj/src/model/setting.ts (4)
packages/hydrooj/src/interface.ts (1) (1)
  • Setting (46-56)
packages/hydrooj/src/service/check.ts (1) (1)
  • apply (77-80)
packages/hydrooj/src/context.ts (2) (2)
  • Context (31-41)
  • Context (68-77)
packages/hydrooj/src/service/db.ts (1) (1)
  • Context (58-66)
packages/hydrooj/src/model/domain.ts (4)
packages/hydrooj/src/interface.ts (1) (1)
  • DomainDoc (306-314)
packages/hydrooj/src/service/bus.ts (1) (1)
  • apply (96-113)
packages/hydrooj/src/plugin-api.ts (2) (2)
  • Context (41-41)
  • db (58-58)
packages/hydrooj/src/service/db.ts (1) (1)
  • Context (58-66)
framework/framework/server.ts (4)
packages/hydrooj/src/service/layers/base.ts (1) (1)
  • ctx (20-72)
packages/hydrooj/src/plugin-api.ts (3) (3)
  • Handler (40-40)
  • Service (41-41)
  • Context (41-41)
framework/framework/interface.ts (1) (1)
  • KnownHandlers (3-5)
packages/hydrooj/src/context.ts (2) (2)
  • Context (31-41)
  • Context (68-77)
packages/hydrooj/src/model/document.ts (7)
packages/hydrooj/src/model/user.ts (1) (1)
  • coll (22-22)
packages/hydrooj/src/model/oplog.ts (1) (1)
  • coll (8-8)
packages/hydrooj/src/model/discussion.ts (1) (1)
  • coll (43-43)
packages/hydrooj/src/model/problem.ts (1) (1)
  • incStatus (431-436)
packages/hydrooj/src/model/token.ts (1) (1)
  • update (53-71)
packages/hydrooj/src/model/record.ts (1) (1)
  • update (195-219)
packages/hydrooj/src/service/monitor.ts (1) (1)
  • update (76-89)
🪛 Biome (1.9.4)
packages/ui-default/backendlib/template.ts

[error] 46-46: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 121-121: eval() exposes to security risks and performance issues.

See the MDN web docs for more details.
Refactor the code so that it doesn't need to call eval().

(lint/security/noGlobalEval)

packages/hydrooj/src/handler/misc.ts

[error] 110-110: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)


[error] 124-124: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

packages/hydrooj/src/loader.ts

[error] 49-49: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

packages/hydrooj/src/model/domain.ts

[error] 138-138: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

framework/framework/server.ts

[error] 139-139: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 140-140: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)

packages/hydrooj/src/handler/domain.ts

[error] 155-155: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 335-335: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

packages/hydrooj/src/model/document.ts

[error] 223-223: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

packages/ui-default/index.ts

[error] 56-56: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

🪛 GitHub Check: CodeQL
build/prepare.js

[failure] 166-166: Potential file system race condition
The file may have changed since it was checked.

🔇 Additional comments (124)
packages/utils/lib/utils.ts (2)

10-10: Good refactoring of logger imports

The import has been updated to include additional components from the 'reggol' package, which enables a more configurable logging approach.


29-31: LGTM: Good encapsulation of logger creation

The createLogger function nicely encapsulates the factory usage and provides a clean interface for creating loggers.

packages/hydrooj/src/handler/domain.ts (5)

105-147: Good refactoring using MongoDB aggregation pipeline

This change improves data retrieval efficiency by replacing direct queries with an aggregation pipeline. The $lookup stage elegantly joins user details from the 'user' collection, reducing the need for separate queries.


259-259: LGTM: Improved role filtering logic

Good change to only filter out 'guest' role instead of both 'default' and 'guest', which aligns with the comment on line 108-109 about displaying users with the default role.


340-358: Good enhancement to domain joining process

The updated get method now properly handles target domains and redirects, with comprehensive domain information in the response. This improves the user experience when joining domains.


322-337:

✅ Verification successful

Good enhancement for cross-domain functionality

The updated prepare method now supports specifying a target domain, enhancing flexibility. The role determination logic is also improved with cleaner privilege checking.

Check if all calling sites have been updated to handle the new parameter:


🏁 Script executed:

#!/bin/bash
# Check for methods that call the prepare method without providing a target parameter
rg -A 2 "prepare\(\s*\{\s*domainId\s*\}\s*\)" --type ts

Length of output: 305


Cross-Domain Functionality Verified: Parameter Handling is Consistent
The enhanced prepare method now supports an optional target domain parameter that defaults to domainId, ensuring that legacy call sites continue to work as expected. Our search only returned the method definition (i.e., the line using { domainId }), with no evidence of call sites omitting necessary updates. All usage appears consistent with the intended behavior.

🧰 Tools
🪛 Biome (1.9.4)

[error] 335-335: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


361-377:

❓ Verification inconclusive

Enhanced domain join post handler

The updated post method properly handles domain joining with target and redirect parameters. The role assignment is now more flexible based on join settings.

Check for any frontend code that might need updating for the new parameters:


🏁 Script executed:

#!/bin/bash
# Look for client-side code that calls the domain join endpoint
rg -A 2 "domain_join" --type js --type ts --type jsx --type tsx | grep -v "ctx.Route"

Length of output: 111


Domain join post handler update – please verify frontend integrations

The updated post method correctly handles domain-join logic with flexible target and redirect parameters, and applies role assignment as intended based on join settings. However, our initial automated client-side search encountered a file type issue (with JSX files). Although no references were found in the .js, .ts, or .tsx files, please manually verify any .jsx usages that might call this endpoint to ensure they’re updated as needed.

  • Server-side: Changes in packages/hydrooj/src/handler/domain.ts (lines 361-377) properly implement the new default behavior.
  • Client-side: Confirm that any code invoking the domain join endpoint (especially in .jsx files) correctly passes or accommodates the optional target and redirect parameters.
build/prepare.js (10)

18-20: TypeScript compilation target and module updated

The TypeScript compilation configuration has been updated to use ES2022 target and features, while changing the module strategy from 'commonjs' to 'preserve'. This represents a modernization of the JavaScript output, enabling newer language features.


22-22: Module resolution strategy updated to 'bundler'

The change from 'node' to 'bundler' moduleResolution aligns with modern TypeScript practices for projects using bundlers like Webpack, Rollup, or Vite. This allows TypeScript to better understand imports in a bundled environment.


37-37: UI-Next reference added to project configuration

A new reference to 'tsconfig.ui-next.json' has been added, indicating the introduction of a new UI component to the project architecture.


78-78: Fixed module filtering logic

The module filtering logic has been improved to properly exclude 'ui-default' and 'ui-next' directories using a more consistent approach with the some() method.


83-87: Extended UI exclusion patterns

Additional exclusion patterns have been added for specific files in the ui-default package, ensuring that these backend-related files are not processed by the UI TypeScript configuration.


123-161: Added new UI-Next TypeScript configuration

A new TypeScript configuration for the 'ui-next' package has been introduced with modern settings:

  • ES2022 features
  • React JSX transform
  • Strict type checking
  • Path aliases for '@/*'
  • Bundler mode optimizations

This properly sets up the development environment for the new UI package.


189-189: Added skipLibCheck to plugins configuration

The skipLibCheck: true option has been added to the plugins configuration, which will speed up TypeScript compilation by skipping type-checking of declaration files (*.d.ts).


197-212: Improved configuration file update logic

The script now uses the new tryUpdate function to update configuration files only when their content has changed. This improves build performance by avoiding unnecessary file writes.


219-219: Refactored module export creation

The module export creation now uses the tryUpdate function, maintaining consistency with the rest of the file and only writing when content has changed.


223-225: Configuration file generation with improved efficiency

All TypeScript configuration files are now generated using the tryUpdate function, including the new tsconfig.ui-next.json file. This ensures consistent behavior and improves build efficiency.

packages/hydrooj/src/model/opcount.ts (1)

16-16: Confirm object structure for res.

By returning res.opcount rather than res.value.opcount, you're assuming the updated document is exposed at the top level. Verify that res and res.opcount are always defined (e.g., res is never null) based on your Mongo driver or wrapper's behavior. Otherwise, you may need to handle potential undefined cases.

Would you like a script to scan references of inc calls and confirm all call sites handle potential errors?

eslint.config.mjs (1)

1-150: Overall ESLint configuration looks solid!

Below are a few considerations:

  1. Rule Overrides
    You’re replacing built-in ESLint rules (e.g., no-unused-vars, no-shadow) with their TypeScript equivalents, which is recommended. Confirm that disabling base rules everywhere matches your entire codebase’s needs.

  2. No-Await-In-Loop
    Setting 'no-await-in-loop' to 'warn' (line 377) is common, but be aware of possible performance bottlenecks for large loops. Consider parallelizing or refactoring if you see slowdowns in practice.

  3. Import Validation
    Turning off rules like 'import/no-unresolved' (line 79 in the second config block) can hide genuine import path mistakes. If feasible, keep them on (with adjustments) to catch broken or missing imports.

  4. Max Length
    'max-len': ['warn', 150] (line 366) is purely stylistic. Ensuring different teams or repos follow the same limit fosters consistency.

These points don’t block merging; everything else looks well-structured.

framework/eslint-config/base.mjs (1)

1-483: Nicely organized ESLint config with broad TypeScript support!

  1. Extensive Overrides
    You’ve silenced several core ESLint checks (e.g., 'no-undef', 'no-redeclare') in favor of TypeScript. Generally correct, but confirm that this covers all team usage scenarios, especially if some JS files aren’t transpiled.

  2. Import Rules
    Disabling 'import/no-unresolved', 'import/no-extraneous-dependencies', etc., can let unresolved or extraneous imports slip by. Consider enabling them in CI or selective directories to protect from broken paths or dependency mismatches.

  3. No-Await-In-Loop
    The 'no-await-in-loop' rule also appears here (if added). Keeping it as 'warn' is fine, but watch for unexpected performance hits in loops.

  4. Potential for Duplicate or Conflicting Config
    Because you’re mixing multiple plugins (@eslint-react, jsx-a11y, github, etc.) and layering them with TypeScript plugin rules, keep an eye on any conflicting or redundant rules. Periodic upgrades or merges might alter rule sets in ways you don’t expect.

Otherwise, the plugin usage, naming conventions, and extended rules appear consistent with typical TS + React projects.

packages/ui-default/backendlib/template.ts (3)

121-121: Avoid using eval if possible.

eval() can introduce serious security and performance risks. Consider refactoring to safer alternatives.

🧰 Tools
🪛 Biome (1.9.4)

[error] 121-121: eval() exposes to security risks and performance issues.

See the MDN web docs for more details.
Refactor the code so that it doesn't need to call eval().

(lint/security/noGlobalEval)


122-128: Security Concern: Limit Global Exposure in Template Engine

Exposing complete global objects (such as Date, Object, String, etc.) creates significant security risks like remote code execution, prototype pollution, and XSS. Instead of exposing these full objects, it's safer to limit the available methods to only those needed.


221-242: Add timeout handling to prevent long-running renders

While there's logging for slow renders (>5000ms), there's no actual timeout mechanism to prevent extremely long-running renders from blocking the server.

packages/hydrooj/src/interface.ts (4)

226-229: Well-structured interface definition.

Good job creating the RecordHistoryDoc interface that extends RecordJudgeInfo and adds the necessary ID fields. This provides good type safety for the record history collection.


663-663: Verify that all accesses to addons have been updated for the new structure

The change from array to Record structure improves lookup performance and allows associating metadata with each addon, but ensure all usages of addons have been updated across the codebase.

#!/bin/bash
# Find all places in the codebase where addons is accessed, to verify they've been updated
rg "addons\[" --type=ts
rg "\.forEach\(.*addons" --type=ts
rg "for.*of.*addons" --type=ts

83-83: Good typing improvement for authenticator extension results.

The type update to use ParsedAuthenticatorData['extensionsData'] provides more precise typing for the authenticator extension results.


552-552: Good database collection definition for record history.

Adding the 'record.history' entry to the Collections interface properly registers the new collection type in the type system.

packages/ui-default/index.ts (6)

7-7: Good import update for new TemplateService.

The import of TemplateService aligns with the refactoring in the template handling system.


25-25: Explicit type annotation improves code clarity.

Adding an explicit type annotation for sections improves code readability and type checking.


56-56: Remove the empty object pattern.

Static analysis flags { } as an unexpected empty pattern. Consider removing it as it doesn't serve any purpose.

-  async get({ }, legacy = false, nohint = false) {
+  async get(legacy = false, nohint = false) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 56-56: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)


77-77: Good update to use context-derived configuration.

Using this.ctx.config.settings instead of SystemSettings is a good practice that leverages the context object and reduces global dependencies.


119-119: Explicit typing of array improves code clarity.

Adding an explicit type annotation for the res array improves code readability and type checking.


167-167: Good transition to using TemplateService.

The update to use the new TemplateService class aligns with the architectural changes in the template handling system.

packages/hydrooj/src/model/document.ts (5)

12-12: Updated import style for bus module.

The import style has changed from import * as bus from '../service/bus' to import bus from '../service/bus', indicating that the module now uses a default export. This is consistent with the broader refactoring approach.


18-18: Correct type usage for TypeScript primitives.

Changing from Symbol to symbol is correct for TypeScript type declarations as it should use the lowercase primitive name.


23-33: Improved type safety with as const assertions.

Using as const for constant declarations creates more precise literal types instead of just number types. This improves type safety throughout the application.


385-391: Good use of nullish coalescing operator.

The refactoring of revPushStatus to use the nullish coalescing operator (||=) is a good use of modern JavaScript features that improves code readability and reduces verbosity.


112-117: Consistent use of await operators improves code readability.

Adding explicit await operators to all returned promises makes async code behavior clearer and improves maintainability. This is a good practice.

Also applies to: 152-157, 163-168, 211-217, 224-230, 255-265, 271-277, 301-311, 328-333, 358-363, 369-374, 397-402, 410-411

framework/framework/server.ts (7)

552-553: Fix FIXME comments for event handler type assertions.

Similar to the previous issue, these event emissions use type assertions that bypass TypeScript's type checking.


569-569: Fix FIXME comments for event handler type assertions.

Similar to the previous issue, these event emissions use type assertions that bypass TypeScript's type checking.


604-604: Fix FIXME comments for event handler type assertions.

Similar to the previous issue, these event emissions use type assertions that bypass TypeScript's type checking.


656-656: Fix FIXME comments for event handler type assertions.

Similar to the previous issue, these event emissions use type assertions that bypass TypeScript's type checking.


44-52: Clean up resources properly with asyncDispose.

The forkContextWithScope function uses the Symbol.asyncDispose protocol, which is great for resource management.

Good use of the async disposable pattern to ensure context resources are properly cleaned up.


787-810: Verify proper cleanup in _applyMixin implementation.

The _applyMixin method correctly stores the original values and restores them during cleanup.

The implementation of _applyMixin properly handles both adding properties and cleaning them up when disposing of the effect.


826-828: Consistent handling of mixins across handler types.

The wsHandlerMixin method is now consistently implemented like other mixin methods.

This implementation properly applies the mixin to the ConnectionHandler prototype and cleans up when done, fixing previous issues.

packages/hydrooj/src/model/oauth.ts (1)

18-18:

❓ Verification inconclusive

Verify database result structure change.

The return value changed from res.value?.uid to res?.uid, suggesting a change in the MongoDB driver or result structure.

Make sure this change is consistent with other model updates in the codebase. Verify that your MongoDB result structure no longer includes a value property or that you're handling both formats correctly.


🏁 Script executed:

#!/bin/bash
# Find other occurrences of MongoDB result handling with value property
echo "Checking other MongoDB result handling patterns:"
rg -A 1 "await coll\.findOneAndUpdate" | rg "\.value"

Length of output: 162


Double-check MongoDB result handling consistency.

It looks like the OAuth model now returns res?.uid instead of the previous res.value?.uid, suggesting an update in how the MongoDB results are structured. Our initial automated search for occurrences of the outdated .value property didn’t return any results, which is encouraging. However, since the grep output was empty—and an output was expected for a conclusive automated check—it’s advisable to manually verify that no other parts of the code still depend on the older result structure.

  • Please review MongoDB update operations (such as those using findOneAndUpdate) to confirm that they no longer expect a value property.
  • Ensure that the updated driver behavior is uniformly applied across all related models.
packages/hydrooj/src/model/blacklist.ts (1)

16-20: Update result handling pattern to match MongoDB response structure.

Changed from assigning the result to a variable and returning res.value to directly returning the await result.

This change aligns with the updated MongoDB result structure handling seen in oauth.ts, improving consistency across the codebase.

packages/hydrooj/src/entry/cli.ts (4)

112-114: Improved service initialization using plugins.

Switching from direct service initialization to the plugin system enhances modularity.

Using plugins for MongoDB and Config services improves the application's architecture by leveraging the dependency injection system.


115-119: Ensure dependencies are available through promise-based injection.

Using promises to wait for dependencies to be injected ensures services are available when needed.

This pattern ensures the loader and config services are fully initialized before proceeding, which prevents potential race conditions.


130-134: Consistent dependency injection pattern.

Using the same promise-based dependency injection pattern for server, setting, and worker services.

Consistently using this pattern improves code predictability and ensures services are properly initialized.


138-138: Simplified plugin loading.

The call to ctx.loader.reloadPlugin has been simplified to remove the unnecessary ctx parameter.

This change correctly reflects that the context is already available within the loader service, reducing redundant parameters.

.github/workflows/build.yml (1)

66-66:

❓ Verification inconclusive

Verify the removal of UI linting in CI workflow.

The lint:ui:ci task has been removed from the parallel execution in the workflow. This change could potentially speed up the CI process, but it might also lead to UI-related code quality issues being missed.


🏁 Script executed:

#!/bin/bash
# Check if UI linting is incorporated elsewhere in the project

# Look for UI linting tasks in package.json scripts
echo "Checking package.json for UI linting scripts:"
jq '.scripts | with_entries(select(.key | contains("lint") and contains("ui")))' package.json

# Check if there are other workflow files that might include UI linting
echo "Checking other workflow files for UI linting tasks:"
rg --type yaml "lint:ui" .github/workflows/

Length of output: 356


Attention: The current changes in the CI workflow now omit the lint:ui:ci task (as seen in the command parallel --tty -j+0 yarn ::: lint:ci build build:ui:production:webpack test). Our inspection—searching for UI lint tasks in both package.json and the other workflow files—yielded no indications of any UI linting elsewhere in the repository. This suggests that the UI linting step is no longer executed in CI.

Please verify that this removal is intentional or that UI-related quality checks are being handled by an alternate mechanism. If the omission is deliberate, consider updating the documentation to reflect this change, ensuring that potential UI issues are not inadvertently overlooked in future CI runs.

packages/hydrooj/src/model/record.ts (6)

2-2: Good addition of the pick utility from lodash.

This import will be used for selectively copying fields from record documents into history records.


23-23: Well-implemented record history collection.

Adding the collHistory collection is a good design choice for maintaining record history before resets, allowing for historical auditing and tracking of changes over time.


236-236: Good replacement of instanceof Array with Array.isArray().

This change follows best practices for array type checking. Array.isArray() is more reliable across different execution contexts and handles array-like objects properly.


250-262: Well-implemented record history preservation.

The implementation correctly:

  1. Fetches records before deletion
  2. Extracts relevant fields using lodash's pick
  3. Preserves the original record ID reference
  4. Creates new ObjectIds for history entries

This enables proper tracking of record changes over time.


283-283: Good conversion of apply function to async.

This change correctly makes the function asynchronous, which is appropriate since it's handling database operations and other asynchronous tasks.


324-327: Good addition of index for collHistory collection.

This properly implements the index creation for the new collHistory collection, which will improve query performance for history lookups. The index is defined on the rid field with descending _id for efficient retrieval.

packages/hydrooj/src/model/schedule.ts (2)

18-25: Improved result handling in getFirst function.

The function now directly checks for the existence of res instead of res.value, simplifying the code. This change also ensures that the entire result object is returned, maintaining consistency with MongoDB's findOneAndDelete operation which returns the entire document.


7-7:

✅ Verification successful

Changed import type for WorkerService.

The import statement has been changed from importing a named type to importing a default type. Ensure this matches the export pattern in the worker service module.


🏁 Script executed:

#!/bin/bash
# Check the export pattern in the worker service module
rg "export default|export class WorkerService" packages/hydrooj/src/service/worker.ts

Length of output: 140


Default Import Verified for WorkerService

The worker service module correctly uses a default export (export default class WorkerService extends Service { ... }), which confirms that the updated import statement in packages/hydrooj/src/model/schedule.ts is correct.

  • Confirmed that WorkerService is exported as a default class.
packages/hydrooj/src/service/db.ts (7)

7-11: Good refactoring of imports for dependency management.

The imports have been updated to include the Context and Service classes, and bus is now imported as a default import. This aligns with modern module import patterns and supports the new service-based architecture.


29-34: Well-structured Context interface extension.

This module declaration properly extends the Context interface to include a db property of type MongoService, enabling typed access to the database service through the context.


35-41: Good implementation of service-based architecture.

The MongoService class now extends Service and accepts a context in its constructor, following a consistent pattern for service initialization and integration with the application's dependency injection system.


43-56: Well-designed static URL retrieval method.

The static getUrl() method effectively encapsulates the logic for retrieving the MongoDB connection URL, handling CI environments and configuration loading. This improves testability and separation of concerns.


58-66: Good implementation of async generator for initialization.

The [Context.init] method replaces the previous start method with an async generator that:

  1. Retrieves the connection URL
  2. Establishes the MongoDB connection
  3. Yields a cleanup function for proper resource management
  4. Sets up a periodic task for index maintenance

This follows modern patterns for asynchronous initialization and cleanup.


69-71: Improved collection name configuration.

The collection method now properly references the config object for prefix and collection mapping, enhancing configurability and flexibility.


182-188: Good backward compatibility with deprecated notice.

This proxy implementation provides backward compatibility for code still directly accessing the db object, while clearly marking it as deprecated in favor of using ctx.db. This facilitates a smooth transition to the new context-based approach.

packages/hydrooj/src/service/worker.ts (2)

12-12: Conversion to default export enhances module import flexibility.

The class has been changed from a named export to a default export, which is more aligned with modern ES module usage patterns. This change enhances module import flexibility, allowing cleaner imports in consuming code.


32-38: Direct property access pattern improves code clarity.

The refactoring now directly accesses properties on the res object instead of going through an intermediate value property. This change aligns with the broader codebase refactoring to simplify data access patterns.

packages/hydrooj/src/handler/misc.ts (2)

17-17: LGTM: Added import for sortFiles utility.

Adding the import for sortFiles function from the utils module is appropriate and ensures the proper organization of dependencies.


112-112: Switch to context-based link validation improves modularity.

The validation logic now uses a dynamic context-based check through this.ctx.get('storage')?.isLinkValid?() instead of a static approach, which is a positive improvement for dependency injection and testability.

packages/elastic/index.ts (5)

4-5: Enhanced imports improve type safety.

The addition of typed imports from 'hydrooj' represents a good refinement in the code organization, enhancing type safety and making dependencies explicit.


20-32: Well-structured service class with schema-based configuration.

The conversion to a service class with explicit schema-based configuration is a significant architectural improvement. The class extends Service and properly declares its configuration schema with appropriate defaults and type constraints.


73-78: Improved error handling for Elasticsearch operations.

The error handling for Elasticsearch operations is properly implemented, only throwing errors that aren't related to the "index_not_found_exception", which is a common and often expected case.


117-124: Add error handling to the script registration callback.

The script registration doesn't include error handling for the run method when used as a callback, which could lead to unhandled promise rejections.


95-117: Add error handling to event listeners.

The event listeners for problem operations don't have try-catch blocks to handle potential errors, which could lead to unhandled promise rejections and affect system stability.

framework/eslint-config/package.json (4)

5-5: Updated main entry point to reflect new ESLint configuration structure.

The main entry point has been updated from "react.yaml" to "base.mjs", which reflects the transition to a more modern ESLint configuration format using JavaScript modules instead of YAML.


7-21: Comprehensive update of ESLint dependencies to support newer features.

The dependencies have been updated to include newer ESLint plugins and tools, particularly for React, TypeScript, and code style enforcement. This is a positive change that will enable better linting capabilities.


26-28: Added TypeScript as an optional dependency.

Adding TypeScript as an optional dependency is a good practice as it allows for flexible integration with projects that may or may not use TypeScript, while still ensuring a specific compatible version is recommended.


24-25:

✅ Verification successful

Upgraded minimum ESLint peer dependency to version 9.

The minimum ESLint version requirement has been increased from 8 to 9, which is appropriate given the updated plugins that may depend on newer ESLint features.

Please verify that all dependent projects are compatible with ESLint 9:


🏁 Script executed:

#!/bin/bash
# Find all package.json files and check their eslint dependencies
find . -name "package.json" -not -path "*/node_modules/*" -exec jq -r 'if .dependencies.eslint then .dependencies.eslint else empty end' {} \;
find . -name "package.json" -not -path "*/node_modules/*" -exec jq -r 'if .devDependencies.eslint then .devDependencies.eslint else empty end' {} \;

Length of output: 305


Compatibility with ESLint 9 confirmed in dependent projects.

Our verification shows that the only ESLint dependency found in the codebase is specified as "^9.22.0", which is compatible with the updated minimum requirement of ">= 9" in framework/eslint-config/package.json. No further changes are needed.

packages/hydrooj/src/settings.ts (6)

3-3: Good change: Improved import clarity for Context and Service

The import has been updated to explicitly import both Context and Service from the context module, making dependencies clearer.


8-12: Well-structured module augmentation

Nice addition of the module declaration to augment the Context interface with the new ConfigService. This ensures proper type safety throughout the application.


14-25: Good architecture: Service-based approach

The new ConfigService class follows good OOP principles by extending the Service base class. The static properties (inject, name, blacklist) clearly define dependencies and behavior rules. This is a good improvement over global variables.


69-77: Good validation: Schema-based configuration verification

The isPatchValid method ensures that configuration changes comply with the defined schema, which is a great approach to maintain configuration integrity.


159-160: Fixed null check in getAccess function

This properly fixes the previously identified logical issue by checking both for object type and null/undefined values.


86-107: Well-implemented migration logic

The _actualMigrate method handles migrating existing configuration values to the new schema-based approach with good error handling and proper type conversion.

packages/hydrooj/src/model/setting.ts (9)

3-3: Updated import from cordis to @cordisjs/core

The import statement has been updated to use the newer @cordisjs/core package instead of cordis.


7-7: Missing dependency in package.json

The Schema import from 'schemastery' is appropriate, but the package may not be declared in dependencies.

Let's verify if schemastery is properly included in your dependencies:

#!/bin/bash
# Check if schemastery is in package.json dependencies
grep -r "\"schemastery\":" --include="package.json" .

73-80: Good type enhancement: Schema metadata extension

The addition of the Schemastery namespace with Meta interface provides a clean way to add domain-specific metadata to schema definitions.


82-119: Potential coverage gap for complex schemas

The schemaToSettings function only handles specific primitive types (number, string, boolean) and has limited support for nested structures (one level of dictionaries).

Consider enhancing the function to support more complex nested structures and additional types to ensure complete schema coverage. The current implementation will throw errors for unsupported schema structures.


121-123: Good refactoring: Setting functions enhanced for schema support

All setting registration functions (PreferenceSetting, AccountSetting, etc.) have been updated to accept both traditional _Setting arrays and Schema objects, using flatMap with the schemaToSettings function for conversion. This provides a nice backward compatibility while enabling the new schema-based approach.

Also applies to: 141-142, 161-162, 177-178, 193-194


291-318: Great showcase of schema-based settings

This is an excellent example of the new schema-based approach to defining settings. It's more structured, type-safe, and provides better developer experience compared to the previous array-based approach.


359-359: Updated module declaration for new package name

The module declaration has been updated to match the new package name @cordisjs/core.


388-388: Good practice: Explicit dependency injection

The explicit injection of database dependency is a good practice for service registration.


395-395: Enhanced context usage: Using ctx.db instead of global

The code now uses the context-based db reference (ctx.db) instead of a global variable, which is a better architectural approach.

packages/hydrooj/src/loader.ts (7)

15-17: Enhanced imports with specific named imports

The imports have been updated to include specific named imports from the context module, improving code clarity.


22-22: Added schemastery import

This import enables schema-based configuration validation in the loader.


54-58: Good practice: Explicit dependency injection and constructor

The static inject property clearly specifies dependencies, and the constructor is properly using the context parameter to initialize the service.


98-107: Well-implemented configuration resolution

The new resolveConfig method properly handles schema-based configuration with support for scoped configurations. The integration with the ConfigService's migration and request methods ensures configuration consistency.


109-126: Improved plugin management

The reloadPlugin method has been updated to use the new resolveConfig method and properly handles plugin application through the context system.


147-153: Enhanced asynchronous initialization

The preload function has been correctly converted to async and now properly awaits the application initialization through the Promise-based approach.


170-172: Consistent async/await usage

The load and loadCli functions now correctly await the preload function's completion, ensuring the application is properly initialized before proceeding.

Also applies to: 209-211

packages/hydrooj/src/model/domain.ts (6)

4-4: Updated import to use direct Context import

The import has been changed to directly import Context from the context module rather than from a service, which is a better approach for clarity.


131-132: Added join filter to countUser queries

The countUser method now includes a join:true filter in both queries, ensuring only users who have explicitly joined the domain are counted.


136-137: Enhanced setUserRole with autojoin parameter

The setUserRole method now includes an optional autojoin parameter that controls whether to set the join property, providing more flexibility.


213-213: Added join check for guest role assignment

This change ensures that users are assigned the guest role if they haven't explicitly joined the domain, improving access control.


259-259: Added join filter to getDictUserByDomainId

The query now only returns domain user records where join is true, ensuring consistency with the domain membership model.


292-312: Good practice: Context-based initialization

The new apply function properly sets up the domain module within the context system. It registers an event handler for cache deletion and ensures database indexes are created, encapsulating initialization logic in a clean way.

The handling of domain cache deletion is well implemented, with proper checks and cleanup of both id and host-based cache entries.

packages/hydrooj/src/entry/common.ts (7)

24-24: Simplified LoadTask type definition

The LoadTask type has been simplified to only include 'model', 'addon', and 'service', removing other options like 'handler', 'lib', and 'script'. This is part of the larger API cleanup in the v5 refactoring.


25-26: Function signature and parameter handling improvements

The getLoader function has been updated to use a more structured approach with Record<string, string> instead of an array of strings, which provides better type safety and key-value mapping. The iteration pattern using Object.entries() makes the code more explicit about handling both names and paths.


29-30: Improved variable naming for better readability

Renamed name to loadType to better reflect its purpose, avoiding confusion with the parameter name now extracted from the entries.


32-33: Simplified plugin reloading

The reloadPlugin call has been simplified by removing unnecessary parameters. This is consistent with the context handling improvements throughout the codebase.


56-57: Consistent plugin loading pattern

Updated builtinModel to follow the same pattern as other loader functions, simplifying the reloadPlugin call by using an empty string instead of an empty object.


60-61: Updated locale function parameter handling

The locale function now accepts a Record<string, string> and uses Object.values() to iterate through the paths, providing a more structured approach to locale loading.


83-90: Improved settings function signature and iteration

The setting function signature has been updated to use a Record<string, string> type for better type safety, and the iteration has been updated to use Object.values(). This is consistent with the changes in other functions.

packages/hydrooj/package.json (9)

3-3: Major version upgrade to v5.0.0-alpha.0

The version has been updated from 4.19.1 to 5.0.0-alpha.0, indicating a major version upgrade with breaking changes. This aligns with the significant architectural changes throughout the codebase.


19-21: Cordis framework migration

Added new dependencies from the Cordis framework ecosystem, replacing the monolithic "cordis" package with more modular components. This suggests a transition to a more modular architecture with better separation of concerns.


22-28: Updated dependencies for better compatibility

The GraphQL tools and libzip dependencies have been updated to newer versions for better compatibility and potentially addressing security issues.


36-36: Updated GraphQL scalars dependency

Updated graphql-scalars to the latest version for improved GraphQL schema support.


46-46: Updated nanoid dependency

Updated nanoid to the latest version for improved ID generation capabilities.


52-52: Updated schemastery dependency

Updated schemastery to the latest version for improved schema validation.


55-58: Updated networking and user-agent dependencies

Updated superagent and ua-parser-js for better HTTP request handling and user agent parsing. These updates may include security fixes and performance improvements.


67-67: Updated TypeScript type definitions

Updated Lodash type definitions for better TypeScript support.


44-44:

❓ Verification inconclusive

Major MongoDB driver upgrade

The MongoDB driver has been upgraded from version 5.x to 6.x, which is a major version change that might introduce breaking changes. Ensure that all MongoDB operations have been tested with the new driver version.


🏁 Script executed:

#!/bin/bash
# Search for MongoDB API usages that might be affected by the driver upgrade
echo "Checking for MongoDB API usages that might need updates..."
rg -A 2 -B 2 "mongodb|Collection\.|Db\.|MongoClient" --type ts

Length of output: 23062


Action Required: Validate MongoDB API Compatibility with v6.x

The mongodb dependency has been upgraded from v5.x to ^6.15.0. A repository-wide search shows that core MongoDB interfaces (e.g., MongoClient, ObjectId, Db, and Collection) are still being used in the same way across multiple files (for example, in packages/hydrooj/src/service/db.ts and packages/hydrooj/src/entry/setup.ts). However, given the major driver upgrade, please ensure that all MongoDB operations—especially connection handling and query methods—are thoroughly tested against the new v6.x driver to catch any subtle behavioral changes.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (2)
packages/hydrooj/src/handler/home.ts (1)

483-494: ⚠️ Potential issue

Critical: Handle potential null from getById

In line 491, the code uses a non-null assertion ! on the result of await user.getById(ddoc._id, this.user._id), which assumes that a valid user document is always returned. To prevent potential runtime errors if getById returns null, explicitly handle the null case.

-                const udoc = await user.getById(ddoc._id, this.user._id);
-                canManage[ddoc._id] = udoc.hasPerm(PERM.PERM_EDIT_DOMAIN);
-                role[ddoc._id] = udoc.role;
+                const udoc = await user.getById(ddoc._id, this.user._id);
+                if (!udoc) {
+                    canManage[ddoc._id] = false;
+                    role[ddoc._id] = '';
+                    continue;
+                }
+                canManage[ddoc._id] = udoc.hasPerm(PERM.PERM_EDIT_DOMAIN);
+                role[ddoc._id] = udoc.role;
packages/hydrooj/src/model/domain.ts (1)

138-138: ⚠️ Potential issue

Use Array.isArray() instead of instanceof Array.

The instanceof Array check can be unreliable when dealing with arrays from different contexts or frames.

- if (!(Array.isArray(uid))) {
+ if (!Array.isArray(uid)) {
🧹 Nitpick comments (6)
packages/hydrooj/src/model/domain.ts (1)

108-108: Return the complete result object.

Instead of returning undefined, the method now returns the complete result object from MongoDB, providing more information to callers.

Consider adding a return type annotation to clarify what callers should expect.

packages/hydrooj/src/handler/domain.ts (2)

333-348: Enhanced domain join preparation with target parameter

The addition of the target parameter makes the prepare method more flexible. The implementation properly checks membership status and role assignment based on privileges.

For line 346, consider using an assignment instead of the delete operator for better performance:

-        if (assignedRole !== 'default') delete this.joinSettings;
+        if (assignedRole !== 'default') this.joinSettings = undefined;
🧰 Tools
🪛 Biome (1.9.4)

[error] 346-346: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


156-156: Performance: Avoid using delete operator

The delete operator can impact performance. Consider using an assignment instead.

-            delete u.user;
+            u.user = undefined;
🧰 Tools
🪛 Biome (1.9.4)

[error] 156-156: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

README.md (3)

124-138: Clarify and Enhance Update Log Entries

The new update log entries in the “Unreleased” section (lines 124–138) introduce several important changes—such as adding a warning about shm space, upgrading to cordis@4, supporting multiple renderers, separating HMR and Watcher components, and more. Please verify that each bullet point is clearly written for end users and that any necessary upgrade or migration instructions are provided (especially for breaking or major dependency changes).

🧰 Tools
🪛 LanguageTool

[uncategorized] ~136-~136: 动词的修饰一般为‘形容词(副词)+地+动词’。您的意思是否是:新"地"加
Context: ...修复文件复制 - core: 支持存储并显示提交记录重测历史 - core: 新的加域逻辑 - ui: UserSelect.Multi: 支持批量粘贴用户名 ...

(wb4)


137-137: Refine Changelog Description

On line 137, the entry “core: 新的加域逻辑” could benefit from more specificity. It may help users better understand the impact if the description details what aspect of the domain logic is being updated (for example, specifying “优化后的加域策略” or similar).


142-149: Review Breaking API Changes

The entries under “Breaking API Changes” (lines 142–149) include several removals and enforced changes (e.g. no longer supporting code reading during checker compilation, mandatory use of dependency injection, removal of legacy bus calls, global assignments, and an upgrade to the Mongo Driver 6). It’s critical to ensure that these breaking changes are well-documented in your migration guides so that downstream users can adapt their integrations without surprises.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f8ed636 and a0f38d9.

📒 Files selected for processing (13)
  • README.md (1 hunks)
  • packages/hydrooj/locales/ko.yaml (1 hunks)
  • packages/hydrooj/locales/zh.yaml (1 hunks)
  • packages/hydrooj/locales/zh_TW.yaml (1 hunks)
  • packages/hydrooj/src/handler/domain.ts (5 hunks)
  • packages/hydrooj/src/handler/home.ts (4 hunks)
  • packages/hydrooj/src/model/domain.ts (9 hunks)
  • packages/ui-default/locales/ko.yaml (2 hunks)
  • packages/ui-default/locales/zh.yaml (7 hunks)
  • packages/ui-default/locales/zh_TW.yaml (2 hunks)
  • packages/ui-default/pages/domain_user.page.js (4 hunks)
  • packages/ui-default/pages/home_domain.page.styl (1 hunks)
  • packages/ui-default/templates/home_domain.html (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/ui-default/templates/home_domain.html
  • packages/ui-default/locales/zh.yaml
🧰 Additional context used
🧬 Code Definitions (2)
packages/hydrooj/src/handler/home.ts (3)
framework/framework/server.ts (1) (1)
  • all (299-299)
packages/hydrooj/src/interface.ts (1) (1)
  • DomainDoc (306-314)
framework/framework/validator.ts (2) (2)
  • Types (13-52)
  • Types (77-190)
packages/hydrooj/src/model/domain.ts (4)
packages/hydrooj/src/interface.ts (1) (1)
  • DomainDoc (306-314)
packages/hydrooj/src/service/bus.ts (1) (1)
  • apply (96-113)
packages/hydrooj/src/plugin-api.ts (2) (2)
  • Context (41-41)
  • db (58-58)
packages/hydrooj/src/service/db.ts (1) (1)
  • Context (58-66)
🪛 Biome (1.9.4)
packages/hydrooj/src/handler/home.ts

[error] 471-471: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)


[error] 509-509: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

packages/hydrooj/src/handler/domain.ts

[error] 156-156: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 168-168: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)


[error] 346-346: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

🪛 LanguageTool
README.md

[uncategorized] ~136-~136: 动词的修饰一般为‘形容词(副词)+地+动词’。您的意思是否是:新"地"加
Context: ...修复文件复制 - core: 支持存储并显示提交记录重测历史 - core: 新的加域逻辑 - ui: UserSelect.Multi: 支持批量粘贴用户名 ...

(wb4)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (37)
packages/hydrooj/src/handler/home.ts (5)

184-185: Good refactor: Extracting geoip from context

The introduction of a local variable geoip improves code readability by avoiding repeated access to this.ctx.get('geoip') throughout the method.


192-195: Consistent with refactoring pattern

The change to use the extracted geoip variable instead of directly accessing this.ctx.geoip makes the code more consistent and readable.


205-205: Consistent with refactoring pattern

Using the extracted geoip variable for accessing the provider property maintains consistency with the earlier changes.


472-474: Good refactor: Improved data structure organization

Renaming res to the more descriptive ddocs and introducing a separate role record improves code organization and readability.


497-497: Good refactor: Consistent response structure

Updating the response body to include role instead of dudict provides a more consistent and clearer response structure.

packages/hydrooj/src/model/domain.ts (13)

4-4: Updated import to include Context.

The import of Context from '../context' has been added to support the new apply function.


62-62: Improved user role assignment with automatic join capability.

The call to setUserRole has been updated to include true for the new autojoin parameter, ensuring that domain owners are automatically marked as joined when the domain is created.


104-106: Enhanced result handling in edit method.

The code now properly uses the result from findOneAndUpdate in subsequent operations and event broadcasting.


114-115: Improved return value handling.

The code now uses optional chaining to safely access the field property when returning from the inc method.

Also applies to: 120-120


130-132: Enhanced user counting with join property.

The countUser method now includes the join: true filter to only count users who have officially joined the domain, rather than all users with any association.


136-138: Improved role assignment with join property support.

The setUserRole method now supports an optional autojoin parameter which allows conditionally setting the join property when assigning roles.


139-146: Enhanced user role update operation.

The role setting operation now provides detailed information by using the MongoDB options returnDocument: 'after' and includeResultMetadata: true.


152-153: Updated bulk user role assignment.

The role update operation now correctly uses the newly defined update variable which includes the autojoin condition.


155-162: Added method to control domain membership.

The new setJoin method provides a dedicated way to manage the join status of users, allowing for leaving/joining domains without changing roles.


183-185: Role filtering improvement in getRoles.

By filtering directly in the array instead of using a loop, the code is more concise and readable.


222-222: Enhanced role determination logic.

Users who haven't joined the domain (!dudoc.join) are now assigned the 'guest' role, unless they have the privilege to view all domains.


268-268: Query filtering enhancement in getDictUserByDomainId.

The method now includes the join: true filter to only retrieve domains that the user has actively joined.


301-321: Added context-based initialization function.

A new apply function has been introduced to handle domain-related initialization tasks:

  1. Setting up an event listener for cache invalidation when domains are deleted
  2. Ensuring database indexes for domain collections

This follows a dependency injection pattern, enabling better testability and modular design.

packages/ui-default/pages/home_domain.page.styl (1)

14-14: Increased action column width.

The width of the .col--action column has been increased from 135px to 200px, providing more space for UI elements like the new "Leave" button.

packages/hydrooj/locales/ko.yaml (1)

812-812: Added Korean localization for domain kick notification.

A new message has been added to inform users when they've been kicked from a domain, showing both the domain name and the user who performed the action.

packages/ui-default/locales/ko.yaml (2)

683-683: Added Korean localization for Leave action.

A new translation entry for "Leave" has been added as "나가기", which will be used for the UI button to leave a domain.


692-692: Updated messaging for domain membership status.

The message has been updated to clarify that users removed from a domain will have the "guest" role (instead of "default") until they rejoin, aligning with the code changes in the DomainModel.

packages/hydrooj/locales/zh_TW.yaml (1)

553-553: Consistent user notification when kicked from a domain.

This new message provides clear feedback to users when they're removed from a domain, showing both the domain name and who performed the action. This improves user experience by providing explicit context for the state change.

packages/ui-default/locales/zh_TW.yaml (2)

241-241: LGTM! New "Leave" translation added.

The addition of "Leave: 離開" provides a translation for a user action, maintaining language consistency in the Traditional Chinese localization.


466-466: Clearer messaging for domain role transitions.

The message now specifically states that removed users will have a "guest role" rather than a "default role" until they rejoin the domain. This provides more precise information about the state transition when users are removed.

packages/hydrooj/locales/zh.yaml (1)

936-936: Consistent user notification when kicked from a domain.

This new message provides clear feedback to users when they're removed from a domain, showing both the domain name and who performed the action. This matches the similar addition in zh_TW.yaml for language consistency.

packages/ui-default/pages/domain_user.page.js (5)

63-65: Updated API for adding users to use plural endpoint.

The operation has been changed from 'set_user' to 'set_users' and now accepts an array of user IDs instead of a single ID. This change maintains consistency with other user management operations that have been pluralized.


94-94: Updated message for user removal confirms guest role assignment.

The confirmation message now specifies that removed users will have the "guest role" until they rejoin, which aligns with the updated localization strings and provides clearer information to administrators.


100-102: Improved semantics for user removal operation.

The operation has been renamed from 'set_users' to 'kick', which better describes the action being performed. The parameter has also been updated from 'uid' to 'uids' to handle multiple users, making the API more consistent.


123-126: Updated to support bulk role assignment.

The API call now uses 'uids' as a parameter name, which accepts an array of user IDs for bulk role updates. This change makes the code more consistent and efficient for managing multiple users simultaneously.


140-142: Updated single user role change to use plural endpoint.

The individual user role change now uses the 'set_users' operation with an array containing a single user ID, maintaining consistency with the updated API pattern used throughout the file.

packages/hydrooj/src/handler/domain.ts (6)

106-160: Improved data aggregation approach with MongoDB pipeline

The refactoring to use MongoDB's aggregation pipeline is a significant improvement over the previous implementation. This approach efficiently joins user details from the user collection, properly filters roles, and produces a cleaner response structure.

🧰 Tools
🪛 Biome (1.9.4)

[error] 156-156: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


175-175: Method renamed to reflect batch processing capability

Changed from postSetUser to postSetUsers to better reflect that it now handles multiple users at once.


185-198: New kick functionality with proper user notification

The new postKick method is well-implemented with:

  1. Proper filtering of users that need updates
  2. Batch processing support
  3. User notifications through the message system

269-269: Role filtering adjustment

Changed to exclude only the 'guest' role instead of both 'default' and 'guest', allowing default role to be selectable.


352-369: Improved domain join interface with detailed domain information

The enhanced response structure now includes comprehensive domain information, making the UI more informative for users trying to join a domain.


373-388: More flexible domain join process with target and redirect parameters

The enhanced post method provides better flexibility for redirects and target domain specification, with proper role assignment based on join settings.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (7)
packages/elastic/index.ts (4)

34-55: ⚠️ Potential issue

Optional parameter access needs safer handling.

While you've provided a default value for the opts parameter in the function signature, the direct access to opts.skip without optional chaining could cause runtime errors.

-        if (!opts.skip) {
+        if (!opts?.skip) {

72-72: 🛠️ Refactor suggestion

Add proper type annotations for the run method parameters.

The parameters in the run method lack proper type annotations, which reduces type safety.

-    async run({ domainId }, report) {
+    async run({ domainId }: { domainId?: string }, report: (status: { message: string }) => void) {

95-116: 🛠️ Refactor suggestion

Add proper error handling to event listeners.

The event handlers for problem operations don't include error handling, which could lead to unhandled promise rejections.

        this.ctx.on('problem/add', async (doc, docId) => {
+           try {
                await this.client.index({
                    index: 'problem',
                    id: `${doc.domainId}/${docId}`,
                    document: processDocument(doc),
                });
+           } catch (error) {
+               this.ctx.logger.error(`Error indexing problem: ${error.message}`);
+           }
        });

Similarly for the other event handlers.


117-124: 🛠️ Refactor suggestion

Handle potential errors in script execution.

The script registration doesn't include error handling for the run method when used as a callback.

-            this.run.bind(this),
+            async (...args) => {
+                try {
+                    return await this.run.bind(this)(...args);
+                } catch (error) {
+                    this.ctx.logger.error(`Error in ensureElasticSearch script: ${error.message}`);
+                    throw error;
+                }
+            },
packages/hydrooj/src/handler/home.ts (3)

471-471: ⚠️ Potential issue

Fix empty object pattern in function parameter.

The empty object pattern { } is flagged by the static analysis tool. This appears to be part of a larger pattern change in the codebase, but you should use a named parameter for clarity.

-    async get({ }, all: boolean) {
+    async get({ domainId }: Record<string, never>, all: boolean) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 471-471: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)


483-494: ⚠️ Potential issue

Critical: Handle potential null from getById

In lines 489-494, the code uses a non-null assertion on the result of user.getById(ddoc._id, this.user._id), which assumes that a valid user document is always returned. Our verification shows that elsewhere in the codebase (e.g., in packages/ui-default/index.ts), conditional logic is applied around getById calls when necessary. To prevent potential runtime errors if getById returns null, it is strongly recommended to explicitly handle the null case.

- const udoc = await user.getById(ddoc._id, this.user._id);
- canManage[ddoc._id] = udoc.hasPerm(PERM.PERM_EDIT_DOMAIN);
- role[ddoc._id] = udoc.role;
+ const udoc = await user.getById(ddoc._id, this.user._id);
+ if (!udoc) {
+     canManage[ddoc._id] = false;
+     role[ddoc._id] = '';
+     continue;
+ }
+ canManage[ddoc._id] = udoc.hasPerm(PERM.PERM_EDIT_DOMAIN);
+ role[ddoc._id] = udoc.role;

508-514: ⚠️ Potential issue

Fix empty object pattern in function parameter

Similar to the previous issue, the empty object pattern { } is flagged by the static analysis tool. Use a named parameter for clarity.

-    async postLeave({ }, id: string) {
+    async postLeave({ domainId }: Record<string, never>, id: string) {

The implementation of this new method is clean and appropriately handles domain leaving functionality.

🧰 Tools
🪛 Biome (1.9.4)

[error] 509-509: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

🧹 Nitpick comments (2)
packages/elastic/index.ts (2)

20-32: Consider removing the console.log statement in the constructor.

The constructor includes a debug console.log statement which should be removed or replaced with proper logging using the context logger.

-        console.log('elastic-search', config);
+        // If logging is needed, use the context logger
+        // this.ctx.logger.debug('elastic-search initialized with config', config);

124-124: Add documentation comments for the provided module.

Adding JSDoc comments to the module provision would help other developers understand what the module does and how to use it.

+        /**
+         * Provides the problemSearch functionality through the elastic search implementation.
+         * @param domainId - The domain ID to search in
+         * @param q - The query string to search for
+         * @param opts - Optional parameters for pagination
+         * @returns A promise resolving to search results
+         */
        this.ctx.provideModule('problemSearch', 'elastic', this.problemSearch.bind(this));
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a0f38d9 and 3a776c3.

📒 Files selected for processing (11)
  • framework/eslint-config/package.json (1 hunks)
  • package.json (2 hunks)
  • packages/elastic/index.ts (2 hunks)
  • packages/hydrooj/src/handler/discussion.ts (1 hunks)
  • packages/hydrooj/src/handler/home.ts (4 hunks)
  • packages/hydrooj/src/loader.ts (6 hunks)
  • packages/hydrooj/src/model/document.ts (13 hunks)
  • packages/hydrooj/src/model/domain.ts (9 hunks)
  • packages/scoreboard-xcpcio/package.json (1 hunks)
  • packages/ui-default/package.json (4 hunks)
  • packages/ui-next/package.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/ui-next/package.json
  • framework/eslint-config/package.json
  • package.json
  • packages/hydrooj/src/model/document.ts
  • packages/ui-default/package.json
🧰 Additional context used
🧬 Code Definitions (3)
packages/elastic/index.ts (7)
packages/hydrooj/src/plugin-api.ts (2) (2)
  • Service (41-41)
  • Context (41-41)
packages/ui-default/backendlib/template.ts (1) (1)
  • Context (254-275)
packages/hydrooj/src/settings.ts (1) (1)
  • Context (30-34)
packages/vjudge/src/index.ts (1) (1)
  • Context (191-196)
packages/hydrooj/src/service/db.ts (1) (1)
  • Context (58-66)
packages/hydrooj/src/interface.ts (1) (1)
  • ProblemSearch (619-619)
packages/hydrooj/src/model/problem.ts (1) (1)
  • ProblemModel (74-675)
packages/hydrooj/src/handler/home.ts (3)
framework/framework/server.ts (1) (1)
  • all (299-299)
packages/hydrooj/src/interface.ts (1) (1)
  • DomainDoc (306-314)
framework/framework/validator.ts (2) (2)
  • Types (13-52)
  • Types (77-190)
packages/hydrooj/src/model/domain.ts (5)
packages/hydrooj/src/interface.ts (1) (1)
  • DomainDoc (306-314)
packages/hydrooj/src/model/user.ts (2) (2)
  • deleteUserCache (28-47)
  • apply (477-495)
packages/hydrooj/src/service/bus.ts (1) (1)
  • apply (96-113)
packages/hydrooj/src/plugin-api.ts (2) (2)
  • Context (41-41)
  • db (58-58)
packages/hydrooj/src/service/db.ts (1) (1)
  • Context (58-66)
🪛 Biome (1.9.4)
packages/hydrooj/src/handler/home.ts

[error] 471-471: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)


[error] 509-509: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

🔇 Additional comments (29)
packages/hydrooj/src/handler/home.ts (6)

184-184: Good refactoring: Extracted geoip context.

Extracting the geoip context into a local variable improves readability and follows the principle of single responsibility. This change simplifies the code by reducing repeated access to this.ctx.geoip.


192-195: Clean code: Consistent use of extracted geoip variable.

The code now uses the extracted geoip variable consistently when setting session.updateGeoip, which improves readability and maintains the code's consistency.


205-205: Consistent refactoring: Using extracted geoip variable.

Using the extracted geoip variable for the geoipProvider property maintains consistency with the earlier changes and improves code readability.


472-473: Better type safety with explicit declarations.

Replacing untyped arrays and objects with explicit type declarations (DomainDoc[] and Record<string, string>) improves type safety and makes the code more self-documenting.


475-477: Improved variable naming with role instead of dudict.

The refactoring replaces dudict with a more descriptive role object, which better represents its purpose of storing user roles in domains.


497-497: Consistent use of role instead of dudict in response.

The response body now uses role instead of dudict, which is consistent with the variable renaming earlier in the method. This makes the code more readable and maintainable.

packages/hydrooj/src/loader.ts (11)

15-17: Enhanced type imports from context.

The imports from './context' now include more specific types like ScopeStatus and EffectScope, which improves code clarity and type safety.


22-22: Added Schema for configuration validation.

Importing Schema from 'schemastery' enables stronger configuration validation, improving the reliability of the configuration system.


53-54: Explicit dependency injection.

The static inject property clearly defines the dependencies required by the Loader service, which enhances maintainability and testability.


55-57: Constructor now accepts Context properly.

The constructor now correctly accepts a Context parameter instead of using the global app, making dependency injection more explicit and improving testability.


58-59: Async event listener for app/started.

The event listener for 'app/started' is now correctly attached to ctx and uses an async callback function, which allows for better async operations handling.


97-106: Well-designed resolveConfig method.

The new resolveConfig method provides a clean way to handle plugin configurations with proper schema validation. It correctly handles configScope and falls back to the root schema when needed.


108-116: Improved reloadPlugin with configuration scope.

The reloadPlugin method now handles configuration scopes and uses the new resolveConfig method, providing better flexibility when loading plugins.


134-136: Better error logging in resolvePlugin.

The error logging in resolvePlugin has been improved to provide more context when a plugin fails to resolve.


146-152: Key improvement: Async preload function with proper Promise handling.

Converting preload to an async function with proper Promise handling for initializing global.app improves the startup sequence and error handling. This ensures that all asynchronous operations are completed before proceeding.


169-171: Load function now properly awaits preload.

The load function is now async and properly awaits the preload function, ensuring that all initialization is completed before continuing.


207-210: LoadCli function now properly awaits preload.

Similar to the load function, loadCli is now async and properly awaits preload, ensuring consistent initialization.

packages/scoreboard-xcpcio/package.json (1)

10-10:

✅ Verification successful

Version update for @xcpcio/board-app dependency.

The dependency version has been updated from ^0.53.2 to ^0.54.0. This is a minor version update that likely introduces new features while maintaining backward compatibility according to semantic versioning principles.


🏁 Script executed:

#!/bin/bash
# Check for any breaking changes or significant updates in the release notes or changelog

# Try to find changelog or release notes for the package
curl -s https://registry.npmjs.org/@xcpcio/board-app | jq '.versions["0.54.0"].dist.tarball' | xargs curl -sL | tar -xzf - -O --wildcards "*/CHANGELOG.md" 2>/dev/null || echo "No CHANGELOG.md found"

# Look for GitHub repository in package info to check releases
curl -s https://registry.npmjs.org/@xcpcio/board-app | jq -r '.repository.url' | sed 's/git+//;s/.git$//' | xargs -I{} curl -s {}/releases/tag/v0.54.0 2>/dev/null | grep -o '<div class="markdown-body">.*</div>' || echo "No release notes found"

Length of output: 467


Dependency Update Approved: @xcpcio/board-app

  • The dependency was updated from ^0.53.2 to ^0.54.0, which is a minor version bump.
  • Verification via the release notes/changelog script returned no changelog or explicit release notes; however, according to semantic versioning, minor updates typically introduce new features without breaking backward compatibility.
  • No further concerns were identified. Please ensure regular testing as usual.
packages/hydrooj/src/handler/discussion.ts (1)

75-75:

✅ Verification successful

Performance optimization added through database hint.

Adding .hint('discussionSort') to the MongoDB query is a good performance optimization that forces the query to use a specific index named 'discussionSort', which should improve the efficiency of discussion listing operations.


🏁 Script executed:

#!/bin/bash
# Check if the discussionSort index is properly defined in the codebase

# Look for index definition in the discussion model
rg -A 3 -B 3 "discussionSort" --glob "*.ts" packages/hydrooj/src/model/discussion.ts

# Check for any createIndex calls related to discussions
rg -A 3 "createIndex.*discussion" --glob "*.ts"

# Look for any schema definitions or migrations that might define this index
rg -A 5 "discussionSort|discussion.*index" --glob "*.ts" packages/hydrooj/src/model/

Length of output: 964


Index 'discussionSort' confirmed and properly applied in the query.
The grep results show that the index named 'discussionSort' is defined in the model (in packages/hydrooj/src/model/document.ts), which validates that using .hint('discussionSort') in the query is a proper and effective performance optimization for discussion listings.

  • Location verified: packages/hydrooj/src/model/document.ts contains the index definition.
  • Handler reference: packages/hydrooj/src/handler/discussion.ts correctly applies the hint in the query.

No further modifications are necessary.

packages/hydrooj/src/model/domain.ts (10)

4-6: Good: Improved module import patterns.

The changes to the import statements are appropriate - importing the Context type for use in the new apply function and switching from namespace import to default import for the bus service aligns with modern JavaScript/TypeScript module patterns.


104-108: Good: Enhanced return value in the edit method.

The edit method now returns the complete result object from findOneAndUpdate instead of just a specific field, providing more information to callers.


120-120: Simplified return value in inc method.

Returning value?.[field] directly provides a cleaner API by returning exactly the incremented field value. The optional chaining correctly handles null cases.


136-138: Use Array.isArray() instead of instanceof Array.

The instanceof Array check can be unreliable when dealing with arrays from different contexts or frames.

- if (!(uid instanceof Array)) {
+ if (!(Array.isArray(uid))) {

136-153: Good: Enhanced setUserRole with autojoin capability.

The addition of the autojoin parameter with a default value of false provides a clean way to optionally set the join property when setting a user's role, maintaining backward compatibility.


155-162: Good: Added dedicated method for join management.

The new setJoin method provides a clean API for managing domain membership, appropriately handling both single users and arrays of users with optimized batch updates for arrays.


301-309: Critical: Mismatch Between Interface and Usage of Host Property

The DomainDoc interface (in packages/hydrooj/src/interface.ts) defines the property as host?: string[], but the code in packages/hydrooj/src/model/domain.ts is accessing ddoc.host. This discrepancy can lead to runtime issues (such as missed cache invalidation) because the expected property name in the interface does not match its usage in the code.

  • Update the code at line 305 in packages/hydrooj/src/model/domain.ts to use ddoc.host instead of ddoc.hosts (or update the interface if the plural form is intended).

301-321: Good: Consolidated initialization into apply function.

The new apply function provides a clean way to initialize all domain-related event handlers and database indexes in one place, improving code organization and maintainability.


268-268:

❓ Verification inconclusive

Verify impact of adding join: true filter condition.

Similar to the change in countUser, this modifies the behavior to only include users who have explicitly joined the domain. This could break existing code that expects to get all domain users regardless of join status.


🏁 Script executed:

#!/bin/bash
# Search for calls to getDictUserByDomainId to verify that callers handle the new behavior
echo "Finding all calls to DomainModel.getDictUserByDomainId:"
rg -A 2 "getDictUserByDomainId" --type ts

Length of output: 1086


Action: Confirm that call sites properly handle the new "joined-only" behavior.

The change to

const dudocs = await collUser.find({ uid, join: true }).toArray();

now filters out users who have not explicitly joined the domain. Our search shows that the only direct consumers of getDictUserByDomainId are in:

  • packages/hydrooj/src/handler/home.ts
  • packages/hydrooj/src/handler/domain.ts

Both call sites currently invoke this method and then process the returned dictionary by extracting the keys. Please verify that neither location expects to include users that haven’t joined the domain. If any caller needs to access all domain users regardless of join status, additional adjustments may be required.


131-132:

✅ Verification successful

Verify impact of adding join: true filter condition.

Adding the join: true condition to the query changes the behavior to only count users who have explicitly joined the domain. This is a behavioral change that might affect existing code that relies on counting all users regardless of their join status.


🏁 Script executed:

#!/bin/bash
# Search for calls to countUser to verify that callers handle the new behavior
echo "Finding all calls to DomainModel.countUser:"
rg -A 2 "countUser" --type ts

Length of output: 678


Action: Confirm the intended behavior of counting only joined users

After verifying the call sites, it appears that the only invocation of DomainModel.countUser is within the same file where a role is always passed (e.g., role.count = await DomainModel.countUser(ddoc._id, role._id);). This means both branches of the method now consistently count only users with join: true. There are no other callers expecting a full count of users regardless of their join status.

  • Location: packages/hydrooj/src/model/domain.ts (both the method definition and its call site)
  • Impact: The filtering condition applies uniformly. If there’s any future need to count all users (including those not joined), a distinct query or changes to this method might be necessary.
  • Next Step: Ensure that the business logic indeed requires counting only joined users in all cases.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (3)
packages/hydrooj/src/upgrade.ts (2)

427-427: ⚠️ Potential issue

Missing import for 'app' dependency.

The code references app.get('config') but there's no import statement for the app object in the file imports.

import yaml from 'js-yaml';
import { pick } from 'lodash';
import moment from 'moment-timezone';
import { ObjectId } from 'mongodb';
import { sleep } from '@hydrooj/utils';
+import { app } from './loader';
import { buildContent } from './lib/content';

706-723: 🛠️ Refactor suggestion

Add error handling to the migration function.

The new migration function for Hydro v5 lacks error handling for database operations, which could lead to incomplete migrations if any operations fail.

// Start Hydro v5
async function _91_92() {
+    try {
        await domain.collUser.updateMany({}, { $set: { join: true } });
        await domain.coll.updateMany(
            { $or: [{ _join: { $exists: false } }, { _join: { $eq: null } }, { '_join.method': domain.JOIN_METHOD_NONE }] },
            { $set: { _join: { method: domain.JOIN_METHOD_ALL, role: 'default', expire: null }, _migratedJoin: true } },
        );
        const domainUser = await domain.coll.find({ domainId: 'system', join: true }, onPrimary)
            .project({ uid: 1 }).toArray();
        const otherUsers = await user.coll.find({ _id: { $gt: 1, $nin: domainUser.map((u) => u.uid) } }, onPrimary)
            .project({ _id: 1 }).toArray();
        await domain.collUser.updateMany(
            { uid: { $in: otherUsers.map((u) => u._id) }, domainId: 'system' },
            { $set: { join: true } },
            { upsert: true },
        );
        return true;
+    } catch (error) {
+        logger.error(`Migration to Hydro v5 failed: ${error.message}`);
+        throw error;
+    }
}

Also consider adding documentation about the purpose of this migration function to improve maintainability.

packages/hydrooj/src/handler/home.ts (1)

483-494: ⚠️ Potential issue

Critical: Handle potential null from getById

The code uses a non-null assertion on the result of user.getById(ddoc._id, this.user._id), which assumes that a valid user document is always returned. This could lead to runtime errors if the user is not found in a domain.

-                const udoc = await user.getById(ddoc._id, this.user._id);
-                canManage[ddoc._id] = udoc.hasPerm(PERM.PERM_EDIT_DOMAIN);
-                role[ddoc._id] = udoc.role;
+                const udoc = await user.getById(ddoc._id, this.user._id);
+                if (udoc) {
+                    canManage[ddoc._id] = udoc.hasPerm(PERM.PERM_EDIT_DOMAIN);
+                    role[ddoc._id] = udoc.role;
+                } else {
+                    canManage[ddoc._id] = false;
+                    role[ddoc._id] = '';
+                }
🧹 Nitpick comments (3)
packages/hydrooj/src/handler/home.ts (1)

471-471: Fix empty object pattern in function parameter

The empty object pattern { } is flagged by the static analysis tool. Use a named parameter for clarity.

-    async get({ }, all: boolean) {
+    async get({ domainId }: Record<string, never>, all: boolean) {
-    async postLeave({ }, id: string) {
+    async postLeave({ domainId }: Record<string, never>, id: string) {

Also applies to: 509-509

🧰 Tools
🪛 Biome (1.9.4)

[error] 471-471: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

packages/hydrooj/src/handler/domain.ts (2)

151-158: Consider avoiding the delete operator for better performance

While the transformation of user data is clean and effective, using the delete operator on line 156 may impact performance.

-            const u = {
-                ...dudoc,
-                ...dudoc.user,
-            };
-            delete u.user;
-            return u;
+            const { user: userData, ...rest } = dudoc;
+            return {
+                ...rest,
+                ...userData,
+            };
🧰 Tools
🪛 Biome (1.9.4)

[error] 156-156: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


334-349: Enhanced domain join flexibility with target parameter

The addition of the target parameter increases flexibility by allowing users to join domains other than the current one. The implementation correctly handles role assignment based on privileges and performs proper validation.

On line 347, consider using a more performance-friendly approach than the delete operator:

-        if (assignedRole !== 'default') delete this.joinSettings;
+        if (assignedRole !== 'default') this.joinSettings = undefined;
🧰 Tools
🪛 Biome (1.9.4)

[error] 347-347: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 917ed3d and 7ed859b.

📒 Files selected for processing (12)
  • packages/hydrooj/locales/zh.yaml (2 hunks)
  • packages/hydrooj/locales/zh_TW.yaml (2 hunks)
  • packages/hydrooj/src/error.ts (1 hunks)
  • packages/hydrooj/src/handler/domain.ts (7 hunks)
  • packages/hydrooj/src/handler/home.ts (5 hunks)
  • packages/hydrooj/src/model/document.ts (13 hunks)
  • packages/hydrooj/src/upgrade.ts (4 hunks)
  • packages/ui-default/locales/ko.yaml (4 hunks)
  • packages/ui-default/locales/zh.yaml (8 hunks)
  • packages/ui-default/locales/zh_TW.yaml (3 hunks)
  • packages/ui-default/templates/domain_join_applications.html (1 hunks)
  • packages/ui-default/templates/home_domain.html (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/ui-default/templates/domain_join_applications.html
  • packages/ui-default/templates/home_domain.html
  • packages/ui-default/locales/zh_TW.yaml
  • packages/ui-default/locales/ko.yaml
  • packages/ui-default/locales/zh.yaml
  • packages/hydrooj/src/model/document.ts
🧰 Additional context used
🧬 Code Definitions (1)
packages/hydrooj/src/error.ts (1)
framework/framework/error.ts (1) (1)
  • ForbiddenError (50-50)
🪛 Biome (1.9.4)
packages/hydrooj/src/handler/home.ts

[error] 471-471: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)


[error] 509-509: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

packages/hydrooj/src/handler/domain.ts

[error] 156-156: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 168-168: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)


[error] 347-347: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

🔇 Additional comments (17)
packages/hydrooj/src/upgrade.ts (1)

39-39: Good addition of read preference configuration.

The onPrimary constant explicitly sets the read preference to primary, which is appropriate for ensuring consistent reads during migration operations.

packages/hydrooj/src/error.ts (1)

45-45: Enhanced error message format for DomainJoinForbiddenError

The error message has been updated to use a more flexible format with placeholders, which will provide users with more specific information about why they cannot join a domain.

packages/hydrooj/locales/zh_TW.yaml (1)

466-467: Added localized messages for domain membership management

These new localization entries provide users with more specific feedback about domain access issues, which is a good improvement to the user experience.

Also applies to: 549-550, 556-556

packages/hydrooj/locales/zh.yaml (1)

790-790: Added localized messages for domain membership management

These new localization entries provide users with more specific feedback about domain access issues, which is a good improvement to the user experience.

Also applies to: 929-930, 938-938

packages/hydrooj/src/handler/home.ts (4)

184-185: Improved code readability with local variable for geoip

Good refactoring by extracting this.ctx.geoip into a local variable, which reduces repetition and makes the code more maintainable.

Also applies to: 192-193, 205-206


471-481: Improved domain retrieval and variable naming

Good change to use more descriptive variable names (ddocs instead of res) and simplify the domain retrieval logic.

🧰 Tools
🪛 Biome (1.9.4)

[error] 471-471: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)


497-498: Improved response structure with role information

The response now includes role instead of dudict, which is a more descriptive and focused property name.


507-515: Added functionality for users to leave domains

This new method provides a way for users to leave domains through the UI, which is a good addition to the user experience. The implementation correctly:

  1. Validates the domain is not 'system'
  2. Checks that the domain exists
  3. Sets the user's join status to false
  4. Redirects back to the previous page
🧰 Tools
🪛 Biome (1.9.4)

[error] 509-509: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

packages/hydrooj/src/handler/domain.ts (9)

106-148: Improved data retrieval with MongoDB aggregation pipeline

The refactoring to use MongoDB's aggregation pipeline with $lookup is a significant improvement. This approach efficiently joins user details from the user collection in a single database operation, reducing the need for additional queries and improving performance for domain user listing.


167-170: Security Check: Update Parameter Destructuring

The security check preventing modification of the domain owner's role is correctly implemented. However, for consistency with other handler methods (e.g., see other methods in domain.ts), the empty object destructuring should be replaced with explicit extraction of domainId.

-async post({ }, uids: number[]) {
+async post({ domainId }, uids: number[]) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 168-168: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)


173-175: Enhanced batch processing with array parameter

Renaming the method to postSetUsers and changing the parameter from a single UID to an array enhances the API's consistency and enables batch processing of user roles.


184-198: Well-implemented user removal with notification

The postKick method is a robust implementation for removing users from a domain:

  1. It checks which users actually need updates before proceeding
  2. It handles both single and multiple user IDs
  3. It properly notifies kicked users with a formatted message

269-269: Streamlined role filtering

The change to only exclude the 'guest' role instead of both 'default' and 'guest' streamlines the role management process and allows default users to be included in role selection.


283-286: Added group assignment capability

Adding the group parameter enhances domain join functionality by allowing users to be automatically assigned to specific groups upon joining, which simplifies user onboarding.


295-295: Group parameter included in join settings

The group parameter is properly incorporated into the join settings structure.


353-370: Improved response with detailed domain information

The enhanced response body now includes comprehensive domain information (name, owner, avatar, bulletin), improving the user experience by providing context about the domain being joined.


374-395: Robust domain join process with group assignment

The updated implementation properly handles:

  1. Invitation code validation
  2. Group assignment when specified
  3. Dynamic role assignment based on join settings
  4. Appropriate redirection after successful join

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (7)
packages/hydrooj/src/upgrade.ts (2)

427-427: ⚠️ Potential issue

Missing import for 'app' dependency.

The code references app.get('config') but there's no import statement for the app object in the file imports.

import yaml from 'js-yaml';
import { pick } from 'lodash';
import moment from 'moment-timezone';
import { ObjectId } from 'mongodb';
import { sleep } from '@hydrooj/utils';
+import { app } from './loader';
import { buildContent } from './lib/content';

706-723: 🛠️ Refactor suggestion

Add error handling to the migration function.

The new migration function for Hydro v5 lacks error handling for database operations, which could lead to incomplete migrations if any operations fail.

// Start Hydro v5
async function _91_92() {
+    try {
        await domain.collUser.updateMany({}, { $set: { join: true } });
        await domain.coll.updateMany(
            { $or: [{ _join: { $exists: false } }, { _join: { $eq: null } }, { '_join.method': domain.JOIN_METHOD_NONE }] },
            { $set: { _join: { method: domain.JOIN_METHOD_ALL, role: 'default', expire: null }, _migratedJoin: true } },
        );
        const domainUser = await domain.collUser.find({ domainId: 'system', join: true }, onPrimary)
            .project({ uid: 1 }).toArray();
        const otherUsers = await user.coll.find({ _id: { $gt: 1, $nin: domainUser.map((u) => u.uid) } }, onPrimary)
            .project({ _id: 1 }).toArray();
        await domain.collUser.updateMany(
            { uid: { $in: otherUsers.map((u) => u._id) }, domainId: 'system' },
            { $set: { join: true } },
            { upsert: true },
        );
        return true;
+    } catch (error) {
+        logger.error(`Migration to Hydro v5 failed: ${error.message}`);
+        throw error;
+    }
}
packages/elastic/index.ts (4)

54-54: ⚠️ Potential issue

Potential null/undefined access still exists.

The code still accesses opts.skip without a safety check, which could lead to runtime errors if opts is undefined.

Apply this fix to ensure safe property access:

-if (!opts.skip) {
+if (!opts?.skip) {

71-77: 🛠️ Refactor suggestion

Missing type annotations for the run method parameters.

The method parameters lack proper type annotations, which was mentioned in a previous review comment. Consider adding proper types to improve type safety.

-async run({ domainId }, report) {
+async run({ domainId }: { domainId?: string }, report: (status: { message: string }) => void) {

94-115: 🛠️ Refactor suggestion

Missing error handling in event listeners.

The event handlers for 'problem/add', 'problem/edit', and 'problem/del' don't include proper error handling. If these operations fail, the errors will propagate as unhandled promise rejections.

Example fix for one of the handlers:

this.ctx.on('problem/add', async (doc, docId) => {
+   try {
        await this.client.index({
            index: 'problem',
            id: `${doc.domainId}/${docId}`,
            document: processDocument(doc),
        });
+   } catch (error) {
+       this.ctx.logger.error(`Error indexing problem: ${error.message}`);
+   }
});

Apply similar error handling to the other event handlers.


116-122: 🛠️ Refactor suggestion

Error handling missing in script registration.

The script registration doesn't include error handling for the run method when used as a callback.

-            this.run.bind(this),
+            async (...args) => {
+                try {
+                    return await this.run.bind(this)(...args);
+                } catch (error) {
+                    this.ctx.logger.error(`Error in ensureElasticSearch script: ${error.message}`);
+                    throw error;
+                }
+            },
framework/framework/server.ts (1)

141-142: ⚠️ Potential issue

Fix unsafe interface-class declaration merging.

The empty interface HandlerCommon<C> followed by a class with the same name is a TypeScript anti-pattern that bypasses type checking for interface properties. When you merge an interface and class declaration, TypeScript won't verify that the class properly initializes interface properties.

-export interface HandlerCommon<C> { } // eslint-disable-line @typescript-eslint/no-unused-vars
-export class HandlerCommon<C> {
+// Use a type alias or rename the interface if you need additional properties later
+export class HandlerCommon<C> {
🧰 Tools
🪛 Biome (1.9.4)

[error] 141-141: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 142-142: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7ed859b and e1f4f69.

📒 Files selected for processing (8)
  • framework/eslint-config/package.json (1 hunks)
  • framework/framework/decorators.ts (5 hunks)
  • framework/framework/server.ts (22 hunks)
  • package.json (2 hunks)
  • packages/elastic/index.ts (2 hunks)
  • packages/hydrooj/src/service/server.ts (9 hunks)
  • packages/hydrooj/src/upgrade.ts (4 hunks)
  • packages/ui-default/package.json (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • framework/framework/decorators.ts
  • framework/eslint-config/package.json
  • package.json
  • packages/ui-default/package.json
🧰 Additional context used
🧬 Code Definitions (3)
packages/elastic/index.ts (3)
packages/hydrooj/src/plugin-api.ts (2)
  • Service (41-41)
  • Context (41-41)
packages/hydrooj/src/interface.ts (1)
  • ProblemSearch (619-619)
packages/hydrooj/src/model/problem.ts (1)
  • ProblemModel (74-675)
packages/hydrooj/src/service/server.ts (4)
packages/hydrooj/src/plugin-api.ts (5)
  • HandlerCommon (7-7)
  • Handler (40-40)
  • Context (41-41)
  • ConnectionHandler (40-40)
  • WebService (7-7)
packages/hydrooj/src/context.ts (2)
  • Context (31-41)
  • Context (68-77)
packages/hydrooj/src/service/bus.ts (1)
  • apply (96-113)
packages/hydrooj/src/error.ts (2)
  • PermissionError (22-27)
  • PrivilegeError (28-33)
framework/framework/server.ts (4)
packages/hydrooj/src/service/layers/user.ts (1)
  • ctx (5-18)
packages/hydrooj/src/plugin-api.ts (3)
  • Handler (40-40)
  • Service (41-41)
  • Context (41-41)
framework/framework/interface.ts (1)
  • KnownHandlers (3-5)
packages/hydrooj/src/context.ts (2)
  • Context (31-41)
  • Context (68-77)
🪛 Biome (1.9.4)
framework/framework/server.ts

[error] 141-141: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 142-142: This class is unsafely merged with an interface.

The interface is declared here.

The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.

(lint/suspicious/noUnsafeDeclarationMerging)

🔇 Additional comments (19)
packages/hydrooj/src/upgrade.ts (1)

39-40: Good addition of MongoDB read preference.

The onPrimary constant ensures database operations are directed to the primary node in a replica set, which is important for write operations and consistency in read operations.

packages/elastic/index.ts (5)

4-4: Good improvement: Added missing imports from hydrooj.

The import statement has been expanded to include necessary types and classes like ProblemSearch, Schema, and Service, which are used in the refactored code. This improves code readability and type safety.


20-25: Well-structured class with proper configuration schema.

The refactoring from global functions to a class-based approach with ElasticSearchService is a significant improvement. The static configuration schema properly defines and validates the required settings with sensible defaults.


26-31: Constructor properly initializes the Elasticsearch client.

The constructor appropriately initializes the client using the configuration URL and stores the config for later use. The use of private modifier for the config parameter is a good practice.


33-33: Improved type safety with proper parameter typing.

The method signature now uses Parameters<ProblemSearch>[2] to ensure type compatibility with the original interface, resolving the previous review comment about missing type annotations.


123-123: Good modularization with module provider.

The use of provideModule to make the problemSearch functionality available to other parts of the application is a good practice. This promotes loose coupling and makes the code more maintainable.

framework/framework/server.ts (8)

339-339: LGTM: Generic context type improves type safety.

The WebService class now accepts a generic type parameter that extends CordisContext, which enables better type checking throughout the application.


489-490: Good use of resource management with new using statement.

Using the new forkContextWithScope utility with the using statement ensures proper cleanup of resources after the HTTP request completes.


598-615: Good improvement in WebSocket cleanup logic.

The new cleanup function for WebSocket connections ensures proper resource cleanup, error handling, and connection termination in all scenarios.


688-712: Fixed condition that always evaluated to false.

The Checker function has been properly refactored to fix the condition that previously always evaluated to false in the check function. This addresses the CodeQL warning reported in the static analysis.


748-748: Good improvement in type safety for Route and Connection handlers.

The Route and Connection methods now correctly use proper type constraints for handler parameters, improving type safety and preventing potential runtime errors.

Also applies to: 757-757


791-814: Well-implemented mixin functionality with proper cleanup.

The new _applyMixin method properly handles applying mixins to class prototypes with appropriate cleanup when the context is disposed. It also properly preserves old values when a property already exists.


830-832: Fixed wsHandlerMixin implementation.

The wsHandlerMixin method now correctly applies mixins to the ConnectionHandler prototype, fixing the previous issue where it would warn about existing properties but not actually assign the new properties.


845-852: Good use of module augmentation for type safety.

The module declaration for @cordisjs/core ensures that the TypeScript compiler knows about the additions to the Context interface, enabling proper type checking for the methods added by the WebService class.

packages/hydrooj/src/service/server.ts (5)

82-91: LGTM: Clean transition to WebService plugin.

The apply function now correctly uses the WebService as a plugin with appropriate configuration settings.


203-234: Good addition of HTTP error handling.

The new httpHandlerMixin properly handles different error scenarios with improved redirection logic for authentication and permission errors. The error handling is more comprehensive and user-friendly.


236-251: Improved WebSocket error handling.

The wsHandlerMixin provides better error handling for WebSocket connections, with appropriate logging and error reporting based on the error type and user state.


258-259: Good domain context extension.

Adding the domain to the handler's context improves the availability of domain-specific information throughout the request lifecycle.


260-270: Good addition of handler creation lifecycle hooks.

The new event handlers for 'handler/create/http' and 'handler/create/ws' provide proper initialization and error handling for both HTTP and WebSocket handlers, enhancing the robustness of the application.

Also applies to: 271-273

Comment on lines +500 to 503
// FIXME: should pass type check
await (this.ctx.parallel as any)('handler/create', h, 'http');
await (this.ctx.parallel as any)('handler/create/http', h);

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add proper type definitions for event handlers instead of type assertions.

Multiple locations use type assertions to any with FIXME comments to bypass TypeScript's type system. This decreases type safety and should be properly addressed.

Create proper type definitions for the event handlers to avoid type assertions:

// In your interfaces file:
interface HandlerEvents<T> {
  'handler/create': [handler: T, type: 'http' | 'ws'];
  'handler/create/http': [handler: T];
  'handler/create/ws': [handler: T];
  'handler/error': [handler: T, error: Error];
  'connection/create': [handler: T];
  'connection/active': [handler: T];
  'connection/close': [handler: T];
}

// Then update the Context interface to include these typed events
interface C extends CordisContext {
  parallel<E extends keyof HandlerEvents<T>, T>(event: E, ...args: HandlerEvents<T>[E]): Promise<void>;
  serial<E extends keyof HandlerEvents<T>, T>(event: E, ...args: HandlerEvents<T>[E]): Promise<void>;
  emit<E extends keyof HandlerEvents<T>, T>(event: E, ...args: HandlerEvents<T>[E]): void;
}

This also applies to similar FIXME comments at lines 553-555, 603-605, 659-659.

Comment on lines +31 to 32
export interface HandlerCommon<C> { // eslint-disable-line @typescript-eslint/no-unused-vars
domain: DomainDoc;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix unsafe interface-class declaration merging in Handler classes.

Similar to the issue in framework/framework/server.ts, there's an unsafe interface-class declaration merging pattern for both Handler and ConnectionHandler.

-export interface HandlerCommon<C> { // eslint-disable-line @typescript-eslint/no-unused-vars
-    domain: DomainDoc;
+// Move interface properties to class implementation

-export class Handler extends HandlerOriginal<Context> {
-    domain: DomainDoc;
+export class Handler extends HandlerOriginal<Context> {
+    declare domain: DomainDoc;

-export class ConnectionHandler extends ConnectionHandlerOriginal<Context> {
-    domain: DomainDoc;
+export class ConnectionHandler extends ConnectionHandlerOriginal<Context> {
+    declare domain: DomainDoc;

Alternative solution: Convert interfaces to type aliases or implement the interfaces in the classes:

// Alternative solution using implements
interface IHandler {
    domain: DomainDoc;
}
export class Handler extends HandlerOriginal<Context> implements IHandler {
    domain: DomainDoc;
}

Also applies to: 74-78

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants