Skip to content

PR: Migration common-v8 to biome and bun#5

Merged
miccy merged 117 commits intomainfrom
sync/bun-migration
Feb 3, 2026
Merged

PR: Migration common-v8 to biome and bun#5
miccy merged 117 commits intomainfrom
sync/bun-migration

Conversation

@miccy
Copy link
Contributor

@miccy miccy commented Feb 2, 2026

Description

This pull request adds internal documentation to support the ongoing migration to Bun and Biome, and provides knowledge resources about new Bun features and best practices for leveraging them in the codebase.

Documentation and Migration Planning:

  • Added a migration plan document outlining the steps to finalize the switch from pnpm/ESLint/Prettier to Bun/Biome, including cleanup of legacy tooling and setting main as the default branch. (.ai/tasks/active/finalize-bun-migration.md)

Bun Features and Best Practices:

  • Added a knowledge base entry summarizing key features introduced in Bun v1.3.7+ (performance optimizations, LLM-friendly build outputs, and native Markdown support), with recommendations for usage in performance-critical code and documentation tooling. (.ai/knowledge/03-bun-features.md)

Task Tracking:

  • Updated the active cherry-pick candidate list to reflect recent and historical commits, maintaining an up-to-date view of changes relevant to the migration process. (.ai/tasks/active/cherry-candidates-raw.txt)

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Refactoring

Checklist

  • Code follows project style guidelines
  • Tests pass locally (bun run check)
  • Documentation updated (if applicable)
  • No secrets or sensitive data included

Related Issues

Summary by CodeRabbit

  • New Features

    • Platform-specific runners and improved structured-concurrency for safer startup/shutdown
    • Native Markdown support in docs
    • Improved accessibility: ARIA labels added to icons and visuals
  • Bug Fixes

    • Robust global error handling and cleanup across environments
    • Addressed hook-usage and lint issues
  • Performance Improvements

    • Migration to a faster toolchain with build/install improvements; async/array performance notes
  • Dependencies

    • React and related packages upgraded

miccy added 8 commits February 2, 2026 04:07
…ws, Dockerfiles, and remove ESLint plugin and Prettier scripts.
…and component props, and temporarily disable ES2025 iterator tests and `useSyncState` export.
… and other dependencies, and switch docs script to Bun.
@miccy miccy requested a review from Copilot February 2, 2026 06:38
@miccy miccy self-assigned this Feb 2, 2026
@miccy miccy added docs Improvements or additions to documentation upstream Needs cherry-pick or merge from upstream feat New feature or request update Update libs and deps labels Feb 2, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 2, 2026

📝 Walkthrough

Walkthrough

Migrates tooling from pnpm/Prettier/ESLint to Bun/Biome, standardizes many imports to TypeScript import type, refactors structured concurrency (TaskDisposableStack → AsyncDisposableStack, runMain → createRunner) with platform-specific runners (Node, Web, React Native), and updates CI, tests, and package metadata. Adds documentation and lint logs.

Changes

