Skip to content

Conversation

@nicotsx
Copy link
Owner

@nicotsx nicotsx commented Jan 5, 2026

Allows for more eslint compatible rules & type aware linting

Summary by CodeRabbit

  • Bug Fixes

    • Fixed retention policy summary text formatting.
  • Chores

    • Switched linting/formatting tooling to Oxlint/Oxfmt.
    • Improved logging and error message formatting for clearer diagnostics.
    • Standardized promise handling to avoid unhandled-promise warnings.
    • Updated project path aliases, configs, and developer dependencies.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 5, 2026

Walkthrough

Switches lint/formatter from Biome to oxlint/oxfmt, updates configs and package scripts, applies widespread explicit promise handling (void/await) across client and server, improves error/log message formatting, adjusts path aliases and TypeScript baseUrl, and removes biome.json.

Changes

Cohort / File(s) Summary
Linting & Formatting Config
/.github/workflows/checks.yml, .oxlintrc.json, .oxfmtrc.json, biome.json, package.json
Replace Biome with oxlint/oxfmt: add ox configs, remove biome.json, update GitHub workflow to use oxlint-action, add oxfmt/oxlint devDependencies and new lint script; remove Biome scripts/devDependency.
Client promise handling (void on navigate/query)
app/client/components/*, app/client/hooks/use-server-events.ts, app/root.tsx, app/client/modules/*/routes/*, app/client/modules/*/components/*, app/client/modules/*/tabs/*
Consistently prefix fire-and-forget calls with void (e.g., navigate(...), queryClient.prefetchQuery, invalidateQueries, refetchQueries) across many client files to explicitly ignore returned Promises.
Server await adjustments
app/server/index.ts, app/server/core/scheduler.ts, app/server/jobs/cleanup-sessions.ts
Await startup() during server bootstrap; await task.stop() / task.destroy() in scheduler stop/clear; await authService.cleanupExpiredSessions() in cleanup job.
SSE handlers made async
app/server/modules/events/events.controller.ts
Convert SSE event handlers to async and await stream.writeSSE() calls for various backup/volume/mirror events.
Error/log formatting improvements
app/server/utils/logger.ts, app/server/utils/rclone.ts, app/server/utils/restic.ts, app/server/modules/backups/backups.service.ts
Use toMessage(error) and/or stringified summary fields when logging errors/results; coerce log messages to strings for consistent output.
Small client fixes & UX strings
app/client/modules/backups/components/create-schedule-form.tsx, app/client/modules/backups/components/snapshot-file-browser.tsx, app/client/components/directory-browser.tsx, app/client/components/restore-form.tsx, app/client/components/snapshots-table.tsx, app/client/components/volume-file-browser.tsx
Stringify numeric retention values (.toString()); convert several prefetch/navigation calls to fire-and-forget (void); remove unused icon import in notification details.
Tests & test setup
app/test/setup.ts, app/server/modules/backups/__tests__/backups.service.test.ts
Prefix logger mock invocation with void; change one test to call executeBackup as fire-and-forget (prefixed with void).
Config & aliases
tsconfig.json, components.json
Remove baseUrl from tsconfig; update path aliases to client-scoped paths (e.g., components~/client/components).

Possibly related PRs

Pre-merge checks

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.65% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately and clearly describes the main objective: migrating from Biome to oxlint/oxformat tooling. It is specific, concise, and reflects the primary focus of the changeset.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@nicotsx nicotsx force-pushed the refactor/oxlint-oxformat branch from 1b8cf0e to e5a0493 Compare January 5, 2026 19:21
Copy link
Contributor

@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: 6

Fix all issues with AI Agents 🤖
In @app/client/hooks/use-server-events.ts:
- Line 120: The current call to queryClient.invalidateQueries() indiscriminately
invalidates all queries; change it to only invalidate volume-related queries by
using the predicate or specific query key form (e.g.,
queryClient.invalidateQueries({ predicate: q => /* match volume keys */
q.queryKey[0] === 'volumes' || q.queryKey.includes('volume') }) or
queryClient.invalidateQueries(['volumes'])); locate the call to
queryClient.invalidateQueries() in use-server-events.ts (the volume event
handler, analogous to the backup handler) and replace it with a scoped
invalidation that targets your app's volume query keys.
- Line 131: The global call to queryClient.invalidateQueries() blindly
invalidates all queries; narrow it to only volume-related queries by replacing
the unscoped invalidation in use-server-events.ts (the calls at the
invalidateQueries() occurrences around the handlers at lines ~120 and ~131) with
a scoped invalidation that targets your volume query keys (e.g., use
invalidateQueries with a predicate that checks query.queryKey for the 'volumes'
key or the exact volume-related key shape used elsewhere in the app, so only
those queries are invalidated).
- Line 152: Replace the blanket invalidate call (the void
queryClient.invalidateQueries() in use-server-events) with a scoped invalidation
that targets only mirror- or repository-related queries: call
queryClient.invalidateQueries with a predicate (or explicit queryKey array) that
checks query.queryKey for 'mirror' or 'repository' (or matches the specific
mirror/repo id) so only those queries are invalidated instead of all queries.
- Around line 90-91: The current use-server-events handler calls
queryClient.invalidateQueries() and queryClient.refetchQueries() with no filters
which invalidates and refetches the entire cache; change these calls to target
only backup-related queries (e.g., use queryClient.invalidateQueries and
queryClient.refetchQueries with a specific queryKey or a predicate that matches
backup keys such as "backup", "backups", or the backup slice used by your app)
so only backup queries are invalidated/refetched; update the calls in
use-server-events.ts where queryClient.invalidateQueries and
queryClient.refetchQueries are invoked to pass the appropriate queryKey or
predicate for backup queries.

