支持 CRDT 的 Type-Safe 实时协作图数据库

Hacker News Top 工具

摘要

Codemix 开源了 @codemix/graph,这是一款具备 TypeScript 原生模式验证、基于 CRDT 的图数据库,并通过 Yjs 实现实时离线优先同步。

暂无内容
查看原文 导出为 Word 导出为 PDF
查看缓存全文

缓存时间: 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 或自定义。
  • 每次变更都校验 —— addVertexaddEdgeupdateProperty 时都会检查属性。
  • 索引随声明创建 —— 哈希、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,无需信用卡。

相似文章

@ycombinator: Ardent (@ArdentAI) 让你在 TB 级规模下 <6秒 克隆任何 Postgres 数据库,让编码代理可以测试代码,工程团队可以快速上线而不用担心影响生产…

X AI KOLs Following

Ardent 是一款 Y Combinator 支持的工具,能在 TB 级规模下于 6 秒内克隆任何 PostgreSQL 数据库,让编码代理和开发者可以在接近生产环境的克隆副本上测试代码,而不会造成停机风险。该工具已被 Supermemory 和 Surface Labs 等公司采用。