Cohort / File(s) Summary
Tooling & Workflows
/.github/workflows/*, README.md, package.json, pnpm-workspace.yaml, prettier.config.mjs, scripts/*
Replace pnpm/node tooling with Bun/Biome in CI, scripts, and docs; pin some actions to commit SHAs; remove Prettier config and legacy pnpm workspace globs.
Structured Concurrency & Runners
packages/common/src/Task.ts, packages/nodejs/src/Task.ts, packages/web/src/Task.ts, packages/react-native/src/Task.ts, packages/*/test/Task.test.ts
Rename TaskDisposableStack→AsyncDisposableStack, replace runMain with createRunner factory, add Shutdown dep and platform-specific runner wrappers (Node signals, window error handlers, React Native ErrorUtils).
Relay / Runner APIs & Apps
packages/nodejs/src/local-first/Relay.ts, apps/relay/src/index.ts, apps/relay/Dockerfile, apps/relay/README.md, apps/relay/tsconfig.json
Rename createNodeJsRelay→startRelay, add createRelayDeps(), switch relay Docker build/runtime to Bun, update tsconfig paths and relay bootstrap usage.
Type-only Imports & Formatting
packages/common/src/**, apps/web/src/**, packages/*/src/**, examples/*/src/**
Mass migration of many runtime imports to import type and broad formatting/type-signature reflows across dozens/hundreds of files.
Tests & Test Setup
packages/*/vitest.config.ts, packages/common/test/_nodeSetup.ts, packages/nodejs/test/setup.ts, packages/web/vitest.config.ts
Add Node/browser test setup polyfills (Promise.try/withResolvers, WebSocket), configure Vitest browser projects (Playwright), add setupFiles and coverage config.
CI/CD Build & Release Changes
.github/workflows/release.yaml, .github/workflows/web-build.yaml, .github/workflows/ci.yaml, .github/workflows/docker.yaml, .github/workflows/socket.yaml
Switch build/publish steps to Bun, update checkout/setup actions, adjust triggers and concurrency, pin actions to commits.
Package Manifests & Exports
packages/*/package.json, apps/web/package.json, packages/nodejs/package.json, packages/react-native/package.json, packages/web/package.json
Update package exports/types to dist/src/**, bump React/types to 19.2.x, change @evolu/* deps to workspace:*, remove format scripts and add Vitest deps.
Editor & Biome Config
biome.json, .vscode/*, .npmrc, .nvmrc
Update biome rules/formatting (add MD support, spacing, new rules), adjust VS Code recommendations/formatters/tasks, remove some npm/noderc entries.
Accessibility & UI tweaks
apps/web/src/components/**/*.tsx, apps/web/src/components/icons/**
Add role/aria-label to SVG icons, remove some role="list" attributes, adjust component props/keys (e.g., Features removed id field → use name).
Console & Common Utilities
packages/common/src/Console.ts, packages/common/src/Buffer.ts, packages/common/src/*
Add default TimeDep for console formatter, re-export noble cipher utils, various type/interface formatting changes.
Documentation, Knowledge & Tasks
.ai/knowledge/*, .ai/tasks/*, CODE_REVIEW_SUMMARY.md, LICENSE, ROADMAP.md
Add knowledge docs (structured concurrency, Bun features), migration task docs, large review summary, update LICENSE and remove ROADMAP.md.
Linting Artifacts
biome_errors.txt, removed scripts/eslint-plugin-evolu.mjs, example ESLint configs`
Add Biome lint error log; delete custom eslint plugin and some example ESLint configs.
Small Behavioral Tweaks & Test Fixes
various tests and small files (e.g., NaN checks → Number.isNaN, effect cleanup returns)
Minor logic adjustments in tests and a few runtime checks (NaN handling), added explicit cleanup returns in some effects.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Poem

"I’m a rabbit with a bun for feet,
Hopping through code, both tidy and neat.
Types now whisper, runners run true,
Signals and windows say howdy-do.
Bun brings the carrots — hop, review!" 🐇✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ 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 'Migration common-v8 to biome and bun' clearly summarizes the main change: a migration from the previous toolchain (pnpm/ESLint/Prettier) to Bun and Biome.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sync/bun-migration

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

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: 12

Caution

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

⚠️ Outside diff range comments (2)
packages/common/test/Object.test.ts (1)

25-36: ⚠️ Potential issue | 🟡 Minor

Test now has duplicate arrow function cases — consider restoring traditional function expression coverage.

Lines 27 and 29 both test () => {} (arrow functions). Based on the isFunction implementation that checks typeof value === "function", both arrow functions and traditional function expressions should return true. The change appears to have inadvertently removed coverage for traditional function expressions.

Suggested fix to restore traditional function coverage
 test("isFunction", () => {
   // eslint-disable-next-line `@typescript-eslint/no-empty-function`
   expect(isFunction(() => {})).toBe(true);
   // eslint-disable-next-line `@typescript-eslint/no-empty-function`
-  expect(isFunction(() => {})).toBe(true);
+  expect(isFunction(function () {})).toBe(true);
   expect(isFunction({})).toBe(false);
   expect(isFunction([])).toBe(false);
   expect(isFunction("fn")).toBe(false);
   expect(isFunction(123)).toBe(false);
   expect(isFunction(null)).toBe(false);
   expect(isFunction(undefined)).toBe(false);
 });
apps/relay/Dockerfile (1)

18-73: ⚠️ Potential issue | 🟠 Major

Remove development notes/planning comments before merge.

This block contains ~55 lines of "thinking out loud" comments (e.g., "Wait, we want bun", "Let's see what pnpm deploy does", "For now, let's assume"). These are planning artifacts that should be removed from production Dockerfiles. Keep only concise, actionable comments that explain the why for future maintainers.

Suggested cleanup
-# Install pnpm and turbo (Wait, we want bun)
-# RUN corepack enable pnpm # Removed
 RUN bun install -g turbo

 # Install dependencies from pruned lockfile
 COPY --from=builder /app/out/json/ .
 RUN bun install --frozen-lockfile

 # Copy source and build
 COPY --from=builder /app/out/full/ .
 # Ensure README.md is available at the root for the build process
 COPY --from=builder /app/README.md ./README.md
 RUN turbo run build

-# Create a minimal production deploy for the relay package
-# Use legacy mode since inject-workspace-packages is not set
-# pnpm deploy is specific to pnpm. Does bun support something similar?
-# Bun doesn't have direct equivalent to `pnpm deploy`.
-# However, we can just copy the built artifacts.
-# Or use `bun build` to bundle.
-# But since this is a monorepo, maybe we should just rely on the build output.
-# Let's see what `pnpm deploy` does: it isolates the package and its deps.
-# For now, let's assume we can just copy the `apps/relay/dist` and `node_modules` if needed.
-# Converting a pnpm monorepo dockerfile to bun can be tricky regarding "pruning" and "deploying".
-# Since `turbo prune` works with json, `bun install` should work with that json.
-# The "deploy" step might be the issue.
-# Alternative: Just run `bun install --production` in the apps/relay folder after build?
-# Let's try to keep it simple.
-
-# REVISED STRATEGY for Deploy step:
-# Since we don't have pnpm deploy, we can manually assemble the production folder.
-# But wait, `turbo prune` creates `out/json` and `out/full`.
-# We installed deps in `installer`.
-# We ran build.
-# Now we want a minimal runner image.
-# We can just copy `node_modules` and `apps/relay/dist`.
-# But `node_modules` at root contains all deps.
-# We might need to prune devDependencies.
-# `bun install --production`?
-# 
-# Let's look at `apps/relay/package.json` to see if it has many deps.
-# It likely has `better-sqlite3`, `ws`, etc.
-# 
-# Usage of `pnpm deploy` is quite specific.
-# If I remove it, I need to ensure `node_modules` are correct.
-# 
-# Maybe I should leave Dockerfile alone for now if I'm not 100% sure about breaking it?
-# The user asked to "fix or disable workflows".
-# If I change the Dockerfile, I must ensure it works.
-# 
-# Let's stick to using `oven/bun` and see if we can replicate the logic.
-# 
-# Actually, `bun` doesn't strictly need `pnpm deploy`.
-# 
-# Let's try to just copy the `dist` and `node_modules` from installer.

+# Assemble production artifacts (replaces pnpm deploy)
 RUN mkdir -p /app/deploy && cp -r apps/relay/dist /app/deploy/dist && cp -r node_modules /app/deploy/node_modules && cp apps/relay/package.json /app/deploy/package.json
🤖 Fix all issues with AI agents
In @.ai/knowledge/03-bun-features.md:
- Line 1: The file contains literal "\n" sequences instead of actual newlines
and a lowercase "markdown" usage; replace the escaped newline characters with
real line breaks so the content is formatted as proper Markdown and change
occurrences of "markdown" (e.g., in the sentence about external markdown parsers
and any references to Bun.markdown) to "Markdown" to correct capitalization;
ensure list items (Performance Optimization, LLM-Friendly Builds, Markdown
Support) are each on their own line and code tokens like Bun.markdown and the
suggested "analyze" script remain unchanged aside from the
newline/capitalization fixes.

In @.ai/tasks/active/finalize-bun-migration.md:
- Around line 13-23: Update the checklist under "Cleanup Legacy Tooling" and
"Verification" to use 2-space indentation for nested list items (to satisfy
markdownlint MD007) and hyphenate compound modifiers such as "pnpm-related",
"eslint-related", and "prettier-related" in the item text; specifically edit the
checklist lines referencing pnpm, eslint, prettier, package.json, and the "lint"
command so nested bullets are indented with two spaces and phrases like "pnpm
related files" become "pnpm-related files", "eslint related files" become
"eslint-related files", and "prettier related files" become "prettier-related
files".

In @.vscode/settings.json:
- Around line 5-7: The change removed import organization on save by keeping
"source.fixAll.biome" under "editor.codeActionsOnSave" but omitting
"source.organizeImports.biome"; if you intended to preserve automatic import
organizing, re-add the "source.organizeImports.biome" entry alongside
"source.fixAll.biome" in the "editor.codeActionsOnSave" object (ensure both keys
exist with the desired values), otherwise confirm the omission is intentional so
imports will no longer be organized on save.

In @.vscode/tasks.json:
- Around line 18-23: The "Lint" VS Code task still uses the ESLint problem
matcher "$eslint-stylish" which doesn't parse Biome output; update the task that
has "label": "Lint" and "command": "bun run lint" to either remove the
problemMatcher entirely and rely on the Biome VS Code extension for diagnostics,
or switch to a custom problemMatcher that parses Biome's single-line reporter by
changing the lint invocation to include "--reporter=github" and adding a
regex-based problemMatcher compatible with GitHub/one-line annotations instead
of "$eslint-stylish".

In `@apps/relay/Dockerfile`:
- Line 74: The Dockerfile currently copies the entire root node_modules (the RUN
mkdir... && cp -r node_modules /app/deploy/node_modules step), which brings
devDependencies into the image; remove the step that copies node_modules and
instead, after copying apps/relay/dist and apps/relay/package.json into
/app/deploy, run bun install --production in /app/deploy to install only
production deps (i.e., replace the cp of node_modules with a command that cd's
into /app/deploy and runs bun install --production so the final image contains
only runtime dependencies).

In `@apps/web/src/components/Search.tsx`:
- Around line 305-310: Remove the unused _pathname and _searchParams variables:
delete the const _pathname = usePathname() and const _searchParams =
useSearchParams() declarations (they were only prefixed to silence the linter).
Ensure the useEffect that calls setOpen(false) remains as-is (dependency
[setOpen]) and, after removing those calls, also remove unused imports of
usePathname and useSearchParams from the top of the file if they are no longer
referenced elsewhere in the component.

In `@biome.json`:
- Around line 41-49: Re-enable the turned-off accessibility and security rules
or add a documented exception: set "useButtonType", "noLabelWithoutControl",
"noSvgWithoutTitle", and "noStaticElementInteractions" back to "warn" or
"error", and set "noDangerouslySetInnerHtml" to "warn" or "error";
alternatively, if there's a valid project-wide rationale, add a clear comment or
companion doc explaining the exception (why it's safe, scope, and any
compensating controls) and reference these rule names ("useButtonType",
"noLabelWithoutControl", "noSvgWithoutTitle", "noStaticElementInteractions",
"noDangerouslySetInnerHtml") where the exception applies.

In `@examples/react-electron/electron/main.ts`:
- Around line 18-19: The comment warns to use bracket notation to avoid Vite's
define plugin but the code uses dot notation (process.env.VITE_DEV_SERVER_URL),
so either revert the access to bracket notation
(process.env['VITE_DEV_SERVER_URL']) to preserve the Vite@2.x workaround for the
VITE_DEV_SERVER_URL export, or if you've verified the workaround is no longer
needed, remove or update the warning comment above the VITE_DEV_SERVER_URL
export to avoid this contradiction; update the file so the comment and the
export of VITE_DEV_SERVER_URL are consistent.

In `@examples/react-expo/app/index.tsx`:
- Around line 385-388: The memo for otherOwnerIds references ownerIds but only
lists appOwner?.id in the dependency array, causing stale results when ownerIds
changes; update the useMemo dependencies to include ownerIds (and keep
appOwner?.id) so otherOwnerIds recalculates whenever ownerIds or appOwner?.id
change—locate the useMemo that defines otherOwnerIds and add ownerIds to its
dependency list.

In `@packages/common/src/Types.ts`:
- Line 37: The new type alias CallbackWithCleanup<T> changed the return from
void to undefined which is a breaking public-API change; either revert the
signature back to "void" to preserve backward compatibility, or keep "undefined"
but update release metadata and docs: bump the package major version, add a
clear changelog entry and update API docs/README noting the stricter return
semantics for CallbackWithCleanup<T> so consumers are informed of the breaking
change.

In `@packages/react/src/index.ts`:
- Around line 6-8: Remove the risk of the TODO being forgotten by opening a
tracking issue for re-enabling the useSyncState export linked to the owner-api
refactor, then update the TODO comment in the index module (the export for
useSyncState / "./useSyncState.js" and the public symbol useSyncState) to
include the issue number/URL and the expected criteria for re-enabling; also add
a short breaking-change note to the package changelog or release notes
indicating that useSyncState has been removed from the public API until that
issue is resolved.

In `@packages/svelte/svelte-types.d.ts`:
- Line 2: The declaration for $effect narrows the callback return to `undefined
| (() => void)` which is incompatible with official Svelte typings; update the
function signature for $effect (the declare function $effect(...) line) so the
callback return type is `void | (() => void)` instead of `undefined | (() =>
void)`, ensuring callbacks returning `void` are accepted and restoring
compatibility with idiomatic Svelte code.
🧹 Nitpick comments (15)
packages/react-native/src/exports/bare-op-sqlite.ts (1)

23-30: Consider removing stale ESLint directives.

Since this PR is migrating from ESLint to Biome, these eslint-disable-next-line comments on lines 23 and 29 will become stale. Consider removing them as part of the migration cleanup, or tracking this for a follow-up pass.

🧹 Proposed cleanup
-// eslint-disable-next-line evolu/require-pure-annotation
 export const evoluReactNativeDeps = createSharedEvoluDeps({
   createSqliteDriver: createOpSqliteDriver,
   reloadApp,
 });

-// eslint-disable-next-line evolu/require-pure-annotation
 export const localAuth = createSharedLocalAuth(SensitiveInfo);
packages/common/test/Function.test.ts (1)

166-178: Prefer describe.skip/test.skip over commented blocks.
This keeps the skipped test visible in Vitest output and makes re-enabling easier.

♻️ Suggested tweak
-  // TODO: Re-enable when TypeScript fully supports ES2025 Iterator Helpers
-  // describe("with ES2025 iterator .toArray()", () => {
-  //   test("converts iterator chain to ReadonlyArray", () => {
-  //     const result = readonly(
-  //       [1, 2, 3]
-  //         .values()
-  //         .map((x) => x * 2)
-  //         .toArray() as Array<number>,
-  //     );
-  //     expect(result).toEqual([2, 4, 6]);
-  //     expectTypeOf(result).toEqualTypeOf<ReadonlyArray<number>>();
-  //   });
-  // });
+  // TODO: Re-enable when TypeScript fully supports ES2025 Iterator Helpers
+  describe.skip("with ES2025 iterator .toArray()", () => {
+    test("converts iterator chain to ReadonlyArray", () => {
+      const result = readonly(
+        [1, 2, 3]
+          .values()
+          .map((x) => x * 2)
+          .toArray() as Array<number>,
+      );
+      expect(result).toEqual([2, 4, 6]);
+      expectTypeOf(result).toEqualTypeOf<ReadonlyArray<number>>();
+    });
+  });
examples/react-electron/electron/preload.ts (1)

24-24: Minor typo: "APTs" should be "APIs".

The comment reads "You can expose other APTs you need here" but likely meant "APIs". This is a pre-existing typo (not introduced in this PR) but would be worth correcting for clarity.

📝 Proposed fix
-  // You can expose other APTs you need here.
+  // You can expose other APIs you need here.
packages/svelte/src/lib/index.svelte.ts (1)

18-19: Consider removing stale ESLint directive after Biome migration.

The eslint-disable comment may be obsolete now that the project has migrated to Biome. If Biome doesn't enforce an equivalent rule, this comment can be cleaned up.

🧹 Optional cleanup
 // just in case we need to add some svelte specific deps
-// eslint-disable-next-line evolu/require-pure-annotation
 export const evoluSvelteDeps = createEvoluDeps();

Alternatively, if Biome has an equivalent rule that needs suppression, update to Biome's directive format.

examples/react-vite-pwa/src/components/EvoluMinimalExample.tsx (1)

58-59: Consider updating ESLint directive to Biome syntax.

Since the project is migrating to Biome, this ESLint directive will become ineffective. Biome uses a different syntax for suppression comments.

♻️ Suggested fix for Biome compatibility
-  // eslint-disable-next-line no-console
+  // biome-ignore lint/suspicious/noConsole: Log unexpected Evolu errors for debugging
   console.error(error);
apps/web/src/components/Features.tsx (2)

324-328: Consider adding bounds checking for pattern access.

patterns[index] assumes that features and patterns arrays have the same length. Currently both have 16 elements, but if someone adds more features without corresponding patterns, this will pass undefined to FeaturePattern.

🛡️ Defensive fix using modulo
       <FeaturePattern
-        pattern={patterns[index]}
+        pattern={patterns[index % patterns.length]}
         mouseX={mouseX}
         mouseY={mouseY}
       />

319-320: Redundant key prop inside component.

The key={feature.id} on line 320 has no effect since the key is already provided at the mapping level (line 352). React uses keys at the iterator level, not inside the rendered component.

🧹 Remove redundant key
     <div
-      key={feature.id}
       onMouseMove={onMouseMove}
       className="group relative flex rounded-2xl bg-zinc-50 transition-shadow hover:shadow-md hover:shadow-zinc-900/5 dark:bg-white/2.5 dark:hover:shadow-black/5"
     >
apps/web/src/components/PlatformSelector.tsx (2)

69-85: Potential unnecessary navigation on mount.

When there's no URL param but a valid store preference exists, this effect triggers router.replace on every mount to sync the URL. This is fine for the first visit, but consider:

  1. The searchParams object reference changes on each render in Next.js, which could cause this effect to re-run more than intended. Since you're only reading from it (via validUrlPlatform derived earlier), you could potentially remove searchParams from the dependency array—though the linter may complain.

  2. The initial URL update on mount may cause a brief flash or re-render. If that's acceptable UX, this is fine.


143-152: Hidden radio inputs lack focus indicator.

The radio inputs have className="hidden", which removes them from the accessibility tree's focus management. While the <label> has has-focus-visible styles, keyboard users may have difficulty understanding which option is focused since the actual radio is hidden.

Consider using sr-only positioning instead of hidden to keep the input in the tab order while visually hiding it, or ensure the label's focus styles are sufficiently prominent.

apps/web/src/components/Header.tsx (1)

171-180: Verbose type annotation pattern.

The explicit ForwardRefExoticComponent type annotation with /*#__PURE__*/ is valid and provides tree-shaking hints, but it's quite verbose. This duplicates the prop types (once in the outer type, once in the forwardRef generic).

