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.
Files changed (227) hide show
  1. package/README.md +407 -0
  2. package/dist/backend/file-backend.d.mts +26 -0
  3. package/dist/backend/file-backend.mjs +83 -0
  4. package/dist/backend/file.d.mts +2 -0
  5. package/dist/backend/file.mjs +2 -0
  6. package/dist/backend/index.d.mts +2 -0
  7. package/dist/backend/index.mjs +1 -0
  8. package/dist/backend/memory-backend.d.mts +25 -0
  9. package/dist/backend/memory-backend.mjs +33 -0
  10. package/dist/backend/memory.d.mts +2 -0
  11. package/dist/backend/memory.mjs +2 -0
  12. package/dist/backend/types.d.mts +90 -0
  13. package/dist/core/errors.d.mts +124 -0
  14. package/dist/core/errors.mjs +168 -0
  15. package/dist/core/hash-digest.d.mts +35 -0
  16. package/dist/core/hash-digest.mjs +50 -0
  17. package/dist/core/hash-file.d.mts +20 -0
  18. package/dist/core/hash-file.mjs +27 -0
  19. package/dist/core/hash-path.d.mts +17 -0
  20. package/dist/core/hash-path.mjs +35 -0
  21. package/dist/core/types/odb.d.mts +63 -0
  22. package/dist/core/types/refs.d.mts +140 -0
  23. package/dist/core/types/refs.mjs +19 -0
  24. package/dist/core/types/shallow.d.mts +52 -0
  25. package/dist/core/types.d.mts +154 -0
  26. package/dist/core/types.mjs +43 -0
  27. package/dist/errors.d.mts +2 -0
  28. package/dist/errors.mjs +2 -0
  29. package/dist/hash-file.d.mts +2 -0
  30. package/dist/hash-file.mjs +2 -0
  31. package/dist/index.d.mts +16 -0
  32. package/dist/index.mjs +14 -0
  33. package/dist/objects/author.d.mts +25 -0
  34. package/dist/objects/author.mjs +45 -0
  35. package/dist/objects/blob.d.mts +15 -0
  36. package/dist/objects/blob.mjs +20 -0
  37. package/dist/objects/codec.d.mts +46 -0
  38. package/dist/objects/codec.mjs +84 -0
  39. package/dist/objects/commit.d.mts +26 -0
  40. package/dist/objects/commit.mjs +160 -0
  41. package/dist/objects/index.d.mts +8 -0
  42. package/dist/objects/index.mjs +8 -0
  43. package/dist/objects/raw.d.mts +85 -0
  44. package/dist/objects/raw.mjs +111 -0
  45. package/dist/objects/tag.d.mts +26 -0
  46. package/dist/objects/tag.mjs +148 -0
  47. package/dist/objects/tree.d.mts +22 -0
  48. package/dist/objects/tree.mjs +66 -0
  49. package/dist/odb/file-utils.mjs +136 -0
  50. package/dist/odb/file.d.mts +22 -0
  51. package/dist/odb/file.mjs +66 -0
  52. package/dist/odb/memory.d.mts +22 -0
  53. package/dist/odb/memory.mjs +54 -0
  54. package/dist/pack/composite-store.d.mts +76 -0
  55. package/dist/pack/composite-store.mjs +133 -0
  56. package/dist/pack/constants.mjs +48 -0
  57. package/dist/pack/crc32.mjs +38 -0
  58. package/dist/pack/delta-apply.d.mts +21 -0
  59. package/dist/pack/delta-apply.mjs +71 -0
  60. package/dist/pack/delta-create.d.mts +28 -0
  61. package/dist/pack/delta-create.mjs +151 -0
  62. package/dist/pack/index.d.mts +16 -0
  63. package/dist/pack/index.mjs +13 -0
  64. package/dist/pack/object-header.d.mts +36 -0
  65. package/dist/pack/object-header.mjs +72 -0
  66. package/dist/pack/ofs-delta-offset.d.mts +35 -0
  67. package/dist/pack/ofs-delta-offset.mjs +59 -0
  68. package/dist/pack/pack-builder-types.d.mts +19 -0
  69. package/dist/pack/pack-builder.d.mts +52 -0
  70. package/dist/pack/pack-builder.mjs +80 -0
  71. package/dist/pack/pack-encoding.mjs +76 -0
  72. package/dist/pack/pack-index-reader.d.mts +57 -0
  73. package/dist/pack/pack-index-reader.mjs +90 -0
  74. package/dist/pack/pack-index-types.d.mts +16 -0
  75. package/dist/pack/pack-index-writer.d.mts +45 -0
  76. package/dist/pack/pack-index-writer.mjs +106 -0
  77. package/dist/pack/pack-reader-resolver.mjs +104 -0
  78. package/dist/pack/pack-reader-types.d.mts +31 -0
  79. package/dist/pack/pack-reader-types.mjs +22 -0
  80. package/dist/pack/pack-reader-utils.mjs +61 -0
  81. package/dist/pack/pack-reader.d.mts +81 -0
  82. package/dist/pack/pack-reader.mjs +171 -0
  83. package/dist/pack/pack-store-loader.mjs +79 -0
  84. package/dist/pack/pack-store-types.d.mts +16 -0
  85. package/dist/pack/pack-store.d.mts +55 -0
  86. package/dist/pack/pack-store.mjs +114 -0
  87. package/dist/pack/pack-writer.mjs +96 -0
  88. package/dist/pack/varint.d.mts +34 -0
  89. package/dist/pack/varint.mjs +57 -0
  90. package/dist/refs/file.d.mts +6 -0
  91. package/dist/refs/file.mjs +222 -0
  92. package/dist/refs/fs-utils.mjs +30 -0
  93. package/dist/refs/memory.d.mts +14 -0
  94. package/dist/refs/memory.mjs +104 -0
  95. package/dist/refs/names.d.mts +57 -0
  96. package/dist/refs/names.mjs +80 -0
  97. package/dist/refs/resolve.d.mts +33 -0
  98. package/dist/refs/resolve.mjs +55 -0
  99. package/dist/refs/shallow/file.d.mts +17 -0
  100. package/dist/refs/shallow/file.mjs +61 -0
  101. package/dist/refs/shallow/memory.d.mts +18 -0
  102. package/dist/refs/shallow/memory.mjs +33 -0
  103. package/dist/repository/core.d.mts +3 -0
  104. package/dist/repository/core.mjs +2 -0
  105. package/dist/repository/create.d.mts +22 -0
  106. package/dist/repository/create.mjs +43 -0
  107. package/dist/repository/file.d.mts +43 -0
  108. package/dist/repository/file.mjs +82 -0
  109. package/dist/repository/import/import-glob.mjs +44 -0
  110. package/dist/repository/import/import-plan-builder.mjs +625 -0
  111. package/dist/repository/import/import-session-types.d.mts +280 -0
  112. package/dist/repository/import/import-session.mjs +96 -0
  113. package/dist/repository/import/import-view.mjs +133 -0
  114. package/dist/repository/memory.d.mts +17 -0
  115. package/dist/repository/memory.mjs +33 -0
  116. package/dist/repository/ops/fetch-operations.mjs +20 -0
  117. package/dist/repository/ops/fetch-types.d.mts +82 -0
  118. package/dist/repository/ops/fetch-url.mjs +82 -0
  119. package/dist/repository/ops/fs-object-operations.mjs +31 -0
  120. package/dist/repository/ops/maintenance-operations.mjs +62 -0
  121. package/dist/repository/ops/maintenance-types.d.mts +42 -0
  122. package/dist/repository/ops/object-operations.mjs +65 -0
  123. package/dist/repository/ops/object-types.d.mts +109 -0
  124. package/dist/repository/ops/push-operations.mjs +16 -0
  125. package/dist/repository/ops/push-resolution.mjs +17 -0
  126. package/dist/repository/ops/push-types.d.mts +72 -0
  127. package/dist/repository/ops/push-url.mjs +45 -0
  128. package/dist/repository/ops/reachability.mjs +60 -0
  129. package/dist/repository/ops/ref-operations.mjs +86 -0
  130. package/dist/repository/ops/ref-types.d.mts +70 -0
  131. package/dist/repository/tree/tree-patch.d.mts +64 -0
  132. package/dist/repository/tree/tree-patch.mjs +268 -0
  133. package/dist/repository/tree/tree-walk.d.mts +46 -0
  134. package/dist/repository/tree/tree-walk.mjs +65 -0
  135. package/dist/repository/tree/tree-writer.mjs +68 -0
  136. package/dist/repository/types.d.mts +36 -0
  137. package/dist/sha1.d.mts +4 -0
  138. package/dist/sha1.mjs +4 -0
  139. package/dist/transport/client/receive-pack/http.d.mts +33 -0
  140. package/dist/transport/client/receive-pack/http.mjs +99 -0
  141. package/dist/transport/client/receive-pack/push-error.d.mts +23 -0
  142. package/dist/transport/client/receive-pack/push-error.mjs +32 -0
  143. package/dist/transport/client/receive-pack/push-pack-plan.d.mts +28 -0
  144. package/dist/transport/client/receive-pack/push-pack-plan.mjs +60 -0
  145. package/dist/transport/client/receive-pack/push-policy.d.mts +19 -0
  146. package/dist/transport/client/receive-pack/push-policy.mjs +64 -0
  147. package/dist/transport/client/receive-pack/push-ref-plan.d.mts +45 -0
  148. package/dist/transport/client/receive-pack/push-ref-plan.mjs +108 -0
  149. package/dist/transport/client/receive-pack/push-report.d.mts +28 -0
  150. package/dist/transport/client/receive-pack/push-report.mjs +84 -0
  151. package/dist/transport/client/receive-pack/push-request-plan.mjs +52 -0
  152. package/dist/transport/client/receive-pack/push.d.mts +32 -0
  153. package/dist/transport/client/receive-pack/push.mjs +97 -0
  154. package/dist/transport/client/receive-pack/request.d.mts +39 -0
  155. package/dist/transport/client/receive-pack/request.mjs +46 -0
  156. package/dist/transport/client/receive-pack/response.d.mts +26 -0
  157. package/dist/transport/client/receive-pack/response.mjs +52 -0
  158. package/dist/transport/client/receive-pack/result.d.mts +34 -0
  159. package/dist/transport/client/receive-pack/result.mjs +100 -0
  160. package/dist/transport/client/upload-pack/capability-advertisement.d.mts +56 -0
  161. package/dist/transport/client/upload-pack/capability-advertisement.mjs +130 -0
  162. package/dist/transport/client/upload-pack/fetch.d.mts +109 -0
  163. package/dist/transport/client/upload-pack/fetch.mjs +392 -0
  164. package/dist/transport/client/upload-pack/http.d.mts +29 -0
  165. package/dist/transport/client/upload-pack/http.mjs +79 -0
  166. package/dist/transport/client/upload-pack/ls-refs.d.mts +75 -0
  167. package/dist/transport/client/upload-pack/ls-refs.mjs +150 -0
  168. package/dist/transport/client/upload-pack/object-info.d.mts +65 -0
  169. package/dist/transport/client/upload-pack/object-info.mjs +111 -0
  170. package/dist/transport/client/upload-pack/types.d.mts +153 -0
  171. package/dist/transport/http/index.d.mts +3 -0
  172. package/dist/transport/http/index.mjs +2 -0
  173. package/dist/transport/http/smart-http.d.mts +46 -0
  174. package/dist/transport/http/smart-http.mjs +176 -0
  175. package/dist/transport/http/types.d.mts +27 -0
  176. package/dist/transport/index.d.mts +9 -0
  177. package/dist/transport/index.mjs +8 -0
  178. package/dist/transport/protocol/object-graph.d.mts +63 -0
  179. package/dist/transport/protocol/object-graph.mjs +149 -0
  180. package/dist/transport/protocol/pkt-line.d.mts +109 -0
  181. package/dist/transport/protocol/pkt-line.mjs +195 -0
  182. package/dist/transport/protocol/ref-advertisement.mjs +185 -0
  183. package/dist/transport/protocol/ref-collection.d.mts +38 -0
  184. package/dist/transport/protocol/ref-collection.mjs +63 -0
  185. package/dist/transport/protocol/ref-match.d.mts +39 -0
  186. package/dist/transport/protocol/ref-match.mjs +42 -0
  187. package/dist/transport/protocol/refspec.d.mts +44 -0
  188. package/dist/transport/protocol/refspec.mjs +79 -0
  189. package/dist/transport/protocol/side-band.d.mts +65 -0
  190. package/dist/transport/protocol/side-band.mjs +142 -0
  191. package/dist/transport/protocol/transport-capabilities.mjs +46 -0
  192. package/dist/transport/protocol/types.d.mts +148 -0
  193. package/dist/transport/protocol/update-refs.d.mts +68 -0
  194. package/dist/transport/protocol/update-refs.mjs +126 -0
  195. package/dist/transport/receive-pack.d.mts +11 -0
  196. package/dist/transport/receive-pack.mjs +11 -0
  197. package/dist/transport/server/receive-pack/advertise.d.mts +28 -0
  198. package/dist/transport/server/receive-pack/advertise.mjs +88 -0
  199. package/dist/transport/server/receive-pack/handler.d.mts +30 -0
  200. package/dist/transport/server/receive-pack/handler.mjs +156 -0
  201. package/dist/transport/server/receive-pack/index.d.mts +6 -0
  202. package/dist/transport/server/receive-pack/index.mjs +6 -0
  203. package/dist/transport/server/receive-pack/parse.d.mts +17 -0
  204. package/dist/transport/server/receive-pack/parse.mjs +80 -0
  205. package/dist/transport/server/receive-pack/report-status.mjs +64 -0
  206. package/dist/transport/server/receive-pack/service.d.mts +41 -0
  207. package/dist/transport/server/receive-pack/service.mjs +39 -0
  208. package/dist/transport/server/receive-pack/types.d.mts +56 -0
  209. package/dist/transport/server/receive-pack/types.mjs +25 -0
  210. package/dist/transport/server/receive-pack/unpack.mjs +119 -0
  211. package/dist/transport/server/upload-pack/advertise.d.mts +20 -0
  212. package/dist/transport/server/upload-pack/advertise.mjs +30 -0
  213. package/dist/transport/server/upload-pack/command.d.mts +43 -0
  214. package/dist/transport/server/upload-pack/command.mjs +56 -0
  215. package/dist/transport/server/upload-pack/fetch.d.mts +43 -0
  216. package/dist/transport/server/upload-pack/fetch.mjs +217 -0
  217. package/dist/transport/server/upload-pack/index.d.mts +7 -0
  218. package/dist/transport/server/upload-pack/index.mjs +7 -0
  219. package/dist/transport/server/upload-pack/ls-refs.d.mts +38 -0
  220. package/dist/transport/server/upload-pack/ls-refs.mjs +113 -0
  221. package/dist/transport/server/upload-pack/service.d.mts +40 -0
  222. package/dist/transport/server/upload-pack/service.mjs +51 -0
  223. package/dist/transport/server/upload-pack/types.d.mts +11 -0
  224. package/dist/transport/server/upload-pack/types.mjs +21 -0
  225. package/dist/transport/upload-pack.d.mts +7 -0
  226. package/dist/transport/upload-pack.mjs +6 -0
  227. package/package.json +98 -0
