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,28 @@
1
+ //#region src/pack/delta-create.d.ts
2
+ /**
3
+ * Delta 创建(编码)
4
+ *
5
+ * 使用哈希表(Rabin-Karp 风格)加速模式匹配:
6
+ * - 预处理 base 中所有 4 字节窗口,构建哈希索引
7
+ * - 对 target 的每个位置,通过哈希表 O(1) 定位候选匹配
8
+ * - 平均时间复杂度 O(B+T),最坏 O(B×T×K)(K 为每桶候选数上限)
9
+ */
10
+ /**
11
+ * 创建 delta 数据(从 base object 到 target object 的差异)
12
+ *
13
+ * 使用哈希表加速贪心匹配策略,相比暴力扫描大幅减少匹配搜索开销。
14
+ *
15
+ * @param base - base object 的原始数据
16
+ * @param target - 目标对象的原始数据
17
+ * @returns delta 数据
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * const base = Buffer.from("hello world");
22
+ * const target = Buffer.from("hello git");
23
+ * const delta = createDelta(base, target);
24
+ * ```
25
+ */
26
+ declare function createDelta(base: Buffer, target: Buffer): Buffer;
27
+ //#endregion
28
+ export { createDelta };
@@ -0,0 +1,151 @@
1
+ import { encodeVarint } from "./varint.mjs";
2
+ //#region src/pack/delta-create.ts
3
+ /**
4
+ * Delta 创建(编码)
5
+ *
6
+ * 使用哈希表(Rabin-Karp 风格)加速模式匹配:
7
+ * - 预处理 base 中所有 4 字节窗口,构建哈希索引
8
+ * - 对 target 的每个位置,通过哈希表 O(1) 定位候选匹配
9
+ * - 平均时间复杂度 O(B+T),最坏 O(B×T×K)(K 为每桶候选数上限)
10
+ */
11
+ /**
12
+ * 创建 delta 数据(从 base object 到 target object 的差异)
13
+ *
14
+ * 使用哈希表加速贪心匹配策略,相比暴力扫描大幅减少匹配搜索开销。
15
+ *
16
+ * @param base - base object 的原始数据
17
+ * @param target - 目标对象的原始数据
18
+ * @returns delta 数据
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * const base = Buffer.from("hello world");
23
+ * const target = Buffer.from("hello git");
24
+ * const delta = createDelta(base, target);
25
+ * ```
26
+ */
27
+ function createDelta(base, target) {
28
+ const parts = [];
29
+ parts.push(encodeVarint(base.length));
30
+ parts.push(encodeVarint(target.length));
31
+ const hashTable = buildHashTable(base);
32
+ let targetOffset = 0;
33
+ while (targetOffset < target.length) {
34
+ const match = findBestMatch(base, target, targetOffset, hashTable);
35
+ if (match && match.length >= 4) {
36
+ parts.push(encodeCopyInstruction(match.offset, match.length));
37
+ targetOffset += match.length;
38
+ continue;
39
+ }
40
+ let insertEnd = targetOffset + 1;
41
+ while (insertEnd < target.length) {
42
+ const nextMatch = findBestMatch(base, target, insertEnd, hashTable);
43
+ if (nextMatch && nextMatch.length >= 4) break;
44
+ insertEnd++;
45
+ if (insertEnd - targetOffset >= 127) break;
46
+ }
47
+ const insertSize = insertEnd - targetOffset;
48
+ parts.push(Buffer.from([insertSize]));
49
+ parts.push(target.subarray(targetOffset, insertEnd));
50
+ targetOffset = insertEnd;
51
+ }
52
+ return Buffer.concat(parts);
53
+ }
54
+ /** 每个哈希值保留的最大候选位置数(防止重复字符串退化) */
55
+ const MAX_CANDIDATES_PER_HASH = 32;
56
+ /**
57
+ * 构建 4 字节窗口哈希表
58
+ *
59
+ * 将 base 中每个 4 字节子串的精确值作为哈希键,
60
+ * 映射到出现该子串的偏移量列表。
61
+ */
62
+ function buildHashTable(base) {
63
+ const table = /* @__PURE__ */ new Map();
64
+ for (let i = 0; i <= base.length - 4; i++) {
65
+ const hash = hash4(base, i);
66
+ let positions = table.get(hash);
67
+ if (!positions) {
68
+ positions = [];
69
+ table.set(hash, positions);
70
+ }
71
+ if (positions.length < MAX_CANDIDATES_PER_HASH) positions.push(i);
72
+ }
73
+ return table;
74
+ }
75
+ /**
76
+ * 计算 Buffer 中 4 字节窗口的 32 位哈希值
77
+ *
78
+ * 使用精确的 4 字节值(大端序)作为哈希,保证相同 4 字节序列得到相同值。
79
+ */
80
+ function hash4(buf, offset) {
81
+ return (buf[offset] << 24 | buf[offset + 1] << 16 | buf[offset + 2] << 8 | buf[offset + 3]) >>> 0;
82
+ }
83
+ /**
84
+ * 使用哈希表查找与 target[targetOffset] 开始的最长匹配
85
+ *
86
+ * 只在哈希表中存在对应 4 字节前缀的位置上搜索匹配并扩展,
87
+ * 替代原实现的暴力全量扫描。
88
+ *
89
+ * @param hashTable - buildHashTable 构建的哈希表
90
+ */
91
+ function findBestMatch(base, target, targetOffset, hashTable) {
92
+ if (targetOffset + 4 > target.length) return null;
93
+ const targetHash = hash4(target, targetOffset);
94
+ const candidates = hashTable.get(targetHash);
95
+ if (!candidates || candidates.length === 0) return null;
96
+ let bestMatch = null;
97
+ const maxLen = Math.min(target.length - targetOffset, 65535);
98
+ for (const baseOffset of candidates) {
99
+ let len = 4;
100
+ while (len < maxLen && baseOffset + len < base.length && base[baseOffset + len] === target[targetOffset + len]) len++;
101
+ if (len > (bestMatch?.length ?? 0)) {
102
+ bestMatch = {
103
+ offset: baseOffset,
104
+ length: len
105
+ };
106
+ if (len === maxLen) break;
107
+ }
108
+ }
109
+ return bestMatch;
110
+ }
111
+ function encodeCopyInstruction(offset, size) {
112
+ const bytes = [];
113
+ let cmd = 128;
114
+ const offsetBytes = [];
115
+ if (offset & 255) {
116
+ cmd |= 1;
117
+ offsetBytes.push(offset & 255);
118
+ }
119
+ if (offset & 65280) {
120
+ cmd |= 2;
121
+ offsetBytes.push(offset >> 8 & 255);
122
+ }
123
+ if (offset & 16711680) {
124
+ cmd |= 4;
125
+ offsetBytes.push(offset >> 16 & 255);
126
+ }
127
+ if (offset & 4278190080) {
128
+ cmd |= 8;
129
+ offsetBytes.push(offset >> 24 & 255);
130
+ }
131
+ const sizeBytes = [];
132
+ if (size !== 65536) {
133
+ if (size & 255) {
134
+ cmd |= 16;
135
+ sizeBytes.push(size & 255);
136
+ }
137
+ if (size & 65280) {
138
+ cmd |= 32;
139
+ sizeBytes.push(size >> 8 & 255);
140
+ }
141
+ if (size & 16711680) {
142
+ cmd |= 64;
143
+ sizeBytes.push(size >> 16 & 255);
144
+ }
145
+ }
146
+ bytes.push(cmd);
147
+ bytes.push(...offsetBytes, ...sizeBytes);
148
+ return Buffer.from(bytes);
149
+ }
150
+ //#endregion
151
+ export { createDelta };
@@ -0,0 +1,16 @@
1
+ import { PackBuildResult } from "./pack-builder-types.mjs";
2
+ import { PackBuilder, createPackBuilder } from "./pack-builder.mjs";
3
+ import { PackObject, packObjectToRaw } from "./pack-reader-types.mjs";
4
+ import { createPackReader } from "./pack-reader.mjs";
5
+ import { PackIndexEntry } from "./pack-index-types.mjs";
6
+ import { PackIndexReader, createPackIndexReader } from "./pack-index-reader.mjs";
7
+ import { PackIndexWriter, createPackIndexWriter } from "./pack-index-writer.mjs";
8
+ import { PackFileInfo } from "./pack-store-types.mjs";
9
+ import { PackObjectStore, createPackObjectStore } from "./pack-store.mjs";
10
+ import { CompositeObjectDatabase, createCompositeObjectDatabase } from "./composite-store.mjs";
11
+ import { applyDelta } from "./delta-apply.mjs";
12
+ import { createDelta } from "./delta-create.mjs";
13
+ import { decodeObjectHeader, encodeObjectHeader } from "./object-header.mjs";
14
+ import { decodeOfsDeltaOffset, encodeOfsDeltaOffset } from "./ofs-delta-offset.mjs";
15
+ import { decodeVarint, encodeVarint } from "./varint.mjs";
16
+ export { CompositeObjectDatabase, type PackBuildResult, type PackBuilder, type PackFileInfo, type PackIndexEntry, type PackIndexReader, type PackIndexWriter, type PackObject, type PackObjectStore, applyDelta, createCompositeObjectDatabase, createDelta, createPackBuilder, createPackIndexReader, createPackIndexWriter, createPackObjectStore, createPackReader, decodeObjectHeader, decodeOfsDeltaOffset, decodeVarint, encodeObjectHeader, encodeOfsDeltaOffset, encodeVarint, packObjectToRaw };
@@ -0,0 +1,13 @@
1
+ import { decodeObjectHeader, encodeObjectHeader } from "./object-header.mjs";
2
+ import { decodeOfsDeltaOffset, encodeOfsDeltaOffset } from "./ofs-delta-offset.mjs";
3
+ import { decodeVarint, encodeVarint } from "./varint.mjs";
4
+ import { applyDelta } from "./delta-apply.mjs";
5
+ import { createDelta } from "./delta-create.mjs";
6
+ import { packObjectToRaw } from "./pack-reader-types.mjs";
7
+ import { createPackReader } from "./pack-reader.mjs";
8
+ import { createPackIndexReader } from "./pack-index-reader.mjs";
9
+ import { createPackIndexWriter } from "./pack-index-writer.mjs";
10
+ import { createPackBuilder } from "./pack-builder.mjs";
11
+ import { createPackObjectStore } from "./pack-store.mjs";
12
+ import { CompositeObjectDatabase, createCompositeObjectDatabase } from "./composite-store.mjs";
13
+ export { CompositeObjectDatabase, applyDelta, createCompositeObjectDatabase, createDelta, createPackBuilder, createPackIndexReader, createPackIndexWriter, createPackObjectStore, createPackReader, decodeObjectHeader, decodeOfsDeltaOffset, decodeVarint, encodeObjectHeader, encodeOfsDeltaOffset, encodeVarint, packObjectToRaw };
@@ -0,0 +1,36 @@
1
+ //#region src/pack/object-header.d.ts
2
+ /**
3
+ * Packfile 对象头部编码/解码
4
+ */
5
+ /**
6
+ * 解码 Packfile 对象头部的变长整数
7
+ *
8
+ * 对象头部格式:
9
+ * - 第 1 字节:高 3 位是类型,低 4 位是大小
10
+ * - 后续字节:高 1 位是继续标志,低 7 位是大小
11
+ *
12
+ * @param buf - 数据缓冲区
13
+ * @param offset - 起始偏移量
14
+ * @returns [类型编号, 大小, 消耗的字节数]
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const [type, size, bytesRead] = decodeObjectHeader(buf, 0);
19
+ * ```
20
+ */
21
+ declare function decodeObjectHeader(buf: Buffer, offset: number): [type: number, size: number, bytesRead: number];
22
+ /**
23
+ * 编码 Packfile 对象头部的变长整数
24
+ *
25
+ * @param type - 对象类型编号(1-7)
26
+ * @param size - 对象大小
27
+ * @returns 编码后的字节缓冲区
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const header = encodeObjectHeader(3, 11);
32
+ * ```
33
+ */
34
+ declare function encodeObjectHeader(type: number, size: number): Buffer;
35
+ //#endregion
36
+ export { decodeObjectHeader, encodeObjectHeader };
@@ -0,0 +1,72 @@
1
+ import { InvalidPackError } from "../core/errors.mjs";
2
+ //#region src/pack/object-header.ts
3
+ /**
4
+ * Packfile 对象头部编码/解码
5
+ */
6
+ /**
7
+ * 解码 Packfile 对象头部的变长整数
8
+ *
9
+ * 对象头部格式:
10
+ * - 第 1 字节:高 3 位是类型,低 4 位是大小
11
+ * - 后续字节:高 1 位是继续标志,低 7 位是大小
12
+ *
13
+ * @param buf - 数据缓冲区
14
+ * @param offset - 起始偏移量
15
+ * @returns [类型编号, 大小, 消耗的字节数]
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * const [type, size, bytesRead] = decodeObjectHeader(buf, 0);
20
+ * ```
21
+ */
22
+ function decodeObjectHeader(buf, offset) {
23
+ if (offset >= buf.length) throw new InvalidPackError("Unexpected end of data in object header");
24
+ const firstByte = buf[offset];
25
+ const type = firstByte >> 4 & 7;
26
+ let size = firstByte & 15;
27
+ let shift = 4;
28
+ let bytesRead = 1;
29
+ if (firstByte & 128) {
30
+ let byte;
31
+ do {
32
+ if (offset + bytesRead >= buf.length) throw new InvalidPackError("Unexpected end of data in variable-length integer");
33
+ byte = buf[offset + bytesRead];
34
+ size |= (byte & 127) << shift;
35
+ shift += 7;
36
+ bytesRead++;
37
+ } while (byte & 128);
38
+ }
39
+ return [
40
+ type,
41
+ size,
42
+ bytesRead
43
+ ];
44
+ }
45
+ /**
46
+ * 编码 Packfile 对象头部的变长整数
47
+ *
48
+ * @param type - 对象类型编号(1-7)
49
+ * @param size - 对象大小
50
+ * @returns 编码后的字节缓冲区
51
+ *
52
+ * @example
53
+ * ```ts
54
+ * const header = encodeObjectHeader(3, 11);
55
+ * ```
56
+ */
57
+ function encodeObjectHeader(type, size) {
58
+ const bytes = [];
59
+ let byte = (type & 7) << 4 | size & 15;
60
+ size >>>= 4;
61
+ if (size > 0) byte |= 128;
62
+ bytes.push(byte);
63
+ while (size > 0) {
64
+ byte = size & 127;
65
+ size >>>= 7;
66
+ if (size > 0) byte |= 128;
67
+ bytes.push(byte);
68
+ }
69
+ return Buffer.from(bytes);
70
+ }
71
+ //#endregion
72
+ export { decodeObjectHeader, encodeObjectHeader };
@@ -0,0 +1,35 @@
1
+ //#region src/pack/ofs-delta-offset.d.ts
2
+ /**
3
+ * Packfile ofs_delta 偏移量编码/解码
4
+ */
5
+ /**
6
+ * 解码 ofs_delta 的负偏移量
7
+ *
8
+ * ofs_delta 使用特殊的变长编码表示相对于当前对象的偏移量。
9
+ * 编码方式:每个字节的最高位是继续标志,低 7 位是数据。
10
+ * 后续字节需要先加 1 再左移,以支持更大的偏移量。
11
+ *
12
+ * @param buf - 数据缓冲区
13
+ * @param offset - 起始偏移量
14
+ * @returns [偏移量, 消耗的字节数]
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const [value, bytesRead] = decodeOfsDeltaOffset(buf, 0);
19
+ * ```
20
+ */
21
+ declare function decodeOfsDeltaOffset(buf: Buffer, offset: number): [offsetValue: number, bytesRead: number];
22
+ /**
23
+ * 编码 ofs_delta 的负偏移量
24
+ *
25
+ * @param offsetValue - 偏移量(正数,表示向后偏移的字节数)
26
+ * @returns 编码后的字节缓冲区
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * const encoded = encodeOfsDeltaOffset(123);
31
+ * ```
32
+ */
33
+ declare function encodeOfsDeltaOffset(offsetValue: number): Buffer;
34
+ //#endregion
35
+ export { decodeOfsDeltaOffset, encodeOfsDeltaOffset };
@@ -0,0 +1,59 @@
1
+ import { InvalidPackError } from "../core/errors.mjs";
2
+ //#region src/pack/ofs-delta-offset.ts
3
+ /**
4
+ * Packfile ofs_delta 偏移量编码/解码
5
+ */
6
+ /**
7
+ * 解码 ofs_delta 的负偏移量
8
+ *
9
+ * ofs_delta 使用特殊的变长编码表示相对于当前对象的偏移量。
10
+ * 编码方式:每个字节的最高位是继续标志,低 7 位是数据。
11
+ * 后续字节需要先加 1 再左移,以支持更大的偏移量。
12
+ *
13
+ * @param buf - 数据缓冲区
14
+ * @param offset - 起始偏移量
15
+ * @returns [偏移量, 消耗的字节数]
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * const [value, bytesRead] = decodeOfsDeltaOffset(buf, 0);
20
+ * ```
21
+ */
22
+ function decodeOfsDeltaOffset(buf, offset) {
23
+ if (offset >= buf.length) throw new InvalidPackError("Unexpected end of data in ofs_delta offset");
24
+ let byte = buf[offset];
25
+ let value = byte & 127;
26
+ let bytesRead = 1;
27
+ while (byte & 128) {
28
+ if (offset + bytesRead >= buf.length) throw new InvalidPackError("Unexpected end of data in ofs_delta offset");
29
+ byte = buf[offset + bytesRead];
30
+ value = value + 1 << 7 | byte & 127;
31
+ bytesRead++;
32
+ }
33
+ return [value, bytesRead];
34
+ }
35
+ /**
36
+ * 编码 ofs_delta 的负偏移量
37
+ *
38
+ * @param offsetValue - 偏移量(正数,表示向后偏移的字节数)
39
+ * @returns 编码后的字节缓冲区
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * const encoded = encodeOfsDeltaOffset(123);
44
+ * ```
45
+ */
46
+ function encodeOfsDeltaOffset(offsetValue) {
47
+ const bytes = [];
48
+ let value = offsetValue;
49
+ bytes.unshift(value & 127);
50
+ value >>>= 7;
51
+ while (value > 0) {
52
+ value--;
53
+ bytes.unshift(value & 127 | 128);
54
+ value >>>= 7;
55
+ }
56
+ return Buffer.from(bytes);
57
+ }
58
+ //#endregion
59
+ export { decodeOfsDeltaOffset, encodeOfsDeltaOffset };
@@ -0,0 +1,19 @@
1
+ //#region src/pack/pack-builder-types.d.ts
2
+ /**
3
+ * Packfile 构建器共享类型
4
+ */
5
+ /**
6
+ * Packfile 构建结果
7
+ */
8
+ interface PackBuildResult {
9
+ /** packfile 文件路径 */
10
+ packPath: string;
11
+ /** 索引文件路径 */
12
+ idxPath: string;
13
+ /** packfile 的 SHA-1 校验和 */
14
+ checksum: string;
15
+ /** 打包的对象数量 */
16
+ objectCount: number;
17
+ }
18
+ //#endregion
19
+ export { PackBuildResult };
@@ -0,0 +1,52 @@
1
+ import { RawGitObject, SHA1 } from "../core/types.mjs";
2
+ import { PackBuildResult } from "./pack-builder-types.mjs";
3
+
4
+ //#region src/pack/pack-builder.d.ts
5
+ /**
6
+ * Packfile 构建器接口
7
+ */
8
+ interface PackBuilder {
9
+ /** 获取已添加的对象数量 */
10
+ readonly objectCount: number;
11
+ /**
12
+ * 添加一个原始对象
13
+ *
14
+ * @param raw - 原始 Git 对象
15
+ * @returns 对象的 SHA-1 哈希
16
+ */
17
+ addRaw(raw: RawGitObject): SHA1;
18
+ /**
19
+ * 构建 packfile 和索引文件
20
+ *
21
+ * @returns 构建结果,包含文件路径和校验和
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const result = builder.build();
26
+ * console.log(`Packfile: ${result.packPath}`);
27
+ * console.log(`Index: ${result.idxPath}`);
28
+ * ```
29
+ */
30
+ build(): PackBuildResult;
31
+ }
32
+ /**
33
+ * 创建 Packfile 构建器
34
+ *
35
+ * @param gitDir - .git 目录的路径
36
+ * @returns Packfile 构建器实例
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * const builder = createPackBuilder("/path/to/.git");
41
+ *
42
+ * // 添加原始对象
43
+ * builder.addRaw(raw);
44
+ *
45
+ * // 构建并写入
46
+ * const result = builder.build();
47
+ * console.log(`已打包 ${result.objectCount} 个对象到 ${result.packPath}`);
48
+ * ```
49
+ */
50
+ declare function createPackBuilder(gitDir: string): PackBuilder;
51
+ //#endregion
52
+ export { PackBuilder, createPackBuilder };
@@ -0,0 +1,80 @@
1
+ import { createPackIndexWriter } from "./pack-index-writer.mjs";
2
+ import { buildEncodedPack, toEncodedPackObject } from "./pack-encoding.mjs";
3
+ import { mkdirSync, writeFileSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ //#region src/pack/pack-builder.ts
6
+ /**
7
+ * Packfile 构建器
8
+ *
9
+ * 将 loose objects 打包成新的 packfile 和索引文件,
10
+ * 并写入到 .git/objects/pack/ 目录。
11
+ *
12
+ * 这是 `git repack` 和 `git gc` 的核心功能。
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * const builder = createPackBuilder(gitDir);
17
+ * builder.addObject(blob);
18
+ * builder.addObject(commit);
19
+ * const result = builder.build();
20
+ * // result => { packPath, idxPath, checksum, objectCount }
21
+ * ```
22
+ */
23
+ /**
24
+ * 创建 Packfile 构建器
25
+ *
26
+ * @param gitDir - .git 目录的路径
27
+ * @returns Packfile 构建器实例
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const builder = createPackBuilder("/path/to/.git");
32
+ *
33
+ * // 添加原始对象
34
+ * builder.addRaw(raw);
35
+ *
36
+ * // 构建并写入
37
+ * const result = builder.build();
38
+ * console.log(`已打包 ${result.objectCount} 个对象到 ${result.packPath}`);
39
+ * ```
40
+ */
41
+ function createPackBuilder(gitDir) {
42
+ const objects = [];
43
+ const hashes = /* @__PURE__ */ new Set();
44
+ function addRaw(raw) {
45
+ const entry = toEncodedPackObject(raw);
46
+ const hash = entry.hash;
47
+ if (hashes.has(hash)) return hash;
48
+ objects.push(entry);
49
+ hashes.add(hash);
50
+ return hash;
51
+ }
52
+ function build() {
53
+ const packDir = join(gitDir, "objects", "pack");
54
+ mkdirSync(packDir, { recursive: true });
55
+ const encoded = buildEncodedPack(objects);
56
+ const idxWriter = createPackIndexWriter();
57
+ for (const entry of encoded.entries) idxWriter.addEntry(entry);
58
+ const idxData = idxWriter.build(encoded.packChecksum);
59
+ const checksumHex = encoded.packChecksum.toString("hex");
60
+ const packPath = join(packDir, `pack-${checksumHex}.pack`);
61
+ const idxPath = join(packDir, `pack-${checksumHex}.idx`);
62
+ writeFileSync(packPath, encoded.packData);
63
+ writeFileSync(idxPath, idxData);
64
+ return {
65
+ packPath,
66
+ idxPath,
67
+ checksum: checksumHex,
68
+ objectCount: objects.length
69
+ };
70
+ }
71
+ return {
72
+ get objectCount() {
73
+ return objects.length;
74
+ },
75
+ addRaw,
76
+ build
77
+ };
78
+ }
79
+ //#endregion
80
+ export { createPackBuilder };
@@ -0,0 +1,76 @@
1
+ import { PACK_SIGNATURE, objectTypeToNumber } from "./constants.mjs";
2
+ import { encodeObjectHeader } from "./object-header.mjs";
3
+ import { crc32Value } from "./crc32.mjs";
4
+ import { createHash } from "node:crypto";
5
+ import { deflateSync } from "node:zlib";
6
+ //#region src/pack/pack-encoding.ts
7
+ /**
8
+ * Packfile 编码共享逻辑
9
+ */
10
+ /**
11
+ * 将原始对象标准化为 pack 编码条目
12
+ *
13
+ * RawGitObject 的 { type, hash, content } 直接映射到 EncodedPackObject 的
14
+ * { type, hash, data },无需额外哈希计算或序列化。
15
+ *
16
+ * @param raw - 原始对象
17
+ * @returns 编码条目
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * const entry = toEncodedPackObject(raw);
22
+ * ```
23
+ */
24
+ function toEncodedPackObject(raw) {
25
+ return {
26
+ type: raw.type,
27
+ hash: raw.hash,
28
+ data: raw.content
29
+ };
30
+ }
31
+ /**
32
+ * 构建 packfile 二进制内容,并返回索引所需元数据
33
+ *
34
+ * @param objects - 已标准化的编码条目
35
+ * @returns pack 数据和索引条目
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * const result = buildEncodedPack(entries);
40
+ * ```
41
+ */
42
+ function buildEncodedPack(objects) {
43
+ const packParts = [];
44
+ const entries = [];
45
+ packParts.push(createPackHeader(objects.length));
46
+ let currentOffset = packParts[0].length;
47
+ for (const object of objects) {
48
+ const objectHeader = encodeObjectHeader(objectTypeToNumber(object.type), object.data.length);
49
+ const compressed = deflateSync(object.data);
50
+ const objectData = Buffer.concat([objectHeader, compressed]);
51
+ entries.push({
52
+ hash: object.hash,
53
+ offset: currentOffset,
54
+ crc32: crc32Value(objectData)
55
+ });
56
+ packParts.push(objectHeader, compressed);
57
+ currentOffset += objectData.length;
58
+ }
59
+ const packWithoutChecksum = Buffer.concat(packParts);
60
+ const packChecksum = createHash("sha1").update(packWithoutChecksum).digest();
61
+ return {
62
+ packWithoutChecksum,
63
+ packChecksum,
64
+ packData: Buffer.concat([packWithoutChecksum, packChecksum]),
65
+ entries
66
+ };
67
+ }
68
+ function createPackHeader(objectCount) {
69
+ const header = Buffer.alloc(12);
70
+ PACK_SIGNATURE.copy(header, 0);
71
+ header.writeUInt32BE(2, 4);
72
+ header.writeUInt32BE(objectCount, 8);
73
+ return header;
74
+ }
75
+ //#endregion
76
+ export { buildEncodedPack, toEncodedPackObject };