gitx.do 0.1.0 → 0.1.2

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 (344) hide show
  1. package/README.md +40 -353
  2. package/dist/do/logger.d.ts +50 -0
  3. package/dist/do/logger.d.ts.map +1 -0
  4. package/dist/do/logger.js +122 -0
  5. package/dist/do/logger.js.map +1 -0
  6. package/dist/{durable-object → do}/schema.d.ts +3 -3
  7. package/dist/do/schema.d.ts.map +1 -0
  8. package/dist/{durable-object → do}/schema.js +4 -3
  9. package/dist/do/schema.js.map +1 -0
  10. package/dist/do/types.d.ts +267 -0
  11. package/dist/do/types.d.ts.map +1 -0
  12. package/dist/do/types.js +62 -0
  13. package/dist/do/types.js.map +1 -0
  14. package/dist/index.d.ts +15 -415
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +31 -483
  17. package/dist/index.js.map +1 -1
  18. package/package.json +13 -21
  19. package/dist/cli/commands/add.d.ts +0 -174
  20. package/dist/cli/commands/add.d.ts.map +0 -1
  21. package/dist/cli/commands/add.js +0 -131
  22. package/dist/cli/commands/add.js.map +0 -1
  23. package/dist/cli/commands/blame.d.ts +0 -259
  24. package/dist/cli/commands/blame.d.ts.map +0 -1
  25. package/dist/cli/commands/blame.js +0 -609
  26. package/dist/cli/commands/blame.js.map +0 -1
  27. package/dist/cli/commands/branch.d.ts +0 -249
  28. package/dist/cli/commands/branch.d.ts.map +0 -1
  29. package/dist/cli/commands/branch.js +0 -693
  30. package/dist/cli/commands/branch.js.map +0 -1
  31. package/dist/cli/commands/commit.d.ts +0 -182
  32. package/dist/cli/commands/commit.d.ts.map +0 -1
  33. package/dist/cli/commands/commit.js +0 -437
  34. package/dist/cli/commands/commit.js.map +0 -1
  35. package/dist/cli/commands/diff.d.ts +0 -464
  36. package/dist/cli/commands/diff.d.ts.map +0 -1
  37. package/dist/cli/commands/diff.js +0 -958
  38. package/dist/cli/commands/diff.js.map +0 -1
  39. package/dist/cli/commands/log.d.ts +0 -239
  40. package/dist/cli/commands/log.d.ts.map +0 -1
  41. package/dist/cli/commands/log.js +0 -535
  42. package/dist/cli/commands/log.js.map +0 -1
  43. package/dist/cli/commands/merge.d.ts +0 -106
  44. package/dist/cli/commands/merge.d.ts.map +0 -1
  45. package/dist/cli/commands/merge.js +0 -55
  46. package/dist/cli/commands/merge.js.map +0 -1
  47. package/dist/cli/commands/review.d.ts +0 -457
  48. package/dist/cli/commands/review.d.ts.map +0 -1
  49. package/dist/cli/commands/review.js +0 -533
  50. package/dist/cli/commands/review.js.map +0 -1
  51. package/dist/cli/commands/status.d.ts +0 -269
  52. package/dist/cli/commands/status.d.ts.map +0 -1
  53. package/dist/cli/commands/status.js +0 -493
  54. package/dist/cli/commands/status.js.map +0 -1
  55. package/dist/cli/commands/web.d.ts +0 -199
  56. package/dist/cli/commands/web.d.ts.map +0 -1
  57. package/dist/cli/commands/web.js +0 -696
  58. package/dist/cli/commands/web.js.map +0 -1
  59. package/dist/cli/fs-adapter.d.ts +0 -656
  60. package/dist/cli/fs-adapter.d.ts.map +0 -1
  61. package/dist/cli/fs-adapter.js +0 -1179
  62. package/dist/cli/fs-adapter.js.map +0 -1
  63. package/dist/cli/fsx-cli-adapter.d.ts +0 -359
  64. package/dist/cli/fsx-cli-adapter.d.ts.map +0 -1
  65. package/dist/cli/fsx-cli-adapter.js +0 -619
  66. package/dist/cli/fsx-cli-adapter.js.map +0 -1
  67. package/dist/cli/index.d.ts +0 -387
  68. package/dist/cli/index.d.ts.map +0 -1
  69. package/dist/cli/index.js +0 -523
  70. package/dist/cli/index.js.map +0 -1
  71. package/dist/cli/ui/components/DiffView.d.ts +0 -7
  72. package/dist/cli/ui/components/DiffView.d.ts.map +0 -1
  73. package/dist/cli/ui/components/DiffView.js +0 -11
  74. package/dist/cli/ui/components/DiffView.js.map +0 -1
  75. package/dist/cli/ui/components/ErrorDisplay.d.ts +0 -6
  76. package/dist/cli/ui/components/ErrorDisplay.d.ts.map +0 -1
  77. package/dist/cli/ui/components/ErrorDisplay.js +0 -11
  78. package/dist/cli/ui/components/ErrorDisplay.js.map +0 -1
  79. package/dist/cli/ui/components/FuzzySearch.d.ts +0 -9
  80. package/dist/cli/ui/components/FuzzySearch.d.ts.map +0 -1
  81. package/dist/cli/ui/components/FuzzySearch.js +0 -12
  82. package/dist/cli/ui/components/FuzzySearch.js.map +0 -1
  83. package/dist/cli/ui/components/LoadingSpinner.d.ts +0 -6
  84. package/dist/cli/ui/components/LoadingSpinner.d.ts.map +0 -1
  85. package/dist/cli/ui/components/LoadingSpinner.js +0 -10
  86. package/dist/cli/ui/components/LoadingSpinner.js.map +0 -1
  87. package/dist/cli/ui/components/NavigationList.d.ts +0 -9
  88. package/dist/cli/ui/components/NavigationList.d.ts.map +0 -1
  89. package/dist/cli/ui/components/NavigationList.js +0 -11
  90. package/dist/cli/ui/components/NavigationList.js.map +0 -1
  91. package/dist/cli/ui/components/ScrollableContent.d.ts +0 -8
  92. package/dist/cli/ui/components/ScrollableContent.d.ts.map +0 -1
  93. package/dist/cli/ui/components/ScrollableContent.js +0 -11
  94. package/dist/cli/ui/components/ScrollableContent.js.map +0 -1
  95. package/dist/cli/ui/components/index.d.ts +0 -7
  96. package/dist/cli/ui/components/index.d.ts.map +0 -1
  97. package/dist/cli/ui/components/index.js +0 -9
  98. package/dist/cli/ui/components/index.js.map +0 -1
  99. package/dist/cli/ui/terminal-ui.d.ts +0 -52
  100. package/dist/cli/ui/terminal-ui.d.ts.map +0 -1
  101. package/dist/cli/ui/terminal-ui.js +0 -121
  102. package/dist/cli/ui/terminal-ui.js.map +0 -1
  103. package/dist/do/BashModule.d.ts +0 -871
  104. package/dist/do/BashModule.d.ts.map +0 -1
  105. package/dist/do/BashModule.js +0 -1143
  106. package/dist/do/BashModule.js.map +0 -1
  107. package/dist/do/FsModule.d.ts +0 -601
  108. package/dist/do/FsModule.d.ts.map +0 -1
  109. package/dist/do/FsModule.js +0 -1120
  110. package/dist/do/FsModule.js.map +0 -1
  111. package/dist/do/GitModule.d.ts +0 -635
  112. package/dist/do/GitModule.d.ts.map +0 -1
  113. package/dist/do/GitModule.js +0 -781
  114. package/dist/do/GitModule.js.map +0 -1
  115. package/dist/do/GitRepoDO.d.ts +0 -281
  116. package/dist/do/GitRepoDO.d.ts.map +0 -1
  117. package/dist/do/GitRepoDO.js +0 -479
  118. package/dist/do/GitRepoDO.js.map +0 -1
  119. package/dist/do/bash-ast.d.ts +0 -246
  120. package/dist/do/bash-ast.d.ts.map +0 -1
  121. package/dist/do/bash-ast.js +0 -888
  122. package/dist/do/bash-ast.js.map +0 -1
  123. package/dist/do/container-executor.d.ts +0 -491
  124. package/dist/do/container-executor.d.ts.map +0 -1
  125. package/dist/do/container-executor.js +0 -730
  126. package/dist/do/container-executor.js.map +0 -1
  127. package/dist/do/index.d.ts +0 -53
  128. package/dist/do/index.d.ts.map +0 -1
  129. package/dist/do/index.js +0 -91
  130. package/dist/do/index.js.map +0 -1
  131. package/dist/do/tiered-storage.d.ts +0 -403
  132. package/dist/do/tiered-storage.d.ts.map +0 -1
  133. package/dist/do/tiered-storage.js +0 -689
  134. package/dist/do/tiered-storage.js.map +0 -1
  135. package/dist/do/withBash.d.ts +0 -231
  136. package/dist/do/withBash.d.ts.map +0 -1
  137. package/dist/do/withBash.js +0 -244
  138. package/dist/do/withBash.js.map +0 -1
  139. package/dist/do/withFs.d.ts +0 -237
  140. package/dist/do/withFs.d.ts.map +0 -1
  141. package/dist/do/withFs.js +0 -387
  142. package/dist/do/withFs.js.map +0 -1
  143. package/dist/do/withGit.d.ts +0 -180
  144. package/dist/do/withGit.d.ts.map +0 -1
  145. package/dist/do/withGit.js +0 -271
  146. package/dist/do/withGit.js.map +0 -1
  147. package/dist/durable-object/object-store.d.ts +0 -633
  148. package/dist/durable-object/object-store.d.ts.map +0 -1
  149. package/dist/durable-object/object-store.js +0 -1161
  150. package/dist/durable-object/object-store.js.map +0 -1
  151. package/dist/durable-object/schema.d.ts.map +0 -1
  152. package/dist/durable-object/schema.js.map +0 -1
  153. package/dist/durable-object/wal.d.ts +0 -416
  154. package/dist/durable-object/wal.d.ts.map +0 -1
  155. package/dist/durable-object/wal.js +0 -445
  156. package/dist/durable-object/wal.js.map +0 -1
  157. package/dist/mcp/adapter.d.ts +0 -772
  158. package/dist/mcp/adapter.d.ts.map +0 -1
  159. package/dist/mcp/adapter.js +0 -895
  160. package/dist/mcp/adapter.js.map +0 -1
  161. package/dist/mcp/sandbox/miniflare-evaluator.d.ts +0 -22
  162. package/dist/mcp/sandbox/miniflare-evaluator.d.ts.map +0 -1
  163. package/dist/mcp/sandbox/miniflare-evaluator.js +0 -140
  164. package/dist/mcp/sandbox/miniflare-evaluator.js.map +0 -1
  165. package/dist/mcp/sandbox/object-store-proxy.d.ts +0 -32
  166. package/dist/mcp/sandbox/object-store-proxy.d.ts.map +0 -1
  167. package/dist/mcp/sandbox/object-store-proxy.js +0 -30
  168. package/dist/mcp/sandbox/object-store-proxy.js.map +0 -1
  169. package/dist/mcp/sandbox/template.d.ts +0 -17
  170. package/dist/mcp/sandbox/template.d.ts.map +0 -1
  171. package/dist/mcp/sandbox/template.js +0 -71
  172. package/dist/mcp/sandbox/template.js.map +0 -1
  173. package/dist/mcp/sandbox.d.ts +0 -764
  174. package/dist/mcp/sandbox.d.ts.map +0 -1
  175. package/dist/mcp/sandbox.js +0 -1362
  176. package/dist/mcp/sandbox.js.map +0 -1
  177. package/dist/mcp/sdk-adapter.d.ts +0 -835
  178. package/dist/mcp/sdk-adapter.d.ts.map +0 -1
  179. package/dist/mcp/sdk-adapter.js +0 -974
  180. package/dist/mcp/sdk-adapter.js.map +0 -1
  181. package/dist/mcp/tools/do.d.ts +0 -32
  182. package/dist/mcp/tools/do.d.ts.map +0 -1
  183. package/dist/mcp/tools/do.js +0 -115
  184. package/dist/mcp/tools/do.js.map +0 -1
  185. package/dist/mcp/tools.d.ts +0 -548
  186. package/dist/mcp/tools.d.ts.map +0 -1
  187. package/dist/mcp/tools.js +0 -1934
  188. package/dist/mcp/tools.js.map +0 -1
  189. package/dist/ops/blame.d.ts +0 -551
  190. package/dist/ops/blame.d.ts.map +0 -1
  191. package/dist/ops/blame.js +0 -1037
  192. package/dist/ops/blame.js.map +0 -1
  193. package/dist/ops/branch.d.ts +0 -766
  194. package/dist/ops/branch.d.ts.map +0 -1
  195. package/dist/ops/branch.js +0 -950
  196. package/dist/ops/branch.js.map +0 -1
  197. package/dist/ops/commit-traversal.d.ts +0 -349
  198. package/dist/ops/commit-traversal.d.ts.map +0 -1
  199. package/dist/ops/commit-traversal.js +0 -821
  200. package/dist/ops/commit-traversal.js.map +0 -1
  201. package/dist/ops/commit.d.ts +0 -555
  202. package/dist/ops/commit.d.ts.map +0 -1
  203. package/dist/ops/commit.js +0 -826
  204. package/dist/ops/commit.js.map +0 -1
  205. package/dist/ops/merge-base.d.ts +0 -397
  206. package/dist/ops/merge-base.d.ts.map +0 -1
  207. package/dist/ops/merge-base.js +0 -691
  208. package/dist/ops/merge-base.js.map +0 -1
  209. package/dist/ops/merge.d.ts +0 -855
  210. package/dist/ops/merge.d.ts.map +0 -1
  211. package/dist/ops/merge.js +0 -1551
  212. package/dist/ops/merge.js.map +0 -1
  213. package/dist/ops/tag.d.ts +0 -247
  214. package/dist/ops/tag.d.ts.map +0 -1
  215. package/dist/ops/tag.js +0 -649
  216. package/dist/ops/tag.js.map +0 -1
  217. package/dist/ops/tree-builder.d.ts +0 -178
  218. package/dist/ops/tree-builder.d.ts.map +0 -1
  219. package/dist/ops/tree-builder.js +0 -271
  220. package/dist/ops/tree-builder.js.map +0 -1
  221. package/dist/ops/tree-diff.d.ts +0 -291
  222. package/dist/ops/tree-diff.d.ts.map +0 -1
  223. package/dist/ops/tree-diff.js +0 -705
  224. package/dist/ops/tree-diff.js.map +0 -1
  225. package/dist/pack/delta.d.ts +0 -248
  226. package/dist/pack/delta.d.ts.map +0 -1
  227. package/dist/pack/delta.js +0 -736
  228. package/dist/pack/delta.js.map +0 -1
  229. package/dist/pack/format.d.ts +0 -446
  230. package/dist/pack/format.d.ts.map +0 -1
  231. package/dist/pack/format.js +0 -572
  232. package/dist/pack/format.js.map +0 -1
  233. package/dist/pack/full-generation.d.ts +0 -612
  234. package/dist/pack/full-generation.d.ts.map +0 -1
  235. package/dist/pack/full-generation.js +0 -1378
  236. package/dist/pack/full-generation.js.map +0 -1
  237. package/dist/pack/generation.d.ts +0 -441
  238. package/dist/pack/generation.d.ts.map +0 -1
  239. package/dist/pack/generation.js +0 -707
  240. package/dist/pack/generation.js.map +0 -1
  241. package/dist/pack/index.d.ts +0 -502
  242. package/dist/pack/index.d.ts.map +0 -1
  243. package/dist/pack/index.js +0 -833
  244. package/dist/pack/index.js.map +0 -1
  245. package/dist/refs/branch.d.ts +0 -668
  246. package/dist/refs/branch.d.ts.map +0 -1
  247. package/dist/refs/branch.js +0 -897
  248. package/dist/refs/branch.js.map +0 -1
  249. package/dist/refs/storage.d.ts +0 -833
  250. package/dist/refs/storage.d.ts.map +0 -1
  251. package/dist/refs/storage.js +0 -1023
  252. package/dist/refs/storage.js.map +0 -1
  253. package/dist/refs/tag.d.ts +0 -860
  254. package/dist/refs/tag.d.ts.map +0 -1
  255. package/dist/refs/tag.js +0 -996
  256. package/dist/refs/tag.js.map +0 -1
  257. package/dist/storage/backend.d.ts +0 -425
  258. package/dist/storage/backend.d.ts.map +0 -1
  259. package/dist/storage/backend.js +0 -41
  260. package/dist/storage/backend.js.map +0 -1
  261. package/dist/storage/fsx-adapter.d.ts +0 -204
  262. package/dist/storage/fsx-adapter.d.ts.map +0 -1
  263. package/dist/storage/fsx-adapter.js +0 -470
  264. package/dist/storage/fsx-adapter.js.map +0 -1
  265. package/dist/storage/lru-cache.d.ts +0 -691
  266. package/dist/storage/lru-cache.d.ts.map +0 -1
  267. package/dist/storage/lru-cache.js +0 -813
  268. package/dist/storage/lru-cache.js.map +0 -1
  269. package/dist/storage/object-index.d.ts +0 -585
  270. package/dist/storage/object-index.d.ts.map +0 -1
  271. package/dist/storage/object-index.js +0 -532
  272. package/dist/storage/object-index.js.map +0 -1
  273. package/dist/storage/r2-pack.d.ts +0 -1257
  274. package/dist/storage/r2-pack.d.ts.map +0 -1
  275. package/dist/storage/r2-pack.js +0 -1770
  276. package/dist/storage/r2-pack.js.map +0 -1
  277. package/dist/tiered/cdc-pipeline.d.ts +0 -1888
  278. package/dist/tiered/cdc-pipeline.d.ts.map +0 -1
  279. package/dist/tiered/cdc-pipeline.js +0 -1880
  280. package/dist/tiered/cdc-pipeline.js.map +0 -1
  281. package/dist/tiered/migration.d.ts +0 -1104
  282. package/dist/tiered/migration.d.ts.map +0 -1
  283. package/dist/tiered/migration.js +0 -1214
  284. package/dist/tiered/migration.js.map +0 -1
  285. package/dist/tiered/parquet-writer.d.ts +0 -1145
  286. package/dist/tiered/parquet-writer.d.ts.map +0 -1
  287. package/dist/tiered/parquet-writer.js +0 -1183
  288. package/dist/tiered/parquet-writer.js.map +0 -1
  289. package/dist/tiered/read-path.d.ts +0 -835
  290. package/dist/tiered/read-path.d.ts.map +0 -1
  291. package/dist/tiered/read-path.js +0 -487
  292. package/dist/tiered/read-path.js.map +0 -1
  293. package/dist/types/capability.d.ts +0 -1385
  294. package/dist/types/capability.d.ts.map +0 -1
  295. package/dist/types/capability.js +0 -36
  296. package/dist/types/capability.js.map +0 -1
  297. package/dist/types/index.d.ts +0 -13
  298. package/dist/types/index.d.ts.map +0 -1
  299. package/dist/types/index.js +0 -18
  300. package/dist/types/index.js.map +0 -1
  301. package/dist/types/objects.d.ts +0 -692
  302. package/dist/types/objects.d.ts.map +0 -1
  303. package/dist/types/objects.js +0 -837
  304. package/dist/types/objects.js.map +0 -1
  305. package/dist/types/storage.d.ts +0 -603
  306. package/dist/types/storage.d.ts.map +0 -1
  307. package/dist/types/storage.js +0 -191
  308. package/dist/types/storage.js.map +0 -1
  309. package/dist/types/worker-loader.d.ts +0 -60
  310. package/dist/types/worker-loader.d.ts.map +0 -1
  311. package/dist/types/worker-loader.js +0 -62
  312. package/dist/types/worker-loader.js.map +0 -1
  313. package/dist/utils/hash.d.ts +0 -197
  314. package/dist/utils/hash.d.ts.map +0 -1
  315. package/dist/utils/hash.js +0 -268
  316. package/dist/utils/hash.js.map +0 -1
  317. package/dist/utils/sha1.d.ts +0 -290
  318. package/dist/utils/sha1.d.ts.map +0 -1
  319. package/dist/utils/sha1.js +0 -582
  320. package/dist/utils/sha1.js.map +0 -1
  321. package/dist/wire/capabilities.d.ts +0 -1044
  322. package/dist/wire/capabilities.d.ts.map +0 -1
  323. package/dist/wire/capabilities.js +0 -941
  324. package/dist/wire/capabilities.js.map +0 -1
  325. package/dist/wire/path-security.d.ts +0 -157
  326. package/dist/wire/path-security.d.ts.map +0 -1
  327. package/dist/wire/path-security.js +0 -307
  328. package/dist/wire/path-security.js.map +0 -1
  329. package/dist/wire/pkt-line.d.ts +0 -345
  330. package/dist/wire/pkt-line.d.ts.map +0 -1
  331. package/dist/wire/pkt-line.js +0 -381
  332. package/dist/wire/pkt-line.js.map +0 -1
  333. package/dist/wire/receive-pack.d.ts +0 -1059
  334. package/dist/wire/receive-pack.d.ts.map +0 -1
  335. package/dist/wire/receive-pack.js +0 -1414
  336. package/dist/wire/receive-pack.js.map +0 -1
  337. package/dist/wire/smart-http.d.ts +0 -799
  338. package/dist/wire/smart-http.d.ts.map +0 -1
  339. package/dist/wire/smart-http.js +0 -945
  340. package/dist/wire/smart-http.js.map +0 -1
  341. package/dist/wire/upload-pack.d.ts +0 -727
  342. package/dist/wire/upload-pack.d.ts.map +0 -1
  343. package/dist/wire/upload-pack.js +0 -1138
  344. package/dist/wire/upload-pack.js.map +0 -1