In @app/server/index.ts:
- Around line 25-27: The code calls startup() fire-and-forget and immediately
logs readiness; change this to await the async startup() call and handle errors:
replace the void startup() invocation with an awaited call (await startup()) in
the top-level async context or wrap startup() in a promise chain, then move or
conditionally run logger.info(`Server is running...`) only after startup
resolves successfully; on rejection catch the error, log details with
logger.error including the error object and exit the process (process.exit(1))
to prevent serving before initialization completes.

In @app/server/utils/logger.ts:
- Line 30: Remove the redundant outer String() wrapper around JSON.stringify to
avoid adding extra quotes for string primitives; change the return so it passes
the raw JSON.stringify(m) result into sanitizeSensitiveData (i.e., replace
String(JSON.stringify(m)) with JSON.stringify(m)), ensuring you keep
sanitizeSensitiveData(...) and the variable m unchanged.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/server/modules/events/events.controller.ts (1)

16-92: Add error handling for async event handlers to prevent unhandled promise rejections.

Event emitters don't automatically handle promises returned from async handlers. When serverEvents.emit() fires these events, the returned promises are ignored, creating floating promises. If stream.writeSSE throws an error (e.g., client disconnect, write failure), it will result in an unhandled promise rejection.

🔎 Recommended fix: Add try-catch blocks to handle errors
-const onBackupStarted = async (data: { scheduleId: number; volumeName: string; repositoryName: string }) => {
-	await stream.writeSSE({
-		data: JSON.stringify(data),
-		event: "backup:started",
-	});
-};
+const onBackupStarted = async (data: { scheduleId: number; volumeName: string; repositoryName: string }) => {
+	try {
+		await stream.writeSSE({
+			data: JSON.stringify(data),
+			event: "backup:started",
+		});
+	} catch (error) {
+		logger.error("Failed to write SSE event backup:started:", error);
+	}
+};

Apply similar try-catch blocks to all other async event handlers: onBackupProgress, onBackupCompleted, onVolumeMounted, onVolumeUnmounted, onVolumeUpdated, onMirrorStarted, and onMirrorCompleted.

🧹 Nitpick comments (2)
app/client/modules/backups/components/create-schedule-form.tsx (1)

731-731: Explicit .toString() may be unnecessary.

Template literals automatically convert numbers to strings, making the explicit .toString() call redundant. However, if oxlint requires explicit conversion (which might be the reason for this change during the migration), then it's fine to keep.

If not required by oxlint, you could simplify to:

🔎 Optional simplification
-return `${value.toString()} ${label}`;
+return `${value} ${label}`;
app/server/utils/logger.ts (1)

6-6: Optional: Redundant String() conversion.

The String() wrapper is safe but likely redundant since info.message should already be a string in the winston format context.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 21040d7 and e5a0493.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (39)
  • .github/workflows/checks.yml
  • .oxfmtrc.json
  • .oxlintrc.json
  • app/client/components/directory-browser.tsx
  • app/client/components/layout.tsx
  • app/client/components/restore-form.tsx
  • app/client/components/snapshots-table.tsx
  • app/client/components/volume-file-browser.tsx
  • app/client/hooks/use-server-events.ts
  • app/client/modules/auth/routes/download-recovery-key.tsx
  • app/client/modules/auth/routes/login.tsx
  • app/client/modules/auth/routes/onboarding.tsx
  • app/client/modules/backups/components/create-schedule-form.tsx
  • app/client/modules/backups/components/snapshot-file-browser.tsx
  • app/client/modules/backups/routes/backup-details.tsx
  • app/client/modules/backups/routes/create-backup.tsx
  • app/client/modules/notifications/routes/create-notification.tsx
  • app/client/modules/notifications/routes/notification-details.tsx
  • app/client/modules/repositories/routes/create-repository.tsx
  • app/client/modules/repositories/routes/repository-details.tsx
  • app/client/modules/settings/routes/settings.tsx
  • app/client/modules/volumes/routes/create-volume.tsx
  • app/client/modules/volumes/routes/volume-details.tsx
  • app/client/modules/volumes/tabs/info.tsx
  • app/root.tsx
  • app/server/core/scheduler.ts
  • app/server/index.ts
  • app/server/jobs/cleanup-sessions.ts
  • app/server/modules/backups/__tests__/backups.service.test.ts
  • app/server/modules/backups/backups.service.ts
  • app/server/modules/events/events.controller.ts
  • app/server/utils/logger.ts
  • app/server/utils/rclone.ts
  • app/server/utils/restic.ts
  • app/test/setup.ts
  • biome.json
  • components.json
  • package.json
  • tsconfig.json
