gitx.do 0.1.1 → 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 (356) 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 +14 -469
  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 -176
  20. package/dist/cli/commands/add.d.ts.map +0 -1
  21. package/dist/cli/commands/add.js +0 -979
  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/checkout.d.ts +0 -73
  32. package/dist/cli/commands/checkout.d.ts.map +0 -1
  33. package/dist/cli/commands/checkout.js +0 -725
  34. package/dist/cli/commands/checkout.js.map +0 -1
  35. package/dist/cli/commands/commit.d.ts +0 -182
  36. package/dist/cli/commands/commit.d.ts.map +0 -1
  37. package/dist/cli/commands/commit.js +0 -457
  38. package/dist/cli/commands/commit.js.map +0 -1
  39. package/dist/cli/commands/diff.d.ts +0 -464
  40. package/dist/cli/commands/diff.d.ts.map +0 -1
  41. package/dist/cli/commands/diff.js +0 -959
  42. package/dist/cli/commands/diff.js.map +0 -1
  43. package/dist/cli/commands/log.d.ts +0 -239
  44. package/dist/cli/commands/log.d.ts.map +0 -1
  45. package/dist/cli/commands/log.js +0 -535
  46. package/dist/cli/commands/log.js.map +0 -1
  47. package/dist/cli/commands/merge.d.ts +0 -106
  48. package/dist/cli/commands/merge.d.ts.map +0 -1
  49. package/dist/cli/commands/merge.js +0 -852
  50. package/dist/cli/commands/merge.js.map +0 -1
  51. package/dist/cli/commands/review.d.ts +0 -457
  52. package/dist/cli/commands/review.d.ts.map +0 -1
  53. package/dist/cli/commands/review.js +0 -558
  54. package/dist/cli/commands/review.js.map +0 -1
  55. package/dist/cli/commands/stash.d.ts +0 -157
  56. package/dist/cli/commands/stash.d.ts.map +0 -1
  57. package/dist/cli/commands/stash.js +0 -655
  58. package/dist/cli/commands/stash.js.map +0 -1
  59. package/dist/cli/commands/status.d.ts +0 -269
  60. package/dist/cli/commands/status.d.ts.map +0 -1
  61. package/dist/cli/commands/status.js +0 -492
  62. package/dist/cli/commands/status.js.map +0 -1
  63. package/dist/cli/commands/web.d.ts +0 -199
  64. package/dist/cli/commands/web.d.ts.map +0 -1
  65. package/dist/cli/commands/web.js +0 -697
  66. package/dist/cli/commands/web.js.map +0 -1
  67. package/dist/cli/fs-adapter.d.ts +0 -656
  68. package/dist/cli/fs-adapter.d.ts.map +0 -1
  69. package/dist/cli/fs-adapter.js +0 -1177
  70. package/dist/cli/fs-adapter.js.map +0 -1
  71. package/dist/cli/fsx-cli-adapter.d.ts +0 -359
  72. package/dist/cli/fsx-cli-adapter.d.ts.map +0 -1
  73. package/dist/cli/fsx-cli-adapter.js +0 -619
  74. package/dist/cli/fsx-cli-adapter.js.map +0 -1
  75. package/dist/cli/index.d.ts +0 -387
  76. package/dist/cli/index.d.ts.map +0 -1
  77. package/dist/cli/index.js +0 -579
  78. package/dist/cli/index.js.map +0 -1
  79. package/dist/cli/ui/components/DiffView.d.ts +0 -12
  80. package/dist/cli/ui/components/DiffView.d.ts.map +0 -1
  81. package/dist/cli/ui/components/DiffView.js +0 -11
  82. package/dist/cli/ui/components/DiffView.js.map +0 -1
  83. package/dist/cli/ui/components/ErrorDisplay.d.ts +0 -10
  84. package/dist/cli/ui/components/ErrorDisplay.d.ts.map +0 -1
  85. package/dist/cli/ui/components/ErrorDisplay.js +0 -11
  86. package/dist/cli/ui/components/ErrorDisplay.js.map +0 -1
  87. package/dist/cli/ui/components/FuzzySearch.d.ts +0 -15
  88. package/dist/cli/ui/components/FuzzySearch.d.ts.map +0 -1
  89. package/dist/cli/ui/components/FuzzySearch.js +0 -12
  90. package/dist/cli/ui/components/FuzzySearch.js.map +0 -1
  91. package/dist/cli/ui/components/LoadingSpinner.d.ts +0 -10
  92. package/dist/cli/ui/components/LoadingSpinner.d.ts.map +0 -1
  93. package/dist/cli/ui/components/LoadingSpinner.js +0 -10
  94. package/dist/cli/ui/components/LoadingSpinner.js.map +0 -1
  95. package/dist/cli/ui/components/NavigationList.d.ts +0 -14
  96. package/dist/cli/ui/components/NavigationList.d.ts.map +0 -1
  97. package/dist/cli/ui/components/NavigationList.js +0 -11
  98. package/dist/cli/ui/components/NavigationList.js.map +0 -1
  99. package/dist/cli/ui/components/ScrollableContent.d.ts +0 -13
  100. package/dist/cli/ui/components/ScrollableContent.d.ts.map +0 -1
  101. package/dist/cli/ui/components/ScrollableContent.js +0 -11
  102. package/dist/cli/ui/components/ScrollableContent.js.map +0 -1
  103. package/dist/cli/ui/components/index.d.ts +0 -7
  104. package/dist/cli/ui/components/index.d.ts.map +0 -1
  105. package/dist/cli/ui/components/index.js +0 -9
  106. package/dist/cli/ui/components/index.js.map +0 -1
  107. package/dist/cli/ui/terminal-ui.d.ts +0 -85
  108. package/dist/cli/ui/terminal-ui.d.ts.map +0 -1
  109. package/dist/cli/ui/terminal-ui.js +0 -121
  110. package/dist/cli/ui/terminal-ui.js.map +0 -1
  111. package/dist/do/BashModule.d.ts +0 -871
  112. package/dist/do/BashModule.d.ts.map +0 -1
  113. package/dist/do/BashModule.js +0 -1143
  114. package/dist/do/BashModule.js.map +0 -1
  115. package/dist/do/FsModule.d.ts +0 -612
  116. package/dist/do/FsModule.d.ts.map +0 -1
  117. package/dist/do/FsModule.js +0 -1120
  118. package/dist/do/FsModule.js.map +0 -1
  119. package/dist/do/GitModule.d.ts +0 -635
  120. package/dist/do/GitModule.d.ts.map +0 -1
  121. package/dist/do/GitModule.js +0 -784
  122. package/dist/do/GitModule.js.map +0 -1
  123. package/dist/do/GitRepoDO.d.ts +0 -281
  124. package/dist/do/GitRepoDO.d.ts.map +0 -1
  125. package/dist/do/GitRepoDO.js +0 -479
  126. package/dist/do/GitRepoDO.js.map +0 -1
  127. package/dist/do/bash-ast.d.ts +0 -246
  128. package/dist/do/bash-ast.d.ts.map +0 -1
  129. package/dist/do/bash-ast.js +0 -888
  130. package/dist/do/bash-ast.js.map +0 -1
  131. package/dist/do/container-executor.d.ts +0 -491
  132. package/dist/do/container-executor.d.ts.map +0 -1
  133. package/dist/do/container-executor.js +0 -731
  134. package/dist/do/container-executor.js.map +0 -1
  135. package/dist/do/index.d.ts +0 -53
  136. package/dist/do/index.d.ts.map +0 -1
  137. package/dist/do/index.js +0 -91
  138. package/dist/do/index.js.map +0 -1
  139. package/dist/do/tiered-storage.d.ts +0 -403
  140. package/dist/do/tiered-storage.d.ts.map +0 -1
  141. package/dist/do/tiered-storage.js +0 -689
  142. package/dist/do/tiered-storage.js.map +0 -1
  143. package/dist/do/withBash.d.ts +0 -231
  144. package/dist/do/withBash.d.ts.map +0 -1
  145. package/dist/do/withBash.js +0 -244
  146. package/dist/do/withBash.js.map +0 -1
  147. package/dist/do/withFs.d.ts +0 -237
  148. package/dist/do/withFs.d.ts.map +0 -1
  149. package/dist/do/withFs.js +0 -387
  150. package/dist/do/withFs.js.map +0 -1
  151. package/dist/do/withGit.d.ts +0 -180
  152. package/dist/do/withGit.d.ts.map +0 -1
  153. package/dist/do/withGit.js +0 -271
  154. package/dist/do/withGit.js.map +0 -1
  155. package/dist/durable-object/object-store.d.ts +0 -633
  156. package/dist/durable-object/object-store.d.ts.map +0 -1
  157. package/dist/durable-object/object-store.js +0 -1164
  158. package/dist/durable-object/object-store.js.map +0 -1
  159. package/dist/durable-object/schema.d.ts.map +0 -1
  160. package/dist/durable-object/schema.js.map +0 -1
  161. package/dist/durable-object/wal.d.ts +0 -416
  162. package/dist/durable-object/wal.d.ts.map +0 -1
  163. package/dist/durable-object/wal.js +0 -445
  164. package/dist/durable-object/wal.js.map +0 -1
  165. package/dist/mcp/adapter.d.ts +0 -772
  166. package/dist/mcp/adapter.d.ts.map +0 -1
  167. package/dist/mcp/adapter.js +0 -895
  168. package/dist/mcp/adapter.js.map +0 -1
  169. package/dist/mcp/sandbox/miniflare-evaluator.d.ts +0 -22
  170. package/dist/mcp/sandbox/miniflare-evaluator.d.ts.map +0 -1
  171. package/dist/mcp/sandbox/miniflare-evaluator.js +0 -140
  172. package/dist/mcp/sandbox/miniflare-evaluator.js.map +0 -1
  173. package/dist/mcp/sandbox/object-store-proxy.d.ts +0 -32
  174. package/dist/mcp/sandbox/object-store-proxy.d.ts.map +0 -1
  175. package/dist/mcp/sandbox/object-store-proxy.js +0 -30
  176. package/dist/mcp/sandbox/object-store-proxy.js.map +0 -1
  177. package/dist/mcp/sandbox/template.d.ts +0 -17
  178. package/dist/mcp/sandbox/template.d.ts.map +0 -1
  179. package/dist/mcp/sandbox/template.js +0 -71
  180. package/dist/mcp/sandbox/template.js.map +0 -1
  181. package/dist/mcp/sandbox.d.ts +0 -764
  182. package/dist/mcp/sandbox.d.ts.map +0 -1
  183. package/dist/mcp/sandbox.js +0 -1362
  184. package/dist/mcp/sandbox.js.map +0 -1
  185. package/dist/mcp/sdk-adapter.d.ts +0 -835
  186. package/dist/mcp/sdk-adapter.d.ts.map +0 -1
  187. package/dist/mcp/sdk-adapter.js +0 -974
  188. package/dist/mcp/sdk-adapter.js.map +0 -1
  189. package/dist/mcp/tools/do.d.ts +0 -32
  190. package/dist/mcp/tools/do.d.ts.map +0 -1
  191. package/dist/mcp/tools/do.js +0 -117
  192. package/dist/mcp/tools/do.js.map +0 -1
  193. package/dist/mcp/tools.d.ts +0 -548
  194. package/dist/mcp/tools.d.ts.map +0 -1
  195. package/dist/mcp/tools.js +0 -3170
  196. package/dist/mcp/tools.js.map +0 -1
  197. package/dist/ops/blame.d.ts +0 -551
  198. package/dist/ops/blame.d.ts.map +0 -1
  199. package/dist/ops/blame.js +0 -1037
  200. package/dist/ops/blame.js.map +0 -1
  201. package/dist/ops/branch.d.ts +0 -766
  202. package/dist/ops/branch.d.ts.map +0 -1
  203. package/dist/ops/branch.js +0 -950
  204. package/dist/ops/branch.js.map +0 -1
  205. package/dist/ops/commit-traversal.d.ts +0 -349
  206. package/dist/ops/commit-traversal.d.ts.map +0 -1
  207. package/dist/ops/commit-traversal.js +0 -821
  208. package/dist/ops/commit-traversal.js.map +0 -1
  209. package/dist/ops/commit.d.ts +0 -555
  210. package/dist/ops/commit.d.ts.map +0 -1
  211. package/dist/ops/commit.js +0 -826
  212. package/dist/ops/commit.js.map +0 -1
  213. package/dist/ops/merge-base.d.ts +0 -397
  214. package/dist/ops/merge-base.d.ts.map +0 -1
  215. package/dist/ops/merge-base.js +0 -691
  216. package/dist/ops/merge-base.js.map +0 -1
  217. package/dist/ops/merge.d.ts +0 -855
  218. package/dist/ops/merge.d.ts.map +0 -1
  219. package/dist/ops/merge.js +0 -1551
  220. package/dist/ops/merge.js.map +0 -1
  221. package/dist/ops/tag.d.ts +0 -247
  222. package/dist/ops/tag.d.ts.map +0 -1
  223. package/dist/ops/tag.js +0 -649
  224. package/dist/ops/tag.js.map +0 -1
  225. package/dist/ops/tree-builder.d.ts +0 -178
  226. package/dist/ops/tree-builder.d.ts.map +0 -1
  227. package/dist/ops/tree-builder.js +0 -271
  228. package/dist/ops/tree-builder.js.map +0 -1
  229. package/dist/ops/tree-diff.d.ts +0 -291
  230. package/dist/ops/tree-diff.d.ts.map +0 -1
  231. package/dist/ops/tree-diff.js +0 -705
  232. package/dist/ops/tree-diff.js.map +0 -1
  233. package/dist/pack/delta.d.ts +0 -248
  234. package/dist/pack/delta.d.ts.map +0 -1
  235. package/dist/pack/delta.js +0 -740
  236. package/dist/pack/delta.js.map +0 -1
  237. package/dist/pack/format.d.ts +0 -446
  238. package/dist/pack/format.d.ts.map +0 -1
  239. package/dist/pack/format.js +0 -572
  240. package/dist/pack/format.js.map +0 -1
  241. package/dist/pack/full-generation.d.ts +0 -612
  242. package/dist/pack/full-generation.d.ts.map +0 -1
  243. package/dist/pack/full-generation.js +0 -1378
  244. package/dist/pack/full-generation.js.map +0 -1
  245. package/dist/pack/generation.d.ts +0 -441
  246. package/dist/pack/generation.d.ts.map +0 -1
  247. package/dist/pack/generation.js +0 -707
  248. package/dist/pack/generation.js.map +0 -1
  249. package/dist/pack/index.d.ts +0 -502
  250. package/dist/pack/index.d.ts.map +0 -1
  251. package/dist/pack/index.js +0 -833
  252. package/dist/pack/index.js.map +0 -1
  253. package/dist/refs/branch.d.ts +0 -683
  254. package/dist/refs/branch.d.ts.map +0 -1
  255. package/dist/refs/branch.js +0 -881
  256. package/dist/refs/branch.js.map +0 -1
  257. package/dist/refs/storage.d.ts +0 -833
  258. package/dist/refs/storage.d.ts.map +0 -1
  259. package/dist/refs/storage.js +0 -1023
  260. package/dist/refs/storage.js.map +0 -1
  261. package/dist/refs/tag.d.ts +0 -860
  262. package/dist/refs/tag.d.ts.map +0 -1
  263. package/dist/refs/tag.js +0 -996
  264. package/dist/refs/tag.js.map +0 -1
  265. package/dist/storage/backend.d.ts +0 -425
  266. package/dist/storage/backend.d.ts.map +0 -1
  267. package/dist/storage/backend.js +0 -41
  268. package/dist/storage/backend.js.map +0 -1
  269. package/dist/storage/fsx-adapter.d.ts +0 -204
  270. package/dist/storage/fsx-adapter.d.ts.map +0 -1
  271. package/dist/storage/fsx-adapter.js +0 -518
  272. package/dist/storage/fsx-adapter.js.map +0 -1
  273. package/dist/storage/lru-cache.d.ts +0 -691
  274. package/dist/storage/lru-cache.d.ts.map +0 -1
  275. package/dist/storage/lru-cache.js +0 -813
  276. package/dist/storage/lru-cache.js.map +0 -1
  277. package/dist/storage/object-index.d.ts +0 -585
  278. package/dist/storage/object-index.d.ts.map +0 -1
  279. package/dist/storage/object-index.js +0 -532
  280. package/dist/storage/object-index.js.map +0 -1
  281. package/dist/storage/r2-pack.d.ts +0 -1257
  282. package/dist/storage/r2-pack.d.ts.map +0 -1
  283. package/dist/storage/r2-pack.js +0 -1773
  284. package/dist/storage/r2-pack.js.map +0 -1
  285. package/dist/tiered/cdc-pipeline.d.ts +0 -1888
  286. package/dist/tiered/cdc-pipeline.d.ts.map +0 -1
  287. package/dist/tiered/cdc-pipeline.js +0 -1880
  288. package/dist/tiered/cdc-pipeline.js.map +0 -1
  289. package/dist/tiered/migration.d.ts +0 -1104
  290. package/dist/tiered/migration.d.ts.map +0 -1
  291. package/dist/tiered/migration.js +0 -1217
  292. package/dist/tiered/migration.js.map +0 -1
  293. package/dist/tiered/parquet-writer.d.ts +0 -1145
  294. package/dist/tiered/parquet-writer.d.ts.map +0 -1
  295. package/dist/tiered/parquet-writer.js +0 -1183
  296. package/dist/tiered/parquet-writer.js.map +0 -1
  297. package/dist/tiered/read-path.d.ts +0 -835
  298. package/dist/tiered/read-path.d.ts.map +0 -1
  299. package/dist/tiered/read-path.js +0 -487
  300. package/dist/tiered/read-path.js.map +0 -1
  301. package/dist/types/capability.d.ts +0 -1385
  302. package/dist/types/capability.d.ts.map +0 -1
  303. package/dist/types/capability.js +0 -36
  304. package/dist/types/capability.js.map +0 -1
  305. package/dist/types/index.d.ts +0 -13
  306. package/dist/types/index.d.ts.map +0 -1
  307. package/dist/types/index.js +0 -18
  308. package/dist/types/index.js.map +0 -1
  309. package/dist/types/interfaces.d.ts +0 -673
  310. package/dist/types/interfaces.d.ts.map +0 -1
  311. package/dist/types/interfaces.js +0 -26
  312. package/dist/types/interfaces.js.map +0 -1
  313. package/dist/types/objects.d.ts +0 -692
  314. package/dist/types/objects.d.ts.map +0 -1
  315. package/dist/types/objects.js +0 -837
  316. package/dist/types/objects.js.map +0 -1
  317. package/dist/types/storage.d.ts +0 -603
  318. package/dist/types/storage.d.ts.map +0 -1
  319. package/dist/types/storage.js +0 -191
  320. package/dist/types/storage.js.map +0 -1
  321. package/dist/types/worker-loader.d.ts +0 -60
  322. package/dist/types/worker-loader.d.ts.map +0 -1
  323. package/dist/types/worker-loader.js +0 -62
  324. package/dist/types/worker-loader.js.map +0 -1
  325. package/dist/utils/hash.d.ts +0 -198
  326. package/dist/utils/hash.d.ts.map +0 -1
  327. package/dist/utils/hash.js +0 -272
  328. package/dist/utils/hash.js.map +0 -1
  329. package/dist/utils/sha1.d.ts +0 -325
  330. package/dist/utils/sha1.d.ts.map +0 -1
  331. package/dist/utils/sha1.js +0 -635
  332. package/dist/utils/sha1.js.map +0 -1
  333. package/dist/wire/capabilities.d.ts +0 -1044
  334. package/dist/wire/capabilities.d.ts.map +0 -1
  335. package/dist/wire/capabilities.js +0 -941
  336. package/dist/wire/capabilities.js.map +0 -1
  337. package/dist/wire/path-security.d.ts +0 -157
  338. package/dist/wire/path-security.d.ts.map +0 -1
  339. package/dist/wire/path-security.js +0 -307
  340. package/dist/wire/path-security.js.map +0 -1
  341. package/dist/wire/pkt-line.d.ts +0 -345
  342. package/dist/wire/pkt-line.d.ts.map +0 -1
  343. package/dist/wire/pkt-line.js +0 -381
  344. package/dist/wire/pkt-line.js.map +0 -1
  345. package/dist/wire/receive-pack.d.ts +0 -1059
  346. package/dist/wire/receive-pack.d.ts.map +0 -1
  347. package/dist/wire/receive-pack.js +0 -1414
  348. package/dist/wire/receive-pack.js.map +0 -1
  349. package/dist/wire/smart-http.d.ts +0 -799
  350. package/dist/wire/smart-http.d.ts.map +0 -1
  351. package/dist/wire/smart-http.js +0 -945
  352. package/dist/wire/smart-http.js.map +0 -1
  353. package/dist/wire/upload-pack.d.ts +0 -727
  354. package/dist/wire/upload-pack.d.ts.map +0 -1
  355. package/dist/wire/upload-pack.js +0 -1141
  356. package/dist/wire/upload-pack.js.map +0 -1