@@ -1,736 +0,0 @@
1
- /**
2
- * @fileoverview Git Packfile Delta Encoding/Decoding
3
- *
4
- * This module implements Git's delta compression algorithm, which is used in packfiles
5
- * to efficiently store objects by encoding only the differences between similar objects.
6
- *
7
- * ## Delta Format Overview
8
- *
9
- * A delta consists of:
10
- * 1. **Source size** - Variable-length integer specifying the base object size
11
- * 2. **Target size** - Variable-length integer specifying the result size
12
- * 3. **Instructions** - Sequence of copy or insert commands
13
- *
14
- * ## Instruction Types
15
- *
16
- * ### Copy Instruction (MSB = 1)
17
- * Copies a range of bytes from the source (base) object.
18
- *
19
- * | Bit | Meaning |
20
- * |--------|-------------------------------------------|
21
- * | 7 | Always 1 (copy marker) |
22
- * | 6-4 | Which size bytes follow (bit mask) |
23
- * | 3-0 | Which offset bytes follow (bit mask) |
24
- *
25
- * Following bytes encode offset (up to 4 bytes) and size (up to 3 bytes).
26
- * If size is 0 after decoding, it means 0x10000 (65536).
27
- *
28
- * ### Insert Instruction (MSB = 0)
29
- * Inserts literal bytes directly into the output.
30
- *
31
- * | Bit | Meaning |
32
- * |--------|-------------------------------------------|
33
- * | 7 | Always 0 (insert marker) |
34
- * | 6-0 | Number of bytes to insert (1-127) |
35
- *
36
- * The instruction byte is followed by that many literal bytes.
37
- *
38
- * ## Performance Optimizations
39
- *
40
- * This implementation includes several performance optimizations:
41
- * - **Rabin fingerprint rolling hash**: O(1) hash updates when sliding the window
42
- * - **Typed arrays for index**: Uses Uint32Array for memory efficiency
43
- * - **Chunked processing**: Memory-efficient processing for large files
44
- * - **Optimized match extension**: SIMD-friendly byte comparison
45
- *
46
- * @module pack/delta
47
- * @see {@link https://git-scm.com/docs/pack-format} Git Pack Format Documentation
48
- *
49
- * @example
50
- * // Apply a delta to reconstruct an object
51
- * import { applyDelta } from './delta';
52
- *
53
- * const baseObject = getBaseObject(); // Uint8Array
54
- * const deltaData = getDeltaData(); // Uint8Array from packfile
55
- * const targetObject = applyDelta(baseObject, deltaData);
56
- *
57
- * @example
58
- * // Create a delta between two objects
59
- * import { createDelta } from './delta';
60
- *
61
- * const oldVersion = new TextEncoder().encode('Hello, World!');
62
- * const newVersion = new TextEncoder().encode('Hello, Universe!');
63
- * const delta = createDelta(oldVersion, newVersion);
64
- */
65
- /**
66
- * Marker byte for copy instructions (MSB set).
67
- * When the MSB is set, the instruction copies bytes from the base object.
68
- *
69
- * @constant {number}
70
- */
71
- export const COPY_INSTRUCTION = 0x80;
72
- /**
73
- * Marker byte for insert instructions (MSB clear).
74
- * When the MSB is clear, the lower 7 bits indicate how many literal bytes follow.
75
- *
76
- * @constant {number}
77
- */
78
- export const INSERT_INSTRUCTION = 0x00;
79
- // =============================================================================
80
- // Rabin Fingerprint Rolling Hash Constants and Implementation
81
- // =============================================================================
82
- /**
83
- * Window size for rolling hash matching.
84
- * 4 bytes is a good balance between collision rate and match granularity.
85
- *
86
- * @constant {number}
87
- */
88
- const WINDOW_SIZE = 4;
89
- /**
90
- * Rabin fingerprint polynomial base.
91
- * Using a prime number provides good hash distribution.
92
- *
93
- * @constant {number}
94
- */
95
- const RABIN_BASE = 257;
96
- /**
97
- * Modulus for Rabin fingerprint to keep values in 32-bit range.
98
- * Using a prime close to 2^31 for good distribution.
99
- *
100
- * @constant {number}
101
- */
102
- const RABIN_MOD = 0x7fffffff; // 2^31 - 1, a Mersenne prime
103
- /**
104
- * Pre-computed power of RABIN_BASE^WINDOW_SIZE mod RABIN_MOD.
105
- * Used for efficiently removing the contribution of the oldest byte.
106
- *
107
- * @constant {number}
108
- */
109
- const RABIN_POW = (() => {
110
- let pow = 1;
111
- for (let i = 0; i < WINDOW_SIZE; i++) {
112
- pow = (pow * RABIN_BASE) % RABIN_MOD;
113
- }
114
- return pow;
115
- })();
116
- /**
117
- * Minimum match length to be worth a copy instruction.
118
- * Smaller matches cost more than they save due to instruction overhead.
119
- *
120
- * @constant {number}
121
- */
122
- const MIN_COPY_SIZE = 4;
123
- /**
124
- * Chunk size for processing large files.
125
- * 64KB chunks balance memory usage and cache efficiency.
126
- *
127
- * @constant {number}
128
- */
129
- const CHUNK_SIZE = 64 * 1024;
130
- /**
131
- * Maximum entries per hash bucket to prevent pathological cases.
132
- * Limits memory usage when many positions hash to the same value.
133
- *
134
- * @constant {number}
135
- */
136
- const MAX_BUCKET_SIZE = 64;
137
- /**
138
- * Computes Rabin fingerprint hash for initial window.
139
- *
140
- * @description Computes the hash value for the first WINDOW_SIZE bytes.
141
- * Subsequent positions use rolling updates for O(1) computation.
142
- *
143
- * @param {Uint8Array} data - The data buffer
144
- * @param {number} offset - Starting offset
145
- * @returns {number} 32-bit hash value
146
- * @internal
147
- */
148
- function rabinHash(data, offset) {
149
- let hash = 0;
150
- for (let i = 0; i < WINDOW_SIZE; i++) {
151
- hash = (hash * RABIN_BASE + data[offset + i]) % RABIN_MOD;
152
- }
153
- return hash;
154
- }
155
- /**
156
- * Updates Rabin fingerprint hash by rolling the window one byte forward.
157
- *
158
- * @description This is the key optimization: O(1) hash update instead of O(WINDOW_SIZE).
159
- * Removes contribution of outgoing byte and adds incoming byte.
160
- *
161
- * Formula: hash' = (hash * BASE - outgoing * BASE^WINDOW + incoming) mod MOD
162
- *
163
- * @param {number} hash - Current hash value
164
- * @param {number} outgoing - Byte leaving the window
165
- * @param {number} incoming - Byte entering the window
166
- * @returns {number} Updated hash value
167
- * @internal
168
- */
169
- function rabinRoll(hash, outgoing, incoming) {
170
- // Remove outgoing byte's contribution and add incoming byte
171
- // hash = hash * BASE - outgoing * BASE^WINDOW + incoming
172
- let newHash = ((hash * RABIN_BASE) % RABIN_MOD - (outgoing * RABIN_POW) % RABIN_MOD + incoming) % RABIN_MOD;
173
- // Ensure positive result
174
- if (newHash < 0)
175
- newHash += RABIN_MOD;
176
- return newHash;
177
- }
178
- /**
179
- * Builds an optimized hash index from the base object using Rabin fingerprints.
180
- *
181
- * @description Creates a memory-efficient index for finding matching byte sequences.
182
- * Uses typed arrays to minimize GC pressure and memory fragmentation.
183
- *
184
- * **Memory optimization:**
185
- * - Uses power-of-2 bucket count for fast modulo (bitwise AND)
186
- * - Limits bucket size to prevent pathological cases
187
- * - Uses Uint32Array/Uint16Array instead of object arrays
188
- *
189
- * @param {Uint8Array} base - The base object to index
190
- * @returns {HashIndex} The built index
191
- * @internal
192
- */
193
- function buildHashIndex(base) {
194
- // Determine optimal bucket count (power of 2, at least 256)
195
- // Aim for average load factor of ~4 entries per bucket
196
- const targetBuckets = Math.max(256, Math.ceil((base.length - WINDOW_SIZE + 1) / 4));
197
- const bucketCount = 1 << Math.ceil(Math.log2(targetBuckets));
198
- const bucketMask = bucketCount - 1;
199
- // Allocate typed arrays
200
- const offsets = new Uint32Array(bucketCount * MAX_BUCKET_SIZE);
201
- const counts = new Uint16Array(bucketCount);
202
- if (base.length < WINDOW_SIZE) {
203
- return { bucketCount, bucketMask, offsets, counts };
204
- }
205
- // Use rolling hash to build index
206
- let hash = rabinHash(base, 0);
207
- addToIndex(0);
208
- for (let i = 1; i <= base.length - WINDOW_SIZE; i++) {
209
- // Roll the hash forward (O(1) operation)
210
- hash = rabinRoll(hash, base[i - 1], base[i + WINDOW_SIZE - 1]);
211
- addToIndex(i);
212
- }
213
- return { bucketCount, bucketMask, offsets, counts };
214
- function addToIndex(offset) {
215
- const bucket = hash & bucketMask;
216
- const count = counts[bucket];
217
- if (count < MAX_BUCKET_SIZE) {
218
- offsets[bucket * MAX_BUCKET_SIZE + count] = offset;
219
- counts[bucket] = count + 1;
220
- }
221
- }
222
- }
223
- /**
224
- * Looks up potential match positions from the hash index.
225
- *
226
- * @param {HashIndex} index - The hash index
227
- * @param {number} hash - The hash to look up
228
- * @returns {Generator<number>} Yields matching offsets
229
- * @internal
230
- */
231
- function* lookupIndex(index, hash) {
232
- const bucket = hash & index.bucketMask;
233
- const count = index.counts[bucket];
234
- const baseOffset = bucket * MAX_BUCKET_SIZE;
235
- for (let i = 0; i < count; i++) {
236
- yield index.offsets[baseOffset + i];
237
- }
238
- }
239
- /**
240
- * Optimized match length calculation using word-at-a-time comparison.
241
- *
242
- * @description Compares bytes in chunks of 4 (as 32-bit integers) where possible,
243
- * falling back to byte-by-byte for the remaining bytes. This is ~4x faster than
244
- * pure byte comparison for long matches.
245
- *
246
- * @param {Uint8Array} a - First array
247
- * @param {number} aOffset - Starting offset in first array
248
- * @param {Uint8Array} b - Second array
249
- * @param {number} bOffset - Starting offset in second array
250
- * @param {number} maxLength - Maximum number of bytes to compare
251
- * @returns {number} Number of matching bytes (0 to maxLength)
252
- * @internal
253
- */
254
- function getMatchLengthOptimized(a, aOffset, b, bOffset, maxLength) {
255
- if (maxLength <= 0)
256
- return 0;
257
- let length = 0;
258
- // Compare 4 bytes at a time using DataView for unaligned access
259
- // This is faster than byte-by-byte for larger matches
260
- const wordCount = (maxLength - length) >>> 2;
261
- if (wordCount > 0) {
262
- const aView = new DataView(a.buffer, a.byteOffset + aOffset, maxLength);
263
- const bView = new DataView(b.buffer, b.byteOffset + bOffset, maxLength);
264
- for (let i = 0; i < wordCount; i++) {
265
- const wordOffset = length;
266
- if (aView.getUint32(wordOffset, true) !== bView.getUint32(wordOffset, true)) {
267
- // Found difference in this word, find exact byte
268
- while (length < maxLength && a[aOffset + length] === b[bOffset + length]) {
269
- length++;
270
- }
271
- return length;
272
- }
273
- length += 4;
274
- }
275
- }
276
- // Compare remaining bytes
277
- while (length < maxLength && a[aOffset + length] === b[bOffset + length]) {
278
- length++;
279
- }
280
- return length;
281
- }
282
- /**
283
- * Parses a variable-length size value from the delta header.
284
- *
285
- * @description Reads the source or target size from a delta's header using
286
- * Git's variable-length integer encoding. Each byte's MSB indicates whether
287
- * more bytes follow, and the lower 7 bits contribute to the value.
288
- *
289
- * **Encoding Details:**
290
- * - Bytes are read sequentially
291
- * - Lower 7 bits of each byte contribute to the result
292
- * - MSB = 1 means more bytes follow
293
- * - MSB = 0 means this is the last byte
294
- * - Maximum of 10 bytes (supports values up to 2^70)
295
- *
296
- * @param {Uint8Array} data - The delta data buffer
297
- * @param {number} offset - Starting byte offset in the buffer
298
- * @returns {DeltaHeaderResult} Object with parsed size and bytes consumed
299
- * @throws {Error} If data ends unexpectedly before size is complete
300
- * @throws {Error} If size encoding exceeds maximum length (corrupted data)
301
- *
302
- * @example
303
- * // Parse source and target sizes from delta
304
- * let offset = 0;
305
- * const source = parseDeltaHeader(delta, offset);
306
- * offset += source.bytesRead;
307
- * const target = parseDeltaHeader(delta, offset);
308
- * offset += target.bytesRead;
309
- *
310
- * console.log(`Base size: ${source.size}, Target size: ${target.size}`);
311
- */
312
- export function parseDeltaHeader(data, offset) {
313
- let size = 0;
314
- let shift = 0;
315
- let bytesRead = 0;
316
- // Maximum bytes for a varint to prevent infinite loops
317
- const MAX_VARINT_BYTES = 10;
318
- while (true) {
319
- if (offset + bytesRead >= data.length) {
320
- throw new Error(`Delta header parsing failed: unexpected end of data at offset ${offset + bytesRead}`);
321
- }
322
- if (bytesRead >= MAX_VARINT_BYTES) {
323
- throw new Error(`Delta header parsing failed: exceeded maximum length of ${MAX_VARINT_BYTES} bytes (possible infinite loop or corrupted data)`);
324
- }
325
- const byte = data[offset + bytesRead];
326
- bytesRead++;
327
- // Add the lower 7 bits to the result
328
- size |= (byte & 0x7f) << shift;
329
- shift += 7;
330
- // If MSB is not set, we're done
331
- if ((byte & 0x80) === 0) {
332
- break;
333
- }
334
- }
335
- return { size, bytesRead };
336
- }
337
- /**
338
- * Encodes a size as a variable-length integer for delta headers.
339
- *
340
- * @description Internal function that encodes sizes using Git's varint format.
341
- * Used when creating delta headers that specify source and target sizes.
342
- *
343
- * @param {number} size - The size value to encode
344
- * @returns {Uint8Array} The encoded bytes
345
- * @internal
346
- */
347
- function encodeDeltaSize(size) {
348
- const bytes = [];
349
- do {
350
- let byte = size & 0x7f;
351
- size >>>= 7;
352
- if (size > 0) {
353
- byte |= 0x80; // Set continuation bit
354
- }
355
- bytes.push(byte);
356
- } while (size > 0);
357
- return new Uint8Array(bytes);
358
- }
359
- /**
360
- * Applies a delta to a base object to produce the target object.
361
- *
362
- * @description Reconstructs the target object by executing the delta's copy and
363
- * insert instructions against the base object. This is the core operation for
364
- * unpacking delta-compressed objects in packfiles.
365
- *
366
- * **Delta Application Process:**
367
- * 1. Parse source (base) size and verify it matches
368
- * 2. Parse target size to allocate result buffer
369
- * 3. Execute instructions sequentially:
370
- * - Copy: copy bytes from base object to result
371
- * - Insert: copy literal bytes from delta to result
372
- * 4. Verify result size matches expected target size
373
- *
374
- * **Error Conditions:**
375
- * - Base object size doesn't match delta's source size
376
- * - Copy instruction references bytes outside base object
377
- * - Instructions would overflow the result buffer
378
- * - Result size doesn't match delta's target size
379
- * - Invalid instruction byte (0x00)
380
- *
381
- * @param {Uint8Array} base - The source/base object to apply delta against
382
- * @param {Uint8Array} delta - The delta data (decompressed from packfile)
383
- * @returns {Uint8Array} The reconstructed target object
384
- * @throws {Error} If base size doesn't match delta's source size
385
- * @throws {Error} If delta contains invalid instructions
386
- * @throws {Error} If copy would read beyond base object bounds
387
- * @throws {Error} If result size doesn't match expected target size
388
- *
389
- * @example
390
- * // Reconstruct an object from base + delta
391
- * const base = await getObject(baseSha);
392
- * const delta = decompressDeltaData(packData, offset);
393
- * const target = applyDelta(base, delta);
394
- *
395
- * @example
396
- * // Error handling
397
- * try {
398
- * const target = applyDelta(base, delta);
399
- * } catch (e) {
400
- * console.error('Delta application failed:', e.message);
401
- * }
402
- */
403
- export function applyDelta(base, delta) {
404
- let offset = 0;
405
- // Parse source size
406
- const sourceHeader = parseDeltaHeader(delta, offset);
407
- offset += sourceHeader.bytesRead;
408
- if (sourceHeader.size !== base.length) {
409
- throw new Error(`Delta source size mismatch: expected ${sourceHeader.size}, got ${base.length}`);
410
- }
411
- // Parse target size
412
- const targetHeader = parseDeltaHeader(delta, offset);
413
- offset += targetHeader.bytesRead;
414
- // Allocate result buffer
415
- const result = new Uint8Array(targetHeader.size);
416
- let resultOffset = 0;
417
- // Process instructions
418
- while (offset < delta.length) {
419
- const cmd = delta[offset++];
420
- if (cmd & COPY_INSTRUCTION) {
421
- // Copy instruction
422
- let copyOffset = 0;
423
- let copySize = 0;
424
- // Read offset bytes (bits 0-3 indicate which bytes are present)
425
- if (cmd & 0x01)
426
- copyOffset |= delta[offset++];
427
- if (cmd & 0x02)
428
- copyOffset |= delta[offset++] << 8;
429
- if (cmd & 0x04)
430
- copyOffset |= delta[offset++] << 16;
431
- if (cmd & 0x08)
432
- copyOffset |= delta[offset++] << 24;
433
- // Read size bytes (bits 4-6 indicate which bytes are present)
434
- if (cmd & 0x10)
435
- copySize |= delta[offset++];
436
- if (cmd & 0x20)
437
- copySize |= delta[offset++] << 8;
438
- if (cmd & 0x40)
439
- copySize |= delta[offset++] << 16;
440
- // Size of 0 means 0x10000 (65536)
441
- if (copySize === 0) {
442
- copySize = 0x10000;
443
- }
444
- // Bounds checking to prevent buffer overflows
445
- if (copyOffset < 0 || copySize < 0) {
446
- throw new Error(`Invalid copy instruction: offset=${copyOffset}, size=${copySize}`);
447
- }
448
- if (copyOffset + copySize > base.length) {
449
- throw new Error(`Copy instruction out of bounds: offset=${copyOffset}, size=${copySize}, base length=${base.length}`);
450
- }
451
- if (resultOffset + copySize > result.length) {
452
- throw new Error(`Copy would overflow result buffer: resultOffset=${resultOffset}, size=${copySize}, result length=${result.length}`);
453
- }
454
- // Copy from base to result
455
- result.set(base.subarray(copyOffset, copyOffset + copySize), resultOffset);
456
- resultOffset += copySize;
457
- }
458
- else if (cmd !== 0) {
459
- // Insert instruction: cmd is the number of bytes to insert
460
- const insertSize = cmd;
461
- result.set(delta.subarray(offset, offset + insertSize), resultOffset);
462
- offset += insertSize;
463
- resultOffset += insertSize;
464
- }
465
- else {
466
- // cmd === 0 is reserved/invalid
467
- throw new Error('Invalid delta instruction: 0x00');
468
- }
469
- }
470
- // Verify we produced the expected size
471
- if (resultOffset !== targetHeader.size) {
472
- throw new Error(`Delta result size mismatch: expected ${targetHeader.size}, got ${resultOffset}`);
473
- }
474
- return result;
475
- }
476
- /**
477
- * Creates a delta that transforms a base object into a target object.
478
- *
479
- * @description Generates delta instructions that can reconstruct the target
480
- * from the base object. Uses a hash-based algorithm to find matching sequences
481
- * and emits copy/insert instructions accordingly.
482
- *
483
- * **Algorithm:**
484
- * 1. Build a hash table of 4-byte sequences in the base object
485
- * 2. Scan through the target looking for matches in the hash table
486
- * 3. For each match found, verify and extend to maximum length
487
- * 4. Emit copy instructions for matches (4+ bytes)
488
- * 5. Emit insert instructions for non-matching data
489
- *
490
- * **Optimization Notes:**
491
- * - Uses 4-byte window for hash matching
492
- * - Minimum copy size is 4 bytes (smaller copies become inserts)
493
- * - Insert instructions are limited to 127 bytes each
494
- * - Empty base results in pure insert delta
495
- * - Empty target results in headers-only delta
496
- *
497
- * **Output Format:**
498
- * - Source size (varint)
499
- * - Target size (varint)
500
- * - Sequence of copy/insert instructions
501
- *
502
- * @param {Uint8Array} base - The source/base object
503
- * @param {Uint8Array} target - The target object to encode as delta
504
- * @returns {Uint8Array} The delta data (can be applied with {@link applyDelta})
505
- *
506
- * @example
507
- * // Create a delta for similar files
508
- * const v1 = new TextEncoder().encode('Hello, World!');
509
- * const v2 = new TextEncoder().encode('Hello, Universe!');
510
- * const delta = createDelta(v1, v2);
511
- *
512
- * // Delta should be smaller than v2 if there's good overlap
513
- * console.log(`Original: ${v2.length}, Delta: ${delta.length}`);
514
- *
515
- * @example
516
- * // Verify delta correctness
517
- * const reconstructed = applyDelta(v1, delta);
518
- * // reconstructed should equal v2
519
- */
520
- export function createDelta(base, target) {
521
- const instructions = [];
522
- // Add source and target size headers
523
- instructions.push(encodeDeltaSize(base.length));
524
- instructions.push(encodeDeltaSize(target.length));
525
- if (target.length === 0) {
526
- // Empty target, just return headers
527
- return concatArrays(instructions);
528
- }
529
- if (base.length === 0) {
530
- // No base to copy from, insert everything
531
- emitInserts(instructions, target, 0, target.length);
532
- return concatArrays(instructions);
533
- }
534
- // Build optimized hash index using Rabin fingerprints
535
- const index = buildHashIndex(base);
536
- // For large files, process in chunks to limit memory pressure
537
- const isLargeFile = target.length > CHUNK_SIZE;
538
- // Scan target and find matches using rolling hash
539
- let targetOffset = 0;
540
- let insertStart = 0;
541
- // Initialize rolling hash if we have enough bytes
542
- let currentHash = target.length >= WINDOW_SIZE ? rabinHash(target, 0) : 0;
543
- while (targetOffset < target.length) {
544
- let bestMatchOffset = -1;
545
- let bestMatchLength = 0;
546
- // Look for a match if we have enough bytes
547
- if (targetOffset <= target.length - WINDOW_SIZE) {
548
- // Look up candidates from the optimized index
549
- for (const baseOffset of lookupIndex(index, currentHash)) {
550
- // Verify the match and extend it using optimized comparison
551
- const maxLength = Math.min(base.length - baseOffset, target.length - targetOffset);
552
- const matchLength = isLargeFile
553
- ? getMatchLengthOptimized(base, baseOffset, target, targetOffset, maxLength)
554
- : getMatchLength(base, baseOffset, target, targetOffset, maxLength);
555
- if (matchLength >= WINDOW_SIZE && matchLength > bestMatchLength) {
556
- bestMatchOffset = baseOffset;
557
- bestMatchLength = matchLength;
558
- }
559
- }
560
- }
561
- if (bestMatchLength >= MIN_COPY_SIZE) {
562
- // Emit pending inserts
563
- if (targetOffset > insertStart) {
564
- emitInserts(instructions, target, insertStart, targetOffset);
565
- }
566
- // Emit copy instruction
567
- emitCopy(instructions, bestMatchOffset, bestMatchLength);
568
- targetOffset += bestMatchLength;
569
- insertStart = targetOffset;
570
- // Re-compute hash at new position (skip rolling for long jumps)
571
- if (targetOffset <= target.length - WINDOW_SIZE) {
572
- currentHash = rabinHash(target, targetOffset);
573
- }
574
- }
575
- else {
576
- targetOffset++;
577
- // Roll the hash forward (O(1) operation)
578
- if (targetOffset <= target.length - WINDOW_SIZE) {
579
- currentHash = rabinRoll(currentHash, target[targetOffset - 1], target[targetOffset + WINDOW_SIZE - 1]);
580
- }
581
- }
582
- }
583
- // Emit any remaining inserts
584
- if (target.length > insertStart) {
585
- emitInserts(instructions, target, insertStart, target.length);
586
- }
587
- return concatArrays(instructions);
588
- }
589
- /**
590
- * Computes a simple hash of a byte sequence for delta matching.
591
- *
592
- * @description Uses a fast multiplicative hash (similar to djb2) for
593
- * building the hash table used in delta creation.
594
- *
595
- * @param {Uint8Array} data - The data buffer
596
- * @param {number} offset - Starting offset
597
- * @param {number} length - Number of bytes to hash
598
- * @returns {number} 32-bit hash value
599
- * @internal
600
- */
601
- function hashBytes(data, offset, length) {
602
- let hash = 0;
603
- for (let i = 0; i < length; i++) {
604
- hash = ((hash << 5) - hash + data[offset + i]) | 0;
605
- }
606
- return hash;
607
- }
608
- /**
609
- * Finds the length of matching bytes between two array regions.
610
- *
611
- * @description Compares bytes starting from the given offsets and returns
612
- * how many consecutive bytes match. Used to extend hash-based matches.
613
- *
614
- * @param {Uint8Array} a - First array
615
- * @param {number} aOffset - Starting offset in first array
616
- * @param {Uint8Array} b - Second array
617
- * @param {number} bOffset - Starting offset in second array
618
- * @param {number} maxLength - Maximum number of bytes to compare
619
- * @returns {number} Number of matching bytes (0 to maxLength)
620
- * @internal
621
- */
622
- function getMatchLength(a, aOffset, b, bOffset, maxLength) {
623
- let length = 0;
624
- while (length < maxLength && a[aOffset + length] === b[bOffset + length]) {
625
- length++;
626
- }
627
- return length;
628
- }
629
- /**
630
- * Emits insert instructions for a range of literal bytes.
631
- *
632
- * @description Insert commands can only encode 1-127 bytes each, so this
633
- * function splits larger ranges into multiple instructions as needed.
634
- *
635
- * @param {Uint8Array[]} instructions - Array to append instructions to
636
- * @param {Uint8Array} data - Source data buffer
637
- * @param {number} start - Starting offset (inclusive)
638
- * @param {number} end - Ending offset (exclusive)
639
- * @internal
640
- */
641
- function emitInserts(instructions, data, start, end) {
642
- const MAX_INSERT = 127;
643
- let offset = start;
644
- while (offset < end) {
645
- const size = Math.min(MAX_INSERT, end - offset);
646
- const instruction = new Uint8Array(1 + size);
647
- instruction[0] = size; // Insert command: size in lower 7 bits
648
- instruction.set(data.subarray(offset, offset + size), 1);
649
- instructions.push(instruction);
650
- offset += size;
651
- }
652
- }
653
- /**
654
- * Emits a copy instruction that copies bytes from the base object.
655
- *
656
- * @description Encodes a copy instruction using Git's compact format where
657
- * only non-zero offset and size bytes are included, indicated by bit flags.
658
- *
659
- * **Encoding Details:**
660
- * - Offset bytes (up to 4) are included based on bits 0-3 of command byte
661
- * - Size bytes (up to 3) are included based on bits 4-6 of command byte
662
- * - Size of 0x10000 (65536) is encoded as no size bytes (size=0 means 0x10000)
663
- * - Offset of 0 means no offset bytes are included
664
- *
665
- * @param {Uint8Array[]} instructions - Array to append the instruction to
666
- * @param {number} offset - Byte offset in base object to copy from
667
- * @param {number} size - Number of bytes to copy
668
- * @internal
669
- */
670
- function emitCopy(instructions, offset, size) {
671
- const bytes = [];
672
- let cmd = COPY_INSTRUCTION;
673
- // Encode offset bytes (little-endian)
674
- if (offset & 0xff) {
675
- cmd |= 0x01;
676
- bytes.push(offset & 0xff);
677
- }
678
- if (offset & 0xff00) {
679
- cmd |= 0x02;
680
- bytes.push((offset >> 8) & 0xff);
681
- }
682
- if (offset & 0xff0000) {
683
- cmd |= 0x04;
684
- bytes.push((offset >> 16) & 0xff);
685
- }
686
- if (offset & 0xff000000) {
687
- cmd |= 0x08;
688
- bytes.push((offset >> 24) & 0xff);
689
- }
690
- // Special case: if offset is 0, we don't emit any offset bytes
691
- // The cmd byte already indicates no offset bytes are present
692
- // Encode size bytes (little-endian)
693
- // Note: size of 0x10000 is encoded as no size bytes (all zero)
694
- if (size !== 0x10000) {
695
- if (size & 0xff) {
696
- cmd |= 0x10;
697
- bytes.push(size & 0xff);
698
- }
699
- if (size & 0xff00) {
700
- cmd |= 0x20;
701
- bytes.push((size >> 8) & 0xff);
702
- }
703
- if (size & 0xff0000) {
704
- cmd |= 0x40;
705
- bytes.push((size >> 16) & 0xff);
706
- }
707
- }
708
- // If size is 0x10000, we don't set any size bits, which encodes as size=0x10000
709
- const instruction = new Uint8Array(1 + bytes.length);
710
- instruction[0] = cmd;
711
- for (let i = 0; i < bytes.length; i++) {
712
- instruction[1 + i] = bytes[i];
713
- }
714
- instructions.push(instruction);
715
- }
716
- /**
717
- * Concatenates multiple Uint8Arrays into a single array.
718
- *
719
- * @param {Uint8Array[]} arrays - Arrays to concatenate
720
- * @returns {Uint8Array} Combined array
721
- * @internal
722
- */
723
- function concatArrays(arrays) {
724
- let totalLength = 0;
725
- for (const arr of arrays) {
726
- totalLength += arr.length;
727
- }
728
- const result = new Uint8Array(totalLength);
729
- let offset = 0;
730
- for (const arr of arrays) {
731
- result.set(arr, offset);
732
- offset += arr.length;
733
- }
734
- return result;
735
- }
736
- //# sourceMappingURL=delta.js.map