@@ -0,0 +1,65 @@
1
+ import { GitError } from "../../core/errors.mjs";
2
+
3
+ //#region src/transport/protocol/side-band.d.ts
4
+ /**
5
+ * side-band 协议错误
6
+ *
7
+ * 当 side-band 数据格式不符合 Git 协议规范时抛出。
8
+ */
9
+ declare class SideBandError extends GitError {
10
+ constructor(message: string);
11
+ }
12
+ /**
13
+ * 从 side-band 编码的响应数据中提取 packfile
14
+ *
15
+ * 将 channel 1 的所有帧拼接为完整的 packfile buffer。
16
+ *
17
+ * @param data - 包含 side-band pkt-line 帧的完整响应数据
18
+ * @returns 拼接后的 packfile buffer
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * const packfile = extractPackfile(responseData);
23
+ * const reader = createPackReader(packfile);
24
+ * ```
25
+ */
26
+ declare function extractPackfile(data: Buffer): Buffer;
27
+ /**
28
+ * 从 side-band 编码的响应数据中提取进度消息
29
+ *
30
+ * 收集 channel 2 的所有消息。
31
+ *
32
+ * @param data - 包含 side-band pkt-line 帧的完整响应数据
33
+ * @returns 进度消息列表
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * const messages = extractProgress(responseData);
38
+ * console.log(messages);
39
+ * // [ "Receiving objects: 10% (1/10)", ... ]
40
+ * ```
41
+ */
42
+ declare function extractProgress(data: Buffer): string[];
43
+ /**
44
+ * 从非 side-band 编码的响应中提取原始 packfile 数据
45
+ *
46
+ * Git 协议中,若未协商 side-band-64k,upload-pack 的响应格式为:
47
+ * `<pkt-line 头部(NAK/ACK)> + <原始 packfile 数据>`。
48
+ * 此函数解析头部 pkt-lines,将剩余原始数据作为 packfile 返回。
49
+ *
50
+ * @param data - 非 side-band 响应的完整数据
51
+ * @returns 原始 packfile buffer
52
+ * @throws {SideBandError} 当尾部无 packfile 数据时
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * const response = Buffer.concat([
57
+ * encodePktLine("NAK\n"),
58
+ * rawPackfileData,
59
+ * ]);
60
+ * const packfile = extractRawPackfile(response);
61
+ * ```
62
+ */
63
+ declare function extractRawPackfile(data: Buffer): Buffer;
64
+ //#endregion
65
+ export { SideBandError, extractPackfile, extractProgress, extractRawPackfile };
@@ -0,0 +1,142 @@
1
+ import { GitError } from "../../core/errors.mjs";
2
+ import { parsePktLines, splitPktLinesFromBuffer } from "./pkt-line.mjs";
3
+ //#region src/transport/protocol/side-band.ts
4
+ /**
5
+ * side-band 多路解复用
6
+ *
7
+ * Git 协议使用 side-band 在单一连接上多路传输数据。
8
+ * side-band-64k 将数据分割为 pkt-line 帧,每帧第一个字节为 channel 编号。
9
+ *
10
+ * Channel 约定:
11
+ * - 0x01: packfile 数据(需拼接为完整 packfile)
12
+ * - 0x02: 进度消息(可用于显示传输进度)
13
+ * - 0x03: 致命错误(传输过程中出错)
14
+ *
15
+ * @see https://git-scm.com/docs/pack-protocol#_side_channel
16
+ */
17
+ /** side-band channel 编号 */
18
+ const CHANNEL_PACKFILE = 1;
19
+ const CHANNEL_PROGRESS = 2;
20
+ const CHANNEL_FATAL = 3;
21
+ /**
22
+ * side-band 协议错误
23
+ *
24
+ * 当 side-band 数据格式不符合 Git 协议规范时抛出。
25
+ */
26
+ var SideBandError = class extends GitError {
27
+ constructor(message) {
28
+ super(`side-band error: ${message}`);
29
+ this.name = "SideBandError";
30
+ }
31
+ };
32
+ /**
33
+ * 从 side-band 编码的响应数据中提取 packfile
34
+ *
35
+ * 将 channel 1 的所有帧拼接为完整的 packfile buffer。
36
+ *
37
+ * @param data - 包含 side-band pkt-line 帧的完整响应数据
38
+ * @returns 拼接后的 packfile buffer
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * const packfile = extractPackfile(responseData);
43
+ * const reader = createPackReader(packfile);
44
+ * ```
45
+ */
46
+ function extractPackfile(data) {
47
+ const chunks = [];
48
+ processSideBand(data, {
49
+ onPackfile(chunk) {
50
+ chunks.push(chunk);
51
+ },
52
+ onProgress() {},
53
+ onFatal(msg) {
54
+ throw new SideBandError(`Server reported fatal error: ${msg}`);
55
+ }
56
+ });
57
+ if (chunks.length === 0) throw new SideBandError("No packfile data found in side-band stream");
58
+ return Buffer.concat(chunks);
59
+ }
60
+ /**
61
+ * 从 side-band 编码的响应数据中提取进度消息
62
+ *
63
+ * 收集 channel 2 的所有消息。
64
+ *
65
+ * @param data - 包含 side-band pkt-line 帧的完整响应数据
66
+ * @returns 进度消息列表
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * const messages = extractProgress(responseData);
71
+ * console.log(messages);
72
+ * // [ "Receiving objects: 10% (1/10)", ... ]
73
+ * ```
74
+ */
75
+ function extractProgress(data) {
76
+ const messages = [];
77
+ processSideBand(data, {
78
+ onPackfile() {},
79
+ onProgress(msg) {
80
+ messages.push(msg);
81
+ },
82
+ onFatal(msg) {
83
+ throw new SideBandError(`Server reported fatal error: ${msg}`);
84
+ }
85
+ });
86
+ return messages;
87
+ }
88
+ /**
89
+ * 从非 side-band 编码的响应中提取原始 packfile 数据
90
+ *
91
+ * Git 协议中,若未协商 side-band-64k,upload-pack 的响应格式为:
92
+ * `<pkt-line 头部(NAK/ACK)> + <原始 packfile 数据>`。
93
+ * 此函数解析头部 pkt-lines,将剩余原始数据作为 packfile 返回。
94
+ *
95
+ * @param data - 非 side-band 响应的完整数据
96
+ * @returns 原始 packfile buffer
97
+ * @throws {SideBandError} 当尾部无 packfile 数据时
98
+ *
99
+ * @example
100
+ * ```ts
101
+ * const response = Buffer.concat([
102
+ * encodePktLine("NAK\n"),
103
+ * rawPackfileData,
104
+ * ]);
105
+ * const packfile = extractRawPackfile(response);
106
+ * ```
107
+ */
108
+ function extractRawPackfile(data) {
109
+ const { trailing } = splitPktLinesFromBuffer(data);
110
+ if (trailing.length === 0) throw new SideBandError("No packfile data found in non-side-band response");
111
+ return trailing;
112
+ }
113
+ /**
114
+ * 处理 side-band 数据流
115
+ *
116
+ * 遍历所有 pkt-line 帧,根据 channel 编号分发到对应回调。
117
+ */
118
+ function processSideBand(data, handlers) {
119
+ const pktLines = parsePktLines(data);
120
+ for (const line of pktLines) {
121
+ if (line.type !== "data") continue;
122
+ const payload = line.payload;
123
+ if (payload.length === 0) continue;
124
+ const channel = payload[0];
125
+ if (payload.length < 2) continue;
126
+ const content = payload.subarray(1);
127
+ switch (channel) {
128
+ case CHANNEL_PACKFILE:
129
+ handlers.onPackfile(content);
130
+ break;
131
+ case CHANNEL_PROGRESS:
132
+ handlers.onProgress(content.toString("utf-8"));
133
+ break;
134
+ case CHANNEL_FATAL:
135
+ handlers.onFatal(content.toString("utf-8"));
136
+ break;
137
+ default: break;
138
+ }
139
+ }
140
+ }
141
+ //#endregion
142
+ export { SideBandError, extractPackfile, extractProgress, extractRawPackfile };
@@ -0,0 +1,46 @@
1
+ //#region src/transport/protocol/transport-capabilities.ts
2
+ /**
3
+ * 传输层能力管理
4
+ *
5
+ * 处理 Git 协议中服务端能力声明与客户端可用能力的过滤。
6
+ * 将 push/fetch 各自的能力白名单与共享的过滤逻辑合并。
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { extractCapabilities, PUSH_CAPABILITIES } from "./transport-capabilities.ts";
11
+ * const caps = extractCapabilities(serverCaps, PUSH_CAPABILITIES);
12
+ * ```
13
+ */
14
+ /** push (receive-pack) 默认支持的客户端能力 */
15
+ const PUSH_CAPABILITIES = [
16
+ "report-status",
17
+ "side-band-64k",
18
+ "ofs-delta",
19
+ "no-progress",
20
+ "delete-refs"
21
+ ];
22
+ /**
23
+ * 从服务端 capabilities 中提取客户端可用的能力列表
24
+ *
25
+ * 将服务端声明的能力与客户端支持白名单取交集,
26
+ * 只返回双方都支持的能力。
27
+ *
28
+ * @param serverCaps - 服务端声明的能力字典
29
+ * @param supported - 客户端支持的能力白名单
30
+ * @returns 双方都支持的能力名称列表
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * const caps = extractCapabilities(
35
+ * { "report-status": true, "side-band-64k": true, "unknown-opt": "v1" },
36
+ * PUSH_CAPABILITIES,
37
+ * );
38
+ * // => ["report-status", "side-band-64k"]
39
+ * ```
40
+ */
41
+ function extractCapabilities(serverCaps, supported) {
42
+ const supportedSet = new Set(supported);
43
+ return Object.keys(serverCaps).filter((cap) => supportedSet.has(cap));
44
+ }
45
+ //#endregion
46
+ export { PUSH_CAPABILITIES, extractCapabilities };
@@ -0,0 +1,148 @@
1
+ import { SHA1 } from "../../core/types.mjs";
2
+
3
+ //#region src/transport/protocol/types.d.ts
4
+ /**
5
+ * Git 服务传输同构接口
6
+ *
7
+ * 只负责获取 ref 广告与发送 RPC body 并返回原始响应体。
8
+ */
9
+ interface GitServiceTransport {
10
+ /** 获取 ref 广告(已解析为 RefAdvertisement,含 defaultBranch) */
11
+ advertise(): Promise<RefAdvertisement>;
12
+ /** 发送协议 RPC 请求,返回原始响应 body */
13
+ request(body: Buffer): Promise<Buffer>;
14
+ }
15
+ /**
16
+ * Receive-pack 传输接口(push)
17
+ */
18
+ type ReceivePackTransport = GitServiceTransport;
19
+ /**
20
+ * 远程引用
21
+ *
22
+ * 表示服务端广告的单个 Git 引用。
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * const ref: RemoteRef = {
27
+ * hash: sha1("95d09f2b10159347eece71399a7e2e907ea3df4f"),
28
+ * name: "refs/heads/main",
29
+ * };
30
+ * ```
31
+ */
32
+ interface RemoteRef {
33
+ /** 引用指向的对象哈希 */
34
+ hash: SHA1;
35
+ /** 引用完整名称,如 "refs/heads/main" */
36
+ name: string;
37
+ /** 如果引用是 annotated tag,此项为最终指向的 peeled 对象哈希 */
38
+ peeled?: SHA1;
39
+ /**
40
+ * 符号引用目标
41
+ * 如 "HEAD" → "refs/heads/main"
42
+ */
43
+ symrefTarget?: string;
44
+ }
45
+ /**
46
+ * 服务端引用广告
47
+ *
48
+ * 包含服务端通过 ref advertisement 响应的能力声明和所有引用。
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * const adv: RefAdvertisement = {
53
+ * capabilities: { multi_ack: true, "symref": "HEAD:refs/heads/main" },
54
+ * refs: [ { hash: sha1("..."), name: "refs/heads/main" } ],
55
+ * };
56
+ * ```
57
+ */
58
+ interface RefAdvertisement {
59
+ /** 服务端能力声明 */
60
+ capabilities: Record<string, string | true>;
61
+ /** 所有广告的引用列表 */
62
+ refs: RemoteRef[];
63
+ /**
64
+ * 远端默认分支(如 refs/heads/main)
65
+ * 由 parseRefAdvertisement 统一解析,调用方不得再读 capabilities.symref
66
+ */
67
+ defaultBranch?: string;
68
+ }
69
+ /**
70
+ * Ref 映射规则
71
+ */
72
+ interface RefMappingRule {
73
+ readonly source: string;
74
+ readonly target: string;
75
+ readonly force?: boolean;
76
+ }
77
+ /**
78
+ * Ref 更新拒绝项
79
+ */
80
+ interface RefUpdateRejection {
81
+ readonly localRef: string;
82
+ readonly reason: string;
83
+ }
84
+ /**
85
+ * 应用 ref 更新结果
86
+ */
87
+ interface ApplyRefUpdatesResult {
88
+ readonly updatedRefs: Map<string, SHA1>;
89
+ readonly rejectedRefs: RefUpdateRejection[];
90
+ }
91
+ /**
92
+ * Push 操作选项
93
+ *
94
+ * 控制 push 行为。纯 push 参数,不含传输层细节(transport、token、headers 等)。
95
+ * 调用方需自行创建 ReceivePackTransport 并传入 push()。
96
+ */
97
+ interface PushOptions {
98
+ /**
99
+ * refspec 列表,格式如 "refs/heads/main:refs/heads/main"
100
+ * 默认为将当前分支推送到远端同名分支(等价于 `git push <url>`)
101
+ */
102
+ refSpecs?: string[];
103
+ /** 是否强制推送(--force),等价于 refspec 的 + 前缀 */
104
+ force?: boolean;
105
+ /**
106
+ * 已知的 shallow 边界 commit 哈希列表
107
+ *
108
+ * 设置此字段后,push 在遍历本地 commit 图遇到边界缺失 parent 时,
109
+ * 会优先检查该哈希是否在 shallow 集合中:
110
+ * - 如果在,按 shallow boundary 处理(允许正常的边界缺失)
111
+ * - 如果不在,按本地损坏报错(避免误判)
112
+ *
113
+ * 通常由 Repository 层自动从 backend.shallow 读取,无需调用方手工设置。
114
+ */
115
+ shallowBoundaries?: SHA1[];
116
+ }
117
+ /**
118
+ * 单条引用更新结果
119
+ *
120
+ * 表示服务端对单个引用更新命令的响应。
121
+ */
122
+ interface PushRefUpdate {
123
+ /** 引用名称,如 "refs/heads/main" */
124
+ refName: string;
125
+ /** 更新前的哈希(服务端原有值) */
126
+ oldHash: SHA1 | null;
127
+ /** 更新后的哈希 */
128
+ newHash: SHA1 | null;
129
+ /** 是否成功 */
130
+ success: boolean;
131
+ /** 失败时的错误消息 */
132
+ error?: string;
133
+ /** 是否强制更新 */
134
+ forced: boolean;
135
+ }
136
+ /**
137
+ * Push 操作结果
138
+ */
139
+ interface PushResult {
140
+ /** 已更新的引用列表 */
141
+ refUpdates: PushRefUpdate[];
142
+ /** 推送的对象数量 */
143
+ objectCount: number;
144
+ /** 服务端推送的进度消息 */
145
+ progress: string[];
146
+ }
147
+ //#endregion
148
+ export { ApplyRefUpdatesResult, GitServiceTransport, PushOptions, PushRefUpdate, PushResult, ReceivePackTransport, RefAdvertisement, RefMappingRule, RefUpdateRejection, RemoteRef };
@@ -0,0 +1,68 @@
1
+ import { SHA1 } from "../../core/types.mjs";
2
+ import { RefStore } from "../../core/types/refs.mjs";
3
+ import { ObjectDatabase } from "../../core/types/odb.mjs";
4
+ import { GitError } from "../../core/errors.mjs";
5
+ import { ApplyRefUpdatesResult, RemoteRef } from "./types.mjs";
6
+
7
+ //#region src/transport/protocol/update-refs.d.ts
8
+ /**
9
+ * Ref 更新计划项
10
+ *
11
+ * 表示一个需要执行的本地 ref 写操作。
12
+ */
13
+ interface RefUpdatePlanItem {
14
+ readonly remoteRef: RemoteRef;
15
+ readonly localRef: string;
16
+ readonly currentLocalHash?: SHA1;
17
+ readonly force: boolean;
18
+ }
19
+ /**
20
+ * Ref 更新错误
21
+ */
22
+ declare class RefUpdateError extends GitError {
23
+ constructor(message: string);
24
+ }
25
+ /**
26
+ * 校验远程 ref 对象可写入 refs/heads/*
27
+ *
28
+ * refs/heads/* 只能指向 commit 对象。
29
+ *
30
+ * @param store - 对象存储
31
+ * @param hash - 远程引用哈希
32
+ * @param refName - 远程引用名称(仅用于错误消息)
33
+ * @returns 可用于写入 refs/heads/* 的哈希
34
+ * @throws RefUpdateError 如果目标对象不存在或不是 commit
35
+ */
36
+ declare function resolveBranchTargetHash(store: ObjectDatabase, hash: SHA1, refName: string): SHA1;
37
+ /**
38
+ * 判断指定 ref 是否属于需要 fast-forward 检查的命名空间
39
+ *
40
+ * Git fetch 语义:仅 refs/heads/* 在没有 + 的 refspec 下要求新 tip 必须是
41
+ * 旧 tip 的子孙(快进)。
42
+ */
43
+ declare function isRefNamespaceRequiringFastForward(refName: string): boolean;
44
+ /**
45
+ * 应用 ref 更新
46
+ *
47
+ * 根据更新计划逐条应用 ref 更新,执行以下校验:
48
+ * - wanted tip 对象存在性校验
49
+ * - refs/heads/* 的 commit 类型校验
50
+ * - refs/tags/* 的非 force 拒绝替换
51
+ * - refs/heads/* 的非 force fast-forward 检查
52
+ *
53
+ * @param store - 对象存储(用于校验对象存在性和类型)
54
+ * @param refs - 本地引用存储
55
+ * @param updates - ref 更新计划项列表
56
+ * @returns 更新结果(成功和拒绝列表)
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * const result = applyRefUpdates(objects, refs, plan.updates);
61
+ * for (const [ref, hash] of result.updatedRefs) {
62
+ * console.log(`Updated ${ref} -> ${hash}`);
63
+ * }
64
+ * ```
65
+ */
66
+ declare function applyRefUpdates(store: ObjectDatabase, refs: RefStore, updates: RefUpdatePlanItem[]): ApplyRefUpdatesResult;
67
+ //#endregion
68
+ export { RefUpdateError, applyRefUpdates, isRefNamespaceRequiringFastForward, resolveBranchTargetHash };
@@ -0,0 +1,126 @@
1
+ import { GitError } from "../../core/errors.mjs";
2
+ import { tryReadObject } from "../../objects/raw.mjs";
3
+ import { isAncestor } from "./object-graph.mjs";
4
+ //#region src/transport/protocol/update-refs.ts
5
+ /**
6
+ * 应用本地 ref 更新
7
+ *
8
+ * 根据 RefUpdatePlanItem[] 应用 ref 更新,执行 fast-forward / tag / object-type 校验,
9
+ * 返回成功更新与拒绝更新明细。
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * const result = applyRefUpdates(store, refs, plan.updates);
14
+ * console.log(`Updated ${result.updatedRefs.size} refs`);
15
+ * ```
16
+ */
17
+ /**
18
+ * Ref 更新错误
19
+ */
20
+ var RefUpdateError = class extends GitError {
21
+ constructor(message) {
22
+ super(`Ref update error: ${message}`);
23
+ this.name = "RefUpdateError";
24
+ }
25
+ };
26
+ /**
27
+ * 校验远程 ref 对象可写入 refs/heads/*
28
+ *
29
+ * refs/heads/* 只能指向 commit 对象。
30
+ *
31
+ * @param store - 对象存储
32
+ * @param hash - 远程引用哈希
33
+ * @param refName - 远程引用名称(仅用于错误消息)
34
+ * @returns 可用于写入 refs/heads/* 的哈希
35
+ * @throws RefUpdateError 如果目标对象不存在或不是 commit
36
+ */
37
+ function resolveBranchTargetHash(store, hash, refName) {
38
+ const obj = tryReadObject(store, hash);
39
+ if (obj === void 0) throw new RefUpdateError(`Object ${hash} for remote ref "${refName}" is missing from the local store. refs/heads/* can only point to commit objects.`);
40
+ if (obj.type === "tag") throw new RefUpdateError(`Remote ref "${refName}" (${hash}) is a tag object, expected commit. refs/heads/* can only point to commit objects.`);
41
+ if (obj.type !== "commit") throw new RefUpdateError(`Remote ref "${refName}" (${hash}) is a ${obj.type}, expected commit. refs/heads/* can only point to commit objects.`);
42
+ return hash;
43
+ }
44
+ /**
45
+ * 判断指定 ref 是否属于需要 fast-forward 检查的命名空间
46
+ *
47
+ * Git fetch 语义:仅 refs/heads/* 在没有 + 的 refspec 下要求新 tip 必须是
48
+ * 旧 tip 的子孙(快进)。
49
+ */
50
+ function isRefNamespaceRequiringFastForward(refName) {
51
+ return refName.startsWith("refs/heads/");
52
+ }
53
+ /**
54
+ * 应用 ref 更新
55
+ *
56
+ * 根据更新计划逐条应用 ref 更新,执行以下校验:
57
+ * - wanted tip 对象存在性校验
58
+ * - refs/heads/* 的 commit 类型校验
59
+ * - refs/tags/* 的非 force 拒绝替换
60
+ * - refs/heads/* 的非 force fast-forward 检查
61
+ *
62
+ * @param store - 对象存储(用于校验对象存在性和类型)
63
+ * @param refs - 本地引用存储
64
+ * @param updates - ref 更新计划项列表
65
+ * @returns 更新结果(成功和拒绝列表)
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * const result = applyRefUpdates(objects, refs, plan.updates);
70
+ * for (const [ref, hash] of result.updatedRefs) {
71
+ * console.log(`Updated ${ref} -> ${hash}`);
72
+ * }
73
+ * ```
74
+ */
75
+ function applyRefUpdates(store, refs, updates) {
76
+ const committedUpdates = [];
77
+ const rejectedRefs = [];
78
+ const rejectedSet = /* @__PURE__ */ new Set();
79
+ for (const item of updates) if (!store.exists(item.remoteRef.hash)) {
80
+ rejectedRefs.push({
81
+ localRef: item.localRef,
82
+ reason: `Object ${item.remoteRef.hash} was advertised but not received in the packfile`
83
+ });
84
+ rejectedSet.add(item.localRef);
85
+ continue;
86
+ }
87
+ for (const item of updates) {
88
+ const { remoteRef, localRef, currentLocalHash, force } = item;
89
+ if (rejectedSet.has(localRef)) continue;
90
+ const writeHash = localRef.startsWith("refs/heads/") ? resolveBranchTargetHash(store, remoteRef.hash, remoteRef.name) : remoteRef.hash;
91
+ if (!force && currentLocalHash !== void 0) {
92
+ if (localRef.startsWith("refs/tags/")) {
93
+ rejectedRefs.push({
94
+ localRef,
95
+ reason: `Tag "${localRef}" already exists and force is not set`
96
+ });
97
+ continue;
98
+ }
99
+ if (isRefNamespaceRequiringFastForward(localRef) && !isAncestor(store, currentLocalHash, writeHash)) {
100
+ rejectedRefs.push({
101
+ localRef,
102
+ reason: `Non-fast-forward update rejected for "${localRef}"`
103
+ });
104
+ continue;
105
+ }
106
+ }
107
+ committedUpdates.push({
108
+ localRef,
109
+ writeHash
110
+ });
111
+ }
112
+ const tx = refs.beginTransaction();
113
+ try {
114
+ for (const { localRef, writeHash } of committedUpdates) tx.write(localRef, writeHash);
115
+ tx.commit();
116
+ } catch (e) {
117
+ tx.rollback();
118
+ throw e;
119
+ }
120
+ return {
121
+ updatedRefs: new Map(committedUpdates.map((u) => [u.localRef, u.writeHash])),
122
+ rejectedRefs
123
+ };
124
+ }
125
+ //#endregion
126
+ export { RefUpdateError, applyRefUpdates, isRefNamespaceRequiringFastForward, resolveBranchTargetHash };
@@ -0,0 +1,11 @@
1
+ import { PushError } from "./client/receive-pack/push-error.mjs";
2
+ import { PushRefItem, determinePushRefs, resolveDefaultRefSpec } from "./client/receive-pack/push-ref-plan.mjs";
3
+ import { checkFastForward } from "./client/receive-pack/push-policy.mjs";
4
+ import { push } from "./client/receive-pack/push.mjs";
5
+ import { computeObjectsToSend, mergePushBoundaries } from "./client/receive-pack/push-pack-plan.mjs";
6
+ import { ReceivePackCommand, buildReceivePackRequest } from "./client/receive-pack/request.mjs";
7
+ import { processPushReport } from "./client/receive-pack/push-report.mjs";
8
+ import { ReceivePackResultError, parseReceivePackResult } from "./client/receive-pack/result.mjs";
9
+ import { ReceivePackResponseError, decodeReceivePackResponse } from "./client/receive-pack/response.mjs";
10
+ import { SmartHttpAuth, SmartHttpError, createReceivePackHttpClient } from "./client/receive-pack/http.mjs";
11
+ export { PushError, type PushRefItem, type ReceivePackCommand, ReceivePackResponseError, ReceivePackResultError, type SmartHttpAuth, SmartHttpError, buildReceivePackRequest, checkFastForward, computeObjectsToSend, createReceivePackHttpClient, decodeReceivePackResponse, determinePushRefs, mergePushBoundaries, parseReceivePackResult, processPushReport, push, resolveDefaultRefSpec };
@@ -0,0 +1,11 @@
1
+ import { PushError } from "./client/receive-pack/push-error.mjs";
2
+ import { SmartHttpError, createReceivePackHttpClient } from "./client/receive-pack/http.mjs";
3
+ import { computeObjectsToSend, mergePushBoundaries } from "./client/receive-pack/push-pack-plan.mjs";
4
+ import { checkFastForward } from "./client/receive-pack/push-policy.mjs";
5
+ import { determinePushRefs, resolveDefaultRefSpec } from "./client/receive-pack/push-ref-plan.mjs";
6
+ import { processPushReport } from "./client/receive-pack/push-report.mjs";
7
+ import { buildReceivePackRequest } from "./client/receive-pack/request.mjs";
8
+ import { ReceivePackResultError, parseReceivePackResult } from "./client/receive-pack/result.mjs";
9
+ import { ReceivePackResponseError, decodeReceivePackResponse } from "./client/receive-pack/response.mjs";
10
+ import { push } from "./client/receive-pack/push.mjs";
11
+ export { PushError, ReceivePackResponseError, ReceivePackResultError, SmartHttpError, buildReceivePackRequest, checkFastForward, computeObjectsToSend, createReceivePackHttpClient, decodeReceivePackResponse, determinePushRefs, mergePushBoundaries, parseReceivePackResult, processPushReport, push, resolveDefaultRefSpec };
@@ -0,0 +1,28 @@
1
+ import { RepositoryBackend } from "../../../backend/types.mjs";
2
+
3
+ //#region src/transport/server/receive-pack/advertise.d.ts
4
+ /**
5
+ * 生成 receive-pack 的 ref 广告
6
+ *
7
+ * 格式:
8
+ * ```
9
+ * 001e# service=git-receive-pack\n
10
+ * 0000
11
+ * <length><hash> <refname>\0<capabilities>\n ← 首行 ref 携带 capabilities
12
+ * <length><hash> <refname>\n ← 后续 ref
13
+ * ...
14
+ * 0000
15
+ * ```
16
+ *
17
+ * @param backend - 仓库后端
18
+ * @returns 完整 advertisement(pkt-line 编码)
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * const buf = advertiseReceivePack(backend);
23
+ * // Response 的 Content-Type 应为 "application/x-git-receive-pack-advertisement"
24
+ * ```
25
+ */
26
+ declare function advertiseReceivePack(backend: RepositoryBackend): Buffer;
27
+ //#endregion
28
+ export { advertiseReceivePack };