💤 Files with no reviewable changes (2)
  • biome.json
  • tsconfig.json
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{ts,tsx,js,jsx,json}

📄 CodeRabbit inference engine (AGENTS.md)

Use Biome for code formatting and linting with bunx biome check --write ., format only with bunx biome format --write ., or lint with bunx biome lint .

Files:

  • app/server/modules/backups/backups.service.ts
  • app/client/modules/settings/routes/settings.tsx
  • app/client/modules/notifications/routes/notification-details.tsx
  • app/client/modules/backups/routes/create-backup.tsx
  • app/client/modules/backups/routes/backup-details.tsx
  • app/client/modules/auth/routes/login.tsx
  • app/server/modules/events/events.controller.ts
  • app/client/modules/backups/components/snapshot-file-browser.tsx
  • app/client/components/directory-browser.tsx
  • app/client/components/restore-form.tsx
  • app/client/modules/auth/routes/onboarding.tsx
  • app/root.tsx
  • app/client/components/layout.tsx
  • app/client/modules/auth/routes/download-recovery-key.tsx
  • app/client/modules/volumes/tabs/info.tsx
  • app/client/hooks/use-server-events.ts
  • app/client/modules/repositories/routes/repository-details.tsx
  • app/server/jobs/cleanup-sessions.ts
  • app/server/utils/rclone.ts
  • app/server/utils/logger.ts
  • app/client/components/volume-file-browser.tsx
  • app/server/modules/backups/__tests__/backups.service.test.ts
  • app/client/components/snapshots-table.tsx
  • app/client/modules/volumes/routes/create-volume.tsx
  • app/client/modules/volumes/routes/volume-details.tsx
  • app/server/index.ts
  • app/client/modules/repositories/routes/create-repository.tsx
  • app/client/modules/backups/components/create-schedule-form.tsx
  • app/server/utils/restic.ts
  • package.json
  • components.json
  • app/server/core/scheduler.ts
  • app/test/setup.ts
  • app/client/modules/notifications/routes/create-notification.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Use tabs (not spaces) for indentation with a line width of 120 characters
Use double quotes for strings
Do not auto-organize imports - imports organization is disabled in Biome
All imports must include file extensions when targeting Node/Bun, as the project uses "type": "module"

Files:

  • app/server/modules/backups/backups.service.ts
  • app/client/modules/settings/routes/settings.tsx
  • app/client/modules/notifications/routes/notification-details.tsx
  • app/client/modules/backups/routes/create-backup.tsx
  • app/client/modules/backups/routes/backup-details.tsx
  • app/client/modules/auth/routes/login.tsx
  • app/server/modules/events/events.controller.ts
  • app/client/modules/backups/components/snapshot-file-browser.tsx
  • app/client/components/directory-browser.tsx
  • app/client/components/restore-form.tsx
  • app/client/modules/auth/routes/onboarding.tsx
  • app/root.tsx
  • app/client/components/layout.tsx
  • app/client/modules/auth/routes/download-recovery-key.tsx
  • app/client/modules/volumes/tabs/info.tsx
  • app/client/hooks/use-server-events.ts
  • app/client/modules/repositories/routes/repository-details.tsx
  • app/server/jobs/cleanup-sessions.ts
  • app/server/utils/rclone.ts
  • app/server/utils/logger.ts
  • app/client/components/volume-file-browser.tsx
  • app/server/modules/backups/__tests__/backups.service.test.ts
  • app/client/components/snapshots-table.tsx
  • app/client/modules/volumes/routes/create-volume.tsx
  • app/client/modules/volumes/routes/volume-details.tsx
  • app/server/index.ts
  • app/client/modules/repositories/routes/create-repository.tsx
  • app/client/modules/backups/components/create-schedule-form.tsx
  • app/server/utils/restic.ts
  • app/server/core/scheduler.ts
  • app/test/setup.ts
  • app/client/modules/notifications/routes/create-notification.tsx
app/server/modules/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Server follows a modular service-oriented architecture with controller-service-database pattern in each module

Files:

  • app/server/modules/backups/backups.service.ts
  • app/server/modules/events/events.controller.ts
  • app/server/modules/backups/__tests__/backups.service.test.ts
app/client/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

app/client/**/*.{ts,tsx}: Client uses TanStack Query for server state management
Client uses Radix UI primitives with custom Tailwind styling
Use Server-Sent Events hook (use-server-events.ts) for real-time updates in the client