If this pattern is intentional for bundler optimization or consistency with other components, it's fine. Otherwise, the simpler inline forwardRef<...>(...) without the explicit outer type would be more maintainable.

.github/workflows/web-build.yaml (1)

29-40: Consider pinning Bun version and verifying NODE_OPTIONS relevance.

Two observations:

  1. bun-version: latest — Using latest in CI can cause unexpected build failures when a new Bun version is released. Consider pinning to a specific version (e.g., 1.2.x or 1.1.45) for reproducible builds.

  2. NODE_OPTIONS: "--max_old_space_size=8192" — This is a Node.js-specific environment variable. Bun uses a different memory model (JavaScriptCore, not V8). Verify whether this setting has any effect on Bun, or if it should be removed/replaced with Bun-equivalent configuration.

Suggested fix to pin Bun version
       - name: Setup Bun
         uses: oven-sh/setup-bun@v2
         with:
-          bun-version: latest
+          bun-version: "1.2"
package.json (1)

22-22: Consider cross-platform compatibility for the clean script.

The change from rimraf to rm -rf may cause issues on Windows systems that don't have POSIX commands available natively. While Bun provides some cross-platform abstractions, rm -rf is not guaranteed to work on all Windows environments.

💡 Alternative using rimraf (already in devDependencies)
-    "clean": "turbo clean && rm -rf node_modules bun.lock .turbo out",
+    "clean": "turbo clean && rimraf node_modules bun.lock .turbo out",
apps/web/src/components/ArticleLayout.tsx (1)