@@ -1,689 +0,0 @@
1
- /**
2
- * @fileoverview R2 Tiered Storage for GitModule
3
- *
4
- * This module provides tiered storage support for Git objects in the GitModule,
5
- * implementing a three-tier architecture:
6
- *
7
- * - **Hot tier**: SQLite in Durable Object (fastest access, limited capacity)
8
- * - **Warm tier**: R2 loose objects (medium latency, larger capacity)
9
- * - **Cold tier**: R2 packfiles (highest latency, most efficient storage)
10
- *
11
- * The module automatically:
12
- * - Promotes frequently accessed objects to the hot tier
13
- * - Demotes old/rarely accessed objects to warm/cold tiers
14
- * - Supports packfile storage in R2 for efficiency
15
- *
16
- * @module do/tiered-storage
17
- *
18
- * @example
19
- * ```typescript
20
- * import { TieredStorage } from 'gitx.do/do'
21
- *
22
- * const storage = new TieredStorage({
23
- * r2: env.R2_BUCKET,
24
- * sql: ctx.storage.sql,
25
- * prefix: 'git/objects',
26
- * hotTierMaxBytes: 50 * 1024 * 1024, // 50MB in SQLite
27
- * promotionThreshold: 3, // Promote after 3 accesses
28
- * demotionAgeDays: 7 // Demote after 7 days without access
29
- * })
30
- *
31
- * // Get an object (checks hot -> warm -> cold)
32
- * const obj = await storage.getObject(sha)
33
- *
34
- * // Store an object (goes to appropriate tier based on size/frequency)
35
- * await storage.putObject(sha, type, data)
36
- * ```
37
- */
38
- // ============================================================================
39
- // TieredStorage Class
40
- // ============================================================================
41
- /**
42
- * TieredStorage - R2 Tiered Storage for GitModule
43
- *
44
- * @description
45
- * Provides a three-tier storage system for Git objects optimized for
46
- * Cloudflare Workers with Durable Objects:
47
- *
48
- * - **Hot tier**: SQLite blob storage in Durable Object
49
- * - Fastest access (local to DO)
50
- * - Limited capacity (50MB default)
51
- * - For frequently accessed objects
52
- *
53
- * - **Warm tier**: R2 loose objects
54
- * - Medium latency (~50-100ms)
55
- * - Unlimited capacity
56
- * - For recently accessed objects
57
- *
58
- * - **Cold tier**: R2 packfiles
59
- * - Highest latency (requires packfile parsing)
60
- * - Most storage efficient
61
- * - For archived/rarely accessed objects
62
- *
63
- * @example
64
- * ```typescript
65
- * const storage = new TieredStorage({
66
- * r2: env.GIT_OBJECTS,
67
- * sql: ctx.storage.sql,
68
- * prefix: 'repos/my-repo/objects'
69
- * })
70
- *
71
- * // Store a new object
72
- * await storage.putObject('abc123...', 'blob', blobData)
73
- *
74
- * // Retrieve an object (auto-promotes on frequent access)
75
- * const result = await storage.getObject('abc123...')
76
- * console.log(`Found in ${result.tier} tier, promoted: ${result.promoted}`)
77
- *
78
- * // Run maintenance (demotes old objects)
79
- * await storage.runMaintenance()
80
- * ```
81
- */
82
- export class TieredStorage {
83
- r2;
84
- sql;
85
- prefix;
86
- hotTierMaxBytes;
87
- promotionThreshold;
88
- demotionAgeDays;
89
- hotTierMaxObjectSize;
90
- autoPromote;
91
- autoDemote;
92
- // Statistics tracking
93
- hotHits = 0;
94
- warmHits = 0;
95
- coldHits = 0;
96
- misses = 0;
97
- promotions = 0;
98
- demotions = 0;
99
- // Schema initialization flag
100
- initialized = false;
101
- /**
102
- * Creates a new TieredStorage instance.
103
- *
104
- * @param options - Configuration options
105
- */
106
- constructor(options) {
107
- this.r2 = options.r2;
108
- this.sql = options.sql;
109
- this.prefix = options.prefix ?? 'git/objects';
110
- this.hotTierMaxBytes = options.hotTierMaxBytes ?? 50 * 1024 * 1024;
111
- this.promotionThreshold = options.promotionThreshold ?? 3;
112
- this.demotionAgeDays = options.demotionAgeDays ?? 7;
113
- this.hotTierMaxObjectSize = options.hotTierMaxObjectSize ?? 1 * 1024 * 1024;
114
- this.autoPromote = options.autoPromote ?? true;
115
- this.autoDemote = options.autoDemote ?? true;
116
- }
117
- /**
118
- * Initialize the SQLite schema for tiered storage.
119
- */
120
- async initialize() {
121
- if (this.initialized)
122
- return;
123
- // Create object metadata table
124
- this.sql.exec(`
125
- CREATE TABLE IF NOT EXISTS git_objects_meta (
126
- sha TEXT PRIMARY KEY,
127
- type TEXT NOT NULL,
128
- size INTEGER NOT NULL,
129
- tier TEXT NOT NULL DEFAULT 'warm',
130
- access_count INTEGER NOT NULL DEFAULT 0,
131
- last_accessed INTEGER NOT NULL,
132
- created_at INTEGER NOT NULL,
133
- pack_id TEXT,
134
- pack_offset INTEGER
135
- )
136
- `);
137
- // Create hot tier blob storage table
138
- this.sql.exec(`
139
- CREATE TABLE IF NOT EXISTS git_objects_hot (
140
- sha TEXT PRIMARY KEY,
141
- type TEXT NOT NULL,
142
- data BLOB NOT NULL,
143
- size INTEGER NOT NULL,
144
- created_at INTEGER NOT NULL
145
- )
146
- `);
147
- // Create index for efficient queries
148
- this.sql.exec(`
149
- CREATE INDEX IF NOT EXISTS idx_git_objects_meta_tier
150
- ON git_objects_meta(tier)
151
- `);
152
- this.sql.exec(`
153
- CREATE INDEX IF NOT EXISTS idx_git_objects_meta_last_accessed
154
- ON git_objects_meta(last_accessed)
155
- `);
156
- this.sql.exec(`
157
- CREATE INDEX IF NOT EXISTS idx_git_objects_meta_access_count
158
- ON git_objects_meta(access_count)
159
- `);
160
- this.initialized = true;
161
- }
162
- /**
163
- * Get an object from the tiered storage.
164
- *
165
- * @description
166
- * Attempts to retrieve the object from each tier in order:
167
- * 1. Hot tier (SQLite)
168
- * 2. Warm tier (R2 loose objects)
169
- * 3. Cold tier (R2 packfiles)
170
- *
171
- * Automatically promotes frequently accessed objects to hotter tiers.
172
- *
173
- * @param sha - 40-character SHA-1 hash of the object
174
- * @returns Object data with tier information, or null if not found
175
- */
176
- async getObject(sha) {
177
- await this.initialize();
178
- // Try hot tier first (SQLite)
179
- const hotResult = await this.getFromHotTier(sha);
180
- if (hotResult) {
181
- this.hotHits++;
182
- await this.recordAccess(sha);
183
- return {
184
- type: hotResult.type,
185
- data: hotResult.data,
186
- tier: 'hot',
187
- promoted: false
188
- };
189
- }
190
- // Get metadata to determine tier
191
- const meta = await this.getMetadata(sha);
192
- // Try warm tier (R2 loose objects)
193
- const warmResult = await this.getFromWarmTier(sha);
194
- if (warmResult) {
195
- this.warmHits++;
196
- await this.recordAccess(sha);
197
- // Check for promotion
198
- let promoted = false;
199
- if (this.autoPromote && meta && meta.accessCount >= this.promotionThreshold) {
200
- promoted = await this.promoteToHot(sha, warmResult.type, warmResult.data);
201
- }
202
- return {
203
- type: warmResult.type,
204
- data: warmResult.data,
205
- tier: 'warm',
206
- promoted
207
- };
208
- }
209
- // Try cold tier (R2 packfiles)
210
- if (meta?.packId && meta.packOffset !== undefined) {
211
- const coldResult = await this.getFromColdTier(meta.packId, meta.packOffset);
212
- if (coldResult) {
213
- this.coldHits++;
214
- await this.recordAccess(sha);
215
- // Check for promotion
216
- let promoted = false;
217
- if (this.autoPromote && meta.accessCount >= this.promotionThreshold) {
218
- // Promote to warm first (not hot, since it came from cold)
219
- await this.promoteToWarm(sha, coldResult.type, coldResult.data);
220
- promoted = true;
221
- }
222
- return {
223
- type: coldResult.type,
224
- data: coldResult.data,
225
- tier: 'cold',
226
- promoted
227
- };
228
- }
229
- }
230
- this.misses++;
231
- return null;
232
- }
233
- /**
234
- * Store an object in the tiered storage.
235
- *
236
- * @description
237
- * Stores the object in the appropriate tier based on size and configuration:
238
- * - Small, new objects go to hot tier if capacity allows
239
- * - Large objects go directly to warm tier
240
- *
241
- * @param sha - 40-character SHA-1 hash
242
- * @param type - Git object type
243
- * @param data - Raw object data
244
- * @returns The tier where the object was stored
245
- */
246
- async putObject(sha, type, data) {
247
- await this.initialize();
248
- const size = data.length;
249
- const now = Date.now();
250
- // Check if object already exists
251
- const existing = await this.getMetadata(sha);
252
- if (existing) {
253
- return existing.tier;
254
- }
255
- // Determine target tier based on size and capacity
256
- let tier = 'warm';
257
- if (size <= this.hotTierMaxObjectSize) {
258
- const currentHotBytes = await this.getHotTierBytes();
259
- if (currentHotBytes + size <= this.hotTierMaxBytes) {
260
- tier = 'hot';
261
- }
262
- }
263
- // Store in appropriate tier
264
- if (tier === 'hot') {
265
- await this.storeInHotTier(sha, type, data);
266
- }
267
- else {
268
- await this.storeInWarmTier(sha, type, data);
269
- }
270
- // Record metadata
271
- this.sql.exec(`INSERT INTO git_objects_meta (sha, type, size, tier, access_count, last_accessed, created_at)
272
- VALUES (?, ?, ?, ?, 0, ?, ?)`, sha, type, size, tier, now, now);
273
- return tier;
274
- }
275
- /**
276
- * Check if an object exists in any tier.
277
- *
278
- * @param sha - 40-character SHA-1 hash
279
- * @returns True if object exists
280
- */
281
- async hasObject(sha) {
282
- await this.initialize();
283
- const meta = await this.getMetadata(sha);
284
- return meta !== null;
285
- }
286
- /**
287
- * Delete an object from all tiers.
288
- *
289
- * @param sha - 40-character SHA-1 hash
290
- */
291
- async deleteObject(sha) {
292
- await this.initialize();
293
- const meta = await this.getMetadata(sha);
294
- if (!meta)
295
- return;
296
- // Delete from hot tier
297
- this.sql.exec('DELETE FROM git_objects_hot WHERE sha = ?', sha);
298
- // Delete from warm tier (R2)
299
- const key = this.buildR2Key(sha);
300
- await this.r2.delete(key);
301
- // Delete metadata
302
- this.sql.exec('DELETE FROM git_objects_meta WHERE sha = ?', sha);
303
- }
304
- /**
305
- * Manually promote an object to the hot tier.
306
- *
307
- * @param sha - Object SHA to promote
308
- * @param type - Object type
309
- * @param data - Object data
310
- * @returns True if promotion succeeded
311
- */
312
- async promoteToHot(sha, type, data) {
313
- await this.initialize();
314
- const size = data.length;
315
- // Check if object fits in hot tier
316
- if (size > this.hotTierMaxObjectSize) {
317
- return false;
318
- }
319
- const currentBytes = await this.getHotTierBytes();
320
- if (currentBytes + size > this.hotTierMaxBytes) {
321
- // Need to evict objects to make room
322
- const evicted = await this.evictFromHotTier(size);
323
- if (!evicted) {
324
- return false;
325
- }
326
- }
327
- // Store in hot tier
328
- await this.storeInHotTier(sha, type, data);
329
- // Update metadata
330
- this.sql.exec('UPDATE git_objects_meta SET tier = ? WHERE sha = ?', 'hot', sha);
331
- this.promotions++;
332
- return true;
333
- }
334
- /**
335
- * Demote an object from hot to warm tier.
336
- *
337
- * @param sha - Object SHA to demote
338
- */
339
- async demoteToWarm(sha) {
340
- await this.initialize();
341
- // Get object from hot tier
342
- const rows = this.sql.exec('SELECT type, data FROM git_objects_hot WHERE sha = ?', sha).toArray();
343
- if (rows.length === 0)
344
- return;
345
- const { type, data } = rows[0];
346
- // Store in warm tier
347
- await this.storeInWarmTier(sha, type, data);
348
- // Remove from hot tier
349
- this.sql.exec('DELETE FROM git_objects_hot WHERE sha = ?', sha);
350
- // Update metadata
351
- this.sql.exec('UPDATE git_objects_meta SET tier = ? WHERE sha = ?', 'warm', sha);
352
- this.demotions++;
353
- }
354
- /**
355
- * Demote an object from warm to cold tier (packfile).
356
- *
357
- * @description
358
- * This is typically done during packfile creation, where multiple
359
- * warm objects are combined into a packfile for efficiency.
360
- *
361
- * @param sha - Object SHA to demote
362
- * @param packId - Packfile ID where object will be stored
363
- * @param packOffset - Byte offset within the packfile
364
- */
365
- async demoteToCold(sha, packId, packOffset) {
366
- await this.initialize();
367
- // Delete from warm tier
368
- const key = this.buildR2Key(sha);
369
- await this.r2.delete(key);
370
- // Update metadata with pack location
371
- this.sql.exec('UPDATE git_objects_meta SET tier = ?, pack_id = ?, pack_offset = ? WHERE sha = ?', 'cold', packId, packOffset, sha);
372
- this.demotions++;
373
- }
374
- /**
375
- * Run maintenance tasks (demotion of old objects).
376
- *
377
- * @description
378
- * This should be called periodically to:
379
- * 1. Demote old hot tier objects to warm
380
- * 2. Optionally pack warm objects into cold tier
381
- *
382
- * @param options - Maintenance options
383
- * @returns Number of objects demoted
384
- */
385
- async runMaintenance(options) {
386
- await this.initialize();
387
- if (!this.autoDemote)
388
- return 0;
389
- const cutoffTime = Date.now() - (this.demotionAgeDays * 24 * 60 * 60 * 1000);
390
- let demoted = 0;
391
- // Find hot tier objects that should be demoted
392
- const rows = this.sql.exec(`SELECT sha FROM git_objects_meta
393
- WHERE tier = 'hot' AND last_accessed < ?
394
- ORDER BY last_accessed ASC
395
- LIMIT 100`, cutoffTime).toArray();
396
- for (const row of rows) {
397
- if (!options?.dryRun) {
398
- await this.demoteToWarm(row.sha);
399
- }
400
- demoted++;
401
- }
402
- return demoted;
403
- }
404
- /**
405
- * Get storage statistics.
406
- */
407
- async getStats() {
408
- await this.initialize();
409
- const hotCount = this.sql.exec("SELECT COUNT(*) as count FROM git_objects_meta WHERE tier = 'hot'").toArray()[0]?.count ?? 0;
410
- const hotBytes = await this.getHotTierBytes();
411
- const warmCount = this.sql.exec("SELECT COUNT(*) as count FROM git_objects_meta WHERE tier = 'warm'").toArray()[0]?.count ?? 0;
412
- const coldCount = this.sql.exec("SELECT COUNT(*) as count FROM git_objects_meta WHERE tier = 'cold'").toArray()[0]?.count ?? 0;
413
- const totalHits = this.hotHits + this.warmHits + this.coldHits;
414
- const totalRequests = totalHits + this.misses;
415
- const hitRate = totalRequests > 0 ? totalHits / totalRequests : 0;
416
- return {
417
- hotTierCount: hotCount,
418
- hotTierBytes: hotBytes,
419
- warmTierCount: warmCount,
420
- coldTierCount: coldCount,
421
- totalObjects: hotCount + warmCount + coldCount,
422
- cacheHitRate: hitRate,
423
- promotions: this.promotions,
424
- demotions: this.demotions
425
- };
426
- }
427
- /**
428
- * Create a packfile from warm tier objects.
429
- *
430
- * @description
431
- * Combines multiple warm tier objects into a packfile stored in R2.
432
- * This is more storage-efficient and can reduce costs.
433
- *
434
- * @param shas - Array of SHA hashes to pack
435
- * @returns Pack ID and size
436
- */
437
- async createPackfile(shas) {
438
- await this.initialize();
439
- // Generate pack ID
440
- const packId = `pack-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
441
- // Collect objects
442
- const objects = [];
443
- for (const sha of shas) {
444
- const result = await this.getFromWarmTier(sha);
445
- if (result) {
446
- objects.push({ sha, ...result });
447
- }
448
- }
449
- if (objects.length === 0) {
450
- return { packId, size: 0, objectCount: 0 };
451
- }
452
- // Build simple packfile format
453
- const packData = this.buildPackfile(objects);
454
- // Store in R2
455
- const packKey = `${this.prefix}/packs/${packId}.pack`;
456
- await this.r2.put(packKey, packData, {
457
- customMetadata: {
458
- objectCount: String(objects.length),
459
- createdAt: new Date().toISOString()
460
- }
461
- });
462
- // Update metadata for each object
463
- let offset = 12; // Pack header size
464
- for (const obj of objects) {
465
- await this.demoteToCold(obj.sha, packId, offset);
466
- offset += obj.data.length + 10; // Rough estimate for object header
467
- }
468
- return {
469
- packId,
470
- size: packData.length,
471
- objectCount: objects.length
472
- };
473
- }
474
- // =========================================================================
475
- // Private Helper Methods
476
- // =========================================================================
477
- /**
478
- * Get object from hot tier (SQLite).
479
- */
480
- async getFromHotTier(sha) {
481
- const rows = this.sql.exec('SELECT type, data FROM git_objects_hot WHERE sha = ?', sha).toArray();
482
- if (rows.length === 0)
483
- return null;
484
- return {
485
- type: rows[0].type,
486
- data: rows[0].data
487
- };
488
- }
489
- /**
490
- * Get object from warm tier (R2 loose objects).
491
- */
492
- async getFromWarmTier(sha) {
493
- const key = this.buildR2Key(sha);
494
- const obj = await this.r2.get(key);
495
- if (!obj)
496
- return null;
497
- const data = new Uint8Array(await obj.arrayBuffer());
498
- const type = (obj.customMetadata?.type ?? 'blob');
499
- return { type, data };
500
- }
501
- /**
502
- * Get object from cold tier (R2 packfile).
503
- */
504
- async getFromColdTier(packId, offset) {
505
- const packKey = `${this.prefix}/packs/${packId}.pack`;
506
- const packObj = await this.r2.get(packKey);
507
- if (!packObj)
508
- return null;
509
- const packData = new Uint8Array(await packObj.arrayBuffer());
510
- // Parse object from packfile at offset
511
- const result = this.parsePackObject(packData, offset);
512
- return result;
513
- }
514
- /**
515
- * Store object in hot tier.
516
- */
517
- async storeInHotTier(sha, type, data) {
518
- const now = Date.now();
519
- this.sql.exec(`INSERT OR REPLACE INTO git_objects_hot (sha, type, data, size, created_at)
520
- VALUES (?, ?, ?, ?, ?)`, sha, type, data, data.length, now);
521
- }
522
- /**
523
- * Store object in warm tier.
524
- */
525
- async storeInWarmTier(sha, type, data) {
526
- const key = this.buildR2Key(sha);
527
- await this.r2.put(key, data, {
528
- customMetadata: {
529
- type,
530
- size: String(data.length),
531
- createdAt: new Date().toISOString()
532
- }
533
- });
534
- }
535
- /**
536
- * Promote object to warm tier.
537
- */
538
- async promoteToWarm(sha, type, data) {
539
- await this.storeInWarmTier(sha, type, data);
540
- this.sql.exec('UPDATE git_objects_meta SET tier = ?, pack_id = NULL, pack_offset = NULL WHERE sha = ?', 'warm', sha);
541
- }
542
- /**
543
- * Get metadata for an object.
544
- */
545
- async getMetadata(sha) {
546
- const rows = this.sql.exec('SELECT * FROM git_objects_meta WHERE sha = ?', sha).toArray();
547
- if (rows.length === 0)
548
- return null;
549
- const row = rows[0];
550
- return {
551
- sha: row.sha,
552
- type: row.type,
553
- size: row.size,
554
- tier: row.tier,
555
- accessCount: row.access_count,
556
- lastAccessed: row.last_accessed,
557
- createdAt: row.created_at,
558
- packId: row.pack_id ?? undefined,
559
- packOffset: row.pack_offset ?? undefined
560
- };
561
- }
562
- /**
563
- * Record an access to an object.
564
- */
565
- async recordAccess(sha) {
566
- const now = Date.now();
567
- this.sql.exec('UPDATE git_objects_meta SET access_count = access_count + 1, last_accessed = ? WHERE sha = ?', now, sha);
568
- }
569
- /**
570
- * Get total bytes in hot tier.
571
- */
572
- async getHotTierBytes() {
573
- const rows = this.sql.exec('SELECT SUM(size) as total FROM git_objects_hot').toArray();
574
- return rows[0]?.total ?? 0;
575
- }
576
- /**
577
- * Evict objects from hot tier to make room.
578
- */
579
- async evictFromHotTier(neededBytes) {
580
- void await this.getHotTierBytes(); // Track current usage
581
- let freedBytes = 0;
582
- const targetFree = neededBytes;
583
- // Get LRU objects from hot tier
584
- const rows = this.sql.exec(`SELECT m.sha, h.size
585
- FROM git_objects_meta m
586
- JOIN git_objects_hot h ON m.sha = h.sha
587
- WHERE m.tier = 'hot'
588
- ORDER BY m.last_accessed ASC
589
- LIMIT 50`).toArray();
590
- for (const row of rows) {
591
- if (freedBytes >= targetFree)
592
- break;
593
- await this.demoteToWarm(row.sha);
594
- freedBytes += row.size;
595
- }
596
- return freedBytes >= targetFree;
597
- }
598
- /**
599
- * Build R2 key for a loose object.
600
- */
601
- buildR2Key(sha) {
602
- // Use git's standard 2-character prefix directory structure
603
- return `${this.prefix}/${sha.slice(0, 2)}/${sha.slice(2)}`;
604
- }
605
- /**
606
- * Build a simple packfile from objects.
607
- */
608
- buildPackfile(objects) {
609
- // Pack header: "PACK" + version (2) + object count
610
- const header = new Uint8Array(12);
611
- header[0] = 0x50; // P
612
- header[1] = 0x41; // A
613
- header[2] = 0x43; // C
614
- header[3] = 0x4B; // K
615
- header[4] = 0x00;
616
- header[5] = 0x00;
617
- header[6] = 0x00;
618
- header[7] = 0x02; // Version 2
619
- // Object count (big endian)
620
- const count = objects.length;
621
- header[8] = (count >> 24) & 0xff;
622
- header[9] = (count >> 16) & 0xff;
623
- header[10] = (count >> 8) & 0xff;
624
- header[11] = count & 0xff;
625
- // Calculate total size
626
- let totalSize = 12; // header
627
- for (const obj of objects) {
628
- totalSize += 1 + obj.data.length; // type byte + data
629
- }
630
- totalSize += 20; // trailing checksum
631
- const pack = new Uint8Array(totalSize);
632
- pack.set(header, 0);
633
- let offset = 12;
634
- const typeMap = {
635
- commit: 1,
636
- tree: 2,
637
- blob: 3,
638
- tag: 4
639
- };
640
- for (const obj of objects) {
641
- // Simple encoding: type nibble + size
642
- const typeNum = typeMap[obj.type] ?? 3;
643
- pack[offset] = (typeNum << 4) | (obj.data.length & 0x0f);
644
- offset++;
645
- pack.set(obj.data, offset);
646
- offset += obj.data.length;
647
- }
648
- // Trailing zeros for checksum (simplified)
649
- return pack;
650
- }
651
- /**
652
- * Parse an object from packfile data at offset.
653
- */
654
- parsePackObject(packData, offset) {
655
- if (offset >= packData.length)
656
- return null;
657
- // Read type and size from first byte
658
- const firstByte = packData[offset];
659
- const typeNum = (firstByte >> 4) & 0x07;
660
- const typeMap = {
661
- 1: 'commit',
662
- 2: 'tree',
663
- 3: 'blob',
664
- 4: 'tag'
665
- };
666
- const type = typeMap[typeNum] ?? 'blob';
667
- // For simplicity, read until next object or end
668
- // In production, this would use proper variable-length encoding
669
- let end = offset + 1;
670
- while (end < packData.length && end < offset + 10000) {
671
- end++;
672
- }
673
- const data = packData.slice(offset + 1, end);
674
- return { type, data };
675
- }
676
- }
677
- // ============================================================================
678
- // Factory Functions
679
- // ============================================================================
680
- /**
681
- * Create a TieredStorage instance.
682
- *
683
- * @param options - Configuration options
684
- * @returns Configured TieredStorage instance
685
- */
686
- export function createTieredStorage(options) {
687
- return new TieredStorage(options);
688
- }
689
- //# sourceMappingURL=tiered-storage.js.map