nano-git 0.1.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 +407 -0
- package/dist/backend/file-backend.d.mts +26 -0
- package/dist/backend/file-backend.mjs +83 -0
- package/dist/backend/file.d.mts +2 -0
- package/dist/backend/file.mjs +2 -0
- package/dist/backend/index.d.mts +2 -0
- package/dist/backend/index.mjs +1 -0
- package/dist/backend/memory-backend.d.mts +25 -0
- package/dist/backend/memory-backend.mjs +33 -0
- package/dist/backend/memory.d.mts +2 -0
- package/dist/backend/memory.mjs +2 -0
- package/dist/backend/types.d.mts +90 -0
- package/dist/core/errors.d.mts +124 -0
- package/dist/core/errors.mjs +168 -0
- package/dist/core/hash-digest.d.mts +35 -0
- package/dist/core/hash-digest.mjs +50 -0
- package/dist/core/hash-file.d.mts +20 -0
- package/dist/core/hash-file.mjs +27 -0
- package/dist/core/hash-path.d.mts +17 -0
- package/dist/core/hash-path.mjs +35 -0
- package/dist/core/types/odb.d.mts +63 -0
- package/dist/core/types/refs.d.mts +140 -0
- package/dist/core/types/refs.mjs +19 -0
- package/dist/core/types/shallow.d.mts +52 -0
- package/dist/core/types.d.mts +154 -0
- package/dist/core/types.mjs +43 -0
- package/dist/errors.d.mts +2 -0
- package/dist/errors.mjs +2 -0
- package/dist/hash-file.d.mts +2 -0
- package/dist/hash-file.mjs +2 -0
- package/dist/index.d.mts +16 -0
- package/dist/index.mjs +14 -0
- package/dist/objects/author.d.mts +25 -0
- package/dist/objects/author.mjs +45 -0
- package/dist/objects/blob.d.mts +15 -0
- package/dist/objects/blob.mjs +20 -0
- package/dist/objects/codec.d.mts +46 -0
- package/dist/objects/codec.mjs +84 -0
- package/dist/objects/commit.d.mts +26 -0
- package/dist/objects/commit.mjs +160 -0
- package/dist/objects/index.d.mts +8 -0
- package/dist/objects/index.mjs +8 -0
- package/dist/objects/raw.d.mts +85 -0
- package/dist/objects/raw.mjs +111 -0
- package/dist/objects/tag.d.mts +26 -0
- package/dist/objects/tag.mjs +148 -0
- package/dist/objects/tree.d.mts +22 -0
- package/dist/objects/tree.mjs +66 -0
- package/dist/odb/file-utils.mjs +136 -0
- package/dist/odb/file.d.mts +22 -0
- package/dist/odb/file.mjs +66 -0
- package/dist/odb/memory.d.mts +22 -0
- package/dist/odb/memory.mjs +54 -0
- package/dist/pack/composite-store.d.mts +76 -0
- package/dist/pack/composite-store.mjs +133 -0
- package/dist/pack/constants.mjs +48 -0
- package/dist/pack/crc32.mjs +38 -0
- package/dist/pack/delta-apply.d.mts +21 -0
- package/dist/pack/delta-apply.mjs +71 -0
- package/dist/pack/delta-create.d.mts +28 -0
- package/dist/pack/delta-create.mjs +151 -0
- package/dist/pack/index.d.mts +16 -0
- package/dist/pack/index.mjs +13 -0
- package/dist/pack/object-header.d.mts +36 -0
- package/dist/pack/object-header.mjs +72 -0
- package/dist/pack/ofs-delta-offset.d.mts +35 -0
- package/dist/pack/ofs-delta-offset.mjs +59 -0
- package/dist/pack/pack-builder-types.d.mts +19 -0
- package/dist/pack/pack-builder.d.mts +52 -0
- package/dist/pack/pack-builder.mjs +80 -0
- package/dist/pack/pack-encoding.mjs +76 -0
- package/dist/pack/pack-index-reader.d.mts +57 -0
- package/dist/pack/pack-index-reader.mjs +90 -0
- package/dist/pack/pack-index-types.d.mts +16 -0
- package/dist/pack/pack-index-writer.d.mts +45 -0
- package/dist/pack/pack-index-writer.mjs +106 -0
- package/dist/pack/pack-reader-resolver.mjs +104 -0
- package/dist/pack/pack-reader-types.d.mts +31 -0
- package/dist/pack/pack-reader-types.mjs +22 -0
- package/dist/pack/pack-reader-utils.mjs +61 -0
- package/dist/pack/pack-reader.d.mts +81 -0
- package/dist/pack/pack-reader.mjs +171 -0
- package/dist/pack/pack-store-loader.mjs +79 -0
- package/dist/pack/pack-store-types.d.mts +16 -0
- package/dist/pack/pack-store.d.mts +55 -0
- package/dist/pack/pack-store.mjs +114 -0
- package/dist/pack/pack-writer.mjs +96 -0
- package/dist/pack/varint.d.mts +34 -0
- package/dist/pack/varint.mjs +57 -0
- package/dist/refs/file.d.mts +6 -0
- package/dist/refs/file.mjs +222 -0
- package/dist/refs/fs-utils.mjs +30 -0
- package/dist/refs/memory.d.mts +14 -0
- package/dist/refs/memory.mjs +104 -0
- package/dist/refs/names.d.mts +57 -0
- package/dist/refs/names.mjs +80 -0
- package/dist/refs/resolve.d.mts +33 -0
- package/dist/refs/resolve.mjs +55 -0
- package/dist/refs/shallow/file.d.mts +17 -0
- package/dist/refs/shallow/file.mjs +61 -0
- package/dist/refs/shallow/memory.d.mts +18 -0
- package/dist/refs/shallow/memory.mjs +33 -0
- package/dist/repository/core.d.mts +3 -0
- package/dist/repository/core.mjs +2 -0
- package/dist/repository/create.d.mts +22 -0
- package/dist/repository/create.mjs +43 -0
- package/dist/repository/file.d.mts +43 -0
- package/dist/repository/file.mjs +82 -0
- package/dist/repository/import/import-glob.mjs +44 -0
- package/dist/repository/import/import-plan-builder.mjs +625 -0
- package/dist/repository/import/import-session-types.d.mts +280 -0
- package/dist/repository/import/import-session.mjs +96 -0
- package/dist/repository/import/import-view.mjs +133 -0
- package/dist/repository/memory.d.mts +17 -0
- package/dist/repository/memory.mjs +33 -0
- package/dist/repository/ops/fetch-operations.mjs +20 -0
- package/dist/repository/ops/fetch-types.d.mts +82 -0
- package/dist/repository/ops/fetch-url.mjs +82 -0
- package/dist/repository/ops/fs-object-operations.mjs +31 -0
- package/dist/repository/ops/maintenance-operations.mjs +62 -0
- package/dist/repository/ops/maintenance-types.d.mts +42 -0
- package/dist/repository/ops/object-operations.mjs +65 -0
- package/dist/repository/ops/object-types.d.mts +109 -0
- package/dist/repository/ops/push-operations.mjs +16 -0
- package/dist/repository/ops/push-resolution.mjs +17 -0
- package/dist/repository/ops/push-types.d.mts +72 -0
- package/dist/repository/ops/push-url.mjs +45 -0
- package/dist/repository/ops/reachability.mjs +60 -0
- package/dist/repository/ops/ref-operations.mjs +86 -0
- package/dist/repository/ops/ref-types.d.mts +70 -0
- package/dist/repository/tree/tree-patch.d.mts +64 -0
- package/dist/repository/tree/tree-patch.mjs +268 -0
- package/dist/repository/tree/tree-walk.d.mts +46 -0
- package/dist/repository/tree/tree-walk.mjs +65 -0
- package/dist/repository/tree/tree-writer.mjs +68 -0
- package/dist/repository/types.d.mts +36 -0
- package/dist/sha1.d.mts +4 -0
- package/dist/sha1.mjs +4 -0
- package/dist/transport/client/receive-pack/http.d.mts +33 -0
- package/dist/transport/client/receive-pack/http.mjs +99 -0
- package/dist/transport/client/receive-pack/push-error.d.mts +23 -0
- package/dist/transport/client/receive-pack/push-error.mjs +32 -0
- package/dist/transport/client/receive-pack/push-pack-plan.d.mts +28 -0
- package/dist/transport/client/receive-pack/push-pack-plan.mjs +60 -0
- package/dist/transport/client/receive-pack/push-policy.d.mts +19 -0
- package/dist/transport/client/receive-pack/push-policy.mjs +64 -0
- package/dist/transport/client/receive-pack/push-ref-plan.d.mts +45 -0
- package/dist/transport/client/receive-pack/push-ref-plan.mjs +108 -0
- package/dist/transport/client/receive-pack/push-report.d.mts +28 -0
- package/dist/transport/client/receive-pack/push-report.mjs +84 -0
- package/dist/transport/client/receive-pack/push-request-plan.mjs +52 -0
- package/dist/transport/client/receive-pack/push.d.mts +32 -0
- package/dist/transport/client/receive-pack/push.mjs +97 -0
- package/dist/transport/client/receive-pack/request.d.mts +39 -0
- package/dist/transport/client/receive-pack/request.mjs +46 -0
- package/dist/transport/client/receive-pack/response.d.mts +26 -0
- package/dist/transport/client/receive-pack/response.mjs +52 -0
- package/dist/transport/client/receive-pack/result.d.mts +34 -0
- package/dist/transport/client/receive-pack/result.mjs +100 -0
- package/dist/transport/client/upload-pack/capability-advertisement.d.mts +56 -0
- package/dist/transport/client/upload-pack/capability-advertisement.mjs +130 -0
- package/dist/transport/client/upload-pack/fetch.d.mts +109 -0
- package/dist/transport/client/upload-pack/fetch.mjs +392 -0
- package/dist/transport/client/upload-pack/http.d.mts +29 -0
- package/dist/transport/client/upload-pack/http.mjs +79 -0
- package/dist/transport/client/upload-pack/ls-refs.d.mts +75 -0
- package/dist/transport/client/upload-pack/ls-refs.mjs +150 -0
- package/dist/transport/client/upload-pack/object-info.d.mts +65 -0
- package/dist/transport/client/upload-pack/object-info.mjs +111 -0
- package/dist/transport/client/upload-pack/types.d.mts +153 -0
- package/dist/transport/http/index.d.mts +3 -0
- package/dist/transport/http/index.mjs +2 -0
- package/dist/transport/http/smart-http.d.mts +46 -0
- package/dist/transport/http/smart-http.mjs +176 -0
- package/dist/transport/http/types.d.mts +27 -0
- package/dist/transport/index.d.mts +9 -0
- package/dist/transport/index.mjs +8 -0
- package/dist/transport/protocol/object-graph.d.mts +63 -0
- package/dist/transport/protocol/object-graph.mjs +149 -0
- package/dist/transport/protocol/pkt-line.d.mts +109 -0
- package/dist/transport/protocol/pkt-line.mjs +195 -0
- package/dist/transport/protocol/ref-advertisement.mjs +185 -0
- package/dist/transport/protocol/ref-collection.d.mts +38 -0
- package/dist/transport/protocol/ref-collection.mjs +63 -0
- package/dist/transport/protocol/ref-match.d.mts +39 -0
- package/dist/transport/protocol/ref-match.mjs +42 -0
- package/dist/transport/protocol/refspec.d.mts +44 -0
- package/dist/transport/protocol/refspec.mjs +79 -0
- package/dist/transport/protocol/side-band.d.mts +65 -0
- package/dist/transport/protocol/side-band.mjs +142 -0
- package/dist/transport/protocol/transport-capabilities.mjs +46 -0
- package/dist/transport/protocol/types.d.mts +148 -0
- package/dist/transport/protocol/update-refs.d.mts +68 -0
- package/dist/transport/protocol/update-refs.mjs +126 -0
- package/dist/transport/receive-pack.d.mts +11 -0
- package/dist/transport/receive-pack.mjs +11 -0
- package/dist/transport/server/receive-pack/advertise.d.mts +28 -0
- package/dist/transport/server/receive-pack/advertise.mjs +88 -0
- package/dist/transport/server/receive-pack/handler.d.mts +30 -0
- package/dist/transport/server/receive-pack/handler.mjs +156 -0
- package/dist/transport/server/receive-pack/index.d.mts +6 -0
- package/dist/transport/server/receive-pack/index.mjs +6 -0
- package/dist/transport/server/receive-pack/parse.d.mts +17 -0
- package/dist/transport/server/receive-pack/parse.mjs +80 -0
- package/dist/transport/server/receive-pack/report-status.mjs +64 -0
- package/dist/transport/server/receive-pack/service.d.mts +41 -0
- package/dist/transport/server/receive-pack/service.mjs +39 -0
- package/dist/transport/server/receive-pack/types.d.mts +56 -0
- package/dist/transport/server/receive-pack/types.mjs +25 -0
- package/dist/transport/server/receive-pack/unpack.mjs +119 -0
- package/dist/transport/server/upload-pack/advertise.d.mts +20 -0
- package/dist/transport/server/upload-pack/advertise.mjs +30 -0
- package/dist/transport/server/upload-pack/command.d.mts +43 -0
- package/dist/transport/server/upload-pack/command.mjs +56 -0
- package/dist/transport/server/upload-pack/fetch.d.mts +43 -0
- package/dist/transport/server/upload-pack/fetch.mjs +217 -0
- package/dist/transport/server/upload-pack/index.d.mts +7 -0
- package/dist/transport/server/upload-pack/index.mjs +7 -0
- package/dist/transport/server/upload-pack/ls-refs.d.mts +38 -0
- package/dist/transport/server/upload-pack/ls-refs.mjs +113 -0
- package/dist/transport/server/upload-pack/service.d.mts +40 -0
- package/dist/transport/server/upload-pack/service.mjs +51 -0
- package/dist/transport/server/upload-pack/types.d.mts +11 -0
- package/dist/transport/server/upload-pack/types.mjs +21 -0
- package/dist/transport/upload-pack.d.mts +7 -0
- package/dist/transport/upload-pack.mjs +6 -0
- package/package.json +98 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { GitError } from "../../../core/errors.mjs";
|
|
2
|
+
import { sha1 } from "../../../core/types.mjs";
|
|
3
|
+
import { parsePktLines } from "../../protocol/pkt-line.mjs";
|
|
4
|
+
//#region src/transport/client/upload-pack/ls-refs.ts
|
|
5
|
+
/**
|
|
6
|
+
* v2 ls-refs 命令
|
|
7
|
+
*
|
|
8
|
+
* 在 Git Wire 协议 v2 中,ls-refs 替代了 v1 的 ref advertisement。
|
|
9
|
+
* 服务端通过独立的 `ls-refs` 命令返回引用列表。
|
|
10
|
+
*
|
|
11
|
+
* 请求格式:
|
|
12
|
+
* ```
|
|
13
|
+
* command=ls-refs\n
|
|
14
|
+
* agent=nano-git/0.1\n
|
|
15
|
+
* 0001
|
|
16
|
+
* symrefs\n
|
|
17
|
+
* peel\n
|
|
18
|
+
* ref-prefix refs/heads/\n
|
|
19
|
+
* 0000
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* 响应格式:
|
|
23
|
+
* ```
|
|
24
|
+
* <oid> <refname>[ <attr>...]\n
|
|
25
|
+
* ...
|
|
26
|
+
* 0000
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @see https://git-scm.com/docs/protocol-v2#_ls_refs
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* ls-refs 命令错误
|
|
33
|
+
*/
|
|
34
|
+
var LsRefsError = class extends GitError {
|
|
35
|
+
constructor(message) {
|
|
36
|
+
super(`ls-refs error: ${message}`);
|
|
37
|
+
this.name = "LsRefsError";
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* 执行 ls-refs 命令
|
|
42
|
+
*
|
|
43
|
+
* @param transport - v2 传输接口
|
|
44
|
+
* @param options - ls-refs 请求选项
|
|
45
|
+
* @returns 解析后的 ref 条目列表
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* const entries = await lsRefs(transport, {
|
|
50
|
+
* symrefs: true,
|
|
51
|
+
* peel: true,
|
|
52
|
+
* refPrefixes: ["refs/heads/"],
|
|
53
|
+
* });
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
async function lsRefs(transport, options) {
|
|
57
|
+
const args = [];
|
|
58
|
+
if (options?.symrefs) args.push("symrefs");
|
|
59
|
+
if (options?.peel) args.push("peel");
|
|
60
|
+
if (options?.unborn) args.push("unborn");
|
|
61
|
+
if (options?.refPrefixes) for (const prefix of options.refPrefixes) args.push(`ref-prefix ${prefix}`);
|
|
62
|
+
return parseLsRefsResponse(await transport.command("ls-refs", args));
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* 解析 ls-refs 响应
|
|
66
|
+
*
|
|
67
|
+
* 从原始 Buffer 中解析 ls-refs 条目。
|
|
68
|
+
*
|
|
69
|
+
* @param data - ls-refs 命令的原始响应数据
|
|
70
|
+
* @returns 解析后的 ref 条目列表
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* const entries = parseLsRefsResponse(response);
|
|
75
|
+
* console.log(entries[0].refname); // "refs/heads/main"
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
function parseLsRefsResponse(data) {
|
|
79
|
+
const lines = parsePktLines(data);
|
|
80
|
+
const entries = [];
|
|
81
|
+
for (const line of lines) {
|
|
82
|
+
if (line.type !== "data") continue;
|
|
83
|
+
const text = line.payload.toString("utf-8").trim();
|
|
84
|
+
if (text.length === 0) continue;
|
|
85
|
+
const spaceIdx = text.indexOf(" ");
|
|
86
|
+
if (spaceIdx === -1) continue;
|
|
87
|
+
const oid = text.substring(0, spaceIdx);
|
|
88
|
+
const parts = text.substring(spaceIdx + 1).trim().split(" ");
|
|
89
|
+
const entry = {
|
|
90
|
+
oid,
|
|
91
|
+
refname: parts[0]
|
|
92
|
+
};
|
|
93
|
+
for (let i = 1; i < parts.length; i++) {
|
|
94
|
+
const attr = parts[i];
|
|
95
|
+
if (attr.startsWith("symref-target:")) entry.symrefTarget = attr.substring(14);
|
|
96
|
+
else if (attr.startsWith("peeled:")) entry.peeled = attr.substring(7);
|
|
97
|
+
}
|
|
98
|
+
entries.push(entry);
|
|
99
|
+
}
|
|
100
|
+
return entries;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 将 v2 ls-refs 结果转换为 v1 兼容的 RefAdvertisement
|
|
104
|
+
*
|
|
105
|
+
* 用于 ImportSession 的透明升级:v2 获取 refs 后,
|
|
106
|
+
* 包装为 v1 的 RefAdvertisement 格式,使上游代码无需改动。
|
|
107
|
+
*
|
|
108
|
+
* @param entries - ls-refs 返回的 ref 条目
|
|
109
|
+
* @returns v1 兼容的 RefAdvertisement
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```ts
|
|
113
|
+
* const entries = await lsRefs(transport);
|
|
114
|
+
* const adv = lsRefsToRefAdvertisement(entries);
|
|
115
|
+
* // 可传递给 ImportSession
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
function lsRefsToRefAdvertisement(entries) {
|
|
119
|
+
const refs = [];
|
|
120
|
+
let defaultBranch;
|
|
121
|
+
const peeledMap = /* @__PURE__ */ new Map();
|
|
122
|
+
for (const entry of entries) if (entry.peeled) {
|
|
123
|
+
const baseName = entry.refname.endsWith("^{}") ? entry.refname.slice(0, -3) : entry.refname;
|
|
124
|
+
peeledMap.set(baseName, entry.peeled);
|
|
125
|
+
}
|
|
126
|
+
for (const entry of entries) {
|
|
127
|
+
if (entry.oid === "unborn") continue;
|
|
128
|
+
if (entry.refname.endsWith("^{}")) continue;
|
|
129
|
+
const ref = {
|
|
130
|
+
hash: sha1(entry.oid),
|
|
131
|
+
name: entry.refname
|
|
132
|
+
};
|
|
133
|
+
if (entry.symrefTarget) ref.symrefTarget = entry.symrefTarget;
|
|
134
|
+
const peeled = peeledMap.get(entry.refname);
|
|
135
|
+
if (peeled) ref.peeled = sha1(peeled);
|
|
136
|
+
refs.push(ref);
|
|
137
|
+
if (entry.refname === "HEAD" && entry.symrefTarget) defaultBranch = entry.symrefTarget;
|
|
138
|
+
}
|
|
139
|
+
if (!defaultBranch && refs.length > 0) {
|
|
140
|
+
const mainBranch = refs.find((r) => r.name === "refs/heads/main" || r.name === "refs/heads/master");
|
|
141
|
+
if (mainBranch) defaultBranch = mainBranch.name;
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
capabilities: {},
|
|
145
|
+
refs,
|
|
146
|
+
defaultBranch
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
//#endregion
|
|
150
|
+
export { LsRefsError, lsRefs, lsRefsToRefAdvertisement, parseLsRefsResponse };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { GitError } from "../../../core/errors.mjs";
|
|
2
|
+
import { V2GitServiceTransport } from "./types.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/transport/client/upload-pack/object-info.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* object-info 命令错误
|
|
7
|
+
*/
|
|
8
|
+
declare class ObjectInfoError extends GitError {
|
|
9
|
+
constructor(message: string);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* object-info 查询结果条目
|
|
13
|
+
*/
|
|
14
|
+
interface ObjectInfoResult {
|
|
15
|
+
readonly oid: string;
|
|
16
|
+
readonly size?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* object-info 查询响应
|
|
20
|
+
*/
|
|
21
|
+
interface ObjectInfoQueryResult {
|
|
22
|
+
readonly attrs: string[];
|
|
23
|
+
readonly objects: ObjectInfoResult[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 执行 object-info 命令
|
|
27
|
+
*
|
|
28
|
+
* 批量查询远端对象的元数据(如 size),无需下载对象内容。
|
|
29
|
+
*
|
|
30
|
+
* @param transport - v2 传输接口
|
|
31
|
+
* @param oids - 要查询的 OID 列表
|
|
32
|
+
* @returns 查询结果
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* const result = await objectInfo(transport, [
|
|
37
|
+
* "95d09f2b10159347eece71399a7e2e907ea3df4f",
|
|
38
|
+
* ]);
|
|
39
|
+
* console.log(result.objects[0]?.size); // 文件大小(字节)
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
declare function objectInfo(transport: V2GitServiceTransport, oids: string[]): Promise<ObjectInfoQueryResult>;
|
|
43
|
+
/**
|
|
44
|
+
* 解析 object-info 响应
|
|
45
|
+
*
|
|
46
|
+
* 格式:
|
|
47
|
+
* ```
|
|
48
|
+
* size\n
|
|
49
|
+
* <oid1> <size1>\n
|
|
50
|
+
* <oid2> <size2>\n
|
|
51
|
+
* 0000
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* @param data - 原始响应数据
|
|
55
|
+
* @returns 解析后的查询结果
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* const result = parseObjectInfoResponse(response);
|
|
60
|
+
* console.log(result.attrs); // ["size"]
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
declare function parseObjectInfoResponse(data: Buffer): ObjectInfoQueryResult;
|
|
64
|
+
//#endregion
|
|
65
|
+
export { ObjectInfoError, ObjectInfoQueryResult, ObjectInfoResult, objectInfo, parseObjectInfoResponse };
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { GitError } from "../../../core/errors.mjs";
|
|
2
|
+
import { parsePktLines } from "../../protocol/pkt-line.mjs";
|
|
3
|
+
//#region src/transport/client/upload-pack/object-info.ts
|
|
4
|
+
/**
|
|
5
|
+
* v2 object-info 命令
|
|
6
|
+
*
|
|
7
|
+
* 在 Git Wire 协议 v2 中,object-info 命令用于批量查询对象信息(如 size),
|
|
8
|
+
* 而不需要实际获取对象内容。主要用于 partial clone 场景。
|
|
9
|
+
*
|
|
10
|
+
* 请求格式:
|
|
11
|
+
* ```
|
|
12
|
+
* command=object-info\n
|
|
13
|
+
* 0001
|
|
14
|
+
* size\n
|
|
15
|
+
* oid <oid1>\n
|
|
16
|
+
* oid <oid2>\n
|
|
17
|
+
* 0000
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* 响应格式:
|
|
21
|
+
* ```
|
|
22
|
+
* size\n
|
|
23
|
+
* <oid1> <size1>\n
|
|
24
|
+
* <oid2> <size2>\n
|
|
25
|
+
* 0000
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @see https://git-scm.com/docs/protocol-v2#_object_info
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* object-info 命令错误
|
|
32
|
+
*/
|
|
33
|
+
var ObjectInfoError = class extends GitError {
|
|
34
|
+
constructor(message) {
|
|
35
|
+
super(`object-info error: ${message}`);
|
|
36
|
+
this.name = "ObjectInfoError";
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* 执行 object-info 命令
|
|
41
|
+
*
|
|
42
|
+
* 批量查询远端对象的元数据(如 size),无需下载对象内容。
|
|
43
|
+
*
|
|
44
|
+
* @param transport - v2 传输接口
|
|
45
|
+
* @param oids - 要查询的 OID 列表
|
|
46
|
+
* @returns 查询结果
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* const result = await objectInfo(transport, [
|
|
51
|
+
* "95d09f2b10159347eece71399a7e2e907ea3df4f",
|
|
52
|
+
* ]);
|
|
53
|
+
* console.log(result.objects[0]?.size); // 文件大小(字节)
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
async function objectInfo(transport, oids) {
|
|
57
|
+
if (oids.length === 0) throw new ObjectInfoError("No OIDs specified for object-info");
|
|
58
|
+
const args = ["size"];
|
|
59
|
+
for (const oid of oids) args.push(`oid ${oid}`);
|
|
60
|
+
return parseObjectInfoResponse(await transport.command("object-info", args));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 解析 object-info 响应
|
|
64
|
+
*
|
|
65
|
+
* 格式:
|
|
66
|
+
* ```
|
|
67
|
+
* size\n
|
|
68
|
+
* <oid1> <size1>\n
|
|
69
|
+
* <oid2> <size2>\n
|
|
70
|
+
* 0000
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* @param data - 原始响应数据
|
|
74
|
+
* @returns 解析后的查询结果
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* const result = parseObjectInfoResponse(response);
|
|
79
|
+
* console.log(result.attrs); // ["size"]
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
function parseObjectInfoResponse(data) {
|
|
83
|
+
const pktLines = parsePktLines(data);
|
|
84
|
+
const objects = [];
|
|
85
|
+
let attrs = [];
|
|
86
|
+
for (const line of pktLines) {
|
|
87
|
+
if (line.type !== "data") continue;
|
|
88
|
+
const text = line.payload.toString("utf-8").trim();
|
|
89
|
+
if (text.length === 0) continue;
|
|
90
|
+
if (attrs.length === 0) {
|
|
91
|
+
attrs = text.split(" ");
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const spaceIdx = text.indexOf(" ");
|
|
95
|
+
if (spaceIdx === -1) objects.push({ oid: text });
|
|
96
|
+
else {
|
|
97
|
+
const oid = text.substring(0, spaceIdx);
|
|
98
|
+
const sizeStr = text.substring(spaceIdx + 1).trim();
|
|
99
|
+
objects.push({
|
|
100
|
+
oid,
|
|
101
|
+
size: parseInt(sizeStr, 10)
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
attrs,
|
|
107
|
+
objects
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
//#endregion
|
|
111
|
+
export { ObjectInfoError, objectInfo, parseObjectInfoResponse };
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
//#region src/transport/client/upload-pack/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Git Wire 协议 v2 类型定义
|
|
4
|
+
*
|
|
5
|
+
* 定义了协议 v2 特有的类型:能力广告、命令式传输接口等。
|
|
6
|
+
* 协议无关的共享类型见 protocol/types.ts。
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* v2 能力广告中的单个命令条目
|
|
10
|
+
*
|
|
11
|
+
* 表示服务端广告的 v2 命令及附加特性。
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const cmd: V2CommandEntry = {
|
|
16
|
+
* name: "fetch",
|
|
17
|
+
* features: ["shallow", "ref-in-want"],
|
|
18
|
+
* };
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
interface V2CommandEntry {
|
|
22
|
+
/** 命令名称,如 "ls-refs"、"fetch"、"push"、"object-info" */
|
|
23
|
+
readonly name: string;
|
|
24
|
+
/** 命令附加特性列表(在 capability 值中声明) */
|
|
25
|
+
readonly features: string[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* v2 能力广告(服务端响应)
|
|
29
|
+
*
|
|
30
|
+
* 对应协议 v2 的能力广告格式:
|
|
31
|
+
* ```
|
|
32
|
+
* version 2\n
|
|
33
|
+
* ls-refs\n
|
|
34
|
+
* fetch=shallow ref-in-want\n
|
|
35
|
+
* push\n
|
|
36
|
+
* object-info\n
|
|
37
|
+
* agent=nano-git/0.1\n
|
|
38
|
+
* 0000
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
interface V2CapabilityAdvertisement {
|
|
42
|
+
/** 服务端能力键值对 */
|
|
43
|
+
readonly capabilities: Record<string, string | true>;
|
|
44
|
+
/** 服务端支持的 v2 命令列表 */
|
|
45
|
+
readonly commands: V2CommandEntry[];
|
|
46
|
+
/** 服务端 agent 字符串 */
|
|
47
|
+
readonly agent?: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* v2 Git 服务传输接口
|
|
51
|
+
*
|
|
52
|
+
* 与 v1 的 GitServiceTransport 不同,v2 是命令式的。
|
|
53
|
+
* - advertise() 只返回能力广告,不含 refs
|
|
54
|
+
* - command() 发送单个命令并返回原始响应
|
|
55
|
+
*/
|
|
56
|
+
interface V2GitServiceTransport {
|
|
57
|
+
/** 获取能力广告 */
|
|
58
|
+
advertise(): Promise<V2CapabilityAdvertisement>;
|
|
59
|
+
/**
|
|
60
|
+
* 执行 v2 命令
|
|
61
|
+
*
|
|
62
|
+
* @param command - 命令名称,如 "ls-refs"、"fetch"
|
|
63
|
+
* @param args - 命令参数列表
|
|
64
|
+
* @param capabilities - 本次请求携带的能力列表(不含 agent)
|
|
65
|
+
* @param body - 额外的原始 body 数据(如 push 的 packfile)
|
|
66
|
+
*/
|
|
67
|
+
command(command: string, args?: string[], capabilities?: string[], body?: Buffer): Promise<Buffer>;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* ls-refs 输出条目
|
|
71
|
+
*
|
|
72
|
+
* 对应 v2 ls-refs 响应中的单行 ref。
|
|
73
|
+
* ```
|
|
74
|
+
* <obj-id> SP <refname> [SP <ref-attribute> ...] LF
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
interface LsRefsEntry {
|
|
78
|
+
/** 对象哈希,unborn 分支时为 "unborn" */
|
|
79
|
+
readonly oid: string;
|
|
80
|
+
/** 引用全名 */
|
|
81
|
+
readonly refname: string;
|
|
82
|
+
/** 符号引用目标(如有) */
|
|
83
|
+
readonly symrefTarget?: string;
|
|
84
|
+
/** peeled 对象哈希(如有) */
|
|
85
|
+
readonly peeled?: string;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* v2 fetch 请求参数
|
|
89
|
+
*/
|
|
90
|
+
interface V2FetchRequest {
|
|
91
|
+
readonly wants: string[];
|
|
92
|
+
readonly haves?: string[];
|
|
93
|
+
readonly done?: boolean;
|
|
94
|
+
readonly wantRefs?: string[];
|
|
95
|
+
readonly thinPack?: boolean;
|
|
96
|
+
readonly noProgress?: boolean;
|
|
97
|
+
readonly includeTag?: boolean;
|
|
98
|
+
readonly ofsDelta?: boolean;
|
|
99
|
+
readonly shallow?: string[];
|
|
100
|
+
readonly deepen?: number;
|
|
101
|
+
readonly deepenRelative?: boolean;
|
|
102
|
+
readonly deepenSince?: number;
|
|
103
|
+
readonly deepenNot?: string[];
|
|
104
|
+
readonly filter?: string;
|
|
105
|
+
readonly sidebandAll?: boolean;
|
|
106
|
+
readonly waitForDone?: boolean;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* v2 fetch 响应
|
|
110
|
+
*
|
|
111
|
+
* 响应包含多个由 delimiter (0001) 分隔的节。
|
|
112
|
+
*/
|
|
113
|
+
interface V2FetchResponse {
|
|
114
|
+
/** acknowledgments 节 */
|
|
115
|
+
readonly acknowledgments?: {
|
|
116
|
+
readonly nak?: boolean;
|
|
117
|
+
readonly acks: string[];
|
|
118
|
+
readonly ready?: boolean;
|
|
119
|
+
};
|
|
120
|
+
/** shallow-info 节 */
|
|
121
|
+
readonly shallowInfo?: {
|
|
122
|
+
readonly shallow: string[];
|
|
123
|
+
readonly unshallow: string[];
|
|
124
|
+
};
|
|
125
|
+
/** wanted-refs 节 */
|
|
126
|
+
readonly wantedRefs?: Array<{
|
|
127
|
+
oid: string;
|
|
128
|
+
refname: string;
|
|
129
|
+
}>;
|
|
130
|
+
/** packfile-uris 节 */
|
|
131
|
+
readonly packfileUris?: Array<{
|
|
132
|
+
oid: string;
|
|
133
|
+
uri: string;
|
|
134
|
+
}>;
|
|
135
|
+
/** 原始 packfile buffer */
|
|
136
|
+
readonly packfile?: Buffer;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* object-info 结果条目
|
|
140
|
+
*/
|
|
141
|
+
interface ObjectInfoEntry {
|
|
142
|
+
readonly oid: string;
|
|
143
|
+
readonly size?: number;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* object-info 响应
|
|
147
|
+
*/
|
|
148
|
+
interface ObjectInfoResponse {
|
|
149
|
+
readonly attrs: string[];
|
|
150
|
+
readonly objects: ObjectInfoEntry[];
|
|
151
|
+
}
|
|
152
|
+
//#endregion
|
|
153
|
+
export { LsRefsEntry, ObjectInfoEntry, ObjectInfoResponse, V2CapabilityAdvertisement, V2CommandEntry, V2FetchRequest, V2FetchResponse, V2GitServiceTransport };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { RepositoryBackend } from "../../backend/types.mjs";
|
|
2
|
+
import { SmartHttpHandler } from "./types.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/transport/http/smart-http.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* 创建 Smart HTTP 处理函数
|
|
7
|
+
*
|
|
8
|
+
* 类似 git-http-backend 的核心入口。
|
|
9
|
+
* 接收标准 Request,返回标准 Response,框架无关。
|
|
10
|
+
*
|
|
11
|
+
* @param backend - 仓库后端
|
|
12
|
+
* @returns HTTP 处理函数
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* // Bun.serve — 直接作为 fetch 处理器
|
|
17
|
+
* import { createSmartHttpHandler } from "nano-git/transport/http";
|
|
18
|
+
* import { openRepository } from "nano-git/repository/file";
|
|
19
|
+
* Bun.serve({ port: 8080, fetch: createSmartHttpHandler(openRepository("/repo")) });
|
|
20
|
+
*
|
|
21
|
+
* // Node.js http
|
|
22
|
+
* import { createServer } from "node:http";
|
|
23
|
+
* const handler = createSmartHttpHandler(openRepository("/repo"));
|
|
24
|
+
* createServer(async (req, res) => {
|
|
25
|
+
* const url = new URL(req.url ?? "/", `http://${req.headers.host}`);
|
|
26
|
+
* const body = await new Promise<Buffer>((resolve) => {
|
|
27
|
+
* const chunks: Buffer[] = [];
|
|
28
|
+
* req.on("data", (c) => chunks.push(c));
|
|
29
|
+
* req.on("end", () => resolve(Buffer.concat(chunks)));
|
|
30
|
+
* });
|
|
31
|
+
* const response = await handler(new Request(url, {
|
|
32
|
+
* method: req.method,
|
|
33
|
+
* headers: Object.fromEntries(Object.entries(req.headers).map(([k, v]) => [k, String(v)])),
|
|
34
|
+
* body: req.method === "POST" ? body : undefined,
|
|
35
|
+
* }));
|
|
36
|
+
* res.writeHead(response.status, Object.fromEntries(response.headers));
|
|
37
|
+
* res.end(Buffer.from(await response.arrayBuffer()));
|
|
38
|
+
* }).listen(8080);
|
|
39
|
+
*
|
|
40
|
+
* // Cloudflare Workers / Deno
|
|
41
|
+
* export default { fetch: createSmartHttpHandler(openRepository("./repo")) };
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
declare function createSmartHttpHandler(backend: RepositoryBackend): SmartHttpHandler;
|
|
45
|
+
//#endregion
|
|
46
|
+
export { createSmartHttpHandler };
|