nano-git 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,13 +8,14 @@
8
8
  - ✅ **SHA-1 哈希计算** — 与 Git 完全兼容的对象哈希
9
9
  - ✅ **Git 对象模型** — 支持 blob、tree、commit、tag 四种对象类型
10
10
  - ✅ **对象序列化/反序列化** — 完整的二进制格式支持
11
- - ✅ **对象存储** — 文件系统存储和内存存储两种模式
11
+ - ✅ **对象存储** — 文件系统存储、内存存储和 SQLite 存储三种模式
12
12
  - ✅ **Packfile 支持** — 读取、写入、索引生成、delta 编解码
13
13
  - ✅ **引用管理** — refs 验证、解析、存储(文件系统 + 内存)
14
14
  - ✅ **仓库 API** — 类似 Git plumbing 命令的高层接口(init、hash-object、cat-file、commit-tree、update-ref 等)
15
15
  - ✅ **增量 Tree Patch** — 不经暂存区直接修改目录结构(`patchTree`、`readTree`、`walkTree`)
16
16
  - ✅ **可达性遍历与 GC** — 基于 refs 的可达对象收集、repack、gc
17
17
  - ✅ **Smart HTTP 传输** — 基于 Bun fetch 的 Git 协议客户端,支持 `fetch()`/`push()` 与完整的 Import Session 物化流程
18
+ - ✅ **远端查询 API** — 将 refs 快照、`object-info` 等纯远端能力独立出 `Repository`
18
19
  - ✅ **类型安全** — 完整的 TypeScript 类型定义
19
20
  - ✅ **Reference Transaction** — 批量 ref 更新的原子性保障,支持 Hooks 回调与自动回滚
20
21
 
@@ -55,6 +56,22 @@ await repo.fetch("https://github.com/user/repo.git");
55
56
  console.log(repo.listBranches());
56
57
  ```
57
58
 
59
+ ### 查询远端 refs / object-info
60
+
61
+ ```typescript
62
+ import { createHttpRemote } from "nano-git/remote/http";
63
+
64
+ const remote = createHttpRemote({
65
+ url: "https://github.com/user/repo.git",
66
+ });
67
+
68
+ const snapshot = await remote.readRefAdvertisement();
69
+ console.log(snapshot.defaultBranch);
70
+
71
+ const info = await remote.fetchObjectInfo(["95d09f2b10159347eece71399a7e2e907ea3df4f"]);
72
+ console.log(info.objects[0]?.size);
73
+ ```
74
+
58
75
  ### 内存仓库完整工作流
59
76
 
60
77
  ```typescript
@@ -138,6 +155,43 @@ repo.updateRef("refs/heads/main", commitHash);
138
155
 
139
156
  `openRepository()` 默认会同时读取 `.git/objects/` 下的 loose objects 和 `.git/objects/pack/` 下的 packed objects,因此可以直接打开经过 `git gc` 或 `git repack` 的真实仓库(包括裸仓库)。搭配 `initRepository()` 的第二个参数可初始化为裸仓库布局。
140
157
 
158
+ ### 使用 SQLite 仓库(Bun 运行时)
159
+
160
+ 适用于需要持久化但又不想管理松散文件的场景——
161
+ 所有对象和引用存在一个 `.sqlite` 文件中。
162
+
163
+ ```typescript
164
+ import { createSqliteRepository } from "nano-git/repository/sqlite";
165
+
166
+ // 创建或打开 SQLite 持久化仓库(支持 using 自动释放)
167
+ using repo = createSqliteRepository("/tmp/cache.sqlite");
168
+
169
+ // 与普通 repo 使用方式完全一致
170
+ const hash = repo.writeBlob(Buffer.from("persistent data"));
171
+ const treeHash = repo.createTree([{ mode: "100644", name: "data.txt", hash }]);
172
+ const commitHash = repo.createCommit(treeHash, [], "SQLite commit", {
173
+ name: "You",
174
+ email: "you@example.com",
175
+ timestamp: Math.floor(Date.now() / 1000),
176
+ timezone: "+0800",
177
+ });
178
+ console.log(`Committed: ${commitHash}`);
179
+
180
+ // 作用域结束时自动关闭数据库连接
181
+ ```
182
+
183
+ 也可拆分使用底层后端:
184
+
185
+ ```typescript
186
+ import { createSqliteRepositoryBackend } from "nano-git/backend/sqlite";
187
+ import { createRepository } from "nano-git/repository/core";
188
+
189
+ const backend = createSqliteRepositoryBackend("/tmp/repo.sqlite");
190
+ const repo = createRepository(backend);
191
+ // 用完记得释放
192
+ backend[Symbol.dispose]();
193
+ ```
194
+
141
195
  ### 生成 Packfile
142
196
 
