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,109 @@
|
|
|
1
|
+
import { ObjectDatabase } from "../../../core/types/odb.mjs";
|
|
2
|
+
import { GitError } from "../../../core/errors.mjs";
|
|
3
|
+
import { V2FetchResponse, V2GitServiceTransport } from "./types.mjs";
|
|
4
|
+
|
|
5
|
+
//#region src/transport/client/upload-pack/fetch.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* v2 fetch 命令错误
|
|
8
|
+
*/
|
|
9
|
+
declare class V2FetchError extends GitError {
|
|
10
|
+
constructor(message: string);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* v2 fetch 参数
|
|
14
|
+
*
|
|
15
|
+
* 对应 git protocol v2 fetch 命令的 arguments 段参数。
|
|
16
|
+
*/
|
|
17
|
+
interface V2FetchParams {
|
|
18
|
+
/** want 列表(对象哈希) */
|
|
19
|
+
readonly wants: string[];
|
|
20
|
+
/** have 列表(对象哈希) */
|
|
21
|
+
readonly haves?: string[];
|
|
22
|
+
/** 是否发送 done(结束协商,直接要求 packfile) */
|
|
23
|
+
readonly done?: boolean;
|
|
24
|
+
/** want-ref 列表(按 ref 名请求) */
|
|
25
|
+
readonly wantRefs?: string[];
|
|
26
|
+
/** 是否请求 thin-pack */
|
|
27
|
+
readonly thinPack?: boolean;
|
|
28
|
+
/** 是否禁用进度消息 */
|
|
29
|
+
readonly noProgress?: boolean;
|
|
30
|
+
/** 是否请求 include-tag */
|
|
31
|
+
readonly includeTag?: boolean;
|
|
32
|
+
/** 是否支持 ofs-delta */
|
|
33
|
+
readonly ofsDelta?: boolean;
|
|
34
|
+
/** shallow 边界 */
|
|
35
|
+
readonly shallow?: string[];
|
|
36
|
+
/** deepen 深度 */
|
|
37
|
+
readonly deepen?: number;
|
|
38
|
+
/** deepen-relative 标志 */
|
|
39
|
+
readonly deepenRelative?: boolean;
|
|
40
|
+
/** deepen-since 时间戳 */
|
|
41
|
+
readonly deepenSince?: number;
|
|
42
|
+
/** deepen-not 排除 */
|
|
43
|
+
readonly deepenNot?: string[];
|
|
44
|
+
/** filter 表达式 */
|
|
45
|
+
readonly filter?: string;
|
|
46
|
+
/** sideband-all 标志 */
|
|
47
|
+
readonly sidebandAll?: boolean;
|
|
48
|
+
/** wait-for-done 标志 */
|
|
49
|
+
readonly waitForDone?: boolean;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 执行 v2 fetch 命令
|
|
53
|
+
*
|
|
54
|
+
* 构建并发送 fetch 请求,返回解析后的完整响应。
|
|
55
|
+
*
|
|
56
|
+
* @param transport - v2 传输接口
|
|
57
|
+
* @param params - fetch 参数
|
|
58
|
+
* @param features - 服务端 fetch 命令支持的附加特性
|
|
59
|
+
* @returns 解析后的 fetch 响应
|
|
60
|
+
* @throws {V2FetchError} 当 wants 为空时
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* const result = await v2Fetch(transport, {
|
|
65
|
+
* wants: [hash1, hash2],
|
|
66
|
+
* ofsDelta: true,
|
|
67
|
+
* done: true,
|
|
68
|
+
* });
|
|
69
|
+
* console.log(result.packfile?.length); // packfile 数据长度
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
declare function v2Fetch(transport: V2GitServiceTransport, params: V2FetchParams, features?: string[]): Promise<V2FetchResponse>;
|
|
73
|
+
/**
|
|
74
|
+
* 解析 v2 fetch 响应
|
|
75
|
+
*
|
|
76
|
+
* v2 fetch 响应由多个节组成,节之间由 delimiter (0001) 分隔。
|
|
77
|
+
* 每个节以节头(如 "acknowledgments")开始。
|
|
78
|
+
*
|
|
79
|
+
* @param data - 原始响应数据
|
|
80
|
+
* @param hasDone - 请求中是否包含 done
|
|
81
|
+
* @param sidebandAll - 是否协商了 sideband-all
|
|
82
|
+
* @returns 解析后的 fetch 响应
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```ts
|
|
86
|
+
* const result = parseV2FetchResponse(responseData, true, false);
|
|
87
|
+
* if (result.packfile) {
|
|
88
|
+
* // 处理 packfile
|
|
89
|
+
* }
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
declare function parseV2FetchResponse(data: Buffer, _hasDone: boolean, sidebandAll: boolean): V2FetchResponse;
|
|
93
|
+
/**
|
|
94
|
+
* 使用 v2 fetch 获取对象并写入对象存储
|
|
95
|
+
*
|
|
96
|
+
* 模拟 v1 fetchPack() 的语义,使 import-plan-builder 可无缝切换。
|
|
97
|
+
*
|
|
98
|
+
* @param store - 对象存储(用于写入 packfile 中的对象)
|
|
99
|
+
* @param v2Trans - v2 传输接口
|
|
100
|
+
* @param wants - want 对象哈希列表
|
|
101
|
+
* @param haves - have 对象哈希列表
|
|
102
|
+
* @param features - 服务端 fetch 命令特性
|
|
103
|
+
* @returns 导入的对象数量
|
|
104
|
+
*/
|
|
105
|
+
declare function v2FetchObjects(db: ObjectDatabase, v2Trans: V2GitServiceTransport, wants: string[], haves?: string[], features?: string[]): Promise<{
|
|
106
|
+
objectCount: number;
|
|
107
|
+
}>;
|
|
108
|
+
//#endregion
|
|
109
|
+
export { V2FetchError, V2FetchParams, parseV2FetchResponse, v2Fetch, v2FetchObjects };
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import { GitError } from "../../../core/errors.mjs";
|
|
2
|
+
import { packObjectToRaw } from "../../../pack/pack-reader-types.mjs";
|
|
3
|
+
import { createPackReader } from "../../../pack/pack-reader.mjs";
|
|
4
|
+
import { splitPktLinesFromBuffer } from "../../protocol/pkt-line.mjs";
|
|
5
|
+
//#region src/transport/client/upload-pack/fetch.ts
|
|
6
|
+
/**
|
|
7
|
+
* v2 fetch 命令
|
|
8
|
+
*
|
|
9
|
+
* 在 Git Wire 协议 v2 中,fetch 替代了 v1 的 upload-pack 协商 + packfile 传输。
|
|
10
|
+
* 支持 want/have/done、want-ref、shallow、thin-pack 等参数。
|
|
11
|
+
*
|
|
12
|
+
* 请求格式:
|
|
13
|
+
* ```
|
|
14
|
+
* command=fetch\n
|
|
15
|
+
* agent=nano-git/0.1\n
|
|
16
|
+
* ofs-delta\n
|
|
17
|
+
* include-tag\n
|
|
18
|
+
* 0001
|
|
19
|
+
* want <oid>\n
|
|
20
|
+
* have <oid>\n
|
|
21
|
+
* done\n
|
|
22
|
+
* 0000
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* 响应格式(节之间由 0001 分隔):
|
|
26
|
+
* ```
|
|
27
|
+
* acknowledgments\n
|
|
28
|
+
* NAK\n (或 ACK <oid>\n ... ready\n)
|
|
29
|
+
* 0001
|
|
30
|
+
* shallow-info\n
|
|
31
|
+
* shallow <oid>\n
|
|
32
|
+
* 0001
|
|
33
|
+
* wanted-refs\n
|
|
34
|
+
* <oid> <refname>\n
|
|
35
|
+
* 0001
|
|
36
|
+
* packfile\n
|
|
37
|
+
* [side-band 多路复用数据]
|
|
38
|
+
* 0000
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @see https://git-scm.com/docs/protocol-v2#_fetch
|
|
42
|
+
*/
|
|
43
|
+
/**
|
|
44
|
+
* v2 fetch 命令错误
|
|
45
|
+
*/
|
|
46
|
+
var V2FetchError = class extends GitError {
|
|
47
|
+
constructor(message) {
|
|
48
|
+
super(`v2 fetch error: ${message}`);
|
|
49
|
+
this.name = "V2FetchError";
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
/** 单轮最多发送的 have 数量 */
|
|
53
|
+
const MAX_HAVES_PER_ROUND = 32;
|
|
54
|
+
/** 侧信道通道编号 */
|
|
55
|
+
const CHANNEL_PACKFILE = 1;
|
|
56
|
+
/**
|
|
57
|
+
* 执行 v2 fetch 命令
|
|
58
|
+
*
|
|
59
|
+
* 构建并发送 fetch 请求,返回解析后的完整响应。
|
|
60
|
+
*
|
|
61
|
+
* @param transport - v2 传输接口
|
|
62
|
+
* @param params - fetch 参数
|
|
63
|
+
* @param features - 服务端 fetch 命令支持的附加特性
|
|
64
|
+
* @returns 解析后的 fetch 响应
|
|
65
|
+
* @throws {V2FetchError} 当 wants 为空时
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* const result = await v2Fetch(transport, {
|
|
70
|
+
* wants: [hash1, hash2],
|
|
71
|
+
* ofsDelta: true,
|
|
72
|
+
* done: true,
|
|
73
|
+
* });
|
|
74
|
+
* console.log(result.packfile?.length); // packfile 数据长度
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
async function v2Fetch(transport, params, features) {
|
|
78
|
+
if (params.wants.length === 0) throw new V2FetchError("No wants specified for fetch");
|
|
79
|
+
const hasFeature = (name) => features !== void 0 && features.includes(name);
|
|
80
|
+
const args = [];
|
|
81
|
+
if (params.thinPack) args.push("thin-pack");
|
|
82
|
+
if (params.noProgress) args.push("no-progress");
|
|
83
|
+
if (params.includeTag) args.push("include-tag");
|
|
84
|
+
if (params.ofsDelta) args.push("ofs-delta");
|
|
85
|
+
if (params.sidebandAll) args.push("sideband-all");
|
|
86
|
+
if (params.waitForDone) args.push("wait-for-done");
|
|
87
|
+
for (const oid of params.wants) args.push(`want ${oid}`);
|
|
88
|
+
if (params.wantRefs && hasFeature("ref-in-want")) for (const ref of params.wantRefs) args.push(`want-ref ${ref}`);
|
|
89
|
+
if (params.done) args.push("done");
|
|
90
|
+
if (!params.done && params.haves) for (const oid of params.haves) args.push(`have ${oid}`);
|
|
91
|
+
if (params.shallow && hasFeature("shallow")) for (const oid of params.shallow) args.push(`shallow ${oid}`);
|
|
92
|
+
if (params.deepen !== void 0 && hasFeature("shallow")) args.push(`deepen ${params.deepen}`);
|
|
93
|
+
if (params.deepenRelative && hasFeature("shallow")) args.push("deepen-relative");
|
|
94
|
+
if (params.deepenSince !== void 0 && hasFeature("shallow")) args.push(`deepen-since ${params.deepenSince}`);
|
|
95
|
+
if (params.deepenNot && hasFeature("shallow")) for (const rev of params.deepenNot) args.push(`deepen-not ${rev}`);
|
|
96
|
+
if (params.filter && hasFeature("filter")) args.push(`filter ${params.filter}`);
|
|
97
|
+
return parseV2FetchResponse(await transport.command("fetch", args, []), params.done ?? false, hasFeature("sideband-all"));
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* 解析 v2 fetch 响应
|
|
101
|
+
*
|
|
102
|
+
* v2 fetch 响应由多个节组成,节之间由 delimiter (0001) 分隔。
|
|
103
|
+
* 每个节以节头(如 "acknowledgments")开始。
|
|
104
|
+
*
|
|
105
|
+
* @param data - 原始响应数据
|
|
106
|
+
* @param hasDone - 请求中是否包含 done
|
|
107
|
+
* @param sidebandAll - 是否协商了 sideband-all
|
|
108
|
+
* @returns 解析后的 fetch 响应
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* const result = parseV2FetchResponse(responseData, true, false);
|
|
113
|
+
* if (result.packfile) {
|
|
114
|
+
* // 处理 packfile
|
|
115
|
+
* }
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
function parseV2FetchResponse(data, _hasDone, sidebandAll) {
|
|
119
|
+
const { lines: pktLines, trailing } = splitPktLinesFromBuffer(data);
|
|
120
|
+
if (sidebandAll && pktLines.length > 0) {
|
|
121
|
+
const first = pktLines[0];
|
|
122
|
+
if (first?.type === "data" && first.payload.length > 1) {
|
|
123
|
+
const withoutChannel = Buffer.concat(pktLines.filter((p) => p.type === "data").map((p) => p.payload.subarray(1)));
|
|
124
|
+
return parseV2FetchResponse(Buffer.concat([withoutChannel, trailing]), false, false);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const sections = [];
|
|
128
|
+
let currentSection = null;
|
|
129
|
+
const packfileFrames = [];
|
|
130
|
+
let inPackfile = false;
|
|
131
|
+
for (const pkt of pktLines) {
|
|
132
|
+
if (pkt.type === "flush") break;
|
|
133
|
+
if (pkt.type === "delimiter") {
|
|
134
|
+
currentSection = null;
|
|
135
|
+
inPackfile = false;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (pkt.type !== "data") continue;
|
|
139
|
+
const payload = pkt.payload;
|
|
140
|
+
const text = payload.toString("utf-8");
|
|
141
|
+
const trimmed = text.replace(/\n$/, "");
|
|
142
|
+
if (currentSection === null && !inPackfile) {
|
|
143
|
+
currentSection = {
|
|
144
|
+
header: trimmed,
|
|
145
|
+
lines: []
|
|
146
|
+
};
|
|
147
|
+
sections.push(currentSection);
|
|
148
|
+
if (trimmed === "packfile") {
|
|
149
|
+
inPackfile = true;
|
|
150
|
+
const headerEndIndex = text.indexOf("\n") + 1;
|
|
151
|
+
if (headerEndIndex > 0 && headerEndIndex < payload.length) packfileFrames.push(payload.subarray(headerEndIndex));
|
|
152
|
+
}
|
|
153
|
+
} else if (inPackfile) packfileFrames.push(payload);
|
|
154
|
+
else if (currentSection) currentSection.lines.push(payload);
|
|
155
|
+
}
|
|
156
|
+
if (trailing.length > 0) packfileFrames.push(trailing);
|
|
157
|
+
const result = {};
|
|
158
|
+
for (const section of sections) switch (section.header) {
|
|
159
|
+
case "acknowledgments":
|
|
160
|
+
result.acknowledgments = parseAcknowledgments(section.lines);
|
|
161
|
+
break;
|
|
162
|
+
case "shallow-info":
|
|
163
|
+
result.shallowInfo = parseShallowInfo(section.lines);
|
|
164
|
+
break;
|
|
165
|
+
case "wanted-refs":
|
|
166
|
+
result.wantedRefs = parseWantedRefs(section.lines);
|
|
167
|
+
break;
|
|
168
|
+
case "packfile-uris":
|
|
169
|
+
result.packfileUris = parsePackfileUris(section.lines);
|
|
170
|
+
break;
|
|
171
|
+
case "packfile":
|
|
172
|
+
if (packfileFrames.length > 0) result.packfile = extractPackfileFromFrames(packfileFrames);
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
return result;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* 解析 acknowledgments 节
|
|
179
|
+
*
|
|
180
|
+
* ```
|
|
181
|
+
* acknowledgments\n
|
|
182
|
+
* NAK\n
|
|
183
|
+
* --- 或 ---
|
|
184
|
+
* ACK <oid>\n
|
|
185
|
+
* ACK <oid>\n
|
|
186
|
+
* ready\n
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
function parseAcknowledgments(lines) {
|
|
190
|
+
const acks = [];
|
|
191
|
+
let nak = false;
|
|
192
|
+
let ready = false;
|
|
193
|
+
for (const line of lines) {
|
|
194
|
+
const text = line.toString("utf-8").trim();
|
|
195
|
+
if (text === "NAK") nak = true;
|
|
196
|
+
else if (text === "ready") ready = true;
|
|
197
|
+
else if (text.startsWith("ACK ")) acks.push(text.substring(4).trim());
|
|
198
|
+
}
|
|
199
|
+
return {
|
|
200
|
+
nak,
|
|
201
|
+
acks,
|
|
202
|
+
ready
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* 解析 shallow-info 节
|
|
207
|
+
*
|
|
208
|
+
* ```
|
|
209
|
+
* shallow-info\n
|
|
210
|
+
* shallow <oid>\n
|
|
211
|
+
* unshallow <oid>\n
|
|
212
|
+
* ```
|
|
213
|
+
*/
|
|
214
|
+
function parseShallowInfo(lines) {
|
|
215
|
+
const shallow = [];
|
|
216
|
+
const unshallow = [];
|
|
217
|
+
for (const line of lines) {
|
|
218
|
+
const text = line.toString("utf-8").trim();
|
|
219
|
+
if (text.startsWith("shallow ")) shallow.push(text.substring(8).trim());
|
|
220
|
+
else if (text.startsWith("unshallow ")) unshallow.push(text.substring(10).trim());
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
shallow,
|
|
224
|
+
unshallow
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* 解析 wanted-refs 节
|
|
229
|
+
*
|
|
230
|
+
* ```
|
|
231
|
+
* wanted-refs\n
|
|
232
|
+
* <oid> <refname>\n
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
function parseWantedRefs(lines) {
|
|
236
|
+
const refs = [];
|
|
237
|
+
for (const line of lines) {
|
|
238
|
+
const text = line.toString("utf-8").trim();
|
|
239
|
+
if (text.length === 0) continue;
|
|
240
|
+
const spaceIdx = text.indexOf(" ");
|
|
241
|
+
if (spaceIdx === -1) continue;
|
|
242
|
+
refs.push({
|
|
243
|
+
oid: text.substring(0, spaceIdx),
|
|
244
|
+
refname: text.substring(spaceIdx + 1).trim()
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
return refs;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* 解析 packfile-uris 节
|
|
251
|
+
*
|
|
252
|
+
* ```
|
|
253
|
+
* packfile-uris\n
|
|
254
|
+
* <oid> <uri>\n
|
|
255
|
+
* ```
|
|
256
|
+
*/
|
|
257
|
+
function parsePackfileUris(lines) {
|
|
258
|
+
const uris = [];
|
|
259
|
+
for (const line of lines) {
|
|
260
|
+
const text = line.toString("utf-8").trim();
|
|
261
|
+
if (text.length === 0) continue;
|
|
262
|
+
const spaceIdx = text.indexOf(" ");
|
|
263
|
+
if (spaceIdx === -1) continue;
|
|
264
|
+
uris.push({
|
|
265
|
+
oid: text.substring(0, spaceIdx),
|
|
266
|
+
uri: text.substring(spaceIdx + 1).trim()
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
return uris;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* 从 side-band pkt-line payload 帧中提取 packfile 数据
|
|
273
|
+
*
|
|
274
|
+
* v2 fetch 响应中 packfile 节的每个 pkt-line payload 格式为:
|
|
275
|
+
* <1-byte-channel><data>
|
|
276
|
+
* channel 1 = packfile 数据
|
|
277
|
+
* channel 2 = 进度消息
|
|
278
|
+
* channel 3 = 致命错误
|
|
279
|
+
*
|
|
280
|
+
* @param frames - pkt-line payload 数组(不含长度前缀,含 channel 字节)
|
|
281
|
+
* @returns 拼接后的完整 packfile buffer
|
|
282
|
+
*/
|
|
283
|
+
function extractPackfileFromFrames(frames) {
|
|
284
|
+
const chunks = [];
|
|
285
|
+
for (const frame of frames) {
|
|
286
|
+
if (frame.length < 1) continue;
|
|
287
|
+
if (frame[0] === CHANNEL_PACKFILE) chunks.push(frame.subarray(1));
|
|
288
|
+
}
|
|
289
|
+
if (chunks.length === 0) throw new V2FetchError("No packfile data found in fetch response");
|
|
290
|
+
return Buffer.concat(chunks);
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* 执行 v2 多轮 fetch 协商
|
|
294
|
+
*
|
|
295
|
+
* v2 的 fetch 协商与 v1 类似,但使用不同的请求/响应格式。
|
|
296
|
+
* 多轮协商中,中间轮以 flush 结尾(不含 done),
|
|
297
|
+
* 最终轮以 done 结尾。
|
|
298
|
+
*
|
|
299
|
+
* @param transport - v2 传输接口
|
|
300
|
+
* @param wants - want 列表
|
|
301
|
+
* @param haveCandidates - have 候选列表(按时间从旧到新排序)
|
|
302
|
+
* @param features - 服务端 fetch 命令特性
|
|
303
|
+
* @returns fetch 响应(含 packfile)
|
|
304
|
+
*/
|
|
305
|
+
async function negotiateV2Fetch(transport, wants, haveCandidates, features) {
|
|
306
|
+
if (wants.length === 0) throw new V2FetchError("No wants specified for fetch");
|
|
307
|
+
if (haveCandidates.length === 0) return v2Fetch(transport, {
|
|
308
|
+
wants,
|
|
309
|
+
ofsDelta: true,
|
|
310
|
+
done: true
|
|
311
|
+
}, features);
|
|
312
|
+
const state = {
|
|
313
|
+
sent: /* @__PURE__ */ new Set(),
|
|
314
|
+
candidates: haveCandidates,
|
|
315
|
+
offset: 0,
|
|
316
|
+
common: []
|
|
317
|
+
};
|
|
318
|
+
const MAX_ROUNDS = 10;
|
|
319
|
+
for (let round = 0; round < MAX_ROUNDS; round++) {
|
|
320
|
+
const roundHaves = [];
|
|
321
|
+
for (const c of state.common) if (!state.sent.has(c)) {
|
|
322
|
+
roundHaves.push(c);
|
|
323
|
+
state.sent.add(c);
|
|
324
|
+
}
|
|
325
|
+
let remaining = MAX_HAVES_PER_ROUND - roundHaves.length;
|
|
326
|
+
while (remaining > 0 && state.offset < state.candidates.length) {
|
|
327
|
+
const candidate = state.candidates[state.offset];
|
|
328
|
+
state.offset++;
|
|
329
|
+
if (!state.sent.has(candidate)) {
|
|
330
|
+
roundHaves.push(candidate);
|
|
331
|
+
state.sent.add(candidate);
|
|
332
|
+
remaining--;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
const isFinalRound = roundHaves.length === 0 || round === MAX_ROUNDS - 1;
|
|
336
|
+
const response = await v2Fetch(transport, {
|
|
337
|
+
wants,
|
|
338
|
+
haves: roundHaves,
|
|
339
|
+
ofsDelta: true
|
|
340
|
+
}, features);
|
|
341
|
+
const ack = response.acknowledgments;
|
|
342
|
+
if (!ack) {
|
|
343
|
+
if (response.packfile) return response;
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
if (ack.acks.length > 0) {
|
|
347
|
+
for (const ackOid of ack.acks) if (!state.common.includes(ackOid)) state.common.push(ackOid);
|
|
348
|
+
}
|
|
349
|
+
if (ack.ready) return v2Fetch(transport, {
|
|
350
|
+
wants,
|
|
351
|
+
haves: roundHaves,
|
|
352
|
+
ofsDelta: true,
|
|
353
|
+
done: true
|
|
354
|
+
}, features);
|
|
355
|
+
if (isFinalRound) return v2Fetch(transport, {
|
|
356
|
+
wants,
|
|
357
|
+
haves: roundHaves,
|
|
358
|
+
ofsDelta: true,
|
|
359
|
+
done: true
|
|
360
|
+
}, features);
|
|
361
|
+
}
|
|
362
|
+
return v2Fetch(transport, {
|
|
363
|
+
wants,
|
|
364
|
+
ofsDelta: true,
|
|
365
|
+
done: true
|
|
366
|
+
}, features);
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* 使用 v2 fetch 获取对象并写入对象存储
|
|
370
|
+
*
|
|
371
|
+
* 模拟 v1 fetchPack() 的语义,使 import-plan-builder 可无缝切换。
|
|
372
|
+
*
|
|
373
|
+
* @param store - 对象存储(用于写入 packfile 中的对象)
|
|
374
|
+
* @param v2Trans - v2 传输接口
|
|
375
|
+
* @param wants - want 对象哈希列表
|
|
376
|
+
* @param haves - have 对象哈希列表
|
|
377
|
+
* @param features - 服务端 fetch 命令特性
|
|
378
|
+
* @returns 导入的对象数量
|
|
379
|
+
*/
|
|
380
|
+
async function v2FetchObjects(db, v2Trans, wants, haves, features) {
|
|
381
|
+
const result = await negotiateV2Fetch(v2Trans, wants, haves ?? [], features);
|
|
382
|
+
if (!result.packfile || result.packfile.length === 0) return { objectCount: 0 };
|
|
383
|
+
const reader = createPackReader(result.packfile);
|
|
384
|
+
let count = 0;
|
|
385
|
+
for (const packObj of reader.objects()) {
|
|
386
|
+
db.ingest(packObjectToRaw(packObj));
|
|
387
|
+
count++;
|
|
388
|
+
}
|
|
389
|
+
return { objectCount: count };
|
|
390
|
+
}
|
|
391
|
+
//#endregion
|
|
392
|
+
export { V2FetchError, parseV2FetchResponse, v2Fetch, v2FetchObjects };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { V2GitServiceTransport } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/transport/client/upload-pack/http.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* v2 HTTP 传输错误
|
|
6
|
+
*/
|
|
7
|
+
declare class V2SmartHttpError extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 创建 v2 HTTP 传输适配器
|
|
12
|
+
*
|
|
13
|
+
* @param url - 远端仓库 URL
|
|
14
|
+
* @param options - 可选认证选项
|
|
15
|
+
* @returns v2 传输接口
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* const transport = createV2HttpTransport("https://github.com/user/repo");
|
|
20
|
+
* const caps = await transport.advertise();
|
|
21
|
+
* const refs = await transport.command("ls-refs", ["symrefs", "peel"]);
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
declare function createV2HttpTransport(url: string, options?: {
|
|
25
|
+
token?: string;
|
|
26
|
+
headers?: Record<string, string>;
|
|
27
|
+
}): V2GitServiceTransport;
|
|
28
|
+
//#endregion
|
|
29
|
+
export { V2SmartHttpError, createV2HttpTransport };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { encodeDelimiterPkt, encodeFlushPkt, encodePktLine } from "../../protocol/pkt-line.mjs";
|
|
2
|
+
import { parseV2CapabilityAdvertisement } from "./capability-advertisement.mjs";
|
|
3
|
+
//#region src/transport/client/upload-pack/http.ts
|
|
4
|
+
/**
|
|
5
|
+
* v2 HTTP 传输适配器
|
|
6
|
+
*
|
|
7
|
+
* Git Wire 协议 v2 的 HTTP 传输层。
|
|
8
|
+
* 负责构建 v2 命令式请求并发送到远端。
|
|
9
|
+
*
|
|
10
|
+
* v2 HTTP 传输流程:
|
|
11
|
+
* 1. advertise() — 获取能力广告(含版本声明)
|
|
12
|
+
* 2. command() — 执行单个命令(ls-refs / fetch / push / object-info)
|
|
13
|
+
*
|
|
14
|
+
* @see https://git-scm.com/docs/protocol-v2#_initial_client_request
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* v2 HTTP 传输错误
|
|
18
|
+
*/
|
|
19
|
+
var V2SmartHttpError = class extends Error {
|
|
20
|
+
constructor(message) {
|
|
21
|
+
super(`v2 smart-http error: ${message}`);
|
|
22
|
+
this.name = "V2SmartHttpError";
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
/** v2 advertise 路径(与 v1 相同,但增加 Git-Protocol 头) */
|
|
26
|
+
const ADVERTISE_PATH = "/info/refs";
|
|
27
|
+
/** v2 命令执行路径 */
|
|
28
|
+
const COMMAND_PATH = "/git-upload-pack";
|
|
29
|
+
/**
|
|
30
|
+
* 创建 v2 HTTP 传输适配器
|
|
31
|
+
*
|
|
32
|
+
* @param url - 远端仓库 URL
|
|
33
|
+
* @param options - 可选认证选项
|
|
34
|
+
* @returns v2 传输接口
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* const transport = createV2HttpTransport("https://github.com/user/repo");
|
|
39
|
+
* const caps = await transport.advertise();
|
|
40
|
+
* const refs = await transport.command("ls-refs", ["symrefs", "peel"]);
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
function createV2HttpTransport(url, options) {
|
|
44
|
+
const baseUrl = url.replace(/\/$/, "");
|
|
45
|
+
const baseHeaders = {
|
|
46
|
+
"User-Agent": "nano-git/0.1",
|
|
47
|
+
"Content-Type": "application/x-git-upload-pack-request",
|
|
48
|
+
Accept: "application/x-git-upload-pack-result",
|
|
49
|
+
"Git-Protocol": "version=2",
|
|
50
|
+
...options?.headers
|
|
51
|
+
};
|
|
52
|
+
if (options?.token) baseHeaders.Authorization = `Bearer ${options.token}`;
|
|
53
|
+
return {
|
|
54
|
+
async advertise() {
|
|
55
|
+
const response = await fetch(`${baseUrl}${ADVERTISE_PATH}?service=git-upload-pack`, { headers: baseHeaders });
|
|
56
|
+
if (!response.ok) throw new V2SmartHttpError(`advertise failed: ${response.status} ${response.statusText}`);
|
|
57
|
+
return parseV2CapabilityAdvertisement(Buffer.from(await response.arrayBuffer()));
|
|
58
|
+
},
|
|
59
|
+
async command(command, args, capabilities, body) {
|
|
60
|
+
const lines = [];
|
|
61
|
+
lines.push(encodePktLine(`command=${command}\n`));
|
|
62
|
+
if (capabilities) for (const cap of capabilities) lines.push(encodePktLine(`${cap}\n`));
|
|
63
|
+
lines.push(encodeDelimiterPkt());
|
|
64
|
+
if (args) for (const arg of args) lines.push(encodePktLine(`${arg}\n`));
|
|
65
|
+
lines.push(encodeFlushPkt());
|
|
66
|
+
if (body) lines.push(body);
|
|
67
|
+
const requestBody = Buffer.concat(lines);
|
|
68
|
+
const response = await fetch(`${baseUrl}${COMMAND_PATH}`, {
|
|
69
|
+
method: "POST",
|
|
70
|
+
headers: baseHeaders,
|
|
71
|
+
body: requestBody
|
|
72
|
+
});
|
|
73
|
+
if (!response.ok) throw new V2SmartHttpError(`command "${command}" failed: ${response.status} ${response.statusText}`);
|
|
74
|
+
return Buffer.from(await response.arrayBuffer());
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
//#endregion
|
|
79
|
+
export { V2SmartHttpError, createV2HttpTransport };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { GitError } from "../../../core/errors.mjs";
|
|
2
|
+
import { RefAdvertisement } from "../../protocol/types.mjs";
|
|
3
|
+
import { LsRefsEntry, V2GitServiceTransport } from "./types.mjs";
|
|
4
|
+
|
|
5
|
+
//#region src/transport/client/upload-pack/ls-refs.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* ls-refs 命令错误
|
|
8
|
+
*/
|
|
9
|
+
declare class LsRefsError extends GitError {
|
|
10
|
+
constructor(message: string);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* ls-refs 请求参数
|
|
14
|
+
*/
|
|
15
|
+
interface LsRefsOptions {
|
|
16
|
+
/** 请求符号引用信息 */
|
|
17
|
+
readonly symrefs?: boolean;
|
|
18
|
+
/** 请求 peeled tag 信息 */
|
|
19
|
+
readonly peel?: boolean;
|
|
20
|
+
/** 按前缀过滤 refs,如 ["refs/heads/", "refs/tags/"] */
|
|
21
|
+
readonly refPrefixes?: string[];
|
|
22
|
+
/** 请求 unborn HEAD 信息 */
|
|
23
|
+
readonly unborn?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 执行 ls-refs 命令
|
|
27
|
+
*
|
|
28
|
+
* @param transport - v2 传输接口
|
|
29
|
+
* @param options - ls-refs 请求选项
|
|
30
|
+
* @returns 解析后的 ref 条目列表
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* const entries = await lsRefs(transport, {
|
|
35
|
+
* symrefs: true,
|
|
36
|
+
* peel: true,
|
|
37
|
+
* refPrefixes: ["refs/heads/"],
|
|
38
|
+
* });
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
declare function lsRefs(transport: V2GitServiceTransport, options?: LsRefsOptions): Promise<LsRefsEntry[]>;
|
|
42
|
+
/**
|
|
43
|
+
* 解析 ls-refs 响应
|
|
44
|
+
*
|
|
45
|
+
* 从原始 Buffer 中解析 ls-refs 条目。
|
|
46
|
+
*
|
|
47
|
+
* @param data - ls-refs 命令的原始响应数据
|
|
48
|
+
* @returns 解析后的 ref 条目列表
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* const entries = parseLsRefsResponse(response);
|
|
53
|
+
* console.log(entries[0].refname); // "refs/heads/main"
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
declare function parseLsRefsResponse(data: Buffer): LsRefsEntry[];
|
|
57
|
+
/**
|
|
58
|
+
* 将 v2 ls-refs 结果转换为 v1 兼容的 RefAdvertisement
|
|
59
|
+
*
|
|
60
|
+
* 用于 ImportSession 的透明升级:v2 获取 refs 后,
|
|
61
|
+
* 包装为 v1 的 RefAdvertisement 格式,使上游代码无需改动。
|
|
62
|
+
*
|
|
63
|
+
* @param entries - ls-refs 返回的 ref 条目
|
|
64
|
+
* @returns v1 兼容的 RefAdvertisement
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* const entries = await lsRefs(transport);
|
|
69
|
+
* const adv = lsRefsToRefAdvertisement(entries);
|
|
70
|
+
* // 可传递给 ImportSession
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
declare function lsRefsToRefAdvertisement(entries: LsRefsEntry[]): RefAdvertisement;
|
|
74
|
+
//#endregion
|
|
75
|
+
export { LsRefsError, LsRefsOptions, lsRefs, lsRefsToRefAdvertisement, parseLsRefsResponse };
|