Files:

  • app/client/modules/settings/routes/settings.tsx
  • app/client/modules/notifications/routes/notification-details.tsx
  • app/client/modules/backups/routes/create-backup.tsx
  • app/client/modules/backups/routes/backup-details.tsx
  • app/client/modules/auth/routes/login.tsx
  • app/client/modules/backups/components/snapshot-file-browser.tsx
  • app/client/components/directory-browser.tsx
  • app/client/components/restore-form.tsx
  • app/client/modules/auth/routes/onboarding.tsx
  • app/client/components/layout.tsx
  • app/client/modules/auth/routes/download-recovery-key.tsx
  • app/client/modules/volumes/tabs/info.tsx
  • app/client/hooks/use-server-events.ts
  • app/client/modules/repositories/routes/repository-details.tsx
  • app/client/components/volume-file-browser.tsx
  • app/client/components/snapshots-table.tsx
  • app/client/modules/volumes/routes/create-volume.tsx
  • app/client/modules/volumes/routes/volume-details.tsx
  • app/client/modules/repositories/routes/create-repository.tsx
  • app/client/modules/backups/components/create-schedule-form.tsx
  • app/client/modules/notifications/routes/create-notification.tsx
app/client/modules/*/routes/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Routes should be organized in feature modules at app/client/modules/*/routes/

Files:

  • app/client/modules/settings/routes/settings.tsx
  • app/client/modules/notifications/routes/notification-details.tsx
  • app/client/modules/backups/routes/create-backup.tsx
  • app/client/modules/backups/routes/backup-details.tsx
  • app/client/modules/auth/routes/login.tsx
  • app/client/modules/auth/routes/onboarding.tsx
  • app/client/modules/auth/routes/download-recovery-key.tsx
  • app/client/modules/repositories/routes/repository-details.tsx
  • app/client/modules/volumes/routes/create-volume.tsx
  • app/client/modules/volumes/routes/volume-details.tsx
  • app/client/modules/repositories/routes/create-repository.tsx
  • app/client/modules/notifications/routes/create-notification.tsx
app/root.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Client entry point is app/root.tsx with React Router v7 SSR

Files:

  • app/root.tsx
app/server/jobs/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

New scheduled jobs must extend Job class, implement run() method, and be registered in app/server/modules/lifecycle/startup.ts with a cron expression

Files:

  • app/server/jobs/cleanup-sessions.ts
app/server/index.ts

📄 CodeRabbit inference engine (AGENTS.md)

Server entry point is app/server/index.ts and initializes the main API server on port 4096

Files:

  • app/server/index.ts
app/server/utils/restic.ts

📄 CodeRabbit inference engine (AGENTS.md)

app/server/utils/restic.ts: Restic password file must have 0600 permissions and should never be exposed
Update buildRepoUrl() in app/server/utils/restic.ts when adding a new repository backend
Update buildEnv() in app/server/utils/restic.ts to handle credentials and configuration when adding a new repository backend
Restic password file is stored in /var/lib/zerobyte/restic/password and auto-generated on first run
Restic cache is stored in /var/lib/zerobyte/restic/cache

Files:

  • app/server/utils/restic.ts
🧠 Learnings (23)
📓 Common learnings
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to **/*.{ts,tsx,js,jsx,json} : Use Biome for code formatting and linting with `bunx biome check --write .`, format only with `bunx biome format --write .`, or lint with `bunx biome lint .`
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to app/root.tsx : Client entry point is `app/root.tsx` with React Router v7 SSR

Applied to files:

  • app/client/modules/auth/routes/login.tsx
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to app/client/modules/*/routes/**/*.{ts,tsx} : Routes should be organized in feature modules at `app/client/modules/*/routes/`

Applied to files:

  • app/client/modules/auth/routes/login.tsx
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to app/client/**/*.{ts,tsx} : Use Server-Sent Events hook (`use-server-events.ts`) for real-time updates in the client

Applied to files:

  • app/server/modules/events/events.controller.ts
  • app/client/hooks/use-server-events.ts
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to app/server/modules/backends/backend.ts : Update backend factory in `app/server/modules/backends/backend.ts` when adding a new volume backend

Applied to files:

  • app/server/modules/events/events.controller.ts
  • app/client/modules/volumes/tabs/info.tsx
  • app/client/modules/volumes/routes/create-volume.tsx
  • app/client/modules/volumes/routes/volume-details.tsx
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to app/client/**/*.{ts,tsx} : Client uses TanStack Query for server state management

Applied to files:

  • app/root.tsx
  • app/client/hooks/use-server-events.ts
  • app/client/components/snapshots-table.tsx
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to app/schemas/volumes.ts : Add schemas for new volume backends to `app/schemas/volumes.ts` and update `volumeConfigSchema` discriminated union

Applied to files:

  • app/client/modules/volumes/tabs/info.tsx
  • app/client/modules/volumes/routes/create-volume.tsx
  • app/client/modules/volumes/routes/volume-details.tsx
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use tabs (not spaces) for indentation with a line width of 120 characters

Applied to files:

  • .oxfmtrc.json
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to app/server/utils/restic.ts : Update `buildRepoUrl()` in `app/server/utils/restic.ts` when adding a new repository backend

Applied to files:

  • app/client/modules/repositories/routes/repository-details.tsx
  • app/server/utils/restic.ts
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to app/server/modules/repositories/repositories.dto.ts : Add DTO schemas in `app/server/modules/repositories/repositories.dto.ts` when adding a new repository backend