143
197
  ```typescript
@@ -305,6 +359,8 @@ bun run examples/demo.ts
305
359
 
306
360
  本库默认入口 `"nano-git"` 直接提供高频的纯计算能力:类型、错误、对象编解码、refs 工具和 SHA-1 工具。
307
361
  带 `node:fs` / `node:zlib` 的运行时能力通过子路径显式导入,例如 `nano-git/repository/file`、`nano-git/pack`、`nano-git/transport/http`。
362
+ 纯远端查询能力通过 `nano-git/remote/http` 导入。
363
+ 基于 `bun:sqlite` 的存储后端通过 `nano-git/odb/sqlite`、`nano-git/refs/sqlite`、`nano-git/backend/sqlite`、`nano-git/repository/sqlite` 等子路径导入。
308
364
  tree-shaking 主要依赖模块本身的无副作用结构,而不是把所有 API 都拆成叶子级子路径。完整入口表见 `package.json` 的 `exports` 与 `src/index.ts` 的 JSDoc。
309
365
 
310
366
  ## Git 对象模型
@@ -381,6 +437,7 @@ bun test
381
437
  - [x] 可达性遍历与 GC(repack、gc)
382
438
  - [x] **Smart HTTP 传输** — pkt-line 编解码、ref 广告解析、side-band 解复用、Fetch / Push 协议、Import Session 集成
383
439
  - [x] **Reference Transaction** — 批量 ref 更新原子性、lock-then-rename 文件事务、生命周期 Hooks
440
+ - [x] **SQLite 存储后端** — 基于 `bun:sqlite` 的单文件持久化,支持对象/refs/shallow 存储、ACID 事务、`Symbol.dispose` 生命周期管理
384
441
 
385
442
  - [x] **Smart HTTP 服务端(upload-pack)** — 类 git-http-backend、框架无关的 HTTP handler,支持 ls-refs 和 fetch 命令,协议实现与编排器解耦
386
443
  - [x] **Smart HTTP 服务端(v1 receive-pack)** — 服务端 push 支持,基于 v1 协议,含 ref 广告、packfile 解包、ref 校验与 report-status
@@ -0,0 +1,44 @@
1
+ import { RepositoryBackend } from "./types.mjs";
2
+
3
+ //#region src/backend/sqlite.d.ts
4
+ /** 创建 SQLite 仓库后端的可选参数 */
5
+ interface CreateSqliteRepositoryBackendOptions {
6
+ /** 开启 WAL 模式,默认 true */
7
+ readonly walMode?: boolean;
8
+ }
9
+ /**
10
+ * SQLite 仓库后端(含资源释放能力)
11
+ *
12
+ * 在 RepositoryBackend 的基础上增加了 [Symbol.dispose](),
13
+ * 支持 `using backend = createSqliteRepositoryBackend(...)` 语法。
14
+ */
15
+ interface SqliteRepositoryBackend extends RepositoryBackend {
16
+ /** 释放 SQLite 数据库连接 */
17
+ [Symbol.dispose](): void;
18
+ }
19
+ /**
20
+ * 创建基于 SQLite 文件的完整仓库后端
21
+ *
22
+ * 内部创建 Database 实例并组合三个子 store。
23
+ * 返回的 backend 实现了 [Symbol.dispose](),可使用 `using` 语法
24
+ * 或在不再使用时手动调用 `backend[Symbol.dispose]()`。
25
+ *
26
+ * @param dbPath - SQLite 数据库文件路径
27
+ * @returns 实现了 SqliteRepositoryBackend 的仓库后端(可用 `using` 管理)
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * // 使用 using 自动释放(推荐)
32
+ * using backend = createSqliteRepositoryBackend("/tmp/repo.sqlite");
33
+ * const repo = createRepository(backend);
34
+ *
35
+ * // 或手动管理
36
+ * const backend = createSqliteRepositoryBackend("/tmp/repo.sqlite");
37
+ * const repo = createRepository(backend);
38
+ * // ... 使用完毕 ...
39
+ * backend[Symbol.dispose]();
40
+ * ```
41
+ */
42
+ declare function createSqliteRepositoryBackend(dbPath: string, options?: CreateSqliteRepositoryBackendOptions): SqliteRepositoryBackend;
43
+ //#endregion
44
+ export { CreateSqliteRepositoryBackendOptions, SqliteRepositoryBackend, createSqliteRepositoryBackend };
@@ -0,0 +1,59 @@
1
+ import { HEADS_PREFIX, HEAD_REF } from "../core/types/refs.mjs";
2
+ import { createSqliteObjectStore } from "../odb/sqlite.mjs";
3
+ import { createSqliteRefStore } from "../refs/sqlite.mjs";
4
+ import { createSqliteShallowStore } from "../refs/shallow/sqlite.mjs";
5
+ import { Database } from "bun:sqlite";
6
+ //#region src/backend/sqlite.ts
7
+ /**
8
+ * 基于 SQLite 的仓库后端
9
+ *
10
+ * 将 SQLite 中的 objects、refs、shallow 存储
11
+ * 组合为统一的 RepositoryBackend。
12
+ *
13
+ * 支持 [Symbol.dispose]() 释放数据库连接,
14
+ * 可使用 `using` 语法管理生命周期。
15
+ */
16
+ /**
17
+ * 创建基于 SQLite 文件的完整仓库后端
18
+ *
19
+ * 内部创建 Database 实例并组合三个子 store。
20
+ * 返回的 backend 实现了 [Symbol.dispose](),可使用 `using` 语法
21
+ * 或在不再使用时手动调用 `backend[Symbol.dispose]()`。
22
+ *
23
+ * @param dbPath - SQLite 数据库文件路径
24
+ * @returns 实现了 SqliteRepositoryBackend 的仓库后端(可用 `using` 管理)
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * // 使用 using 自动释放(推荐)
29
+ * using backend = createSqliteRepositoryBackend("/tmp/repo.sqlite");
30
+ * const repo = createRepository(backend);
31
+ *
32
+ * // 或手动管理
33
+ * const backend = createSqliteRepositoryBackend("/tmp/repo.sqlite");
34
+ * const repo = createRepository(backend);
35
+ * // ... 使用完毕 ...
36
+ * backend[Symbol.dispose]();
37
+ * ```
38
+ */
39
+ function createSqliteRepositoryBackend(dbPath, options = {}) {
40
+ const db = new Database(dbPath);
41
+ if (options.walMode !== false) db.run("PRAGMA journal_mode = WAL");
42
+ db.run("CREATE TABLE IF NOT EXISTS objects (hash TEXT PRIMARY KEY, type TEXT NOT NULL, content BLOB NOT NULL)");
43
+ db.run("CREATE TABLE IF NOT EXISTS refs (name TEXT PRIMARY KEY, target TEXT NOT NULL)");
44
+ db.run("CREATE TABLE IF NOT EXISTS shallow (hash TEXT PRIMARY KEY)");
45
+ db.run("INSERT OR IGNORE INTO refs (name, target) VALUES (?, ?)", [HEAD_REF, `ref: ${HEADS_PREFIX}main`]);
46
+ return {
47
+ gitDir: dbPath,
48
+ objects: createSqliteObjectStore(db),
49
+ refs: createSqliteRefStore(db),
50
+ shallow: createSqliteShallowStore(db),
51
+ packs: null,
52
+ /** 释放 SQLite 数据库连接 */
53
+ [Symbol.dispose]() {
54
+ db.close();
55
+ }
56
+ };
57
+ }
58
+ //#endregion
59
+ export { createSqliteRepositoryBackend };
package/dist/index.d.mts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { GitAuthor, GitBlob, GitCommit, GitCommitExtraHeader, GitObject, GitTag, GitTree, ObjectType, RawGitObject, SHA1, TreeEntry, assertObjectType, sha1 } from "./core/types.mjs";
2
2
  import { PackRepackOptions, RepositoryBackend, RepositoryGCOptions, RepositoryPackSupport, RepositoryRepackOptions } from "./backend/types.mjs";
3
3
  import { CircularReferenceError, DeltaError, GitError, InvalidObjectError, InvalidPackError, InvalidSHA1Error, ObjectNotFoundError, PackError, PackIndexError, PreconditionCheckError, RefNotFoundError, RepositoryError, TransactionError } from "./core/errors.mjs";
4
+ import { RemoteSource } from "./remote/types.mjs";
4
5
  import { FileRepository, Repository } from "./repository/types.mjs";