23-24: Minor: Inconsistent ReactNode reference.

The component uses React.ReactNode for the children prop type (line 23) but uses the directly imported ReactNode for the return type (line 24). Consider using the imported ReactNode consistently for both.

💅 Proposed consistency fix
 export const ArticleLayout = ({
   article,
   children,
 }: {
   article: ArticleWithSlug;
-  children: React.ReactNode;
+  children: ReactNode;
 }): ReactNode => (
.github/workflows/release.yaml (1)

22-24: Consider pinning Bun version for reproducible releases.

Using bun-version: latest may cause non-reproducible builds if Bun releases introduce breaking changes. For release workflows, pinning to a specific version (e.g., bun-version: "1.2.0") provides more predictable behavior.

💡 Proposed fix to pin Bun version
       - uses: oven-sh/setup-bun@v2
         with:
-          bun-version: latest
+          bun-version: "1.2.0"
packages/common/src/Task.ts (1)

2971-2983: Consider keeping implementation signatures closer to overloads to retain internal type safety.
If the Task<any, any, any> implementation types are intentional, feel free to ignore; otherwise tightening them preserves compiler checks in internal usage.

Also applies to: 3079-3088, 3305-3361

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

steida and others added 3 commits February 2, 2026 12:16
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: Miccy <code@miccy.dev>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: Miccy <code@miccy.dev>
@miccy miccy requested a review from Copilot February 2, 2026 20:10
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 168 out of 179 changed files in this pull request and generated 6 comments.

steida and others added 6 commits February 2, 2026 23:21
Replace the old runMain pattern with a shutdown-aware createRunner that injects a shutdown promise into deps and installs global signal and error handlers (SIGINT, SIGTERM, SIGHUP, uncaughtException, unhandledRejection). Move Node.js runner wiring into packages/nodejs/src/Task.ts, resolve shutdown via process signals, and ensure listeners are cleaned up on runner dispose. Rename relay APIs: createNodeJsRelayBetterSqliteDeps -> createRelayDeps and createNodeJsRelay -> startRelay, update examples and the apps/relay entry to use startRelay and createRunner. Simplify task typing in packages/common (introduce AnyTask and use it in InferTask* helpers, add CreateRunner type, remove MainTask), and adjust the local-first Relay implementation to handle sqlite errors by logging and returning ok(stack). Update tests to reflect the new createRunner/shutdown behavior and to verify signal/error handling and listener cleanup. README updated to reflect the API rename.
Introduce a browser-specific Task runner and tests. Implements createRunner in packages/web/src/Task.ts that composes the common runner, creates a console child named "global", registers global "error" and "unhandledrejection" handlers (logging via createUnknownError), and removes those listeners when the runner is disposed. Adds vitest tests in packages/web/test/Task.test.ts to verify custom deps merging, mocked listener registration/removal, real-event logging for ErrorEvent and PromiseRejectionEvent, and that handlers are detached after disposal.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Miccy <code@miccy.dev>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Miccy <code@miccy.dev>
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

🤖 Fix all issues with AI agents
In `@packages/common/test/Time.test.ts`:
- Around line 16-22: The test captures `after` before calling `time.now()`,
allowing `timeNow` to sometimes exceed `after + 10`; update the ordering so you
call `time.now()` first and assign it to `timeNow`, then capture `after`,
preserving the invariant that `timeNow` lies between `before` and `after`
(variables: before, time, timeNow, after) when using `createTime()` /
`time.now()`.

Comment on lines +16 to +22
const before = Date.now();
const time = createTime();
const now = Date.now();
// Allow small difference due to execution time
expect(time.now()).toBeGreaterThanOrEqual(now - 10);
expect(time.now()).toBeLessThanOrEqual(now + 10);
const after = Date.now();
const timeNow = time.now();
// time.now() should be between before and after with small tolerance
expect(timeNow).toBeGreaterThanOrEqual(before - 10);
expect(timeNow).toBeLessThanOrEqual(after + 10);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix timestamp ordering to avoid a flaky window check.

after is captured before timeNow, so timeNow can exceed after + 10 under load. Capture timeNow first, then after, to preserve the “between before and after” invariant.

🔧 Proposed fix
-      const after = Date.now();
-      const timeNow = time.now();
+      const timeNow = time.now();
+      const after = Date.now();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const before = Date.now();
const time = createTime();
const now = Date.now();
// Allow small difference due to execution time
expect(time.now()).toBeGreaterThanOrEqual(now - 10);
expect(time.now()).toBeLessThanOrEqual(now + 10);
const after = Date.now();
const timeNow = time.now();
// time.now() should be between before and after with small tolerance
expect(timeNow).toBeGreaterThanOrEqual(before - 10);
expect(timeNow).toBeLessThanOrEqual(after + 10);
const before = Date.now();
const time = createTime();
const timeNow = time.now();
const after = Date.now();
// time.now() should be between before and after with small tolerance
expect(timeNow).toBeGreaterThanOrEqual(before - 10);
expect(timeNow).toBeLessThanOrEqual(after + 10);
🤖 Prompt for AI Agents
In `@packages/common/test/Time.test.ts` around lines 16 - 22, The test captures
`after` before calling `time.now()`, allowing `timeNow` to sometimes exceed
`after + 10`; update the ordering so you call `time.now()` first and assign it
to `timeNow`, then capture `after`, preserving the invariant that `timeNow` lies
between `before` and `after` (variables: before, time, timeNow, after) when
using `createTime()` / `time.now()`.

@miccy
Copy link
Contributor Author

miccy commented Feb 3, 2026

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/common/test/Time.test.ts`:
- Around line 16-22: The test captures `after` before calling `time.now()`,
allowing `timeNow` to sometimes exceed `after + 10`; update the ordering so you
call `time.now()` first and assign it to `timeNow`, then capture `after`,
preserving the invariant that `timeNow` lies between `before` and `after`
(variables: before, time, timeNow, after) when using `createTime()` /
`time.now()`.

@copilot Zkontroluj to a pokud je to validní, udělej fix

Copy link

Copilot AI commented Feb 3, 2026

@miccy I've opened a new pull request, #19, to work on those changes. Once the pull request is ready, I'll request review from you.

…k<unknown, unknown> for better type safety

Co-authored-by: miccy <9729864+miccy@users.noreply.github.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 219 out of 231 changed files in this pull request and generated 9 comments.

Comments suppressed due to low confidence (1)

.ai/knowledge/03-bun-features.md:2

  • This markdown file appears to contain literal \n escape sequences and is effectively a single long line. Convert it to real newlines so it renders correctly and is maintainable in diffs/reviews.
# Bun v1.3.7+ Features\n\n## Performance Optimization\n\n- Bun v1.3.7 introduces significant performance improvements in `async/await`, `Array.from`, and `array.flat`.\n- Leverage these improvements in performance-critical code paths, especially in `packages/common` and loop-heavy logic.\n\n## LLM-Friendly Builds\n\n- Use `bun build --metafile-md` to generate Markdown-formatted build metafiles.\n- This is useful for analyzing bundle size and dependencies with AI tools.\n- Consider adding a script: `"analyze": "bun build --metafile-md out/meta.md ..."`.\n\n## Markdown Support\n\n- Bun v1.3.8 adds a native Markdown parser: `Bun.markdown`.\n- This can replace external markdown parsers for simple use cases or documentation generation scripts.\n- Check if `typedoc-plugin-markdown` or other scripts can utilize this native feature.\n

Comment on lines 10 to 17
export const useOwner = (owner: SyncOwner | null): void => {
if (owner == null) return;

// biome-ignore lint/correctness/useHookAtTopLevel: intentional
const evolu = useEvolu();

// biome-ignore lint/correctness/useHookAtTopLevel: intentional
evolu.useOwner(owner);
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

Early-returning before calling useEvolu() triggers Biome’s useHookAtTopLevel error and (more importantly) makes hook call order depend on owner. Call useEvolu() unconditionally at the top of the composable, then no-op if owner is null.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +11
// Polyfills for Node.js test environment
// The @evolu/common package uses ES2024+ features

// Polyfill Promise.try for Node.js/Bun versions that don't support it (ES2024)
// The @evolu/common package uses Promise.try in Task.ts
if (!(Promise as any).try) {
(Promise as any).try = <T, Args extends readonly unknown[]>(
callback: (...args: Args) => T | PromiseLike<T>,
...args: Args
): Promise<T> => new Promise((resolve) => resolve(callback(...args)));
}
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

This test setup polyfills Promise.try, but the package code (packages/nodejs/src/Task.ts) uses Promise.withResolvers. If tests run in an environment that lacks Promise.withResolvers (e.g., some Bun/Node versions), they will fail before any assertions. Consider adding a Promise.withResolvers polyfill here (or reusing the shared polyfill setup from packages/common/test/_nodeSetup.ts).

Copilot uses AI. Check for mistakes.
Comment on lines 3 to +13
on:
pull_request:
branches: ["*"]
paths:
- "apps/web/**"
push:
branches: ["main"]
paths:
- "apps/web/**"
merge_group:
workflow_dispatch:
# pull_request:
# branches: ["*"]
# paths:
# - "apps/web/**"
# push:
# branches: ["main"]
# paths:
# - "apps/web/**"
# merge_group:
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

This workflow no longer runs on PRs/pushes (only workflow_dispatch). That removes automated web build coverage for normal development and can let breakages merge unnoticed. If this is intentional for the fork, it should be explicitly documented; otherwise, restore the PR/push triggers.

Copilot uses AI. Check for mistakes.
Comment on lines 3 to +7
on:
push:
branches:
- main
workflow_dispatch: # for manual triggering
workflow_dispatch:
# push:
# branches:
# - main
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

The release workflow’s push trigger on main is commented out, so releases won’t run automatically anymore. If releases are still expected from main, re-enable the trigger; if not, document the new release process to avoid operational surprises.

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +27
"lint-monorepo": "bunx sherif@latest",
"format": "biome format --write .",
"verify": "bun run format && bun run build && bun run test && bun run test:coverage && bun run lint && bun run lint-monorepo",
"clean": "turbo clean && rimraf node_modules bun.lock .turbo out",
"version": "changeset version",
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

PR description emphasizes documentation/migration planning, but this change set also alters core runtime APIs (e.g., new platform-specific createRunner, relay startup behavior) and CI/workflow triggers. Please update the PR description (or split the PR) so reviewers and downstream consumers can assess the breaking/operational impact accurately.

Copilot uses AI. Check for mistakes.
fix: Replace `any` with `unknown` in pool function return type
@miccy
Copy link
Contributor Author

miccy commented Feb 3, 2026

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link

Copilot AI commented Feb 3, 2026

@miccy I've opened a new pull request, #20, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 2 commits February 3, 2026 18:26
@miccy
Copy link
Contributor Author

miccy commented Feb 3, 2026

@copilot opět je rozbitá CI. Fixni to

Copilot AI mentioned this pull request Feb 3, 2026
8 tasks
Copy link

Copilot AI commented Feb 3, 2026

@miccy I've opened a new pull request, #21, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 4 commits February 3, 2026 19:03
Co-authored-by: miccy <9729864+miccy@users.noreply.github.com>
Co-authored-by: miccy <9729864+miccy@users.noreply.github.com>
Co-authored-by: miccy <9729864+miccy@users.noreply.github.com>
Fix Biome lint errors in web Task tests
@miccy miccy merged commit 25013bf into main Feb 3, 2026
5 checks passed
@miccy miccy deleted the sync/bun-migration branch February 10, 2026 01:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Improvements or additions to documentation feat New feature or request update Update libs and deps upstream Needs cherry-pick or merge from upstream

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Phase 2: Refactor arrayFrom (Breaking Change) Phase 1: Cherry-pick common-v8 & Fix Build Errors

4 participants