Applied to files:

  • app/client/modules/repositories/routes/repository-details.tsx
  • app/client/modules/repositories/routes/create-repository.tsx
📚 Learning: 2025-12-22T19:49:56.761Z
Learnt from: nicotsx
Repo: nicotsx/zerobyte PR: 197
File: app/client/modules/repositories/components/create-repository-form.tsx:112-112
Timestamp: 2025-12-22T19:49:56.761Z
Learning: During the repository import flow, when users provide a full path to an existing restic repository, do not implement server-side path sanitization for this flow. Rely on Restic to validate the path; the operation will fail if the path does not point to a valid restic repository. This guidance applies to repository import components under app/client/modules/repositories (not just the specified file).

Applied to files:

  • app/client/modules/repositories/routes/repository-details.tsx
  • app/client/modules/repositories/routes/create-repository.tsx
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to app/server/jobs/**/*.ts : New scheduled jobs must extend `Job` class, implement `run()` method, and be registered in `app/server/modules/lifecycle/startup.ts` with a cron expression

Applied to files:

  • app/server/jobs/cleanup-sessions.ts
  • app/server/core/scheduler.ts
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to app/server/core/capabilities.ts : System will gracefully degrade if rclone capability is unavailable, requiring `/root/.config/rclone` directory access

Applied to files:

  • app/server/utils/rclone.ts
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to app/server/index.ts : Server entry point is `app/server/index.ts` and initializes the main API server on port 4096

Applied to files:

  • app/server/index.ts
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to app/server/modules/**/*.ts : Server follows a modular service-oriented architecture with controller-service-database pattern in each module

Applied to files:

  • app/server/index.ts
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to app/server/utils/restic.ts : Update `buildEnv()` in `app/server/utils/restic.ts` to handle credentials and configuration when adding a new repository backend

Applied to files:

  • app/server/utils/restic.ts
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to app/server/utils/restic.ts : Restic cache is stored in `/var/lib/zerobyte/restic/cache`

Applied to files:

  • app/server/utils/restic.ts
📚 Learning: 2025-11-29T15:55:09.080Z
Learnt from: nicotsx
Repo: nicotsx/zerobyte PR: 78
File: app/server/modules/repositories/repositories.service.ts:221-223
Timestamp: 2025-11-29T15:55:09.080Z
Learning: Restic's restore command has built-in path validation that prevents writing outside the specified --target directory. It normalizes and validates paths to reject any attempts to escape the target location, so application-level path sanitization is not required when using restic restore.

