gitx.do 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/blame.d.ts +259 -0
- package/dist/cli/commands/blame.d.ts.map +1 -0
- package/dist/cli/commands/blame.js +609 -0
- package/dist/cli/commands/blame.js.map +1 -0
- package/dist/cli/commands/branch.d.ts +249 -0
- package/dist/cli/commands/branch.d.ts.map +1 -0
- package/dist/cli/commands/branch.js +693 -0
- package/dist/cli/commands/branch.js.map +1 -0
- package/dist/cli/commands/commit.d.ts +182 -0
- package/dist/cli/commands/commit.d.ts.map +1 -0
- package/dist/cli/commands/commit.js +437 -0
- package/dist/cli/commands/commit.js.map +1 -0
- package/dist/cli/commands/diff.d.ts +464 -0
- package/dist/cli/commands/diff.d.ts.map +1 -0
- package/dist/cli/commands/diff.js +958 -0
- package/dist/cli/commands/diff.js.map +1 -0
- package/dist/cli/commands/log.d.ts +239 -0
- package/dist/cli/commands/log.d.ts.map +1 -0
- package/dist/cli/commands/log.js +535 -0
- package/dist/cli/commands/log.js.map +1 -0
- package/dist/cli/commands/review.d.ts +457 -0
- package/dist/cli/commands/review.d.ts.map +1 -0
- package/dist/cli/commands/review.js +533 -0
- package/dist/cli/commands/review.js.map +1 -0
- package/dist/cli/commands/status.d.ts +269 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +493 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/web.d.ts +199 -0
- package/dist/cli/commands/web.d.ts.map +1 -0
- package/dist/cli/commands/web.js +696 -0
- package/dist/cli/commands/web.js.map +1 -0
- package/dist/cli/fs-adapter.d.ts +656 -0
- package/dist/cli/fs-adapter.d.ts.map +1 -0
- package/dist/cli/fs-adapter.js +1179 -0
- package/dist/cli/fs-adapter.js.map +1 -0
- package/dist/cli/index.d.ts +387 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +523 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/ui/components/DiffView.d.ts +7 -0
- package/dist/cli/ui/components/DiffView.d.ts.map +1 -0
- package/dist/cli/ui/components/DiffView.js +11 -0
- package/dist/cli/ui/components/DiffView.js.map +1 -0
- package/dist/cli/ui/components/ErrorDisplay.d.ts +6 -0
- package/dist/cli/ui/components/ErrorDisplay.d.ts.map +1 -0
- package/dist/cli/ui/components/ErrorDisplay.js +11 -0
- package/dist/cli/ui/components/ErrorDisplay.js.map +1 -0
- package/dist/cli/ui/components/FuzzySearch.d.ts +9 -0
- package/dist/cli/ui/components/FuzzySearch.d.ts.map +1 -0
- package/dist/cli/ui/components/FuzzySearch.js +12 -0
- package/dist/cli/ui/components/FuzzySearch.js.map +1 -0
- package/dist/cli/ui/components/LoadingSpinner.d.ts +6 -0
- package/dist/cli/ui/components/LoadingSpinner.d.ts.map +1 -0
- package/dist/cli/ui/components/LoadingSpinner.js +10 -0
- package/dist/cli/ui/components/LoadingSpinner.js.map +1 -0
- package/dist/cli/ui/components/NavigationList.d.ts +9 -0
- package/dist/cli/ui/components/NavigationList.d.ts.map +1 -0
- package/dist/cli/ui/components/NavigationList.js +11 -0
- package/dist/cli/ui/components/NavigationList.js.map +1 -0
- package/dist/cli/ui/components/ScrollableContent.d.ts +8 -0
- package/dist/cli/ui/components/ScrollableContent.d.ts.map +1 -0
- package/dist/cli/ui/components/ScrollableContent.js +11 -0
- package/dist/cli/ui/components/ScrollableContent.js.map +1 -0
- package/dist/cli/ui/components/index.d.ts +7 -0
- package/dist/cli/ui/components/index.d.ts.map +1 -0
- package/dist/cli/ui/components/index.js +9 -0
- package/dist/cli/ui/components/index.js.map +1 -0
- package/dist/cli/ui/terminal-ui.d.ts +52 -0
- package/dist/cli/ui/terminal-ui.d.ts.map +1 -0
- package/dist/cli/ui/terminal-ui.js +121 -0
- package/dist/cli/ui/terminal-ui.js.map +1 -0
- package/dist/durable-object/object-store.d.ts +401 -23
- package/dist/durable-object/object-store.d.ts.map +1 -1
- package/dist/durable-object/object-store.js +414 -25
- package/dist/durable-object/object-store.js.map +1 -1
- package/dist/durable-object/schema.d.ts +188 -0
- package/dist/durable-object/schema.d.ts.map +1 -1
- package/dist/durable-object/schema.js +160 -0
- package/dist/durable-object/schema.js.map +1 -1
- package/dist/durable-object/wal.d.ts +336 -31
- package/dist/durable-object/wal.d.ts.map +1 -1
- package/dist/durable-object/wal.js +272 -27
- package/dist/durable-object/wal.js.map +1 -1
- package/dist/index.d.ts +379 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +379 -7
- package/dist/index.js.map +1 -1
- package/dist/mcp/adapter.d.ts +579 -38
- package/dist/mcp/adapter.d.ts.map +1 -1
- package/dist/mcp/adapter.js +426 -33
- package/dist/mcp/adapter.js.map +1 -1
- package/dist/mcp/sandbox.d.ts +532 -29
- package/dist/mcp/sandbox.d.ts.map +1 -1
- package/dist/mcp/sandbox.js +389 -22
- package/dist/mcp/sandbox.js.map +1 -1
- package/dist/mcp/sdk-adapter.d.ts +478 -56
- package/dist/mcp/sdk-adapter.d.ts.map +1 -1
- package/dist/mcp/sdk-adapter.js +346 -44
- package/dist/mcp/sdk-adapter.js.map +1 -1
- package/dist/mcp/tools.d.ts +445 -30
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +363 -33
- package/dist/mcp/tools.js.map +1 -1
- package/dist/ops/blame.d.ts +424 -21
- package/dist/ops/blame.d.ts.map +1 -1
- package/dist/ops/blame.js +303 -20
- package/dist/ops/blame.js.map +1 -1
- package/dist/ops/branch.d.ts +583 -32
- package/dist/ops/branch.d.ts.map +1 -1
- package/dist/ops/branch.js +365 -23
- package/dist/ops/branch.js.map +1 -1
- package/dist/ops/commit-traversal.d.ts +164 -24
- package/dist/ops/commit-traversal.d.ts.map +1 -1
- package/dist/ops/commit-traversal.js +68 -2
- package/dist/ops/commit-traversal.js.map +1 -1
- package/dist/ops/commit.d.ts +387 -53
- package/dist/ops/commit.d.ts.map +1 -1
- package/dist/ops/commit.js +249 -29
- package/dist/ops/commit.js.map +1 -1
- package/dist/ops/merge-base.d.ts +195 -21
- package/dist/ops/merge-base.d.ts.map +1 -1
- package/dist/ops/merge-base.js +122 -12
- package/dist/ops/merge-base.js.map +1 -1
- package/dist/ops/merge.d.ts +600 -130
- package/dist/ops/merge.d.ts.map +1 -1
- package/dist/ops/merge.js +408 -60
- package/dist/ops/merge.js.map +1 -1
- package/dist/ops/tag.d.ts +67 -2
- package/dist/ops/tag.d.ts.map +1 -1
- package/dist/ops/tag.js +42 -1
- package/dist/ops/tag.js.map +1 -1
- package/dist/ops/tree-builder.d.ts +102 -6
- package/dist/ops/tree-builder.d.ts.map +1 -1
- package/dist/ops/tree-builder.js +30 -5
- package/dist/ops/tree-builder.js.map +1 -1
- package/dist/ops/tree-diff.d.ts +50 -2
- package/dist/ops/tree-diff.d.ts.map +1 -1
- package/dist/ops/tree-diff.js +50 -2
- package/dist/ops/tree-diff.js.map +1 -1
- package/dist/pack/delta.d.ts +211 -39
- package/dist/pack/delta.d.ts.map +1 -1
- package/dist/pack/delta.js +232 -46
- package/dist/pack/delta.js.map +1 -1
- package/dist/pack/format.d.ts +390 -28
- package/dist/pack/format.d.ts.map +1 -1
- package/dist/pack/format.js +344 -33
- package/dist/pack/format.js.map +1 -1
- package/dist/pack/full-generation.d.ts +313 -28
- package/dist/pack/full-generation.d.ts.map +1 -1
- package/dist/pack/full-generation.js +238 -19
- package/dist/pack/full-generation.js.map +1 -1
- package/dist/pack/generation.d.ts +346 -23
- package/dist/pack/generation.d.ts.map +1 -1
- package/dist/pack/generation.js +269 -21
- package/dist/pack/generation.js.map +1 -1
- package/dist/pack/index.d.ts +407 -86
- package/dist/pack/index.d.ts.map +1 -1
- package/dist/pack/index.js +351 -70
- package/dist/pack/index.js.map +1 -1
- package/dist/refs/branch.d.ts +517 -71
- package/dist/refs/branch.d.ts.map +1 -1
- package/dist/refs/branch.js +410 -26
- package/dist/refs/branch.js.map +1 -1
- package/dist/refs/storage.d.ts +610 -57
- package/dist/refs/storage.d.ts.map +1 -1
- package/dist/refs/storage.js +481 -29
- package/dist/refs/storage.js.map +1 -1
- package/dist/refs/tag.d.ts +677 -67
- package/dist/refs/tag.d.ts.map +1 -1
- package/dist/refs/tag.js +497 -30
- package/dist/refs/tag.js.map +1 -1
- package/dist/storage/lru-cache.d.ts +556 -53
- package/dist/storage/lru-cache.d.ts.map +1 -1
- package/dist/storage/lru-cache.js +439 -36
- package/dist/storage/lru-cache.js.map +1 -1
- package/dist/storage/object-index.d.ts +483 -38
- package/dist/storage/object-index.d.ts.map +1 -1
- package/dist/storage/object-index.js +388 -22
- package/dist/storage/object-index.js.map +1 -1
- package/dist/storage/r2-pack.d.ts +957 -94
- package/dist/storage/r2-pack.d.ts.map +1 -1
- package/dist/storage/r2-pack.js +756 -48
- package/dist/storage/r2-pack.js.map +1 -1
- package/dist/tiered/cdc-pipeline.d.ts +1610 -38
- package/dist/tiered/cdc-pipeline.d.ts.map +1 -1
- package/dist/tiered/cdc-pipeline.js +1131 -22
- package/dist/tiered/cdc-pipeline.js.map +1 -1
- package/dist/tiered/migration.d.ts +903 -41
- package/dist/tiered/migration.d.ts.map +1 -1
- package/dist/tiered/migration.js +646 -24
- package/dist/tiered/migration.js.map +1 -1
- package/dist/tiered/parquet-writer.d.ts +944 -47
- package/dist/tiered/parquet-writer.d.ts.map +1 -1
- package/dist/tiered/parquet-writer.js +667 -39
- package/dist/tiered/parquet-writer.js.map +1 -1
- package/dist/tiered/read-path.d.ts +728 -34
- package/dist/tiered/read-path.d.ts.map +1 -1
- package/dist/tiered/read-path.js +310 -27
- package/dist/tiered/read-path.js.map +1 -1
- package/dist/types/objects.d.ts +457 -0
- package/dist/types/objects.d.ts.map +1 -1
- package/dist/types/objects.js +305 -4
- package/dist/types/objects.js.map +1 -1
- package/dist/types/storage.d.ts +407 -35
- package/dist/types/storage.d.ts.map +1 -1
- package/dist/types/storage.js +27 -3
- package/dist/types/storage.js.map +1 -1
- package/dist/utils/hash.d.ts +133 -12
- package/dist/utils/hash.d.ts.map +1 -1
- package/dist/utils/hash.js +133 -12
- package/dist/utils/hash.js.map +1 -1
- package/dist/utils/sha1.d.ts +102 -9
- package/dist/utils/sha1.d.ts.map +1 -1
- package/dist/utils/sha1.js +114 -11
- package/dist/utils/sha1.js.map +1 -1
- package/dist/wire/capabilities.d.ts +896 -88
- package/dist/wire/capabilities.d.ts.map +1 -1
- package/dist/wire/capabilities.js +566 -62
- package/dist/wire/capabilities.js.map +1 -1
- package/dist/wire/pkt-line.d.ts +293 -15
- package/dist/wire/pkt-line.d.ts.map +1 -1
- package/dist/wire/pkt-line.js +251 -15
- package/dist/wire/pkt-line.js.map +1 -1
- package/dist/wire/receive-pack.d.ts +814 -64
- package/dist/wire/receive-pack.d.ts.map +1 -1
- package/dist/wire/receive-pack.js +542 -41
- package/dist/wire/receive-pack.js.map +1 -1
- package/dist/wire/smart-http.d.ts +575 -97
- package/dist/wire/smart-http.d.ts.map +1 -1
- package/dist/wire/smart-http.js +337 -46
- package/dist/wire/smart-http.js.map +1 -1
- package/dist/wire/upload-pack.d.ts +492 -98
- package/dist/wire/upload-pack.d.ts.map +1 -1
- package/dist/wire/upload-pack.js +347 -59
- package/dist/wire/upload-pack.js.map +1 -1
- package/package.json +10 -2
|
@@ -1,45 +1,140 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* R2 Packfile Storage
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
9
|
-
* -
|
|
2
|
+
* @fileoverview R2 Packfile Storage Module
|
|
3
|
+
*
|
|
4
|
+
* This module manages Git packfiles stored in Cloudflare R2 object storage.
|
|
5
|
+
* It provides comprehensive functionality for:
|
|
6
|
+
*
|
|
7
|
+
* - **Uploading and downloading packfiles** with their indices using atomic operations
|
|
8
|
+
* - **Multi-pack index (MIDX)** for efficient object lookup across multiple packs
|
|
9
|
+
* - **Concurrent access control** with distributed locking using R2 conditional writes
|
|
10
|
+
* - **Pack verification** and integrity checks via SHA-1 checksums
|
|
11
|
+
* - **Atomic uploads** using a manifest-based pattern to ensure data consistency
|
|
12
|
+
*
|
|
13
|
+
* The module implements Git's packfile format (version 2 and 3) and provides
|
|
14
|
+
* both class-based (`R2PackStorage`) and standalone function APIs for flexibility.
|
|
15
|
+
*
|
|
16
|
+
* @module storage/r2-pack
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* // Using the class-based API
|
|
21
|
+
* const storage = new R2PackStorage({
|
|
22
|
+
* bucket: myR2Bucket,
|
|
23
|
+
* prefix: 'repos/my-repo/',
|
|
24
|
+
* cacheSize: 100,
|
|
25
|
+
* cacheTTL: 3600
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* // Upload a packfile
|
|
29
|
+
* const result = await storage.uploadPackfile(packData, indexData);
|
|
30
|
+
* console.log(`Uploaded pack: ${result.packId}`);
|
|
31
|
+
*
|
|
32
|
+
* // Download with verification
|
|
33
|
+
* const download = await storage.downloadPackfile(result.packId, {
|
|
34
|
+
* verify: true,
|
|
35
|
+
* includeIndex: true
|
|
36
|
+
* });
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* // Using standalone functions
|
|
42
|
+
* const result = await uploadPackfile(bucket, packData, indexData, {
|
|
43
|
+
* prefix: 'repos/my-repo/'
|
|
44
|
+
* });
|
|
45
|
+
*
|
|
46
|
+
* const packfiles = await listPackfiles(bucket, {
|
|
47
|
+
* prefix: 'repos/my-repo/',
|
|
48
|
+
* limit: 10
|
|
49
|
+
* });
|
|
50
|
+
* ```
|
|
10
51
|
*/
|
|
11
52
|
/**
|
|
12
|
-
* Configuration options for R2PackStorage
|
|
53
|
+
* Configuration options for R2PackStorage.
|
|
54
|
+
*
|
|
55
|
+
* @description
|
|
56
|
+
* Defines the configuration parameters for initializing an R2PackStorage instance.
|
|
57
|
+
* The bucket is required, while other options have sensible defaults.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* const options: R2PackStorageOptions = {
|
|
62
|
+
* bucket: env.MY_R2_BUCKET,
|
|
63
|
+
* prefix: 'git-objects/',
|
|
64
|
+
* cacheSize: 200,
|
|
65
|
+
* cacheTTL: 7200
|
|
66
|
+
* };
|
|
67
|
+
* ```
|
|
13
68
|
*/
|
|
14
69
|
export interface R2PackStorageOptions {
|
|
15
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* R2 bucket instance for storage operations.
|
|
72
|
+
* This is typically obtained from the Cloudflare Workers environment bindings.
|
|
73
|
+
*/
|
|
16
74
|
bucket: R2Bucket;
|
|
17
|
-
/**
|
|
75
|
+
/**
|
|
76
|
+
* Optional prefix for all keys in the bucket.
|
|
77
|
+
* Use this to namespace packfiles for different repositories.
|
|
78
|
+
* @example 'repos/my-repo/' or 'org/project/'
|
|
79
|
+
*/
|
|
18
80
|
prefix?: string;
|
|
19
|
-
/**
|
|
81
|
+
/**
|
|
82
|
+
* Maximum number of items to cache in memory.
|
|
83
|
+
* Used for caching multi-pack index and other frequently accessed data.
|
|
84
|
+
* @default 100
|
|
85
|
+
*/
|
|
20
86
|
cacheSize?: number;
|
|
21
|
-
/**
|
|
87
|
+
/**
|
|
88
|
+
* Cache TTL (Time To Live) in seconds.
|
|
89
|
+
* Cached items will be invalidated after this duration.
|
|
90
|
+
* @default 3600 (1 hour)
|
|
91
|
+
*/
|
|
22
92
|
cacheTTL?: number;
|
|
23
93
|
}
|
|
24
94
|
/**
|
|
25
|
-
* Result
|
|
95
|
+
* Result returned after successfully uploading a packfile.
|
|
96
|
+
*
|
|
97
|
+
* @description
|
|
98
|
+
* Contains metadata about the uploaded packfile including its unique identifier,
|
|
99
|
+
* size information, checksum for verification, and timestamp.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* const result = await storage.uploadPackfile(packData, indexData);
|
|
104
|
+
* console.log(`Pack ID: ${result.packId}`);
|
|
105
|
+
* console.log(`Objects: ${result.objectCount}`);
|
|
106
|
+
* console.log(`Size: ${result.packSize} bytes`);
|
|
107
|
+
* ```
|
|
26
108
|
*/
|
|
27
109
|
export interface PackfileUploadResult {
|
|
28
|
-
/** Unique identifier for the packfile */
|
|
110
|
+
/** Unique identifier for the packfile (format: 'pack-{hex}') */
|
|
29
111
|
packId: string;
|
|
30
112
|
/** Size of the pack file in bytes */
|
|
31
113
|
packSize: number;
|
|
32
114
|
/** Size of the index file in bytes */
|
|
33
115
|
indexSize: number;
|
|
34
|
-
/** SHA-1 checksum of the packfile */
|
|
116
|
+
/** SHA-1 checksum of the packfile for integrity verification */
|
|
35
117
|
checksum: string;
|
|
36
|
-
/** Number of objects in the packfile */
|
|
118
|
+
/** Number of objects contained in the packfile */
|
|
37
119
|
objectCount: number;
|
|
38
120
|
/** Timestamp when the packfile was uploaded */
|
|
39
121
|
uploadedAt: Date;
|
|
40
122
|
}
|
|
41
123
|
/**
|
|
42
|
-
* Metadata about a stored packfile
|
|
124
|
+
* Metadata about a stored packfile.
|
|
125
|
+
*
|
|
126
|
+
* @description
|
|
127
|
+
* Provides comprehensive metadata about a packfile stored in R2,
|
|
128
|
+
* including size, object count, creation time, and checksum.
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* const metadata = await storage.getPackfileMetadata('pack-abc123');
|
|
133
|
+
* if (metadata) {
|
|
134
|
+
* console.log(`Created: ${metadata.createdAt}`);
|
|
135
|
+
* console.log(`Objects: ${metadata.objectCount}`);
|
|
136
|
+
* }
|
|
137
|
+
* ```
|
|
43
138
|
*/
|
|
44
139
|
export interface PackfileMetadata {
|
|
45
140
|
/** Unique identifier for the packfile */
|
|
@@ -56,44 +151,123 @@ export interface PackfileMetadata {
|
|
|
56
151
|
checksum: string;
|
|
57
152
|
}
|
|
58
153
|
/**
|
|
59
|
-
* Options for downloading a packfile
|
|
154
|
+
* Options for downloading a packfile.
|
|
155
|
+
*
|
|
156
|
+
* @description
|
|
157
|
+
* Configures the download behavior including whether to include the index,
|
|
158
|
+
* request byte ranges for partial reads, verify checksums, or throw on missing packs.
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```typescript
|
|
162
|
+
* // Download with index and verification
|
|
163
|
+
* const result = await storage.downloadPackfile(packId, {
|
|
164
|
+
* includeIndex: true,
|
|
165
|
+
* verify: true
|
|
166
|
+
* });
|
|
167
|
+
*
|
|
168
|
+
* // Partial download (first 1MB)
|
|
169
|
+
* const partial = await storage.downloadPackfile(packId, {
|
|
170
|
+
* byteRange: { start: 0, end: 1048575 }
|
|
171
|
+
* });
|
|
172
|
+
* ```
|
|
60
173
|
*/
|
|
61
174
|
export interface DownloadPackfileOptions {
|
|
62
175
|
/** Include the index file in the download */
|
|
63
176
|
includeIndex?: boolean;
|
|
64
|
-
/**
|
|
177
|
+
/**
|
|
178
|
+
* Byte range to download for partial reads.
|
|
179
|
+
* Useful for streaming large packfiles or resuming interrupted downloads.
|
|
180
|
+
*/
|
|
65
181
|
byteRange?: {
|
|
66
182
|
start: number;
|
|
67
183
|
end: number;
|
|
68
184
|
};
|
|
69
|
-
/**
|
|
185
|
+
/**
|
|
186
|
+
* Verify checksum on download.
|
|
187
|
+
* When true, computes SHA-1 of downloaded data and compares with stored checksum.
|
|
188
|
+
*/
|
|
70
189
|
verify?: boolean;
|
|
71
|
-
/**
|
|
190
|
+
/**
|
|
191
|
+
* Throw if packfile not found.
|
|
192
|
+
* When true, throws R2PackError instead of returning null.
|
|
193
|
+
* @default false
|
|
194
|
+
*/
|
|
72
195
|
required?: boolean;
|
|
73
196
|
}
|
|
74
197
|
/**
|
|
75
|
-
* Result of downloading a packfile
|
|
198
|
+
* Result of downloading a packfile.
|
|
199
|
+
*
|
|
200
|
+
* @description
|
|
201
|
+
* Contains the downloaded packfile data and optionally the index data
|
|
202
|
+
* if `includeIndex` was specified in the download options.
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```typescript
|
|
206
|
+
* const result = await storage.downloadPackfile(packId, { includeIndex: true });
|
|
207
|
+
* if (result) {
|
|
208
|
+
* console.log(`Pack size: ${result.packData.length}`);
|
|
209
|
+
* if (result.indexData) {
|
|
210
|
+
* console.log(`Index size: ${result.indexData.length}`);
|
|
211
|
+
* }
|
|
212
|
+
* }
|
|
213
|
+
* ```
|
|
76
214
|
*/
|
|
77
215
|
export interface DownloadPackfileResult {
|
|
78
|
-
/** The packfile data */
|
|
216
|
+
/** The packfile data as a Uint8Array */
|
|
79
217
|
packData: Uint8Array;
|
|
80
|
-
/** The index file data (if includeIndex was true) */
|
|
218
|
+
/** The index file data (only present if includeIndex was true) */
|
|
81
219
|
indexData?: Uint8Array;
|
|
82
|
-
/** Whether the checksum was verified */
|
|
220
|
+
/** Whether the checksum was verified (only present if verify was true) */
|
|
83
221
|
verified?: boolean;
|
|
84
222
|
}
|
|
85
223
|
/**
|
|
86
|
-
* Options for uploading a packfile
|
|
224
|
+
* Options for uploading a packfile.
|
|
225
|
+
*
|
|
226
|
+
* @description
|
|
227
|
+
* Configures upload behavior including retry count and atomic upload settings.
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* ```typescript
|
|
231
|
+
* const result = await storage.uploadPackfile(packData, indexData, {
|
|
232
|
+
* retries: 5,
|
|
233
|
+
* skipAtomic: false // Use atomic upload for safety
|
|
234
|
+
* });
|
|
235
|
+
* ```
|
|
87
236
|
*/
|
|
88
237
|
export interface UploadPackfileOptions {
|
|
89
|
-
/**
|
|
238
|
+
/**
|
|
239
|
+
* Number of retries on failure.
|
|
240
|
+
* Each retry uses exponential backoff.
|
|
241
|
+
*/
|
|
90
242
|
retries?: number;
|
|
91
|
-
/**
|
|
243
|
+
/**
|
|
244
|
+
* Skip atomic upload pattern.
|
|
245
|
+
* Use only for testing or migration scenarios where atomicity is not required.
|
|
246
|
+
* @default false
|
|
247
|
+
*/
|
|
92
248
|
skipAtomic?: boolean;
|
|
93
249
|
}
|
|
94
250
|
/**
|
|
95
|
-
* Pack manifest for atomic uploads
|
|
96
|
-
*
|
|
251
|
+
* Pack manifest for atomic uploads.
|
|
252
|
+
*
|
|
253
|
+
* @description
|
|
254
|
+
* A manifest marks a pack as "complete" only after both pack and index are uploaded.
|
|
255
|
+
* This ensures atomic uploads where partial uploads are detected and can be cleaned up.
|
|
256
|
+
*
|
|
257
|
+
* The upload process follows these steps:
|
|
258
|
+
* 1. Upload pack and index to staging paths
|
|
259
|
+
* 2. Create manifest in 'staging' status
|
|
260
|
+
* 3. Copy from staging to final location
|
|
261
|
+
* 4. Update manifest to 'complete' status
|
|
262
|
+
* 5. Clean up staging files
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* ```typescript
|
|
266
|
+
* const manifest = await storage.getPackManifest(packId);
|
|
267
|
+
* if (manifest?.status === 'complete') {
|
|
268
|
+
* console.log('Pack upload is complete and verified');
|
|
269
|
+
* }
|
|
270
|
+
* ```
|
|
97
271
|
*/
|
|
98
272
|
export interface PackManifest {
|
|
99
273
|
/** Version of the manifest format */
|
|
@@ -110,109 +284,290 @@ export interface PackManifest {
|
|
|
110
284
|
indexSize: number;
|
|
111
285
|
/** Number of objects in the packfile */
|
|
112
286
|
objectCount: number;
|
|
113
|
-
/**
|
|
287
|
+
/** ISO 8601 timestamp when the pack was completed */
|
|
114
288
|
completedAt: string;
|
|
115
|
-
/**
|
|
289
|
+
/**
|
|
290
|
+
* Upload status.
|
|
291
|
+
* - 'staging': Upload in progress
|
|
292
|
+
* - 'complete': Upload finished and verified
|
|
293
|
+
*/
|
|
116
294
|
status: 'staging' | 'complete';
|
|
117
295
|
}
|
|
118
296
|
/**
|
|
119
|
-
* Entry in the multi-pack index
|
|
297
|
+
* Entry in the multi-pack index (MIDX).
|
|
298
|
+
*
|
|
299
|
+
* @description
|
|
300
|
+
* Represents a single object's location within the multi-pack index.
|
|
301
|
+
* Used for efficient O(log n) binary search across all objects in all packs.
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* ```typescript
|
|
305
|
+
* const entry = lookupObjectInMultiPack(midx, objectId);
|
|
306
|
+
* if (entry) {
|
|
307
|
+
* const packId = midx.packIds[entry.packIndex];
|
|
308
|
+
* console.log(`Object found in pack ${packId} at offset ${entry.offset}`);
|
|
309
|
+
* }
|
|
310
|
+
* ```
|
|
120
311
|
*/
|
|
121
312
|
export interface MultiPackIndexEntry {
|
|
122
313
|
/** 40-character hex SHA-1 object ID */
|
|
123
314
|
objectId: string;
|
|
124
315
|
/** Index of the pack in the packIds array */
|
|
125
316
|
packIndex: number;
|
|
126
|
-
/**
|
|
317
|
+
/** Byte offset within the pack file where the object data begins */
|
|
127
318
|
offset: number;
|
|
128
319
|
}
|
|
129
320
|
/**
|
|
130
|
-
* Multi-pack index structure
|
|
321
|
+
* Multi-pack index (MIDX) structure.
|
|
322
|
+
*
|
|
323
|
+
* @description
|
|
324
|
+
* Provides a single index across multiple pack files for efficient object lookup.
|
|
325
|
+
* Entries are sorted by objectId to enable binary search.
|
|
326
|
+
*
|
|
327
|
+
* The MIDX format follows Git's multi-pack-index specification with:
|
|
328
|
+
* - MIDX signature (4 bytes)
|
|
329
|
+
* - Version number
|
|
330
|
+
* - Pack ID list
|
|
331
|
+
* - Sorted object entries
|
|
332
|
+
* - Trailing checksum
|
|
333
|
+
*
|
|
334
|
+
* @example
|
|
335
|
+
* ```typescript
|
|
336
|
+
* const midx = await storage.getMultiPackIndex();
|
|
337
|
+
* console.log(`Index contains ${midx.entries.length} objects across ${midx.packIds.length} packs`);
|
|
338
|
+
* ```
|
|
131
339
|
*/
|
|
132
340
|
export interface MultiPackIndex {
|
|
133
341
|
/** Version of the multi-pack index format */
|
|
134
342
|
version: number;
|
|
135
|
-
/** Array of pack IDs in this index */
|
|
343
|
+
/** Array of pack IDs included in this index */
|
|
136
344
|
packIds: string[];
|
|
137
345
|
/** Sorted entries for all objects across all packs */
|
|
138
346
|
entries: MultiPackIndexEntry[];
|
|
139
|
-
/** SHA-1 checksum of the index */
|
|
347
|
+
/** SHA-1 checksum of the index for integrity verification */
|
|
140
348
|
checksum: Uint8Array;
|
|
141
349
|
}
|
|
142
350
|
/**
|
|
143
|
-
* Handle for a distributed lock
|
|
144
|
-
*
|
|
351
|
+
* Handle for a distributed lock.
|
|
352
|
+
*
|
|
353
|
+
* @description
|
|
354
|
+
* Contains all information needed to release or refresh a distributed lock.
|
|
355
|
+
* Locks are implemented using R2 conditional writes (ETags) for atomicity.
|
|
356
|
+
*
|
|
357
|
+
* @example
|
|
358
|
+
* ```typescript
|
|
359
|
+
* const handle = await storage.acquireDistributedLock('my-resource', 30000);
|
|
360
|
+
* if (handle) {
|
|
361
|
+
* try {
|
|
362
|
+
* // Do work while holding the lock
|
|
363
|
+
* await storage.refreshDistributedLock(handle, 30000); // Extend TTL
|
|
364
|
+
* } finally {
|
|
365
|
+
* await storage.releaseDistributedLock(handle);
|
|
366
|
+
* }
|
|
367
|
+
* }
|
|
368
|
+
* ```
|
|
145
369
|
*/
|
|
146
370
|
export interface LockHandle {
|
|
147
|
-
/** Resource that is locked */
|
|
371
|
+
/** Resource identifier that is locked */
|
|
148
372
|
resource: string;
|
|
149
|
-
/** Unique lock ID for this holder */
|
|
373
|
+
/** Unique lock ID for this holder (used for ownership verification) */
|
|
150
374
|
lockId: string;
|
|
151
|
-
/** ETag for conditional operations */
|
|
375
|
+
/** ETag for conditional operations (ensures lock hasn't been modified) */
|
|
152
376
|
etag: string;
|
|
153
|
-
/** When the lock expires (
|
|
377
|
+
/** When the lock expires (milliseconds since epoch) */
|
|
154
378
|
expiresAt: number;
|
|
155
379
|
}
|
|
156
380
|
/**
|
|
157
|
-
* Content stored in a lock file
|
|
381
|
+
* Content stored in a lock file.
|
|
382
|
+
*
|
|
383
|
+
* @description
|
|
384
|
+
* The JSON content stored in the R2 lock file. Used for lock ownership
|
|
385
|
+
* verification and debugging lock contention issues.
|
|
158
386
|
*/
|
|
159
387
|
export interface LockFileContent {
|
|
160
|
-
/** Unique lock ID */
|
|
388
|
+
/** Unique lock ID for ownership verification */
|
|
161
389
|
lockId: string;
|
|
162
390
|
/** Resource being locked */
|
|
163
391
|
resource: string;
|
|
164
|
-
/** When the lock expires (
|
|
392
|
+
/** When the lock expires (milliseconds since epoch) */
|
|
165
393
|
expiresAt: number;
|
|
166
|
-
/** When the lock was acquired (
|
|
394
|
+
/** When the lock was acquired (milliseconds since epoch) */
|
|
167
395
|
acquiredAt: number;
|
|
168
|
-
/** Worker/process identifier
|
|
396
|
+
/** Worker/process identifier for debugging lock contention */
|
|
169
397
|
holder?: string;
|
|
170
398
|
}
|
|
171
399
|
/**
|
|
172
|
-
* Lock on a packfile for write operations
|
|
400
|
+
* Lock on a packfile for write operations.
|
|
401
|
+
*
|
|
402
|
+
* @description
|
|
403
|
+
* Provides methods to check lock status, release the lock, and optionally
|
|
404
|
+
* refresh the lock's TTL. Used to prevent concurrent modifications to packfiles.
|
|
405
|
+
*
|
|
406
|
+
* @example
|
|
407
|
+
* ```typescript
|
|
408
|
+
* const lock = await storage.acquireLock(packId, { ttl: 60000 });
|
|
409
|
+
* try {
|
|
410
|
+
* // Perform operations on the packfile
|
|
411
|
+
* if (!lock.isHeld()) {
|
|
412
|
+
* throw new Error('Lock expired!');
|
|
413
|
+
* }
|
|
414
|
+
* } finally {
|
|
415
|
+
* await lock.release();
|
|
416
|
+
* }
|
|
417
|
+
* ```
|
|
173
418
|
*/
|
|
174
419
|
export interface PackLock {
|
|
175
420
|
/** Pack ID that is locked */
|
|
176
421
|
packId: string;
|
|
177
|
-
/** Check if lock is still held */
|
|
422
|
+
/** Check if lock is still held (not expired and not released) */
|
|
178
423
|
isHeld(): boolean;
|
|
179
|
-
/** Release the lock */
|
|
424
|
+
/** Release the lock, allowing other processes to acquire it */
|
|
180
425
|
release(): Promise<void>;
|
|
181
|
-
/**
|
|
426
|
+
/**
|
|
427
|
+
* Refresh the lock TTL.
|
|
428
|
+
* @returns true if refresh succeeded, false if lock was lost
|
|
429
|
+
*/
|
|
182
430
|
refresh?(): Promise<boolean>;
|
|
183
|
-
/** Get the underlying distributed lock handle */
|
|
431
|
+
/** Get the underlying distributed lock handle (for advanced use) */
|
|
184
432
|
handle?: LockHandle;
|
|
185
433
|
}
|
|
186
434
|
/**
|
|
187
|
-
* Options for acquiring a lock
|
|
435
|
+
* Options for acquiring a lock.
|
|
436
|
+
*
|
|
437
|
+
* @description
|
|
438
|
+
* Configures lock acquisition behavior including timeout, TTL, and holder identification.
|
|
439
|
+
*
|
|
440
|
+
* @example
|
|
441
|
+
* ```typescript
|
|
442
|
+
* const lock = await storage.acquireLock(packId, {
|
|
443
|
+
* timeout: 10000, // Wait up to 10 seconds
|
|
444
|
+
* ttl: 30000, // Lock expires after 30 seconds
|
|
445
|
+
* holder: 'worker-1'
|
|
446
|
+
* });
|
|
447
|
+
* ```
|
|
188
448
|
*/
|
|
189
449
|
export interface AcquireLockOptions {
|
|
190
|
-
/**
|
|
450
|
+
/**
|
|
451
|
+
* Timeout in milliseconds to wait for lock acquisition.
|
|
452
|
+
* If 0, fails immediately if lock is held.
|
|
453
|
+
* @default 0
|
|
454
|
+
*/
|
|
191
455
|
timeout?: number;
|
|
192
|
-
/**
|
|
456
|
+
/**
|
|
457
|
+
* TTL in milliseconds after which lock auto-expires.
|
|
458
|
+
* Prevents deadlocks if the holder crashes.
|
|
459
|
+
* @default 30000
|
|
460
|
+
*/
|
|
193
461
|
ttl?: number;
|
|
194
|
-
/** Worker/process identifier for debugging */
|
|
462
|
+
/** Worker/process identifier for debugging lock contention */
|
|
195
463
|
holder?: string;
|
|
196
464
|
}
|
|
197
465
|
/**
|
|
198
|
-
* Result of listing packfiles
|
|
466
|
+
* Result of listing packfiles.
|
|
467
|
+
*
|
|
468
|
+
* @description
|
|
469
|
+
* Contains the list of packfile metadata and an optional cursor for pagination.
|
|
470
|
+
*
|
|
471
|
+
* @example
|
|
472
|
+
* ```typescript
|
|
473
|
+
* let cursor: string | undefined;
|
|
474
|
+
* do {
|
|
475
|
+
* const result = await storage.listPackfiles({ limit: 10, cursor });
|
|
476
|
+
* for (const pack of result.items) {
|
|
477
|
+
* console.log(pack.packId);
|
|
478
|
+
* }
|
|
479
|
+
* cursor = result.cursor;
|
|
480
|
+
* } while (cursor);
|
|
481
|
+
* ```
|
|
199
482
|
*/
|
|
200
483
|
export interface ListPackfilesResult {
|
|
201
484
|
/** Array of packfile metadata */
|
|
202
485
|
items: PackfileMetadata[];
|
|
203
|
-
/** Cursor for
|
|
486
|
+
/** Cursor for fetching the next page of results */
|
|
204
487
|
cursor?: string;
|
|
205
488
|
}
|
|
206
489
|
/**
|
|
207
|
-
* Error thrown by R2 pack operations
|
|
490
|
+
* Error thrown by R2 pack operations.
|
|
491
|
+
*
|
|
492
|
+
* @description
|
|
493
|
+
* Custom error class for R2 packfile operations with error codes for
|
|
494
|
+
* programmatic error handling.
|
|
495
|
+
*
|
|
496
|
+
* Error codes:
|
|
497
|
+
* - `NOT_FOUND`: Packfile does not exist
|
|
498
|
+
* - `LOCKED`: Packfile is locked by another process
|
|
499
|
+
* - `INVALID_DATA`: Packfile format is invalid
|
|
500
|
+
* - `CHECKSUM_MISMATCH`: Checksum verification failed
|
|
501
|
+
* - `NETWORK_ERROR`: R2 network/connectivity issue
|
|
502
|
+
*
|
|
503
|
+
* @example
|
|
504
|
+
* ```typescript
|
|
505
|
+
* try {
|
|
506
|
+
* await storage.downloadPackfile(packId, { required: true });
|
|
507
|
+
* } catch (error) {
|
|
508
|
+
* if (error instanceof R2PackError) {
|
|
509
|
+
* switch (error.code) {
|
|
510
|
+
* case 'NOT_FOUND':
|
|
511
|
+
* console.log('Pack does not exist');
|
|
512
|
+
* break;
|
|
513
|
+
* case 'CHECKSUM_MISMATCH':
|
|
514
|
+
* console.log('Pack is corrupted');
|
|
515
|
+
* break;
|
|
516
|
+
* }
|
|
517
|
+
* }
|
|
518
|
+
* }
|
|
519
|
+
* ```
|
|
208
520
|
*/
|
|
209
521
|
export declare class R2PackError extends Error {
|
|
210
522
|
readonly code: 'NOT_FOUND' | 'LOCKED' | 'INVALID_DATA' | 'CHECKSUM_MISMATCH' | 'NETWORK_ERROR';
|
|
211
523
|
readonly packId?: string | undefined;
|
|
524
|
+
/**
|
|
525
|
+
* Creates a new R2PackError.
|
|
526
|
+
*
|
|
527
|
+
* @param message - Human-readable error message
|
|
528
|
+
* @param code - Error code for programmatic handling
|
|
529
|
+
* @param packId - Optional pack ID related to the error
|
|
530
|
+
*/
|
|
212
531
|
constructor(message: string, code: 'NOT_FOUND' | 'LOCKED' | 'INVALID_DATA' | 'CHECKSUM_MISMATCH' | 'NETWORK_ERROR', packId?: string | undefined);
|
|
213
532
|
}
|
|
214
533
|
/**
|
|
215
|
-
* R2 Packfile Storage class
|
|
534
|
+
* R2 Packfile Storage class.
|
|
535
|
+
*
|
|
536
|
+
* @description
|
|
537
|
+
* Main class for managing Git packfiles in Cloudflare R2 object storage.
|
|
538
|
+
* Provides methods for uploading, downloading, listing, and managing packfiles
|
|
539
|
+
* with support for atomic uploads, distributed locking, and multi-pack indexing.
|
|
540
|
+
*
|
|
541
|
+
* @example
|
|
542
|
+
* ```typescript
|
|
543
|
+
* // Initialize storage
|
|
544
|
+
* const storage = new R2PackStorage({
|
|
545
|
+
* bucket: env.GIT_BUCKET,
|
|
546
|
+
* prefix: 'repos/my-repo/',
|
|
547
|
+
* cacheSize: 100,
|
|
548
|
+
* cacheTTL: 3600
|
|
549
|
+
* });
|
|
550
|
+
*
|
|
551
|
+
* // Upload a packfile atomically
|
|
552
|
+
* const result = await storage.uploadPackfile(packData, indexData);
|
|
553
|
+
*
|
|
554
|
+
* // Download with verification
|
|
555
|
+
* const download = await storage.downloadPackfile(result.packId, {
|
|
556
|
+
* verify: true,
|
|
557
|
+
* includeIndex: true
|
|
558
|
+
* });
|
|
559
|
+
*
|
|
560
|
+
* // List all packfiles
|
|
561
|
+
* const list = await storage.listPackfiles();
|
|
562
|
+
*
|
|
563
|
+
* // Acquire lock for write operations
|
|
564
|
+
* const lock = await storage.acquireLock(packId, { ttl: 30000 });
|
|
565
|
+
* try {
|
|
566
|
+
* // Perform operations
|
|
567
|
+
* } finally {
|
|
568
|
+
* await lock.release();
|
|
569
|
+
* }
|
|
570
|
+
* ```
|
|
216
571
|
*/
|
|
217
572
|
export declare class R2PackStorage {
|
|
218
573
|
private _bucket;
|
|
@@ -220,11 +575,27 @@ export declare class R2PackStorage {
|
|
|
220
575
|
private _cacheTTL;
|
|
221
576
|
private _midxCache;
|
|
222
577
|
private _indexChecksums;
|
|
578
|
+
/**
|
|
579
|
+
* Creates a new R2PackStorage instance.
|
|
580
|
+
*
|
|
581
|
+
* @param options - Configuration options for the storage instance
|
|
582
|
+
*
|
|
583
|
+
* @example
|
|
584
|
+
* ```typescript
|
|
585
|
+
* const storage = new R2PackStorage({
|
|
586
|
+
* bucket: env.MY_BUCKET,
|
|
587
|
+
* prefix: 'repos/my-repo/',
|
|
588
|
+
* cacheSize: 100,
|
|
589
|
+
* cacheTTL: 3600
|
|
590
|
+
* });
|
|
591
|
+
* ```
|
|
592
|
+
*/
|
|
223
593
|
constructor(options: R2PackStorageOptions);
|
|
224
594
|
private _buildKey;
|
|
225
595
|
/**
|
|
226
|
-
*
|
|
596
|
+
* Uploads a packfile and its index to R2 atomically.
|
|
227
597
|
*
|
|
598
|
+
* @description
|
|
228
599
|
* Uses a manifest-based pattern to ensure atomic uploads:
|
|
229
600
|
* 1. Upload pack and index to staging paths
|
|
230
601
|
* 2. Create manifest in 'staging' status
|
|
@@ -234,55 +605,224 @@ export declare class R2PackStorage {
|
|
|
234
605
|
*
|
|
235
606
|
* If the process fails at any point, the pack is not considered complete
|
|
236
607
|
* until a valid manifest with status 'complete' exists.
|
|
608
|
+
*
|
|
609
|
+
* @param packData - Raw packfile bytes (must have valid PACK signature)
|
|
610
|
+
* @param indexData - Pack index file bytes
|
|
611
|
+
* @param options - Optional upload configuration
|
|
612
|
+
*
|
|
613
|
+
* @returns Upload result with pack ID, sizes, checksum, and object count
|
|
614
|
+
*
|
|
615
|
+
* @throws {R2PackError} With code 'INVALID_DATA' if packfile is invalid
|
|
616
|
+
* @throws {R2PackError} With code 'NETWORK_ERROR' if bucket is unavailable
|
|
617
|
+
*
|
|
618
|
+
* @example
|
|
619
|
+
* ```typescript
|
|
620
|
+
* const result = await storage.uploadPackfile(packData, indexData);
|
|
621
|
+
* console.log(`Uploaded: ${result.packId}`);
|
|
622
|
+
* console.log(`Objects: ${result.objectCount}`);
|
|
623
|
+
* console.log(`Checksum: ${result.checksum}`);
|
|
624
|
+
* ```
|
|
237
625
|
*/
|
|
238
626
|
uploadPackfile(packData: Uint8Array, indexData: Uint8Array, options?: UploadPackfileOptions): Promise<PackfileUploadResult>;
|
|
239
627
|
/**
|
|
240
|
-
*
|
|
628
|
+
* Gets the manifest for a packfile.
|
|
629
|
+
*
|
|
630
|
+
* @description
|
|
631
|
+
* Retrieves the manifest JSON that tracks the upload status of a packfile.
|
|
632
|
+
* Returns null if no manifest exists (legacy packs or invalid pack ID).
|
|
633
|
+
*
|
|
634
|
+
* @param packId - Pack identifier to get manifest for
|
|
635
|
+
* @returns Pack manifest or null if not found
|
|
636
|
+
*
|
|
637
|
+
* @example
|
|
638
|
+
* ```typescript
|
|
639
|
+
* const manifest = await storage.getPackManifest('pack-abc123');
|
|
640
|
+
* if (manifest?.status === 'complete') {
|
|
641
|
+
* console.log('Pack is ready for use');
|
|
642
|
+
* } else {
|
|
643
|
+
* console.log('Pack upload is incomplete');
|
|
644
|
+
* }
|
|
645
|
+
* ```
|
|
241
646
|
*/
|
|
242
647
|
getPackManifest(packId: string): Promise<PackManifest | null>;
|
|
243
648
|
/**
|
|
244
|
-
*
|
|
649
|
+
* Checks if a packfile upload is complete.
|
|
245
650
|
*
|
|
651
|
+
* @description
|
|
246
652
|
* A pack is considered complete if:
|
|
247
653
|
* 1. It has a manifest with status 'complete', OR
|
|
248
654
|
* 2. It was uploaded before the atomic upload feature (legacy packs without manifest)
|
|
249
655
|
* AND both .pack and .idx files exist
|
|
656
|
+
*
|
|
657
|
+
* @param packId - Pack identifier to check
|
|
658
|
+
* @returns true if pack is complete and ready for use
|
|
659
|
+
*
|
|
660
|
+
* @example
|
|
661
|
+
* ```typescript
|
|
662
|
+
* if (await storage.isPackComplete(packId)) {
|
|
663
|
+
* const data = await storage.downloadPackfile(packId);
|
|
664
|
+
* }
|
|
665
|
+
* ```
|
|
250
666
|
*/
|
|
251
667
|
isPackComplete(packId: string): Promise<boolean>;
|
|
252
668
|
/**
|
|
253
|
-
*
|
|
669
|
+
* Downloads a packfile from R2.
|
|
670
|
+
*
|
|
671
|
+
* @description
|
|
672
|
+
* Downloads pack data with optional index file. Verifies pack completeness
|
|
673
|
+
* before downloading and optionally verifies checksum integrity.
|
|
674
|
+
*
|
|
675
|
+
* @param packId - Pack identifier to download
|
|
676
|
+
* @param options - Download options (includeIndex, verify, byteRange, required)
|
|
677
|
+
*
|
|
678
|
+
* @returns Download result with pack data, or null if not found (unless required=true)
|
|
679
|
+
*
|
|
680
|
+
* @throws {R2PackError} With code 'NOT_FOUND' if required=true and pack not found
|
|
681
|
+
* @throws {R2PackError} With code 'CHECKSUM_MISMATCH' if verify=true and verification fails
|
|
682
|
+
*
|
|
683
|
+
* @example
|
|
684
|
+
* ```typescript
|
|
685
|
+
* // Basic download
|
|
686
|
+
* const result = await storage.downloadPackfile(packId);
|
|
687
|
+
*
|
|
688
|
+
* // Download with verification and index
|
|
689
|
+
* const verified = await storage.downloadPackfile(packId, {
|
|
690
|
+
* verify: true,
|
|
691
|
+
* includeIndex: true
|
|
692
|
+
* });
|
|
693
|
+
*
|
|
694
|
+
* // Required download (throws if not found)
|
|
695
|
+
* const required = await storage.downloadPackfile(packId, { required: true });
|
|
696
|
+
* ```
|
|
254
697
|
*/
|
|
255
698
|
downloadPackfile(packId: string, options?: DownloadPackfileOptions): Promise<DownloadPackfileResult | null>;
|
|
256
699
|
/**
|
|
257
|
-
*
|
|
700
|
+
* Gets metadata for a packfile.
|
|
701
|
+
*
|
|
702
|
+
* @description
|
|
703
|
+
* Retrieves metadata about a packfile including size, object count,
|
|
704
|
+
* creation time, and checksum without downloading the full pack.
|
|
705
|
+
*
|
|
706
|
+
* @param packId - Pack identifier to get metadata for
|
|
707
|
+
* @returns Packfile metadata or null if not found
|
|
708
|
+
*
|
|
709
|
+
* @example
|
|
710
|
+
* ```typescript
|
|
711
|
+
* const metadata = await storage.getPackfileMetadata(packId);
|
|
712
|
+
* if (metadata) {
|
|
713
|
+
* console.log(`Size: ${metadata.packSize} bytes`);
|
|
714
|
+
* console.log(`Objects: ${metadata.objectCount}`);
|
|
715
|
+
* }
|
|
716
|
+
* ```
|
|
258
717
|
*/
|
|
259
718
|
getPackfileMetadata(packId: string): Promise<PackfileMetadata | null>;
|
|
260
719
|
/**
|
|
261
|
-
*
|
|
720
|
+
* Lists all packfiles in storage.
|
|
721
|
+
*
|
|
722
|
+
* @description
|
|
723
|
+
* Returns a paginated list of packfile metadata. Use the cursor for
|
|
724
|
+
* fetching subsequent pages of results.
|
|
725
|
+
*
|
|
726
|
+
* @param options - Pagination options (limit, cursor)
|
|
727
|
+
* @returns List of packfile metadata with optional cursor for pagination
|
|
728
|
+
*
|
|
729
|
+
* @example
|
|
730
|
+
* ```typescript
|
|
731
|
+
* // List first 10 packfiles
|
|
732
|
+
* const first = await storage.listPackfiles({ limit: 10 });
|
|
733
|
+
*
|
|
734
|
+
* // Get next page
|
|
735
|
+
* if (first.cursor) {
|
|
736
|
+
* const next = await storage.listPackfiles({ limit: 10, cursor: first.cursor });
|
|
737
|
+
* }
|
|
738
|
+
* ```
|
|
262
739
|
*/
|
|
263
740
|
listPackfiles(options?: {
|
|
264
741
|
limit?: number;
|
|
265
742
|
cursor?: string;
|
|
266
743
|
}): Promise<ListPackfilesResult & PackfileMetadata[]>;
|
|
267
744
|
/**
|
|
268
|
-
*
|
|
745
|
+
* Deletes a packfile, its index, and manifest.
|
|
746
|
+
*
|
|
747
|
+
* @description
|
|
748
|
+
* Removes all files associated with a packfile and updates the
|
|
749
|
+
* multi-pack index if needed.
|
|
750
|
+
*
|
|
751
|
+
* @param packId - Pack identifier to delete
|
|
752
|
+
* @returns true if pack was deleted, false if it didn't exist
|
|
753
|
+
*
|
|
754
|
+
* @example
|
|
755
|
+
* ```typescript
|
|
756
|
+
* if (await storage.deletePackfile(packId)) {
|
|
757
|
+
* console.log('Pack deleted successfully');
|
|
758
|
+
* } else {
|
|
759
|
+
* console.log('Pack not found');
|
|
760
|
+
* }
|
|
761
|
+
* ```
|
|
269
762
|
*/
|
|
270
763
|
deletePackfile(packId: string): Promise<boolean>;
|
|
271
764
|
/**
|
|
272
|
-
*
|
|
765
|
+
* Downloads just the index file for a packfile.
|
|
766
|
+
*
|
|
767
|
+
* @description
|
|
768
|
+
* Retrieves only the pack index file, useful for object lookups
|
|
769
|
+
* without downloading the full packfile.
|
|
770
|
+
*
|
|
771
|
+
* @param packId - Pack identifier to download index for
|
|
772
|
+
* @returns Index data or null if not found
|
|
773
|
+
*
|
|
774
|
+
* @example
|
|
775
|
+
* ```typescript
|
|
776
|
+
* const indexData = await storage.downloadIndex(packId);
|
|
777
|
+
* if (indexData) {
|
|
778
|
+
* // Parse and use the index
|
|
779
|
+
* }
|
|
780
|
+
* ```
|
|
273
781
|
*/
|
|
274
782
|
downloadIndex(packId: string): Promise<Uint8Array | null>;
|
|
275
783
|
/**
|
|
276
|
-
*
|
|
784
|
+
* Uploads a new index for an existing packfile.
|
|
785
|
+
*
|
|
786
|
+
* @description
|
|
787
|
+
* Replaces the index file for an existing packfile. Useful for
|
|
788
|
+
* regenerating corrupted indices or updating index format.
|
|
789
|
+
*
|
|
790
|
+
* @param packId - Pack identifier to upload index for
|
|
791
|
+
* @param indexData - New index file data
|
|
792
|
+
*
|
|
793
|
+
* @throws {R2PackError} With code 'NOT_FOUND' if packfile doesn't exist
|
|
794
|
+
*
|
|
795
|
+
* @example
|
|
796
|
+
* ```typescript
|
|
797
|
+
* const newIndex = generatePackIndex(packData);
|
|
798
|
+
* await storage.uploadIndex(packId, newIndex);
|
|
799
|
+
* ```
|
|
277
800
|
*/
|
|
278
801
|
uploadIndex(packId: string, indexData: Uint8Array): Promise<void>;
|
|
279
802
|
/**
|
|
280
|
-
*
|
|
803
|
+
* Verifies that an index matches its packfile.
|
|
804
|
+
*
|
|
805
|
+
* @description
|
|
806
|
+
* Compares the current index checksum against the stored checksum
|
|
807
|
+
* to detect corruption or tampering.
|
|
808
|
+
*
|
|
809
|
+
* @param packId - Pack identifier to verify index for
|
|
810
|
+
* @returns true if index is valid, false if missing or corrupted
|
|
811
|
+
*
|
|
812
|
+
* @example
|
|
813
|
+
* ```typescript
|
|
814
|
+
* if (await storage.verifyIndex(packId)) {
|
|
815
|
+
* console.log('Index is valid');
|
|
816
|
+
* } else {
|
|
817
|
+
* console.log('Index needs to be regenerated');
|
|
818
|
+
* }
|
|
819
|
+
* ```
|
|
281
820
|
*/
|
|
282
821
|
verifyIndex(packId: string): Promise<boolean>;
|
|
283
822
|
/**
|
|
284
|
-
*
|
|
823
|
+
* Cleans up orphaned staging files.
|
|
285
824
|
*
|
|
825
|
+
* @description
|
|
286
826
|
* This should be called on startup to clean up any staging files
|
|
287
827
|
* left behind by failed uploads. It will:
|
|
288
828
|
* 1. List all files in the staging directory
|
|
@@ -290,68 +830,277 @@ export declare class R2PackStorage {
|
|
|
290
830
|
* 3. If not complete, delete the staging files and any partial final files
|
|
291
831
|
*
|
|
292
832
|
* @returns Array of pack IDs that were cleaned up
|
|
833
|
+
*
|
|
834
|
+
* @example
|
|
835
|
+
* ```typescript
|
|
836
|
+
* // Call on worker startup
|
|
837
|
+
* const cleaned = await storage.cleanupOrphanedStagingFiles();
|
|
838
|
+
* if (cleaned.length > 0) {
|
|
839
|
+
* console.log(`Cleaned up ${cleaned.length} orphaned uploads`);
|
|
840
|
+
* }
|
|
841
|
+
* ```
|
|
293
842
|
*/
|
|
294
843
|
cleanupOrphanedStagingFiles(): Promise<string[]>;
|
|
295
844
|
/**
|
|
296
|
-
*
|
|
845
|
+
* Rebuilds the multi-pack index from all packfiles.
|
|
846
|
+
*
|
|
847
|
+
* @description
|
|
848
|
+
* Creates a new MIDX by scanning all packfiles and building a sorted
|
|
849
|
+
* index of all objects. Call this after adding or removing packs.
|
|
850
|
+
*
|
|
851
|
+
* @example
|
|
852
|
+
* ```typescript
|
|
853
|
+
* await storage.rebuildMultiPackIndex();
|
|
854
|
+
* const midx = await storage.getMultiPackIndex();
|
|
855
|
+
* console.log(`Indexed ${midx.entries.length} objects`);
|
|
856
|
+
* ```
|
|
297
857
|
*/
|
|
298
858
|
rebuildMultiPackIndex(): Promise<void>;
|
|
299
859
|
/**
|
|
300
|
-
*
|
|
860
|
+
* Gets the current multi-pack index.
|
|
861
|
+
*
|
|
862
|
+
* @description
|
|
863
|
+
* Returns the MIDX from cache if available and not expired,
|
|
864
|
+
* otherwise fetches from R2. Returns an empty index if none exists.
|
|
865
|
+
*
|
|
866
|
+
* @returns Current multi-pack index
|
|
867
|
+
*
|
|
868
|
+
* @example
|
|
869
|
+
* ```typescript
|
|
870
|
+
* const midx = await storage.getMultiPackIndex();
|
|
871
|
+
* const entry = lookupObjectInMultiPack(midx, objectSha);
|
|
872
|
+
* if (entry) {
|
|
873
|
+
* const packId = midx.packIds[entry.packIndex];
|
|
874
|
+
* console.log(`Object is in pack ${packId}`);
|
|
875
|
+
* }
|
|
876
|
+
* ```
|
|
301
877
|
*/
|
|
302
878
|
getMultiPackIndex(): Promise<MultiPackIndex>;
|
|
303
879
|
/**
|
|
304
|
-
*
|
|
880
|
+
* Acquires a distributed lock on a resource using R2 conditional writes.
|
|
881
|
+
*
|
|
882
|
+
* @description
|
|
883
|
+
* Uses R2's conditional write feature (ETags) to implement distributed locking.
|
|
884
|
+
* Locks automatically expire after the TTL to prevent deadlocks.
|
|
885
|
+
*
|
|
305
886
|
* @param resource - Resource identifier to lock
|
|
306
|
-
* @param ttlMs - Time-to-live in milliseconds
|
|
887
|
+
* @param ttlMs - Time-to-live in milliseconds
|
|
307
888
|
* @param holder - Optional identifier for the lock holder (for debugging)
|
|
889
|
+
*
|
|
308
890
|
* @returns LockHandle if acquired, null if lock is held by another process
|
|
891
|
+
*
|
|
892
|
+
* @example
|
|
893
|
+
* ```typescript
|
|
894
|
+
* const handle = await storage.acquireDistributedLock('my-resource', 30000, 'worker-1');
|
|
895
|
+
* if (handle) {
|
|
896
|
+
* try {
|
|
897
|
+
* // Do work while holding the lock
|
|
898
|
+
* } finally {
|
|
899
|
+
* await storage.releaseDistributedLock(handle);
|
|
900
|
+
* }
|
|
901
|
+
* } else {
|
|
902
|
+
* console.log('Could not acquire lock - resource is busy');
|
|
903
|
+
* }
|
|
904
|
+
* ```
|
|
309
905
|
*/
|
|
310
906
|
acquireDistributedLock(resource: string, ttlMs?: number, holder?: string): Promise<LockHandle | null>;
|
|
311
907
|
/**
|
|
312
|
-
*
|
|
908
|
+
* Releases a distributed lock.
|
|
909
|
+
*
|
|
910
|
+
* @description
|
|
911
|
+
* Releases the lock only if the caller still owns it (verified by lockId).
|
|
912
|
+
* Safe to call even if lock has expired or been taken by another process.
|
|
913
|
+
*
|
|
313
914
|
* @param handle - Lock handle returned from acquireDistributedLock
|
|
915
|
+
*
|
|
916
|
+
* @example
|
|
917
|
+
* ```typescript
|
|
918
|
+
* const handle = await storage.acquireDistributedLock('resource');
|
|
919
|
+
* if (handle) {
|
|
920
|
+
* try {
|
|
921
|
+
* // Do work
|
|
922
|
+
* } finally {
|
|
923
|
+
* await storage.releaseDistributedLock(handle);
|
|
924
|
+
* }
|
|
925
|
+
* }
|
|
926
|
+
* ```
|
|
314
927
|
*/
|
|
315
928
|
releaseDistributedLock(handle: LockHandle): Promise<void>;
|
|
316
929
|
/**
|
|
317
|
-
*
|
|
930
|
+
* Refreshes a distributed lock to extend its TTL.
|
|
931
|
+
*
|
|
932
|
+
* @description
|
|
933
|
+
* Extends the lock's expiration time. Useful for long-running operations
|
|
934
|
+
* that need to hold the lock longer than the original TTL.
|
|
935
|
+
*
|
|
318
936
|
* @param handle - Lock handle to refresh
|
|
319
|
-
* @param ttlMs - New TTL in milliseconds
|
|
937
|
+
* @param ttlMs - New TTL in milliseconds
|
|
938
|
+
*
|
|
320
939
|
* @returns true if refresh succeeded, false if lock was lost
|
|
940
|
+
*
|
|
941
|
+
* @example
|
|
942
|
+
* ```typescript
|
|
943
|
+
* const handle = await storage.acquireDistributedLock('resource', 30000);
|
|
944
|
+
* if (handle) {
|
|
945
|
+
* // Do some work...
|
|
946
|
+
*
|
|
947
|
+
* // Extend the lock for another 30 seconds
|
|
948
|
+
* if (await storage.refreshDistributedLock(handle, 30000)) {
|
|
949
|
+
* // Continue working
|
|
950
|
+
* } else {
|
|
951
|
+
* // Lock was lost, abort operation
|
|
952
|
+
* }
|
|
953
|
+
* }
|
|
954
|
+
* ```
|
|
321
955
|
*/
|
|
322
956
|
refreshDistributedLock(handle: LockHandle, ttlMs?: number): Promise<boolean>;
|
|
323
957
|
/**
|
|
324
|
-
*
|
|
958
|
+
* Cleans up expired locks from R2 storage.
|
|
959
|
+
*
|
|
960
|
+
* @description
|
|
961
|
+
* Scans all lock files and removes those that have expired.
|
|
325
962
|
* This should be called periodically to remove stale lock files
|
|
963
|
+
* left by crashed processes.
|
|
964
|
+
*
|
|
326
965
|
* @returns Number of locks cleaned up
|
|
966
|
+
*
|
|
967
|
+
* @example
|
|
968
|
+
* ```typescript
|
|
969
|
+
* // Run periodically (e.g., every 5 minutes)
|
|
970
|
+
* const cleaned = await storage.cleanupExpiredLocks();
|
|
971
|
+
* console.log(`Cleaned up ${cleaned} expired locks`);
|
|
972
|
+
* ```
|
|
327
973
|
*/
|
|
328
974
|
cleanupExpiredLocks(): Promise<number>;
|
|
329
975
|
/**
|
|
330
|
-
*
|
|
331
|
-
*
|
|
976
|
+
* Acquires a lock on a packfile (backward-compatible wrapper).
|
|
977
|
+
*
|
|
978
|
+
* @description
|
|
979
|
+
* High-level API for acquiring a pack lock with optional timeout.
|
|
980
|
+
* Uses distributed locking with R2 conditional writes internally.
|
|
981
|
+
*
|
|
982
|
+
* @param packId - Pack identifier to lock
|
|
983
|
+
* @param options - Lock acquisition options
|
|
984
|
+
*
|
|
985
|
+
* @returns PackLock interface for managing the lock
|
|
986
|
+
*
|
|
987
|
+
* @throws {R2PackError} With code 'LOCKED' if lock cannot be acquired
|
|
988
|
+
*
|
|
989
|
+
* @example
|
|
990
|
+
* ```typescript
|
|
991
|
+
* const lock = await storage.acquireLock(packId, {
|
|
992
|
+
* timeout: 10000,
|
|
993
|
+
* ttl: 30000,
|
|
994
|
+
* holder: 'my-worker'
|
|
995
|
+
* });
|
|
996
|
+
*
|
|
997
|
+
* try {
|
|
998
|
+
* // Perform pack operations
|
|
999
|
+
* if (lock.refresh) {
|
|
1000
|
+
* await lock.refresh(); // Extend lock if needed
|
|
1001
|
+
* }
|
|
1002
|
+
* } finally {
|
|
1003
|
+
* await lock.release();
|
|
1004
|
+
* }
|
|
1005
|
+
* ```
|
|
332
1006
|
*/
|
|
333
1007
|
acquireLock(packId: string, options?: AcquireLockOptions): Promise<PackLock>;
|
|
334
1008
|
}
|
|
335
1009
|
/**
|
|
336
|
-
*
|
|
1010
|
+
* Uploads a packfile to R2.
|
|
1011
|
+
*
|
|
1012
|
+
* @description
|
|
1013
|
+
* Standalone function for uploading a packfile. Creates a temporary
|
|
1014
|
+
* R2PackStorage instance internally.
|
|
1015
|
+
*
|
|
1016
|
+
* @param bucket - R2 bucket instance
|
|
1017
|
+
* @param packData - Raw packfile bytes
|
|
1018
|
+
* @param indexData - Pack index file bytes
|
|
1019
|
+
* @param options - Optional configuration including prefix
|
|
1020
|
+
*
|
|
1021
|
+
* @returns Upload result with pack ID, sizes, and checksum
|
|
1022
|
+
*
|
|
1023
|
+
* @throws {R2PackError} If packfile is invalid or upload fails
|
|
1024
|
+
*
|
|
1025
|
+
* @example
|
|
1026
|
+
* ```typescript
|
|
1027
|
+
* const result = await uploadPackfile(bucket, packData, indexData, {
|
|
1028
|
+
* prefix: 'repos/my-repo/'
|
|
1029
|
+
* });
|
|
1030
|
+
* console.log(`Uploaded: ${result.packId}`);
|
|
1031
|
+
* ```
|
|
337
1032
|
*/
|
|
338
1033
|
export declare function uploadPackfile(bucket: R2Bucket, packData: Uint8Array, indexData: Uint8Array, options?: {
|
|
339
1034
|
prefix?: string;
|
|
340
1035
|
}): Promise<PackfileUploadResult>;
|
|
341
1036
|
/**
|
|
342
|
-
*
|
|
1037
|
+
* Downloads a packfile from R2.
|
|
1038
|
+
*
|
|
1039
|
+
* @description
|
|
1040
|
+
* Standalone function for downloading a packfile. Creates a temporary
|
|
1041
|
+
* R2PackStorage instance internally.
|
|
1042
|
+
*
|
|
1043
|
+
* @param bucket - R2 bucket instance
|
|
1044
|
+
* @param packId - Pack identifier to download
|
|
1045
|
+
* @param options - Download options and prefix
|
|
1046
|
+
*
|
|
1047
|
+
* @returns Download result or null if not found
|
|
1048
|
+
*
|
|
1049
|
+
* @throws {R2PackError} If required=true and pack not found, or verification fails
|
|
1050
|
+
*
|
|
1051
|
+
* @example
|
|
1052
|
+
* ```typescript
|
|
1053
|
+
* const result = await downloadPackfile(bucket, packId, {
|
|
1054
|
+
* prefix: 'repos/my-repo/',
|
|
1055
|
+
* verify: true
|
|
1056
|
+
* });
|
|
1057
|
+
* ```
|
|
343
1058
|
*/
|
|
344
1059
|
export declare function downloadPackfile(bucket: R2Bucket, packId: string, options?: DownloadPackfileOptions & {
|
|
345
1060
|
prefix?: string;
|
|
346
1061
|
}): Promise<DownloadPackfileResult | null>;
|
|
347
1062
|
/**
|
|
348
|
-
*
|
|
1063
|
+
* Gets packfile metadata.
|
|
1064
|
+
*
|
|
1065
|
+
* @description
|
|
1066
|
+
* Standalone function for retrieving packfile metadata without downloading
|
|
1067
|
+
* the full pack.
|
|
1068
|
+
*
|
|
1069
|
+
* @param bucket - R2 bucket instance
|
|
1070
|
+
* @param packId - Pack identifier
|
|
1071
|
+
* @param options - Optional prefix configuration
|
|
1072
|
+
*
|
|
1073
|
+
* @returns Packfile metadata or null if not found
|
|
1074
|
+
*
|
|
1075
|
+
* @example
|
|
1076
|
+
* ```typescript
|
|
1077
|
+
* const metadata = await getPackfileMetadata(bucket, packId);
|
|
1078
|
+
* if (metadata) {
|
|
1079
|
+
* console.log(`Objects: ${metadata.objectCount}`);
|
|
1080
|
+
* }
|
|
1081
|
+
* ```
|
|
349
1082
|
*/
|
|
350
1083
|
export declare function getPackfileMetadata(bucket: R2Bucket, packId: string, options?: {
|
|
351
1084
|
prefix?: string;
|
|
352
1085
|
}): Promise<PackfileMetadata | null>;
|
|
353
1086
|
/**
|
|
354
|
-
*
|
|
1087
|
+
* Lists all packfiles.
|
|
1088
|
+
*
|
|
1089
|
+
* @description
|
|
1090
|
+
* Standalone function for listing packfiles with pagination support.
|
|
1091
|
+
*
|
|
1092
|
+
* @param bucket - R2 bucket instance
|
|
1093
|
+
* @param options - Prefix and pagination options
|
|
1094
|
+
*
|
|
1095
|
+
* @returns Array of packfile metadata
|
|
1096
|
+
*
|
|
1097
|
+
* @example
|
|
1098
|
+
* ```typescript
|
|
1099
|
+
* const packs = await listPackfiles(bucket, {
|
|
1100
|
+
* prefix: 'repos/my-repo/',
|
|
1101
|
+
* limit: 50
|
|
1102
|
+
* });
|
|
1103
|
+
* ```
|
|
355
1104
|
*/
|
|
356
1105
|
export declare function listPackfiles(bucket: R2Bucket, options?: {
|
|
357
1106
|
prefix?: string;
|
|
@@ -359,34 +1108,148 @@ export declare function listPackfiles(bucket: R2Bucket, options?: {
|
|
|
359
1108
|
cursor?: string;
|
|
360
1109
|
}): Promise<PackfileMetadata[]>;
|
|
361
1110
|
/**
|
|
362
|
-
*
|
|
1111
|
+
* Deletes a packfile.
|
|
1112
|
+
*
|
|
1113
|
+
* @description
|
|
1114
|
+
* Standalone function for deleting a packfile and its associated files.
|
|
1115
|
+
*
|
|
1116
|
+
* @param bucket - R2 bucket instance
|
|
1117
|
+
* @param packId - Pack identifier to delete
|
|
1118
|
+
* @param options - Optional prefix configuration
|
|
1119
|
+
*
|
|
1120
|
+
* @returns true if deleted, false if not found
|
|
1121
|
+
*
|
|
1122
|
+
* @example
|
|
1123
|
+
* ```typescript
|
|
1124
|
+
* if (await deletePackfile(bucket, packId)) {
|
|
1125
|
+
* console.log('Deleted');
|
|
1126
|
+
* }
|
|
1127
|
+
* ```
|
|
363
1128
|
*/
|
|
364
1129
|
export declare function deletePackfile(bucket: R2Bucket, packId: string, options?: {
|
|
365
1130
|
prefix?: string;
|
|
366
1131
|
}): Promise<boolean>;
|
|
367
1132
|
/**
|
|
368
|
-
*
|
|
1133
|
+
* Creates a multi-pack index from all packfiles in the bucket.
|
|
1134
|
+
*
|
|
1135
|
+
* @description
|
|
1136
|
+
* Standalone function that rebuilds the MIDX and returns the result.
|
|
1137
|
+
*
|
|
1138
|
+
* @param bucket - R2 bucket instance
|
|
1139
|
+
* @param options - Optional prefix configuration
|
|
1140
|
+
*
|
|
1141
|
+
* @returns The newly created multi-pack index
|
|
1142
|
+
*
|
|
1143
|
+
* @example
|
|
1144
|
+
* ```typescript
|
|
1145
|
+
* const midx = await createMultiPackIndex(bucket, { prefix: 'repos/my-repo/' });
|
|
1146
|
+
* console.log(`Indexed ${midx.entries.length} objects`);
|
|
1147
|
+
* ```
|
|
369
1148
|
*/
|
|
370
1149
|
export declare function createMultiPackIndex(bucket: R2Bucket, options?: {
|
|
371
1150
|
prefix?: string;
|
|
372
1151
|
}): Promise<MultiPackIndex>;
|
|
373
1152
|
/**
|
|
374
|
-
*
|
|
1153
|
+
* Parses a multi-pack index from raw bytes.
|
|
1154
|
+
*
|
|
1155
|
+
* @description
|
|
1156
|
+
* Deserializes the binary MIDX format into a MultiPackIndex structure.
|
|
1157
|
+
* Validates the signature and format.
|
|
1158
|
+
*
|
|
1159
|
+
* @param data - Raw MIDX bytes
|
|
1160
|
+
* @returns Parsed multi-pack index
|
|
1161
|
+
*
|
|
1162
|
+
* @throws {R2PackError} With code 'INVALID_DATA' if format is invalid
|
|
1163
|
+
*
|
|
1164
|
+
* @example
|
|
1165
|
+
* ```typescript
|
|
1166
|
+
* const midxData = await bucket.get('packs/multi-pack-index');
|
|
1167
|
+
* if (midxData) {
|
|
1168
|
+
* const midx = parseMultiPackIndex(new Uint8Array(await midxData.arrayBuffer()));
|
|
1169
|
+
* console.log(`Contains ${midx.entries.length} objects`);
|
|
1170
|
+
* }
|
|
1171
|
+
* ```
|
|
375
1172
|
*/
|
|
376
1173
|
export declare function parseMultiPackIndex(data: Uint8Array): MultiPackIndex;
|
|
377
1174
|
/**
|
|
378
|
-
*
|
|
1175
|
+
* Looks up an object in the multi-pack index using binary search.
|
|
1176
|
+
*
|
|
1177
|
+
* @description
|
|
1178
|
+
* Efficiently finds an object's location across all packs using O(log n)
|
|
1179
|
+
* binary search on the sorted entries.
|
|
1180
|
+
*
|
|
1181
|
+
* @param midx - Multi-pack index to search
|
|
1182
|
+
* @param objectId - 40-character hex SHA-1 object ID to find
|
|
1183
|
+
*
|
|
1184
|
+
* @returns Entry with pack index and offset, or null if not found
|
|
1185
|
+
*
|
|
1186
|
+
* @example
|
|
1187
|
+
* ```typescript
|
|
1188
|
+
* const midx = await storage.getMultiPackIndex();
|
|
1189
|
+
* const entry = lookupObjectInMultiPack(midx, 'abc123...');
|
|
1190
|
+
* if (entry) {
|
|
1191
|
+
* const packId = midx.packIds[entry.packIndex];
|
|
1192
|
+
* const offset = entry.offset;
|
|
1193
|
+
* console.log(`Found in ${packId} at offset ${offset}`);
|
|
1194
|
+
* }
|
|
1195
|
+
* ```
|
|
379
1196
|
*/
|
|
380
1197
|
export declare function lookupObjectInMultiPack(midx: MultiPackIndex, objectId: string): MultiPackIndexEntry | null;
|
|
381
1198
|
/**
|
|
382
|
-
*
|
|
1199
|
+
* Acquires a lock on a packfile.
|
|
1200
|
+
*
|
|
1201
|
+
* @description
|
|
1202
|
+
* Standalone function for acquiring a pack lock using distributed locking.
|
|
1203
|
+
*
|
|
1204
|
+
* @param bucket - R2 bucket instance
|
|
1205
|
+
* @param packId - Pack identifier to lock
|
|
1206
|
+
* @param options - Lock options and prefix
|
|
1207
|
+
*
|
|
1208
|
+
* @returns PackLock interface for managing the lock
|
|
1209
|
+
*
|
|
1210
|
+
* @throws {R2PackError} With code 'LOCKED' if lock cannot be acquired
|
|
1211
|
+
*
|
|
1212
|
+
* @example
|
|
1213
|
+
* ```typescript
|
|
1214
|
+
* const lock = await acquirePackLock(bucket, packId, {
|
|
1215
|
+
* prefix: 'repos/my-repo/',
|
|
1216
|
+
* timeout: 10000,
|
|
1217
|
+
* ttl: 30000
|
|
1218
|
+
* });
|
|
1219
|
+
*
|
|
1220
|
+
* try {
|
|
1221
|
+
* // Do work
|
|
1222
|
+
* } finally {
|
|
1223
|
+
* await lock.release();
|
|
1224
|
+
* }
|
|
1225
|
+
* ```
|
|
383
1226
|
*/
|
|
384
1227
|
export declare function acquirePackLock(bucket: R2Bucket, packId: string, options?: AcquireLockOptions & {
|
|
385
1228
|
prefix?: string;
|
|
386
1229
|
}): Promise<PackLock>;
|
|
387
1230
|
/**
|
|
388
|
-
*
|
|
389
|
-
*
|
|
1231
|
+
* Releases a lock on a packfile.
|
|
1232
|
+
*
|
|
1233
|
+
* @description
|
|
1234
|
+
* Standalone function for releasing a pack lock.
|
|
1235
|
+
*
|
|
1236
|
+
* Note: This function requires a valid PackLock with a handle to properly
|
|
1237
|
+
* release distributed locks. For best results, use the lock.release() method
|
|
1238
|
+
* on the PackLock object returned from acquirePackLock.
|
|
1239
|
+
*
|
|
1240
|
+
* @param bucket - R2 bucket instance
|
|
1241
|
+
* @param packId - Pack identifier to unlock
|
|
1242
|
+
* @param options - Optional prefix configuration
|
|
1243
|
+
*
|
|
1244
|
+
* @example
|
|
1245
|
+
* ```typescript
|
|
1246
|
+
* // Preferred: use lock.release()
|
|
1247
|
+
* const lock = await acquirePackLock(bucket, packId);
|
|
1248
|
+
* await lock.release();
|
|
1249
|
+
*
|
|
1250
|
+
* // Alternative: use standalone function (less safe)
|
|
1251
|
+
* await releasePackLock(bucket, packId);
|
|
1252
|
+
* ```
|
|
390
1253
|
*/
|
|
391
1254
|
export declare function releasePackLock(bucket: R2Bucket, packId: string, options?: {
|
|
392
1255
|
prefix?: string;
|