5
6
  import { hashData, hashObject } from "./core/hash-digest.mjs";
6
7
  import { isValidSHA1 } from "./core/hash-path.mjs";
@@ -13,4 +14,4 @@ import { deserialize, deserializeContent, serialize, serializeContent } from "./
13
14
  import { decodeObject, encodeObject, readObject, tryReadObject, writeObject } from "./objects/raw.mjs";
14
15
  import { branchNameToRef, normalizeShortRefName, tagNameToRef, validateRefName, validateRefPrefix } from "./refs/names.mjs";
15
16
  import { resolveRefHash, resolveSymbolicRef, resolveTargetHash } from "./refs/resolve.mjs";
16
- export { CircularReferenceError, DeltaError, type FileRepository, type GitAuthor, type GitBlob, type GitCommit, type GitCommitExtraHeader, GitError, type GitObject, type GitTag, type GitTree, InvalidObjectError, InvalidPackError, InvalidSHA1Error, ObjectNotFoundError, type ObjectType, PackError, PackIndexError, type PackRepackOptions, PreconditionCheckError, type RawGitObject, RefNotFoundError, type Repository, type RepositoryBackend, RepositoryError, type RepositoryGCOptions, type RepositoryPackSupport, type RepositoryRepackOptions, type SHA1, TransactionError, type TreeEntry, assertObjectType, branchNameToRef, decodeObject, deserialize, deserializeBlob, deserializeCommit, deserializeContent, deserializeTag, deserializeTree, encodeObject, formatAuthor, hashData, hashObject, isValidSHA1, normalizeShortRefName, parseAuthor, readObject, resolveRefHash, resolveSymbolicRef, resolveTargetHash, serialize, serializeBlob, serializeCommit, serializeContent, serializeTag, serializeTree, sha1, tagNameToRef, tryReadObject, validateRefName, validateRefPrefix, writeObject };
17
+ export { CircularReferenceError, DeltaError, type FileRepository, type GitAuthor, type GitBlob, type GitCommit, type GitCommitExtraHeader, GitError, type GitObject, type GitTag, type GitTree, InvalidObjectError, InvalidPackError, InvalidSHA1Error, ObjectNotFoundError, type ObjectType, PackError, PackIndexError, type PackRepackOptions, PreconditionCheckError, type RawGitObject, RefNotFoundError, type RemoteSource, type Repository, type RepositoryBackend, RepositoryError, type RepositoryGCOptions, type RepositoryPackSupport, type RepositoryRepackOptions, type SHA1, TransactionError, type TreeEntry, assertObjectType, branchNameToRef, decodeObject, deserialize, deserializeBlob, deserializeCommit, deserializeContent, deserializeTag, deserializeTree, encodeObject, formatAuthor, hashData, hashObject, isValidSHA1, normalizeShortRefName, parseAuthor, readObject, resolveRefHash, resolveSymbolicRef, resolveTargetHash, serialize, serializeBlob, serializeCommit, serializeContent, serializeTag, serializeTree, sha1, tagNameToRef, tryReadObject, validateRefName, validateRefPrefix, writeObject };
@@ -0,0 +1,23 @@
1
+ import { ObjectDatabase } from "../core/types/odb.mjs";
2
+ import { Database } from "bun:sqlite";
3
+
4
+ //#region src/odb/sqlite.d.ts
5
+ /**
6
+ * 创建基于 SQLite 的对象数据库
7
+ *
8
+ * @param db - 已打开的 bun:sqlite Database 实例
9
+ * @returns 符合 ObjectDatabase 接口的存储后端
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { Database } from "bun:sqlite";
14
+ * const db = new Database("/tmp/repo.sqlite");
15
+ * const store = createSqliteObjectStore(db);
16
+ *
17
+ * store.ingest(raw);
18
+ * const obj = store.read(hash);
19
+ * ```
20
+ */
21
+ declare function createSqliteObjectStore(db: Database): ObjectDatabase;
22
+ //#endregion
23
+ export { createSqliteObjectStore };
@@ -0,0 +1,83 @@
1
+ import { ObjectNotFoundError } from "../core/errors.mjs";
2
+ import { sha1 } from "../core/types.mjs";
3
+ import { hashObject } from "../core/hash-digest.mjs";
4
+ //#region src/odb/sqlite.ts
5
+ /**
6
+ * 基于 SQLite 的对象数据库(raw-first)
7
+ *
8
+ * 所有对象存储在 SQLite 数据库的 objects 表中。
9
+ * 使用 INSERT OR IGNORE 实现幂等写入,使用 db.transaction() 实现批量原子写入。
10
+ *
11
+ * 表创建由上层 createSqliteRepositoryBackend 负责,
12
+ * 本模块只操作已存在的表,不负责 DDL。
13
+ */
14
+ /**
15
+ * 创建基于 SQLite 的对象数据库
16
+ *
17
+ * @param db - 已打开的 bun:sqlite Database 实例
18
+ * @returns 符合 ObjectDatabase 接口的存储后端
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * import { Database } from "bun:sqlite";
23
+ * const db = new Database("/tmp/repo.sqlite");
24
+ * const store = createSqliteObjectStore(db);
25
+ *
26
+ * store.ingest(raw);
27
+ * const obj = store.read(hash);
28
+ * ```
29
+ */
30
+ function createSqliteObjectStore(db) {
31
+ const selectStmt = db.query("SELECT hash, type, content FROM objects WHERE hash = ?");
32
+ const existsStmt = db.query("SELECT 1 FROM objects WHERE hash = ?");
33
+ const insertStmt = db.query("INSERT OR IGNORE INTO objects (hash, type, content) VALUES (?, ?, ?)");
34
+ const deleteStmt = db.query("DELETE FROM objects WHERE hash = ?");
35
+ const listStmt = db.query("SELECT hash FROM objects ORDER BY hash");
36
+ /** 批量插入的事务包装 */
37
+ const ingestManyTx = db.transaction((objects) => {
38
+ for (const raw of objects) {
39
+ const expectedHash = hashObject(raw.type, raw.content);
40
+ if (expectedHash !== raw.hash) throw new Error(`RawGitObject hash mismatch: expected ${expectedHash}, got ${raw.hash}`);
41
+ insertStmt.run(raw.hash, raw.type, raw.content);
42
+ }
43
+ });
44
+ return {
45
+ ingest(raw) {
46
+ const expectedHash = hashObject(raw.type, raw.content);
47
+ if (expectedHash !== raw.hash) throw new Error(`RawGitObject hash mismatch: expected ${expectedHash}, got ${raw.hash}`);
48
+ insertStmt.run(raw.hash, raw.type, raw.content);
49
+ },
50
+ ingestMany(objects) {
51
+ ingestManyTx(objects);
52
+ },
53
+ read(hash) {
54
+ const row = selectStmt.get(hash);
55
+ if (!row) throw new ObjectNotFoundError(hash);
56
+ return {
57
+ hash: sha1(row.hash),
58
+ type: row.type,
59
+ content: Buffer.from(row.content)
60
+ };
61
+ },
62
+ tryRead(hash) {
63
+ const row = selectStmt.get(hash);
64
+ if (!row) return;
65
+ return {
66
+ hash: sha1(row.hash),
67
+ type: row.type,
68
+ content: Buffer.from(row.content)
69
+ };
70
+ },
71
+ exists(hash) {
72
+ return existsStmt.get(hash) !== null;
73
+ },
74
+ list() {
75
+ return listStmt.all().map((row) => sha1(row.hash));
76
+ },
77
+ delete(hash) {
78
+ deleteStmt.run(hash);
79
+ }
80
+ };
81
+ }
82
+ //#endregion
83
+ export { createSqliteObjectStore };
@@ -0,0 +1,23 @@
1
+ import { ShallowStore } from "../../core/types/shallow.mjs";
2
+ import { Database } from "bun:sqlite";
3
+
4
+ //#region src/refs/shallow/sqlite.d.ts
5
+ /**
6
+ * 创建基于 SQLite 的 shallow 边界存储
7
+ *
8
+ * @param db - 已打开的 bun:sqlite Database 实例
9
+ * @returns 符合 ShallowStore 接口的存储后端
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { Database } from "bun:sqlite";
14
+ * const db = new Database("/tmp/repo.sqlite");
15
+ * const store = createSqliteShallowStore(db);
16
+ *
17
+ * store.write([hashA, hashB]);
18
+ * console.log(store.isShallow(hashA)); // true
19
+ * ```
20
+ */
21
+ declare function createSqliteShallowStore(db: Database): ShallowStore;
22
+ //#endregion
23
+ export { createSqliteShallowStore };
@@ -0,0 +1,61 @@
1
+ import { sha1 } from "../../core/types.mjs";
2
+ //#region src/refs/shallow/sqlite.ts
3
+ /**
4
+ * 基于 SQLite 的 Shallow 存储
5
+ *
6
+ * 所有 shallow 边界存储在 SQLite 数据库的 shallow 表中。
7
+ * write 使用 DELETE + INSERT 全量替换模式(与 memory/file 后端一致)。
8
+ * applyUpdate 使用 SQL 事务做增量更新。
9
+ *
10
+ * 表创建由上层 createSqliteRepositoryBackend 负责,
11
+ * 本模块只操作已存在的表,不负责 DDL。
12
+ */
13
+ /**
14
+ * 创建基于 SQLite 的 shallow 边界存储
15
+ *
16
+ * @param db - 已打开的 bun:sqlite Database 实例
17
+ * @returns 符合 ShallowStore 接口的存储后端
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * import { Database } from "bun:sqlite";
22
+ * const db = new Database("/tmp/repo.sqlite");
23
+ * const store = createSqliteShallowStore(db);
24
+ *
25
+ * store.write([hashA, hashB]);
26
+ * console.log(store.isShallow(hashA)); // true
27
+ * ```
28
+ */
29
+ function createSqliteShallowStore(db) {
30
+ const selectAllStmt = db.query("SELECT hash FROM shallow ORDER BY hash");
31
+ const selectExistsStmt = db.query("SELECT 1 FROM shallow WHERE hash = ?");
32
+ const deleteAllStmt = db.query("DELETE FROM shallow");
33
+ const insertStmt = db.query("INSERT OR IGNORE INTO shallow (hash) VALUES (?)");
34
+ const deleteOneStmt = db.query("DELETE FROM shallow WHERE hash = ?");
35
+ /** 全量替换事务 */
36
+ const replaceAllTx = db.transaction((boundaries) => {
37
+ deleteAllStmt.run();
38
+ for (const hash of boundaries) insertStmt.run(hash);
39
+ });
40
+ /** 增量更新事务 */
41
+ const applyUpdateTx = db.transaction((update) => {
42
+ for (const hash of update.unshallow) deleteOneStmt.run(hash);
43
+ for (const hash of update.shallow) insertStmt.run(hash);
44
+ });
45
+ return {
46
+ read() {
47
+ return selectAllStmt.all().map((row) => sha1(row.hash));
48
+ },
49
+ write(boundaries) {
50
+ replaceAllTx(boundaries);
51
+ },
52
+ applyUpdate(update) {
53
+ applyUpdateTx(update);
54
+ },
55
+ isShallow(hash) {
56
+ return selectExistsStmt.get(hash) !== null;
57
+ }
58
+ };
59
+ }
60
+ //#endregion
61
+ export { createSqliteShallowStore };
@@ -0,0 +1,23 @@
1
+ import { RefStore } from "../core/types/refs.mjs";
2
+ import { Database } from "bun:sqlite";
3
+
4
+ //#region src/refs/sqlite.d.ts
5
+ /**
6
+ * 创建基于 SQLite 的 RefStore
7
+ *
8
+ * @param db - 已打开的 bun:sqlite Database 实例(生命周期由调用方管理)
9
+ * @returns 符合 RefStore 接口的存储后端(含事务支持)
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { Database } from "bun:sqlite";
14
+ * const db = new Database("/tmp/repo.sqlite");
15
+ * const store = createSqliteRefStore(db);
16
+ *
17
+ * store.write("refs/heads/main", "abc123");
18
+ * const content = store.read("refs/heads/main");
19
+ * ```
20
+ */
21
+ declare function createSqliteRefStore(db: Database): RefStore;
22
+ //#endregion
23
+ export { createSqliteRefStore };
@@ -0,0 +1,135 @@
1
+ import { RefNotFoundError, TransactionError } from "../core/errors.mjs";
2
+ import { validateRefName, validateRefPrefix } from "./names.mjs";
3
+ //#region src/refs/sqlite.ts
4
+ /**
5
+ * 基于 SQLite 的 Refs 存储
6
+ *
7
+ * 所有引用存储在 SQLite 数据库的 refs 表中。
8
+ * 使用 INSERT OR REPLACE 实现幂等写入,使用 db.transaction() 实现事务原子性。
9
+ *
10
+ * 表创建由上层 createSqliteRepositoryBackend 负责,
11
+ * 本模块只操作已存在的表,不负责 DDL。
12
+ */
13
+ /**
14
+ * 创建基于 SQLite 的 RefStore
15
+ *
16
+ * @param db - 已打开的 bun:sqlite Database 实例(生命周期由调用方管理)
17
+ * @returns 符合 RefStore 接口的存储后端(含事务支持)
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * import { Database } from "bun:sqlite";
22
+ * const db = new Database("/tmp/repo.sqlite");
23
+ * const store = createSqliteRefStore(db);
24
+ *
25
+ * store.write("refs/heads/main", "abc123");
26
+ * const content = store.read("refs/heads/main");
27
+ * ```
28
+ */
29
+ function createSqliteRefStore(db) {
30
+ const selectStmt = db.query("SELECT target FROM refs WHERE name = ?");
31
+ const selectExistsStmt = db.query("SELECT 1 FROM refs WHERE name = ?");
32
+ const insertStmt = db.query("INSERT OR REPLACE INTO refs (name, target) VALUES (?, ?)");
33
+ const deleteStmt = db.query("DELETE FROM refs WHERE name = ?");
34
+ const listPrefixStmt = db.query("SELECT name FROM refs WHERE name >= ? AND name < ? ORDER BY name");
35
+ const listAllStmt = db.query("SELECT name FROM refs WHERE name LIKE 'refs/%' ORDER BY name");
36
+ /**
37
+ * 开启一个新的事务
38
+ *
39
+ * 所有变更暂存于 JS Map,commit() 时通过 SQLite 事务原子性写入。
40
+ */
41
+ function beginTransaction(hooks) {
42
+ const pending = /* @__PURE__ */ new Map();
43
+ const snapshot = /* @__PURE__ */ new Map();
44
+ for (const row of listAllStmt.all()) {
45
+ const val = selectStmt.get(row.name);
46
+ if (val !== null) snapshot.set(row.name, val.target);
47
+ }
48
+ let committed = false;
49
+ return {
50
+ get pendingCount() {
51
+ return pending.size;
52
+ },
53
+ write(ref, content) {
54
+ if (committed) throw new TransactionError("Transaction already committed");
55
+ validateRefName(ref);
56
+ pending.set(ref, content.trimEnd());
57
+ },
58
+ delete(ref) {
59
+ if (committed) throw new TransactionError("Transaction already committed");
60
+ validateRefName(ref);
61
+ const inDb = selectExistsStmt.get(ref) !== null;
62
+ const inPending = pending.has(ref);
63
+ if (!inDb && !inPending) throw new RefNotFoundError(ref);
64
+ pending.set(ref, null);
65
+ },
66
+ commit() {
67
+ if (committed) throw new TransactionError("Transaction already committed");
68
+ committed = true;
69
+ const txSnapshot = freezePending(pending);
70
+ try {
71
+ for (const hook of hooks ?? []) hook.onPrepare?.(txSnapshot);
72
+ db.transaction(() => {
73
+ for (const [ref, content] of pending) if (content === null) {
74
+ if (!snapshot.has(ref) && !selectExistsStmt.get(ref)) throw new RefNotFoundError(ref);
75
+ deleteStmt.run(ref);
76
+ } else insertStmt.run(ref, content);
77
+ })();
78
+ for (const hook of hooks ?? []) hook.onCommitted?.(txSnapshot);
79
+ } catch (e) {
80
+ for (const hook of hooks ?? []) hook.onAborted?.(txSnapshot);
81
+ throw e;
82
+ }
83
+ },
84
+ rollback() {
85
+ if (committed) return;
86
+ committed = true;
87
+ const txSnapshot = freezePending(pending);
88
+ for (const hook of hooks ?? []) hook.onAborted?.(txSnapshot);
89
+ }
90
+ };
91
+ }
92
+ return {
93
+ read(ref) {
94
+ validateRefName(ref);
95
+ return selectStmt.get(ref)?.target ?? null;
96
+ },
97
+ write(ref, content) {
98
+ validateRefName(ref);
99
+ insertStmt.run(ref, content.trimEnd());
100
+ },
101
+ delete(ref) {
102
+ validateRefName(ref);
103
+ if (!selectExistsStmt.get(ref)) throw new RefNotFoundError(ref);
104
+ deleteStmt.run(ref);
105
+ },
106
+ list(prefix) {
107
+ validateRefPrefix(prefix);
108
+ const end = prefix + "";
109
+ return listPrefixStmt.all(prefix, end).map((row) => row.name);
110
+ },
111
+ listAll() {
112
+ return listAllStmt.all().map((row) => row.name);
113
+ },
114
+ beginTransaction
115
+ };
116
+ }
117
+ /**
118
+ * 将 pending Map 冻结为只读快照
119
+ */
120
+ function freezePending(pending) {
121
+ const writes = [];
122
+ const deletes = [];
123
+ for (const [ref, content] of pending) if (content === null) deletes.push({ ref });
124
+ else writes.push({
125
+ ref,
126
+ content
127
+ });
128
+ return Object.freeze({
129
+ pendingCount: pending.size,
130
+ writes: Object.freeze(writes),
131
+ deletes: Object.freeze(deletes)
132
+ });
133
+ }
134
+ //#endregion
135
+ export { createSqliteRefStore };
@@ -0,0 +1,51 @@
1
+ import { RemoteSource } from "./types.mjs";
2
+ import { RefAdvertisement } from "../transport/protocol/types.mjs";
3
+ import { LsRefsEntry, V2CapabilityAdvertisement } from "../transport/client/upload-pack/types.mjs";
4
+ import { LsRefsOptions } from "../transport/client/upload-pack/ls-refs.mjs";
5
+ import { ObjectInfoQueryResult } from "../transport/client/upload-pack/object-info.mjs";
6
+
7
+ //#region src/remote/http.d.ts
8
+ /**
9
+ * 远端 HTTP 查询接口
10
+ */
11
+ interface HttpRemote {
12
+ /** 远端来源配置 */
13
+ readonly source: Readonly<RemoteSource>;
14
+ /** 读取 v2 能力广告 */
15
+ advertise(): Promise<V2CapabilityAdvertisement>;
16
+ /** 原样执行 ls-refs 查询 */
17
+ listRefs(options?: LsRefsOptions): Promise<LsRefsEntry[]>;
18
+ /** 读取适合高层 API 使用的 ref 快照 */
19
+ readRefAdvertisement(): Promise<RefAdvertisement>;
20
+ /** 查询对象元数据(协议 v2 object-info) */
21
+ fetchObjectInfo(oids: string[]): Promise<ObjectInfoQueryResult>;
22
+ }
23
+ /**
24
+ * 创建基于 Smart HTTP 的远端查询对象
25
+ *
26
+ * 适用于只依赖远端 URL / 认证信息的查询,
27
+ * 例如 refs 快照和 object-info,不需要本地 repo 上下文。
28
+ *
29
+ * @param source - 远端来源
30
+ * @returns 远端查询对象
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * import { createHttpRemote } from "nano-git/remote/http";
35
+ *
36
+ * const remote = createHttpRemote({
37
+ * url: "https://github.com/user/repo.git",
38
+ * });
39
+ *
40
+ * const snapshot = await remote.readRefAdvertisement();
41
+ * const info = await remote.fetchObjectInfo([
42
+ * "95d09f2b10159347eece71399a7e2e907ea3df4f",
43
+ * ]);
44
+ *
45
+ * console.log(snapshot.defaultBranch);
46
+ * console.log(info.objects[0]?.size);
47
+ * ```
48
+ */
49
+ declare function createHttpRemote(source: RemoteSource): HttpRemote;
50
+ //#endregion
51
+ export { HttpRemote, createHttpRemote };
@@ -0,0 +1,74 @@
1
+ import { createV2HttpTransport } from "../transport/client/upload-pack/http.mjs";
2
+ import { lsRefs, lsRefsToRefAdvertisement } from "../transport/client/upload-pack/ls-refs.mjs";
3
+ import { objectInfo } from "../transport/client/upload-pack/object-info.mjs";
4
+ //#region src/remote/http.ts
5
+ /**
6
+ * 基于 HTTP 的远端 Git 查询 API
7
+ *
8
+ * 将纯远端查询能力从 Repository 中拆出:
9
+ * - refs 快照
10
+ * - v2 object-info
11
+ * - 协议能力广告
12
+ */
13
+ /**
14
+ * 创建基于 Smart HTTP 的远端查询对象
15
+ *
16
+ * 适用于只依赖远端 URL / 认证信息的查询,
17
+ * 例如 refs 快照和 object-info,不需要本地 repo 上下文。
18
+ *
19
+ * @param source - 远端来源
20
+ * @returns 远端查询对象
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * import { createHttpRemote } from "nano-git/remote/http";
25
+ *
26
+ * const remote = createHttpRemote({
27
+ * url: "https://github.com/user/repo.git",
28
+ * });
29
+ *
30
+ * const snapshot = await remote.readRefAdvertisement();
31
+ * const info = await remote.fetchObjectInfo([
32
+ * "95d09f2b10159347eece71399a7e2e907ea3df4f",
33
+ * ]);
34
+ *
35
+ * console.log(snapshot.defaultBranch);
36
+ * console.log(info.objects[0]?.size);
37
+ * ```
38
+ */
39
+ function createHttpRemote(source) {
40
+ const frozenSource = Object.freeze({
41
+ url: source.url,
42
+ token: source.token,
43
+ headers: source.headers ? Object.freeze({ ...source.headers }) : void 0
44
+ });
45
+ const transport = createV2HttpTransport(frozenSource.url, {
46
+ token: frozenSource.token,
47
+ headers: frozenSource.headers
48
+ });
49
+ return {
50
+ source: frozenSource,
51
+ advertise() {
52
+ return transport.advertise();
53
+ },
54
+ listRefs(options) {
55
+ return lsRefs(transport, options);
56
+ },
57
+ async readRefAdvertisement() {
58
+ return lsRefsToRefAdvertisement(await lsRefs(transport, {
59
+ symrefs: true,
60
+ peel: true,
61
+ refPrefixes: [
62
+ "HEAD",
63
+ "refs/heads/",
64
+ "refs/tags/"
65
+ ]
66
+ }));
67
+ },
68
+ fetchObjectInfo(oids) {
69
+ return objectInfo(transport, oids);
70
+ }
71
+ };
72
+ }
73
+ //#endregion
74
+ export { createHttpRemote };
@@ -0,0 +1,20 @@
1
+ //#region src/remote/types.d.ts
2
+ /**
3
+ * 远端来源类型定义
4
+ *
5
+ * 只描述"从哪里读",不描述"写到哪里"。
6
+ * 可被远端查询 API 与仓库导入 API 共同复用。
7
+ */
8
+ /**
9
+ * 远端 Git 数据来源
10
+ */
11
+ interface RemoteSource {
12
+ /** 远端仓库 URL */
13
+ readonly url: string;
14
+ /** 认证 token(用于 bearer 或 basic auth) */
15
+ readonly token?: string;
16
+ /** 自定义请求头 */
17
+ readonly headers?: Record<string, string>;
18
+ }
19
+ //#endregion
20
+ export { RemoteSource };
@@ -1,21 +1,8 @@
1
1
  import { SHA1 } from "../../core/types.mjs";