Applied to files:

  • app/server/utils/restic.ts
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to **/*.{ts,tsx,js,jsx,json} : Use Biome for code formatting and linting with `bunx biome check --write .`, format only with `bunx biome format --write .`, or lint with `bunx biome lint .`

Applied to files:

  • package.json
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Use `bun run tsc` for type checking and generating React Router types

Applied to files:

  • package.json
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Use `bun run test` to run all tests, or `bunx dotenv-cli -e .env.test -- bun test --preload ./app/test/setup.ts` for specific test files

Applied to files:

  • package.json
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Use `bun run build` for production builds

Applied to files:

  • package.json
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Use `bun run gen:api-client` to generate TypeScript API client from OpenAPI spec

Applied to files:

  • package.json
🧬 Code graph analysis (7)
app/server/modules/backups/backups.service.ts (3)
app/server/utils/logger.ts (1)
  • logger (36-41)
app/server/utils/errors.ts (1)
  • toMessage (16-19)
app/server/index.ts (1)
  • error (48-50)
app/client/modules/repositories/routes/repository-details.tsx (1)
app/client/api-client/@tanstack/react-query.gen.ts (2)
  • listSnapshotsOptions (464-475)
  • deleteRepositoryMutation (393-405)
app/server/jobs/cleanup-sessions.ts (1)
app/server/modules/auth/auth.service.ts (1)
  • authService (179-179)
app/server/utils/logger.ts (1)
app/server/utils/sanitize.ts (1)
  • sanitizeSensitiveData (5-22)
app/server/modules/backups/__tests__/backups.service.test.ts (1)
app/server/modules/backups/backups.service.ts (1)
  • backupsService (723-738)
app/server/index.ts (1)
app/server/modules/lifecycle/startup.ts (1)
  • startup (44-87)
app/server/utils/restic.ts (1)
app/server/utils/logger.ts (1)
  • logger (36-41)
🔇 Additional comments (42)
app/client/modules/volumes/tabs/info.tsx (1)

40-40: LGTM—Explicit fire-and-forget navigation.

The void operator correctly discards the Promise returned by navigate(), making the fire-and-forget intent explicit. This is appropriate here since the mutation has already succeeded, the toast is shown, and no follow-up logic depends on navigation completing.


Note: The retrieved learning mentions using Biome for linting, but this PR specifically migrates the project from Biome to oxlint/oxformat, so that guideline is now outdated.

app/client/modules/backups/routes/create-backup.tsx (1)

62-62: LGTM! Proper handling of fire-and-forget promise.

The void operator correctly indicates intentional fire-and-forget behavior for the navigation promise, satisfying oxlint's floating promise rules.


Note: The coding guidelines and retrieved learnings still reference Biome for linting and formatting. These should be updated to reflect the migration to oxlint/oxformat as part of this PR or in a follow-up.

Based on learnings and coding guidelines that reference Biome, which this PR is moving away from.

app/server/modules/events/events.controller.ts (1)

1-126: Update coding guidelines to reflect the tooling change from Biome to oxlint/oxformat.

The coding guidelines and retrieved learnings still reference Biome for formatting and linting, but this PR removes Biome in favor of oxlint/oxformat. Please update the project documentation (likely AGENTS.md or similar) to reflect the new tooling commands and usage.

Based on learnings, the project previously used Biome, but this PR transitions to oxlint/oxformat—please ensure all documentation is updated accordingly.

app/server/utils/restic.ts (3)

361-362: LGTM: Explicit cleanup logic is clearer.

The refactoring from logical AND expressions to explicit if statements improves readability without changing behavior. Both nullable file paths are properly handled.


396-396: LGTM: Improved error logging with arktype's summary.

The changes correctly use the summary property from arktype's type.errors instances to produce concise, human-readable validation error messages. This is the recommended approach for logging arktype validation failures and provides better diagnostics than logging the entire error object.

Also applies to: 487-487, 532-533, 715-716, 725-725


1-930: Note: Biome-related learnings and guidelines are now outdated.

This PR migrates the project from Biome to oxlint/oxformat. The retrieved learnings and coding guidelines that reference Biome should be updated to reflect the new tooling.

Based on learnings and coding guidelines, the project previously used Biome for formatting and linting, but this PR replaces it with oxlint/oxformat.

app/server/core/scheduler.ts (2)

43-49: Verify if task.destroy() is asynchronous.

According to the standard node-cron API, destroy() is a synchronous method that returns void, not a Promise. Awaiting a synchronous method is unnecessary and misleading.

If destroy() is indeed synchronous, remove the await. If it is asynchronous in your node-cron version, consider using Promise.all() for concurrent execution instead of sequential awaiting.

🔎 Proposed fix if destroy() is synchronous
 async clear() {
   for (const task of this.tasks) {
-    await task.destroy();
+    task.destroy();
   }
   this.tasks = [];
   logger.info("Scheduler cleared all tasks");
 }

35-41: No changes needed. The await keywords for task.stop() and task.destroy() are correct.

Node-cron's stop() and destroy() methods have signatures that return void | Promise<void> depending on the task type (synchronous for basic in-process tasks, asynchronous for background/forked tasks). Awaiting these methods properly handles both cases and ensures cleanup completion before proceeding, which is the correct pattern.

Likely an incorrect or invalid review comment.

app/client/modules/auth/routes/login.tsx (1)

50-56: LGTM! Fire-and-forget navigation pattern is appropriate.

The void operator correctly signals that the navigation promises are intentionally not awaited. This is the right approach for post-login navigation where you want to redirect immediately without blocking on the navigation promise.

app/client/modules/backups/components/snapshot-file-browser.tsx (1)

70-77: LGTM! Prefetch fire-and-forget pattern is correct.

Using void with prefetchQuery is the appropriate pattern for optimistic data prefetching. The prefetch is an optimization that doesn't require waiting for completion.

app/client/modules/repositories/routes/create-repository.tsx (1)

35-41: LGTM! Fire-and-forget navigation after successful creation.

The void operator appropriately signals that the navigation promise is intentionally discarded. This is the correct pattern for post-mutation navigation.

app/root.tsx (1)

27-37: LGTM! Fire-and-forget query invalidation is appropriate for mutation cache handlers.

Using void with invalidateQueries() correctly signals that these invalidations are intentionally not awaited. This is a common pattern in mutation cache configuration where you want to trigger cache updates without blocking the mutation lifecycle.

Note: If invalidation fails silently, stale data might persist in the cache. This is the existing behavior, now made explicit through the void operator.

app/server/modules/backups/backups.service.ts (1)

22-36: LGTM! Error message formatting is now consistent.

Using toMessage(error) for logging aligns with the error handling pattern used throughout this file and ensures proper sanitization of sensitive data. This change makes the error logging consistent with other catch blocks in this service (e.g., lines 255, 323, 328, 371, 375, 403).

app/client/modules/notifications/routes/notification-details.tsx (1)

69-69: LGTM: Fire-and-forget navigation is appropriate here.

The void operator correctly marks the navigation promise as intentionally ignored after successful deletion.

app/client/modules/repositories/routes/repository-details.tsx (2)

70-70: LGTM: Prefetch optimization correctly marked as fire-and-forget.

The void operator appropriately indicates that the prefetch promise result is intentionally ignored.


77-77: LGTM: Fire-and-forget navigation is appropriate here.

The void operator correctly marks the navigation promise as intentionally ignored after successful deletion.

app/client/modules/notifications/routes/create-notification.tsx (1)

36-36: LGTM: Fire-and-forget navigation is appropriate here.

The void operator correctly marks the navigation promise as intentionally ignored after successful creation.

.oxfmtrc.json (1)

1-6: Remove experimentalSortImports as it enables automatic import organization.

The experimentalSortImports: {} setting actively enables oxfmt's import sorting feature with default settings. This conflicts with the project coding guidelines that specify: "Do not auto-organize imports - imports organization is disabled in Biome." Remove this line from the configuration to comply with project standards.

⛔ Skipped due to learnings
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Do not auto-organize imports - imports organization is disabled in Biome
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to **/*.{ts,tsx,js,jsx,json} : Use Biome for code formatting and linting with `bunx biome check --write .`, format only with `bunx biome format --write .`, or lint with `bunx biome lint .`
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use tabs (not spaces) for indentation with a line width of 120 characters
app/client/modules/auth/routes/download-recovery-key.tsx (1)

