Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
7fa2b32
fix(deps): upgrade vitest 2.1.9 → 4.0.18, fix breaking changes
flyingrobots Mar 4, 2026
63dd929
docs(changelog): add vitest 4 upgrade to [Unreleased]
flyingrobots Mar 4, 2026
cbd1b01
fix(test): externalize roaring in vitest config for Bun compatibility
flyingrobots Mar 4, 2026
d43472c
fix(test): move roaring externalization to test.server.deps.external
flyingrobots Mar 4, 2026
aee350d
fix(test): add ssr.external for roaring native module under Bun
flyingrobots Mar 4, 2026
4393a6c
fix(test): use createRequire fallback for roaring native module under…
flyingrobots Mar 4, 2026
6c70e0d
fix(docker): build roaring native module in Bun container
flyingrobots Mar 4, 2026
3c525b7
fix(docker): use multi-stage build for roaring native module
flyingrobots Mar 4, 2026
15bbcd8
fix(docker): exclude bitmap tests from Bun suite (V8 API incompatibil…
flyingrobots Mar 4, 2026
4b425ba
fix: preserve both load failures in roaring fallback (CodeRabbit)
flyingrobots Mar 4, 2026
0a1139c
feat: add roaring-wasm WASM fallback for Bun/Deno bitmap indexes
flyingrobots Mar 4, 2026
60039ba
docs: add roaring-wasm to dependency tables and What's New
flyingrobots Mar 4, 2026
5bdfe64
fix: use RoaringModule type for adaptWasmApi param (tsc strict)
flyingrobots Mar 4, 2026
a0fd67f
feat: add levels, transitiveReduction, transitiveClosure, rootAncesto…
flyingrobots Mar 4, 2026
8d394dd
docs(roadmap): add B149-B151 large-graph streaming backlog items
flyingrobots Mar 4, 2026
cf3cba8
docs(roadmap): add B152-B156 streaming API, layout, and structural di…
flyingrobots Mar 4, 2026
7f49780
docs(roadmap): priority triage — 45 items into P0–P6 tiers with wave …
flyingrobots Mar 4, 2026
88e7b03
fix(roaring): reset nativeAvailability cache on reinit, preserve per-…
flyingrobots Mar 4, 2026
8d5f910
docs(readme): fix What's New heading to reflect unreleased status
flyingrobots Mar 4, 2026
7b77bc1
docs(changelog): add roaring cache reset and AggregateError fix entries
flyingrobots Mar 4, 2026
21dae78
fix(types): add JSDoc type annotations to roaring test module variable
flyingrobots Mar 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
657 changes: 339 additions & 318 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@
"prettier": "^3.4.2",
"typescript": "^5.9.3",
"typescript-eslint": "^8.54.0",
"vitest": "^2.1.8"
"vitest": "^4.0.18"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
},
"keywords": [
"git",
Expand Down
14 changes: 8 additions & 6 deletions test/unit/cli/doctor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ vi.mock('../../../bin/cli/shared.js', () => ({

// Mock HealthCheckService
vi.mock('../../../src/domain/services/HealthCheckService.js', () => ({
default: vi.fn().mockImplementation(() => ({
getHealth: vi.fn().mockResolvedValue({
status: 'healthy',
components: { repository: { status: 'healthy', latencyMs: 1 } },
}),
})),
default: vi.fn().mockImplementation(function () {
return {
getHealth: vi.fn().mockResolvedValue({
status: 'healthy',
components: { repository: { status: 'healthy', latencyMs: 1 } },
}),
};
}),
}));

// Mock ClockAdapter
Expand Down
18 changes: 9 additions & 9 deletions test/unit/domain/WarpGraph.cascadeDelete.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest';
import WarpGraph from '../../../src/domain/WarpGraph.js';
import { createGitRepo } from '../../helpers/warpGraphTestUtils.js';

describe('Cascade delete mode (HS/DELGUARD/3)', () => {
describe('Cascade delete mode (HS/DELGUARD/3)', { timeout: 15000 }, () => {
it('cascade delete generates EdgeRemove ops for 3 connected edges + NodeRemove', async () => {
const repo = await createGitRepo('cascade');
try {
Expand Down Expand Up @@ -49,7 +49,7 @@ describe('Cascade delete mode (HS/DELGUARD/3)', () => {
} finally {
await repo.cleanup();
}
}, { timeout: 15000 });
});

it('materialized state has no dangling edges after cascade delete', async () => {
const repo = await createGitRepo('cascade');
Expand Down Expand Up @@ -90,7 +90,7 @@ describe('Cascade delete mode (HS/DELGUARD/3)', () => {
} finally {
await repo.cleanup();
}
}, { timeout: 15000 });
});

it('cascade delete on node with no edges produces only NodeRemove', async () => {
const repo = await createGitRepo('cascade');
Expand Down Expand Up @@ -121,7 +121,7 @@ describe('Cascade delete mode (HS/DELGUARD/3)', () => {
} finally {
await repo.cleanup();
}
}, { timeout: 15000 });
});

it('cascade delete handles both incoming and outgoing edges', async () => {
const repo = await createGitRepo('cascade');
Expand Down Expand Up @@ -174,7 +174,7 @@ describe('Cascade delete mode (HS/DELGUARD/3)', () => {
} finally {
await repo.cleanup();
}
}, { timeout: 15000 });
});

it('cascade delete handles self-loop edge correctly', async () => {
const repo = await createGitRepo('cascade');
Expand Down Expand Up @@ -220,7 +220,7 @@ describe('Cascade delete mode (HS/DELGUARD/3)', () => {
} finally {
await repo.cleanup();
}
}, { timeout: 15000 });
});

it('generated EdgeRemove ops appear in committed patch (auditable)', async () => {
const repo = await createGitRepo('cascade');
Expand Down Expand Up @@ -264,7 +264,7 @@ describe('Cascade delete mode (HS/DELGUARD/3)', () => {
} finally {
await repo.cleanup();
}
}, { timeout: 15000 });
});

it('cascade mode preserves unrelated edges', async () => {
const repo = await createGitRepo('cascade');
Expand Down Expand Up @@ -306,7 +306,7 @@ describe('Cascade delete mode (HS/DELGUARD/3)', () => {
} finally {
await repo.cleanup();
}
}, { timeout: 15000 });
});

it('without cascade mode, removeNode does not generate EdgeRemove ops', async () => {
const repo = await createGitRepo('cascade');
Expand Down Expand Up @@ -338,5 +338,5 @@ describe('Cascade delete mode (HS/DELGUARD/3)', () => {
} finally {
await repo.cleanup();
}
}, { timeout: 15000 });
});
});
28 changes: 14 additions & 14 deletions test/unit/domain/WarpGraph.deleteGuardEnforce.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { describe, it, expect, vi, afterEach } from 'vitest';
import WarpGraph from '../../../src/domain/WarpGraph.js';
import { createGitRepo } from '../../helpers/warpGraphTestUtils.js';