2
+ import { RemoteSource } from "../../remote/types.mjs";
2
3
  import { RefAdvertisement, RemoteRef } from "../../transport/protocol/types.mjs";
3
4
 
4
5
  //#region src/repository/import/import-session-types.d.ts
5
- /**
6
- * 远端 Git 数据来源
7
- *
8
- * 只描述"从哪里读",不描述"写到哪里"。
9
- * ImportSource 不包含命名空间映射规则。
10
- */
11
- interface ImportSource {
12
- /** 远端仓库 URL */
13
- readonly url: string;
14
- /** 认证 token(用于 bearer 或 basic auth) */
15
- readonly token?: string;
16
- /** 自定义请求头 */
17
- readonly headers?: Record<string, string>;
18
- }
19
6
  /**
20
7
  * 远端 ref 视图
21
8
  *
@@ -244,7 +231,7 @@ interface ImportApplyResult {
244
231
  * 想刷新远端状态时,必须重新创建 session。
245
232
  */
246
233
  interface ImportSession {
247
- readonly source: ImportSource;
234
+ readonly source: RemoteSource;
248
235
  readonly advertisement: RefAdvertisement;
249
236
  select(pattern: string): ImportView;
250
237
  selectRefs(patterns: readonly string[]): ImportView;
@@ -274,7 +261,7 @@ interface RepoImportOperations {
274
261
  * const branches = session.select("refs/heads/*");
275
262
  * ```
276
263
  */
277
- openImportSession(source: ImportSource): Promise<ImportSession>;
264
+ openImportSession(source: RemoteSource): Promise<ImportSession>;
278
265
  }
279
266
  //#endregion
280
267
  export { RepoImportOperations };
@@ -1,7 +1,5 @@
1
1
  import { hashObject } from "../../core/hash-digest.mjs";
2
2
  import { readObject, writeObject } from "../../objects/raw.mjs";
3
- import { createV2HttpTransport } from "../../transport/client/upload-pack/http.mjs";
4
- import { objectInfo } from "../../transport/client/upload-pack/object-info.mjs";
5
3
  import { patchTree } from "../tree/tree-patch.mjs";
6
4
  //#region src/repository/ops/object-operations.ts
7
5
  /**
@@ -55,9 +53,6 @@ function createObjectRepositoryOperations(objects) {
55
53
  },
56
54
  patchTree(rootHash, ops) {
57
55
  return patchTree(objects, rootHash, ops);
58
- },
59
- async fetchObjectInfo(url, oids, token) {
60
- return objectInfo(createV2HttpTransport(url, { token }), oids);
61
56
  }
62
57
  };
63
58
  }
@@ -1,5 +1,4 @@
1
1
  import { GitAuthor, GitObject, SHA1, TreeEntry } from "../../core/types.mjs";
2
- import { ObjectInfoQueryResult } from "../../transport/client/upload-pack/object-info.mjs";
3
2
  import { TreePatchOp, TreePatchResult } from "../tree/tree-patch.mjs";
4
3
 
5
4
  //#region src/repository/ops/object-types.d.ts
@@ -67,26 +66,6 @@ interface RepositoryObjectOperations {
67
66
  * ```
68
67
  */
69
68
  patchTree(rootHash: SHA1, ops: TreePatchOp[]): TreePatchResult;
70
- /**
71
- * 查询远端对象信息(协议 v2 object-info)
72
- *
73
- * 批量查询远端对象的元数据(如 size),无需下载对象内容。
74
- * 仅在远端支持 Git Wire 协议 v2 时可用。
75
- *
76
- * @param url - 远端仓库 URL
77
- * @param oids - 要查询的 OID 列表
78
- * @param token - 可选认证 token
79
- * @returns 对象信息列表(含 size 等元数据)
80
- *
81
- * @example
82
- * ```ts
83
- * const result = await repo.fetchObjectInfo("https://github.com/user/repo", [
84
- * "95d09f2b10159347eece71399a7e2e907ea3df4f",
85
- * ]);
86
- * console.log(result.objects[0]?.size); // 文件大小
87
- * ```
88
- */
89
- fetchObjectInfo(url: string, oids: string[], token?: string): Promise<ObjectInfoQueryResult>;
90
69
  }
91
70
  /**
92
71
  * 文件系统对象操作扩展
@@ -0,0 +1,28 @@
1
+ import { CreateSqliteRepositoryBackendOptions } from "../backend/sqlite.mjs";
2
+ import { Repository } from "./types.mjs";
3
+
4
+ //#region src/repository/sqlite.d.ts
5
+ /**
6
+ * 创建基于 SQLite 文件的持久化仓库
7
+ *
8
+ * 相比直接使用 createSqliteRepositoryBackend + createRepository,
9
+ * 此函数提供了更简洁的一步到位接口。
10
+ *
11
+ * @param dbPath - SQLite 数据库文件路径
12
+ * @param options - 可选参数(如 walMode)
13
+ * @returns 仓库实例(附带 [Symbol.dispose](),可用 `using` 管理)
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * // 使用 using 自动释放(推荐)
18
+ * using repo = createSqliteRepository("/tmp/repo.sqlite");
19
+ * repo.createBranch("main", repo.createTree([]));
20
+ * repo.writeBlob(Buffer.from("data"));
21
+ * // 作用域结束时自动关闭数据库连接
22
+ * ```
23
+ */
24
+ declare function createSqliteRepository(dbPath: string, options?: CreateSqliteRepositoryBackendOptions): Repository & {
25
+ [Symbol.dispose](): void;
26
+ };
27
+ //#endregion
28
+ export { createSqliteRepository };
@@ -0,0 +1,45 @@
1
+ import { createSqliteRepositoryBackend } from "../backend/sqlite.mjs";
2
+ import { createRepository } from "./create.mjs";
3
+ //#region src/repository/sqlite.ts
4
+ /**
5
+ * SQLite 仓库便捷创建函数
6
+ *
7
+ * 一键创建基于 SQLite 的持久化 Git 仓库。
8
+ * 内部组合 createSqliteRepositoryBackend + createRepository,
9
+ * 返回的 repo 自带 [Symbol.dispose](),可用 `using` 管理生命周期。
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { createSqliteRepository } from "nano-git/repository/sqlite";
14
+ *
15
+ * using repo = createSqliteRepository("/tmp/cache.sqlite");
16
+ * const hash = repo.writeBlob(Buffer.from("hello world"));
17
+ * // 作用域结束时自动 db.close()
18
+ * ```
19
+ */
20
+ /**
21
+ * 创建基于 SQLite 文件的持久化仓库
22
+ *
23
+ * 相比直接使用 createSqliteRepositoryBackend + createRepository,
24
+ * 此函数提供了更简洁的一步到位接口。
25
+ *
26
+ * @param dbPath - SQLite 数据库文件路径
27
+ * @param options - 可选参数(如 walMode)
28
+ * @returns 仓库实例(附带 [Symbol.dispose](),可用 `using` 管理)
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * // 使用 using 自动释放(推荐)
33
+ * using repo = createSqliteRepository("/tmp/repo.sqlite");
34
+ * repo.createBranch("main", repo.createTree([]));
35
+ * repo.writeBlob(Buffer.from("data"));
36
+ * // 作用域结束时自动关闭数据库连接
37
+ * ```
38
+ */
39
+ function createSqliteRepository(dbPath, options) {
40
+ const backend = createSqliteRepositoryBackend(dbPath, options);
41
+ const repo = createRepository(backend);
42
+ return Object.assign(repo, { [Symbol.dispose]: () => backend[Symbol.dispose]() });
43
+ }
44
+ //#endregion
45
+ export { createSqliteRepository };
@@ -1,7 +1,7 @@
1
1
  import { LsRefsEntry, ObjectInfoEntry, ObjectInfoResponse, V2CapabilityAdvertisement, V2CommandEntry, V2FetchRequest, V2FetchResponse, V2GitServiceTransport } from "./client/upload-pack/types.mjs";
2
+ import { LsRefsError, LsRefsOptions, lsRefs, lsRefsToRefAdvertisement, parseLsRefsResponse } from "./client/upload-pack/ls-refs.mjs";
2
3
  import { ObjectInfoError, ObjectInfoQueryResult, ObjectInfoResult, objectInfo, parseObjectInfoResponse } from "./client/upload-pack/object-info.mjs";
3
4
  import { V2CapabilityError, getCommandFeatures, hasCommand, parseV2CapabilityAdvertisement } from "./client/upload-pack/capability-advertisement.mjs";
4
5
  import { V2SmartHttpError, createV2HttpTransport } from "./client/upload-pack/http.mjs";
5
- import { LsRefsError, LsRefsOptions, lsRefs, lsRefsToRefAdvertisement, parseLsRefsResponse } from "./client/upload-pack/ls-refs.mjs";
6
6
  import { V2FetchError, V2FetchParams, parseV2FetchResponse, v2Fetch, v2FetchObjects } from "./client/upload-pack/fetch.mjs";
7
7
  export { type LsRefsEntry, LsRefsError, type LsRefsOptions, type ObjectInfoEntry, ObjectInfoError, type ObjectInfoQueryResult, type ObjectInfoResponse, type ObjectInfoResult, type V2CapabilityAdvertisement, V2CapabilityError, type V2CommandEntry, V2FetchError, type V2FetchParams, type V2FetchRequest, type V2FetchResponse, type V2GitServiceTransport, V2SmartHttpError, createV2HttpTransport, getCommandFeatures, hasCommand, lsRefs, lsRefsToRefAdvertisement, objectInfo, parseLsRefsResponse, parseObjectInfoResponse, parseV2CapabilityAdvertisement, parseV2FetchResponse, v2Fetch, v2FetchObjects };
@@ -1,6 +1,6 @@
1
1
  import { V2CapabilityError, getCommandFeatures, hasCommand, parseV2CapabilityAdvertisement } from "./client/upload-pack/capability-advertisement.mjs";
2
2
  import { V2SmartHttpError, createV2HttpTransport } from "./client/upload-pack/http.mjs";
3
3
  import { LsRefsError, lsRefs, lsRefsToRefAdvertisement, parseLsRefsResponse } from "./client/upload-pack/ls-refs.mjs";
4
- import { V2FetchError, parseV2FetchResponse, v2Fetch, v2FetchObjects } from "./client/upload-pack/fetch.mjs";
5
4
  import { ObjectInfoError, objectInfo, parseObjectInfoResponse } from "./client/upload-pack/object-info.mjs";
5
+ import { V2FetchError, parseV2FetchResponse, v2Fetch, v2FetchObjects } from "./client/upload-pack/fetch.mjs";
6
6
  export { LsRefsError, ObjectInfoError, V2CapabilityError, V2FetchError, V2SmartHttpError, createV2HttpTransport, getCommandFeatures, hasCommand, lsRefs, lsRefsToRefAdvertisement, objectInfo, parseLsRefsResponse, parseObjectInfoResponse, parseV2CapabilityAdvertisement, parseV2FetchResponse, v2Fetch, v2FetchObjects };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nano-git",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -11,11 +11,13 @@
11
11
  "./backend": "./src/backend/index.ts",
12
12
  "./backend/file": "./src/backend/file.ts",
13
13
  "./backend/memory": "./src/backend/memory.ts",
14
+ "./backend/sqlite": "./src/backend/sqlite.ts",
14
15
  "./errors": "./src/errors.ts",
15
16
  "./hash-file": "./src/hash-file.ts",
16
17
  "./objects": "./src/objects/index.ts",
17
18
  "./odb/file": "./src/odb/file.ts",
18
19
  "./odb/memory": "./src/odb/memory.ts",
20
+ "./odb/sqlite": "./src/odb/sqlite.ts",
19
21
  "./pack": "./src/pack/index.ts",
20
22
  "./refs/file": "./src/refs/file.ts",
21
23
  "./refs/memory": "./src/refs/memory.ts",
@@ -23,9 +25,13 @@
23
25
  "./refs/resolve": "./src/refs/resolve.ts",
24
26
  "./refs/shallow/file": "./src/refs/shallow/file.ts",
25
27
  "./refs/shallow/memory": "./src/refs/shallow/memory.ts",
28
+ "./refs/shallow/sqlite": "./src/refs/shallow/sqlite.ts",
29
+ "./refs/sqlite": "./src/refs/sqlite.ts",
30
+ "./remote/http": "./src/remote/http.ts",
26
31
  "./repository/core": "./src/repository/core.ts",
27
32
  "./repository/file": "./src/repository/file.ts",
28
33
  "./repository/memory": "./src/repository/memory.ts",
34
+ "./repository/sqlite": "./src/repository/sqlite.ts",
29
35
  "./repository/tree/tree-patch": "./src/repository/tree/tree-patch.ts",
30
36
  "./repository/tree/tree-walk": "./src/repository/tree/tree-walk.ts",
31
37
  "./sha1": "./src/sha1.ts",
@@ -42,11 +48,13 @@
42
48
  "./backend": "./dist/backend/index.mjs",
43
49
  "./backend/file": "./dist/backend/file.mjs",
44
50
  "./backend/memory": "./dist/backend/memory.mjs",
51
+ "./backend/sqlite": "./dist/backend/sqlite.mjs",
45
52
  "./errors": "./dist/errors.mjs",
46
53
  "./hash-file": "./dist/hash-file.mjs",
47
54
  "./objects": "./dist/objects/index.mjs",
48
55
  "./odb/file": "./dist/odb/file.mjs",
49
56
  "./odb/memory": "./dist/odb/memory.mjs",
57
+ "./odb/sqlite": "./dist/odb/sqlite.mjs",
50
58
  "./pack": "./dist/pack/index.mjs",
51
59
  "./refs/file": "./dist/refs/file.mjs",
52
60
  "./refs/memory": "./dist/refs/memory.mjs",
@@ -54,9 +62,13 @@
54
62
  "./refs/resolve": "./dist/refs/resolve.mjs",
55
63
  "./refs/shallow/file": "./dist/refs/shallow/file.mjs",
56
64
  "./refs/shallow/memory": "./dist/refs/shallow/memory.mjs",
65
+ "./refs/shallow/sqlite": "./dist/refs/shallow/sqlite.mjs",
66
+ "./refs/sqlite": "./dist/refs/sqlite.mjs",
67
+ "./remote/http": "./dist/remote/http.mjs",
57
68
  "./repository/core": "./dist/repository/core.mjs",
58
69
  "./repository/file": "./dist/repository/file.mjs",
59
70
  "./repository/memory": "./dist/repository/memory.mjs",
71
+ "./repository/sqlite": "./dist/repository/sqlite.mjs",
60
72
  "./repository/tree/tree-patch": "./dist/repository/tree/tree-patch.mjs",
61
73
  "./repository/tree/tree-walk": "./dist/repository/tree/tree-walk.mjs",
62
74
  "./sha1": "./dist/sha1.mjs",