45-45: LGTM! Proper fire-and-forget pattern.

The void operator correctly indicates that the navigation promise is intentionally discarded. This is the standard pattern to satisfy linters while preserving the fire-and-forget behavior.

app/client/modules/backups/routes/backup-details.tsx (1)

123-123: LGTM! Correct promise handling pattern.

The void operator appropriately indicates intentional fire-and-forget navigation after successful schedule deletion.

app/client/modules/volumes/routes/create-volume.tsx (1)

36-36: LGTM! Proper fire-and-forget navigation.

The void operator correctly handles the intentionally discarded navigation promise after successful volume creation.

app/client/components/volume-file-browser.tsx (1)

49-54: LGTM! Correct fire-and-forget prefetch pattern.

The void operator appropriately indicates that the prefetch operation is intentionally fire-and-forget. Prefetching doesn't require waiting for completion, making this pattern ideal.

.github/workflows/checks.yml (1)

28-31: Configuration file is properly in place for oxlint-action migration.

The .oxlintrc.json configuration file exists and is valid JSON. The migration to oxlint-action with deny-warnings: true is properly configured for strict linting enforcement.

app/server/jobs/cleanup-sessions.ts (1)

5-9: LGTM! Proper async handling.

Adding await ensures the session cleanup completes before returning the result, which is the correct pattern for this scheduled job.

app/client/modules/auth/routes/onboarding.tsx (1)

57-60: LGTM! Correct fire-and-forget pattern.

The void operator explicitly indicates the navigation promise is intentionally discarded, satisfying the typescript/no-floating-promises lint rule while maintaining the intended behavior.

app/server/utils/rclone.ts (1)

3-3: LGTM! Improved error message formatting.

The changes consistently improve error handling:

  • Explicit .toString() conversions make type handling clear
  • toMessage() utility standardizes error formatting across the codebase

These align with the error handling patterns observed in other server modules.

Also applies to: 13-13, 40-40, 74-74

.oxlintrc.json (1)

1-150: LGTM! Comprehensive oxlint configuration.

The configuration provides a thorough set of linting rules appropriate for migrating from Biome to oxlint:

  • The typescript/no-floating-promises rule (line 84) drives the void operator usage seen throughout the PR
  • Severity set to "warn" eases migration while still surfacing issues
  • Appropriate ignore patterns for generated code (api-client)

Note: This PR intentionally supersedes the retrieved learning about using Biome for linting, as the migration to oxlint is the explicit purpose of this refactor.

Based on learnings, the previous guideline recommended Biome, but this PR deliberately replaces it with oxlint/oxformat.

components.json (1)

14-18: LGTM! Path aliases are now more explicit.

The updated aliases clearly indicate client-side code paths, improving code organization and maintainability.

package.json (2)

7-7: Update coding guidelines and learnings to reflect the Biome → oxlint migration.

The lint script change looks good and aligns with the PR objectives. However, the coding guidelines and learnings still reference Biome for formatting and linting, which conflicts with this change.

Based on coding guidelines and learnings, the documentation needs updating to replace references to Biome with oxlint/oxfmt commands.


103-105: All oxlint package versions verified and secure.

The specified versions (oxfmt@0.22.0, oxlint@1.36.0, oxlint-tsgolint@0.10.1) all exist on npm, carry no known security advisories, and are actively maintained as part of the oxc project.

app/client/modules/settings/routes/settings.tsx (1)

57-57: LGTM! Fire-and-forget navigation is appropriate here.

The void operator correctly handles the navigation Promise in the logout flow. Since we're redirecting to login, we don't need to await the result.

app/client/components/directory-browser.tsx (1)

26-26: LGTM! Fire-and-forget prefetch is appropriate.

Prefetching is naturally a fire-and-forget operation, and the void operator properly handles the Promise to satisfy linting requirements.

app/client/modules/volumes/routes/volume-details.tsx (1)

76-79: LGTM! Fire-and-forget navigation pattern.

The void operator explicitly discards the Promise returned by navigate, satisfying the new linter's requirement to handle all promises. This is a standard fire-and-forget pattern for post-mutation navigation.

app/client/components/layout.tsx (1)

32-34: LGTM! Fire-and-forget navigation pattern.