describe('WarpGraph deleteGuard enforcement (HS/DELGUARD/2)', () => {
describe('WarpGraph deleteGuard enforcement (HS/DELGUARD/2)', { timeout: 15000 }, () => {
/** @type {any} */
let repo;

Expand Down Expand Up @@ -40,7 +40,7 @@ describe('WarpGraph deleteGuard enforcement (HS/DELGUARD/2)', () => {
expect(() => patch.removeNode('n1')).toThrow(
/Cannot delete node 'n1': node has attached data.*propert/
);
}, { timeout: 15000 });
});

it('throws when deleting a node that has edges', async () => {
repo = await createGitRepo('delguard');
Expand All @@ -65,7 +65,7 @@ describe('WarpGraph deleteGuard enforcement (HS/DELGUARD/2)', () => {
expect(() => patch.removeNode('n1')).toThrow(
/Cannot delete node 'n1': node has attached data.*edge/
);
}, { timeout: 15000 });
});

it('throws when deleting a node that is an edge target', async () => {
repo = await createGitRepo('delguard');
Expand All @@ -90,7 +90,7 @@ describe('WarpGraph deleteGuard enforcement (HS/DELGUARD/2)', () => {
expect(() => patch.removeNode('n2')).toThrow(
/Cannot delete node 'n2': node has attached data.*edge/
);
}, { timeout: 15000 });
});

it('succeeds when deleting a node with no attached data', async () => {
repo = await createGitRepo('delguard');
Expand All @@ -115,7 +115,7 @@ describe('WarpGraph deleteGuard enforcement (HS/DELGUARD/2)', () => {

expect(typeof sha).toBe('string');
expect(sha.length).toBe(40);
}, { timeout: 15000 });
});

it('mentions both edges and properties in error when both exist', async () => {
repo = await createGitRepo('delguard');
Expand All @@ -140,7 +140,7 @@ describe('WarpGraph deleteGuard enforcement (HS/DELGUARD/2)', () => {
expect(() => patch.removeNode('n1')).toThrow(
/1 edge\(s\) and 1 propert/
);
}, { timeout: 15000 });
});

it('error message suggests cascade mode', async () => {
repo = await createGitRepo('delguard');
Expand All @@ -162,7 +162,7 @@ describe('WarpGraph deleteGuard enforcement (HS/DELGUARD/2)', () => {
expect(() => patch.removeNode('n1')).toThrow(
/set onDeleteWithData to 'cascade'/
);
}, { timeout: 15000 });
});
});

// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -206,7 +206,7 @@ describe('WarpGraph deleteGuard enforcement (HS/DELGUARD/2)', () => {
expect(warnSpy).toHaveBeenCalledOnce();
expect(warnSpy.mock.calls[0][0]).toMatch(/Deleting node 'n1'/);
expect(warnSpy.mock.calls[0][0]).toMatch(/propert/);
}, { timeout: 15000 });
});

it('logs warning via logger when deleting node with edges', async () => {
repo = await createGitRepo('delguard');
Expand Down Expand Up @@ -234,7 +234,7 @@ describe('WarpGraph deleteGuard enforcement (HS/DELGUARD/2)', () => {
expect(typeof sha).toBe('string');
expect(warnSpy).toHaveBeenCalled();
expect(warnSpy.mock.calls[0][0]).toMatch(/edge/);
}, { timeout: 15000 });
});

it('does not warn when deleting node with no attached data', async () => {
repo = await createGitRepo('delguard');
Expand All @@ -260,7 +260,7 @@ describe('WarpGraph deleteGuard enforcement (HS/DELGUARD/2)', () => {

expect(typeof sha).toBe('string');
expect(warnSpy).not.toHaveBeenCalled();
}, { timeout: 15000 });
});
});

// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -291,7 +291,7 @@ describe('WarpGraph deleteGuard enforcement (HS/DELGUARD/2)', () => {
expect(() => patch.removeNode('n1')).toThrow(
/Cannot delete node 'n1'/
);
}, { timeout: 15000 });
});

it('warn mode works through writer().commitPatch()', async () => {
repo = await createGitRepo('delguard');
Expand Down Expand Up @@ -319,7 +319,7 @@ describe('WarpGraph deleteGuard enforcement (HS/DELGUARD/2)', () => {
expect(typeof sha).toBe('string');
expect(warnSpy).toHaveBeenCalledOnce();
expect(warnSpy.mock.calls[0][0]).toMatch(/propert/);
}, { timeout: 15000 });
});
});

// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -354,7 +354,7 @@ describe('WarpGraph deleteGuard enforcement (HS/DELGUARD/2)', () => {

expect(typeof sha).toBe('string');
expect(warnSpy).not.toHaveBeenCalled();
}, { timeout: 15000 });
});
});

