支持 CRDT 的 Type-Safe 实时协作图数据库
摘要
Codemix 开源了 @codemix/graph,这是一款具备 TypeScript 原生模式验证、基于 CRDT 的图数据库,并通过 Yjs 实现实时离线优先同步。
查看缓存全文
缓存时间: 2026/04/21 11:19
@codemix/graph - codemix
来源:https://codemix.com/graph
航线演示
全球航线演示
将真实航线快照加载到图中,并用 TypeScript 查询。
在线演示
把头像贴到墙上
由 @codemix/graph 与 @codemix/y-graph-storage 驱动——真正的图数据库,通过 Yjs CRDT 在所有打开的标签页之间同步。添加自己、拖动头像、画连线。
安装
从 npm 安装——无原生依赖,任何支持 Node 或打包工具的环境都能跑。
$ pnpm add @codemix/graph
**注意:**这是 alpha 阶段软件。我们在 codemix 生产环境使用,已能满足自身需求,但用于你自己的数据时请谨慎。
定义模式
用普通对象描述顶点、边与索引。属性类型会贯穿所有查询、遍历与变更——无需强制转换,无运行时报错。
import { Graph, GraphSchema, InMemoryGraphStorage } from "@codemix/graph";
import { z } from "zod";
const schema = {
vertices: {
User: {
properties: {
email: { type: z.email(), index: { type: "hash", unique: true } },
name: { type: z.string() },
},
},
Repo: {
properties: {
name: { type: z.string() },
stars: { type: z.number() },
},
},
},
edges: {
OWNS: { properties: {} },
FOLLOWS: { properties: {} },
},
} as const satisfies GraphSchema;
const graph = new Graph({ schema, storage: new InMemoryGraphStorage() });
- → 任意标准模式库 —— Zod、Valibot、ArkType 或自定义。
- → 每次变更都校验 ——
addVertex、addEdge、updateProperty时都会检查属性。 - → 索引随声明创建 —— 哈希、B 树、全文;惰性构建,增量维护。
添加数据
通过图实例添加顶点与边。属性参数在编译时与运行时都会按模式校验。
// 添加顶点 —— 参数按标签的属性模式进行类型检查
const alice = graph.addVertex("User", { name: "Alice", email: "[email protected]" });
const bob = graph.addVertex("User", { name: "Bob", email: "[email protected]" });
const myRepo = graph.addVertex("Repo", { name: "my-repo", stars: 0 });
// 添加边
graph.addEdge(alice, "OWNS", myRepo, {});
graph.addEdge(bob, "FOLLOWS", alice, {});
// 读取属性 —— 类型来自模式
alice.get("name"); // string
myRepo.get("stars"); // number
// 就地更新
graph.updateProperty(myRepo, "stars", 42);
// 或通过元素自身
myRepo.set("stars", 42);
编写类型安全查询
Gremlin 风格的遍历 API —— 步骤名熟悉,但每个标签、属性键、跳转都由 TypeScript 按模式校验。
开始遍历
import { GraphTraversal } from "@codemix/graph";
const g = new GraphTraversal(graph);
for (const path of g.V().hasLabel("User")) {
path.value.get("name"); // string ✓
path.value.get("email"); // string ✓
}
按属性过滤
// 精确匹配或谓词
const [alice] = g.V()
.hasLabel("User")
.has("email", "[email protected]");
const seniors = g.V()
.hasLabel("User")
.where((v) => v.get("name").startsWith("A"));
沿边遍历
// 沿 User → Repo 的 OWNS 边
for (const path of g.V()
.hasLabel("User")
.has("email", "[email protected]")
.out("OWNS").hasLabel("Repo")) {
path.value.get("stars"); // number —— 来自 Repo 模式
}
标记与选择
// 在多跳处捕获顶点并一起投影
for (const { user, repo } of g.V()
.hasLabel("User").as("user")
.out("FOLLOWS")
.out("OWNS").hasLabel("Repo").as("repo")
.select("user", "repo")) {
console.log(
user.value.get("name"), // string
repo.value.get("stars"), // number
);
}
离线优先同步与实时协作
把 InMemoryGraphStorage 换成 YGraph,整张图就活在 Yjs (https://yjs.dev/) CRDT 文档里。所有遍历、Cypher 查询、索引照常工作——只是额外获得了无冲突同步。
接入 provider
import * as Y from "yjs";
import { WebsocketProvider } from "y-websocket";
import { YGraph } from "@codemix/y-graph-storage";
const doc = new Y.Doc();
const graph = new YGraph({ schema, doc });
// 连接任意 Yjs provider —— 同步自动完成。
// 每个加入房间的节点都会看到同一张图。
const provider = new WebsocketProvider("wss://my-server", "graph-room", doc);
订阅细粒度变更
// 本地与远程变更都会触发事件
const unsubscribe = graph.subscribe({
next(change) {
// change.kind 为以下之一:
// "vertex.added" | "vertex.deleted"
// "edge.added" | "edge.deleted"
// "vertex.property.set" | "vertex.property.changed"
console.log(change.kind, change.id);
},
});
实时查询
// 包装任意遍历,当结果集可能变化时重新触发
const topRepos = graph.query((g) =>
g.V().hasLabel("Repo").order("stars", "desc").limit(10)
);
const unsubscribe = topRepos.subscribe({
next() {
for (const path of topRepos) {
console.log(path.value.get("name"), path.value.get("stars"));
}
},
});
// 在其他地方添加或更新 Repo —— 哪怕是远程节点 ——
// 也会自动触发订阅者。
graph.updateProperty(myRepo, "stars", 99);
协作属性类型
import { ZodYText, ZodYArray } from "@codemix/y-graph-storage";
import { z } from "zod";
// 在模式中声明 Y.Text / Y.Array / Y.Map 属性
const schema = {
vertices: {
Document: {
properties: {
title: { type: ZodYText }, // 协作字符串
tags: { type: ZodYArray(z.string()) }, // 协作数组
},
},
},
edges: {},
} as const satisfies GraphSchema;
// 普通值自动转换 —— 无需手动构造 Y.*
const doc = graph.addVertex("Document", { title: "Hello", tags: ["crdt"] });
// 就地变更 —— 所有节点无冲突地看到变化
doc.get("title").insert(5, ", world");
doc.get("tags").push(["graph"]);
面向 API 与 LLM 的 Cypher 查询
同一张图也支持类 Cypher 的字符串查询语言——适合通过 MCP 服务器向 LLM 暴露数据,或让外部客户端无需引入遍历库即可执行即席查询。
解析并执行
import { parseQueryToSteps, createTraverser } from "@codemix/graph";
const { steps, postprocess } = parseQueryToSteps(`
MATCH (u:User)-[:OWNS]->(r:Repo)
WHERE r.stars > 100
RETURN u.name, r.name
ORDER BY r.stars DESC
LIMIT 10
`);
const traverser = createTraverser(steps);
for (const row of traverser.traverse(graph, [])) {
console.log(postprocess(row));
// { u: { name: "Alice" }, r: { name: "my-repo" } }
}
参数化查询
// 传递参数,避免字符串拼接
const { steps, postprocess } = parseQueryToSteps(`
MATCH (u:User { email: $email })-[:OWNS]->(r:Repo)
RETURN r.name, r.stars
`);
const traverser = createTraverser(steps);
const rows = Array.from(
traverser.traverse(graph, [{ email: "[email protected]" }])
).map(postprocess);
变更
// 支持 CREATE、MERGE、SET、DELETE
const { steps } = parseQueryToSteps(`
MATCH (r:Repo { name: $name })
SET r.stars = r.stars + 1
`);
createTraverser(steps).traverse(graph, [{ name: "my-repo" }]);
// 强制只读 —— 遇到写子句会抛出 ReadonlyGraphError
const { steps: safeSteps } = parseQueryToSteps(query, { readonly: true });
许可与历史
本包采用 MIT 许可。
最初由 Charles Pick(https://x.com/c_pick)作为研究项目编写,他是 codemix(https://codemix.com/)创始人,也是臭名昭著的 ts-sql(https://github.com/codemix/ts-sql)演示作者。后来我们在构建 codemix(https://codemix.com/)时需要结构化知识图谱,于是改造了代码,加入 Y.js(https://yjs.dev/)支持,再后来 Opus 4.5 又添加了类 Cypher 查询语言。
在 GitHub 上给我们加星(https://github.com/codemix/graph)
顺便看看
产品唯一真相源。面向人类与 AI。
codemix 捕捉你真正的“意图”——业务领域、用户流程、概念、约束——并自动与代码库保持同步。
通过聊天、图表或协作编辑来变更产品。让编码代理在开发与代码审查中拥有真正的理解。团队中的每个代理共享同一份上下文。
从零创造,或导入现有代码库即可开始。
从零构建全新产品
免费试用 codemix,无需信用卡。
相似文章
@thomasp85:我激动万分,终于可以揭开我们2026年所做工作的神秘面纱:请认识 ggsql!一个全新的扩展……
Posit 宣布推出 ggsql 的 alpha 版本。ggsql 是一种新的 SQL 语言扩展,将图形语法风格的数据可视化引入 SQL,兼容 Quarto、Jupyter notebooks、Positron 和 VS Code。用户可以使用受 ggplot2 启发的熟悉 SQL 语法,创建分层、结构化的可视化图表。
Show HN: Ctx – 跨 Claude Code 与 Codex 都能用的 /resume
Ctx 是一款本地优先的上下文管理器,开发者可用它在 Claude Code 和 Codex 之间绑定、恢复并分叉精确对话,杜绝记录漂移,依托 SQLite 与本地文件。
我为 Codex 打造了一款 GNOME 扩展,集成本地/远程历史记录、实时过滤、Markdown 导出与只读 MCP 服务器
该开发者为 Codex 打造了一款功能全面的 GNOME Shell 扩展,新增了原生 GTK 历史记录管理、本地/远程会话浏览、Markdown 导出,以及支持多设备配对与安全管控的只读 MCP 服务器。
@tom_doerr: 将项目转换为AI代理可导航的知识图谱 https://github.com/Muvon/octocode
Octocode将代码项目转换为AI代理(如Claude、Cursor和Windsurf)可导航的知识图谱,采用tree-sitter AST解析和MCP集成,实现语义搜索和依赖导航。
@ycombinator: Ardent (@ArdentAI) 让你在 TB 级规模下 <6秒 克隆任何 Postgres 数据库,让编码代理可以测试代码,工程团队可以快速上线而不用担心影响生产…
Ardent 是一款 Y Combinator 支持的工具,能在 TB 级规模下于 6 秒内克隆任何 PostgreSQL 数据库,让编码代理和开发者可以在接近生产环境的克隆副本上测试代码,而不会造成停机风险。该工具已被 Supermemory 和 Surface Labs 等公司采用。