The void operator explicitly discards the Promise returned by navigate, satisfying the new linter's requirement. The logout flow correctly navigates to the login page without awaiting the navigation Promise.

app/test/setup.ts (1)

7-14: LGTM! Logger mock configuration is correct.

The void operator is applied to the mock.module() call for consistency with the linter configuration. While mock.module() is synchronous in Bun, this change is harmless and maintains consistency with the PR's broader pattern of explicitly handling all return values.

app/client/components/restore-form.tsx (2)

85-92: LGTM! Fire-and-forget prefetch pattern.

The void operator appropriately handles the Promise returned by prefetchQuery. This prefetch operation is intended to run in the background without blocking the user interaction.


101-106: LGTM! Fire-and-forget navigation pattern.

The void operator explicitly discards the Promise returned by navigate, satisfying the linter requirement. Navigation after successful restore is appropriate and doesn't need to be awaited.

app/server/modules/backups/__tests__/backups.service.test.ts (1)

104-104: LGTM! Fire-and-forget pattern for concurrency test.

The void operator is appropriate here to start the first backup without awaiting it, allowing the test to verify that a second concurrent call is correctly skipped. The test logic correctly validates the concurrency guard in executeBackup.

app/client/components/snapshots-table.tsx (4)

52-56: LGTM! Proper promise handling with void operator.

The addition of the void operator correctly indicates that the promise returned by invalidateQueries() is intentionally ignored. This is safe here since the subsequent state updates don't depend on the invalidation completing, and the query refetch will happen automatically.


64-67: LGTM! Consistent promise handling.

The void operator is correctly applied here, consistent with the pattern used in the deleteSnapshots mutation above.


72-74: LGTM! Standard fire-and-forget navigation pattern.

The void operator appropriately marks the navigation as a fire-and-forget operation, which is the standard pattern for click handlers.


1-307: Note: Coding guidelines reference outdated tooling.

The coding guidelines and learnings still reference Biome for linting and formatting, but this PR transitions the project to oxlint and oxformat. Consider updating the guidelines and learnings to reflect the new tooling.

Based on coding guidelines and learnings, which reference outdated tooling being replaced by this PR.

Copy link
Contributor

@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

🧹 Nitpick comments (1)
app/server/index.ts (1)

25-25: Excellent fix - critical race condition resolved.

The change from void startup(); to await startup(); correctly addresses the previous critical issue. The server will now complete all initialization (scheduler setup, volume mounting, job scheduling) before proceeding to create the HTTP server on line 41.

Optional: Consider adding error handling and success logging.

For improved robustness and observability, you might add:

🔎 Optional improvements
+try {
 	await startup();
+	logger.info("Server startup completed successfully");
+} catch (err) {
+	logger.error(`Server startup failed: ${err instanceof Error ? err.message : String(err)}`);
+	process.exit(1);
+}
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e5a0493 and 14106cc.

📒 Files selected for processing (2)
  • .oxfmtrc.json
  • app/server/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • .oxfmtrc.json
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx,js,jsx,json}

📄 CodeRabbit inference engine (AGENTS.md)

Use Biome for code formatting and linting with bunx biome check --write ., format only with bunx biome format --write ., or lint with bunx biome lint .

Files:

  • app/server/index.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Use tabs (not spaces) for indentation with a line width of 120 characters
Use double quotes for strings
Do not auto-organize imports - imports organization is disabled in Biome
All imports must include file extensions when targeting Node/Bun, as the project uses "type": "module"

Files:

  • app/server/index.ts
app/server/index.ts

📄 CodeRabbit inference engine (AGENTS.md)

Server entry point is app/server/index.ts and initializes the main API server on port 4096

Files:

  • app/server/index.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to **/*.{ts,tsx,js,jsx,json} : Use Biome for code formatting and linting with `bunx biome check --write .`, format only with `bunx biome format --write .`, or lint with `bunx biome lint .`
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Do not auto-organize imports - imports organization is disabled in Biome
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to app/server/index.ts : Server entry point is `app/server/index.ts` and initializes the main API server on port 4096

Applied to files:

  • app/server/index.ts
📚 Learning: 2025-12-28T17:31:39.171Z
Learnt from: CR
Repo: nicotsx/zerobyte PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T17:31:39.171Z
Learning: Applies to app/server/modules/**/*.ts : Server follows a modular service-oriented architecture with controller-service-database pattern in each module

Applied to files:

  • app/server/index.ts
🧬 Code graph analysis (1)
app/server/index.ts (1)
app/server/modules/lifecycle/startup.ts (1)
  • startup (44-87)

@nicotsx nicotsx merged commit b216219 into main Jan 5, 2026
6 checks passed
@nicotsx nicotsx deleted the refactor/oxlint-oxformat branch January 5, 2026 20:04
nicotsx added a commit that referenced this pull request Jan 6, 2026
* chore: install and configure oxlint

* chore: fix liniting issues

* chore: install and configure oxfmt

* ci: add oxlint action instead of biome

* chore: pr feedbacks

* Revert "chore: pr feedbacks"

This reverts commit 525dcd8.
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