// ---------------------------------------------------------------------------
Expand All @@ -375,6 +375,6 @@ describe('WarpGraph deleteGuard enforcement (HS/DELGUARD/2)', () => {
// removeNode should not throw because there's no state to check against
const patch = await graph.createPatch();
expect(() => patch.removeNode('n1')).not.toThrow();
}, { timeout: 15000 });
});
});
});
24 changes: 12 additions & 12 deletions test/unit/domain/WarpGraph.noCoordination.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ async function assertLinearWriterChain(/** @type {any} */ persistence, /** @type
}

describe('No-coordination regression suite', () => {
it('keeps writer refs linear after sync cycles', async () => {
it('keeps writer refs linear after sync cycles', { timeout: 20000 }, async () => {
const repoA = await createGitRepo('nocoord');
const repoB = await createGitRepo('nocoord');

Expand Down Expand Up @@ -67,7 +67,7 @@ describe('No-coordination regression suite', () => {
await repoA.cleanup();
await repoB.cleanup();
}
}, { timeout: 20000 });
});

it('does not enumerate other writer heads during commit', async () => {
const repo = await createGitRepo('nocoord');
Expand All @@ -89,7 +89,7 @@ describe('No-coordination regression suite', () => {
}
});

it('survives random sync/commit interleavings without merge commits', async () => {
it('survives random sync/commit interleavings without merge commits', { timeout: 30000 }, async () => {
const opArb = fc.array(
fc.constantFrom('commitA', 'commitB', 'syncAB', 'syncBA'),
{ minLength: 1, maxLength: 6 }
Expand Down Expand Up @@ -138,10 +138,10 @@ describe('No-coordination regression suite', () => {
}),
{ seed: 4242, numRuns: 8 }
);
}, { timeout: 30000 });
});

describe('Lamport clock global-max monotonicity', () => {
it('first-time writer beats existing writer when it materializes first', async () => {
it('first-time writer beats existing writer when it materializes first', { timeout: 20000 }, async () => {
// Regression: when writer B makes its very first commit to a repo where writer A
// has already committed at tick N, B must commit at tick > N so its operations
// win the LWW CRDT tiebreaker — not lose to A's tick-1 commit.
Expand Down Expand Up @@ -191,9 +191,9 @@ describe('No-coordination regression suite', () => {
} finally {
await repo.cleanup();
}
}, { timeout: 20000 });
});

it('_maxObservedLamport is updated after each commit on the same instance', async () => {
it('_maxObservedLamport is updated after each commit on the same instance', { timeout: 10000 }, async () => {
const repo = await createGitRepo('lamport-mono');
try {
const graph = await WarpGraph.open({
Expand All @@ -219,9 +219,9 @@ describe('No-coordination regression suite', () => {
} finally {
await repo.cleanup();
}
}, { timeout: 10000 });
});

it('cross-writer PropSet LWW: later writer override is not silently discarded', async () => {
it('cross-writer PropSet LWW: later writer override is not silently discarded', { timeout: 20000 }, async () => {
// Regression for: "Lamport clock doesn't advance past cross-writer ticks
// during materialize()" — Writer A commits setProperty at tick N, Writer B
// materializes (observes A), then commits setProperty for the same key.
Expand Down Expand Up @@ -284,9 +284,9 @@ describe('No-coordination regression suite', () => {
} finally {
await repo.cleanup();
}
}, { timeout: 20000 });
});

it('materialize updates _maxObservedLamport from observed patches', async () => {
it('materialize updates _maxObservedLamport from observed patches', { timeout: 10000 }, async () => {
const repo = await createGitRepo('lamport-mono');
try {
// Seed with writer-z at tick 1
Expand Down Expand Up @@ -317,7 +317,7 @@ describe('No-coordination regression suite', () => {
} finally {
await repo.cleanup();
}
}, { timeout: 10000 });
});
});

});
4 changes: 2 additions & 2 deletions test/unit/domain/WarpGraph.patchMany.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest';
import WarpGraph from '../../../src/domain/WarpGraph.js';
import { createGitRepo } from '../../helpers/warpGraphTestUtils.js';

describe('WarpGraph.patchMany()', () => {
describe('WarpGraph.patchMany()', { timeout: 30000 }, () => {
it('returns empty array when called with no arguments', async () => {
const repo = await createGitRepo('patchMany-empty');
try {
Expand Down Expand Up @@ -147,4 +147,4 @@ describe('WarpGraph.patchMany()', () => {
await repo.cleanup();
}
});
}, { timeout: 30000 });
});
8 changes: 4 additions & 4 deletions test/unit/domain/WarpGraph.syncMaterialize.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest';
import WarpGraph from '../../../src/domain/WarpGraph.js';
import { createGitRepo } from '../../helpers/warpGraphTestUtils.js';

describe('syncWith({ materialize }) option', () => {
describe('syncWith({ materialize }) option', { timeout: 20000 }, () => {
it('syncWith(peer, { materialize: true }) returns fresh state in result', async () => {
const repoA = await createGitRepo('syncmat');
const repoB = await createGitRepo('syncmat');
Expand Down Expand Up @@ -38,7 +38,7 @@ describe('syncWith({ materialize }) option', () => {
await repoA.cleanup();
await repoB.cleanup();
}
}, { timeout: 20000 });
});

it('syncWith(peer) (default) does NOT auto-materialize — result has no state field', async () => {
const repoA = await createGitRepo('syncmat');
Expand Down Expand Up @@ -69,7 +69,7 @@ describe('syncWith({ materialize }) option', () => {
await repoA.cleanup();
await repoB.cleanup();
}
}, { timeout: 20000 });
});

it('sync applies 0 patches + materialize:true — materialize still runs', async () => {
const repoA = await createGitRepo('syncmat');
Expand Down Expand Up @@ -102,5 +102,5 @@ describe('syncWith({ materialize }) option', () => {
await repoA.cleanup();
await repoB.cleanup();
}
}, { timeout: 20000 });
});
});
Loading
Loading