gitx.do 0.0.2 → 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 +1 -1
|
@@ -1,19 +1,94 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Git wire protocol capability negotiation
|
|
2
|
+
* @fileoverview Git wire protocol capability negotiation
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* This module implements the capability negotiation mechanism used in Git's wire protocol.
|
|
5
|
+
* Capabilities are exchanged during the initial handshake between git client and server
|
|
6
|
+
* to determine what features are supported by both sides, enabling backward compatibility
|
|
7
|
+
* and feature detection.
|
|
6
8
|
*
|
|
7
|
-
* Protocol
|
|
8
|
-
* Protocol v2: Capabilities are advertised line by line in the initial handshake
|
|
9
|
+
* ## Protocol Versions
|
|
9
10
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
11
|
+
* **Protocol v1:**
|
|
12
|
+
* - Capabilities are sent as a space-separated list after the first ref line
|
|
13
|
+
* - Format: `<oid> <refname>\0<cap1> <cap2> cap3=value...`
|
|
14
|
+
* - The NUL byte (`\0`) separates ref information from capabilities
|
|
15
|
+
* - Only the first ref line contains capabilities
|
|
16
|
+
*
|
|
17
|
+
* **Protocol v2:**
|
|
18
|
+
* - Capabilities are advertised line by line in the initial handshake
|
|
19
|
+
* - Starts with `version 2` line
|
|
20
|
+
* - Each capability on its own line, with optional values after `=`
|
|
21
|
+
* - More structured and extensible than v1
|
|
22
|
+
*
|
|
23
|
+
* ## Common Capabilities
|
|
24
|
+
*
|
|
25
|
+
* **Fetch operations:**
|
|
26
|
+
* - `multi_ack`, `multi_ack_detailed`: Improved negotiation
|
|
27
|
+
* - `thin-pack`: Send thin packs requiring client to resolve deltas
|
|
28
|
+
* - `side-band`, `side-band-64k`: Multiplexed data channels
|
|
29
|
+
* - `ofs-delta`: Use offset-based delta encoding
|
|
30
|
+
* - `shallow`: Support shallow clone operations
|
|
31
|
+
*
|
|
32
|
+
* **Push operations:**
|
|
33
|
+
* - `report-status`, `report-status-v2`: Push result reporting
|
|
34
|
+
* - `atomic`: All-or-nothing ref updates
|
|
35
|
+
* - `delete-refs`: Allow ref deletion
|
|
36
|
+
* - `push-options`: Support push options
|
|
37
|
+
*
|
|
38
|
+
* ## Usage Example
|
|
39
|
+
*
|
|
40
|
+
* ```typescript
|
|
41
|
+
* import {
|
|
42
|
+
* parseCapabilityString,
|
|
43
|
+
* findCommonCapabilities,
|
|
44
|
+
* buildCapabilityString,
|
|
45
|
+
* DEFAULT_FETCH_CAPABILITIES_V1
|
|
46
|
+
* } from './capabilities';
|
|
47
|
+
*
|
|
48
|
+
* // Parse capabilities from server advertisement
|
|
49
|
+
* const serverCaps = parseCapabilityString('abc123... refs/heads/main\0multi_ack side-band-64k');
|
|
50
|
+
*
|
|
51
|
+
* // Find common capabilities
|
|
52
|
+
* const clientCaps = DEFAULT_FETCH_CAPABILITIES_V1.map(name => ({ name }));
|
|
53
|
+
* const common = findCommonCapabilities(clientCaps, serverCaps);
|
|
54
|
+
*
|
|
55
|
+
* // Build capability string for request
|
|
56
|
+
* const capString = buildCapabilityString([
|
|
57
|
+
* { name: 'multi_ack' },
|
|
58
|
+
* { name: 'agent', value: 'gitdo/1.0' }
|
|
59
|
+
* ]);
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @module wire/capabilities
|
|
63
|
+
* @see {@link https://git-scm.com/docs/protocol-capabilities} - Protocol capabilities reference
|
|
64
|
+
* @see {@link https://git-scm.com/docs/protocol-v2} - Protocol v2 specification
|
|
12
65
|
*/
|
|
13
66
|
// ============================================================================
|
|
14
67
|
// Constants
|
|
15
68
|
// ============================================================================
|
|
16
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* Default client capabilities for fetch operations (protocol v1).
|
|
71
|
+
*
|
|
72
|
+
* @description
|
|
73
|
+
* A sensible set of capabilities for fetch operations that provides
|
|
74
|
+
* good performance while maintaining compatibility. These are commonly
|
|
75
|
+
* supported by modern Git servers.
|
|
76
|
+
*
|
|
77
|
+
* - `multi_ack_detailed`: Efficient negotiation with detailed feedback
|
|
78
|
+
* - `side-band-64k`: Large multiplexed data channels for progress/data
|
|
79
|
+
* - `thin-pack`: Receive thin packs (smaller transfer size)
|
|
80
|
+
* - `ofs-delta`: Efficient delta encoding
|
|
81
|
+
* - `agent`: Identify the client
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* const clientCaps = DEFAULT_FETCH_CAPABILITIES_V1.map(name => ({ name }));
|
|
86
|
+
* // Add agent value
|
|
87
|
+
* clientCaps.find(c => c.name === 'agent')!.value = 'gitdo/1.0';
|
|
88
|
+
*
|
|
89
|
+
* const selected = selectFetchCapabilities(serverCaps, clientCaps);
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
17
92
|
export const DEFAULT_FETCH_CAPABILITIES_V1 = [
|
|
18
93
|
'multi_ack_detailed',
|
|
19
94
|
'side-band-64k',
|
|
@@ -21,14 +96,46 @@ export const DEFAULT_FETCH_CAPABILITIES_V1 = [
|
|
|
21
96
|
'ofs-delta',
|
|
22
97
|
'agent',
|
|
23
98
|
];
|
|
24
|
-
/**
|
|
99
|
+
/**
|
|
100
|
+
* Default client capabilities for push operations (protocol v1).
|
|
101
|
+
*
|
|
102
|
+
* @description
|
|
103
|
+
* A sensible set of capabilities for push operations that provides
|
|
104
|
+
* detailed feedback and compatibility with modern Git servers.
|
|
105
|
+
*
|
|
106
|
+
* - `report-status`: Receive detailed push result status
|
|
107
|
+
* - `side-band-64k`: Multiplexed channels for status/errors
|
|
108
|
+
* - `agent`: Identify the client
|
|
109
|
+
* - `quiet`: Suppress unnecessary progress output
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```typescript
|
|
113
|
+
* const pushCaps = DEFAULT_PUSH_CAPABILITIES_V1.map(name => ({ name }));
|
|
114
|
+
* pushCaps.find(c => c.name === 'agent')!.value = 'gitdo/1.0';
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
25
117
|
export const DEFAULT_PUSH_CAPABILITIES_V1 = [
|
|
26
118
|
'report-status',
|
|
27
119
|
'side-band-64k',
|
|
28
120
|
'agent',
|
|
29
121
|
'quiet',
|
|
30
122
|
];
|
|
31
|
-
/**
|
|
123
|
+
/**
|
|
124
|
+
* Minimum required capabilities for basic fetch.
|
|
125
|
+
*
|
|
126
|
+
* @description
|
|
127
|
+
* Capabilities that must be present for fetch to work correctly.
|
|
128
|
+
* Currently empty as Git is designed to work with minimal capabilities,
|
|
129
|
+
* but this can be populated if specific capabilities become required.
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```typescript
|
|
133
|
+
* const missing = validateRequiredCapabilities(serverCaps, REQUIRED_FETCH_CAPABILITIES);
|
|
134
|
+
* if (missing.length > 0) {
|
|
135
|
+
* throw new Error(`Server missing required capabilities: ${missing.join(', ')}`);
|
|
136
|
+
* }
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
32
139
|
export const REQUIRED_FETCH_CAPABILITIES = [];
|
|
33
140
|
// ============================================================================
|
|
34
141
|
// Parsing Functions
|
|
@@ -36,10 +143,28 @@ export const REQUIRED_FETCH_CAPABILITIES = [];
|
|
|
36
143
|
/**
|
|
37
144
|
* Parse a capability string from ref advertisement (protocol v1).
|
|
38
145
|
*
|
|
39
|
-
*
|
|
146
|
+
* @description
|
|
147
|
+
* Extracts capabilities from a protocol v1 ref advertisement line.
|
|
148
|
+
* The capabilities appear after a NUL byte (`\0`) separator following
|
|
149
|
+
* the ref information. This is only present on the first ref line.
|
|
150
|
+
*
|
|
151
|
+
* Line format: `<oid> <refname>\0<cap1> <cap2> cap3=value...`
|
|
152
|
+
*
|
|
153
|
+
* @param line - The ref advertisement line containing capabilities
|
|
154
|
+
* @returns Parsed capability set with version 1
|
|
155
|
+
*
|
|
156
|
+
* @throws {Error} If the line doesn't contain a NUL byte separator
|
|
40
157
|
*
|
|
41
|
-
* @
|
|
42
|
-
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```typescript
|
|
160
|
+
* // Parse from first ref line
|
|
161
|
+
* const line = 'abc123def456789012345678901234567890abcd refs/heads/main\0multi_ack side-band-64k agent=git/2.30.0';
|
|
162
|
+
* const caps = parseCapabilityString(line);
|
|
163
|
+
*
|
|
164
|
+
* console.log(caps.version); // 1
|
|
165
|
+
* console.log(caps.capabilities.has('multi_ack')); // true
|
|
166
|
+
* console.log(caps.capabilities.get('agent')); // 'git/2.30.0'
|
|
167
|
+
* ```
|
|
43
168
|
*/
|
|
44
169
|
export function parseCapabilityString(line) {
|
|
45
170
|
// Find the NUL byte that separates ref info from capabilities
|
|
@@ -64,8 +189,28 @@ export function parseCapabilityString(line) {
|
|
|
64
189
|
/**
|
|
65
190
|
* Parse individual capability entries from a space-separated string.
|
|
66
191
|
*
|
|
192
|
+
* @description
|
|
193
|
+
* Parses a whitespace-separated capability string into individual entries.
|
|
194
|
+
* Handles both simple capabilities (`multi_ack`) and capabilities with
|
|
195
|
+
* values (`agent=git/2.30.0`).
|
|
196
|
+
*
|
|
67
197
|
* @param capString - Space-separated capability string
|
|
68
198
|
* @returns Array of capability entries
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* ```typescript
|
|
202
|
+
* // Simple capabilities
|
|
203
|
+
* const caps1 = parseCapabilities('multi_ack thin-pack ofs-delta');
|
|
204
|
+
* // [{ name: 'multi_ack' }, { name: 'thin-pack' }, { name: 'ofs-delta' }]
|
|
205
|
+
*
|
|
206
|
+
* // Capabilities with values
|
|
207
|
+
* const caps2 = parseCapabilities('agent=git/2.30.0 symref=HEAD:refs/heads/main');
|
|
208
|
+
* // [{ name: 'agent', value: 'git/2.30.0' }, { name: 'symref', value: 'HEAD:refs/heads/main' }]
|
|
209
|
+
*
|
|
210
|
+
* // Empty string
|
|
211
|
+
* const caps3 = parseCapabilities('');
|
|
212
|
+
* // []
|
|
213
|
+
* ```
|
|
69
214
|
*/
|
|
70
215
|
export function parseCapabilities(capString) {
|
|
71
216
|
// Trim and split by whitespace
|
|
@@ -91,12 +236,41 @@ export function parseCapabilities(capString) {
|
|
|
91
236
|
/**
|
|
92
237
|
* Parse a ref advertisement line (protocol v1).
|
|
93
238
|
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
239
|
+
* @description
|
|
240
|
+
* Parses a single line from the server's ref advertisement. The first
|
|
241
|
+
* line has a special format including capabilities after a NUL byte,
|
|
242
|
+
* while subsequent lines contain only the OID and ref name.
|
|
243
|
+
*
|
|
244
|
+
* First line format: `<oid> <refname>\0<capabilities>`
|
|
245
|
+
* Subsequent lines: `<oid> <refname>`
|
|
96
246
|
*
|
|
97
247
|
* @param line - The pkt-line data (without length prefix)
|
|
98
248
|
* @param isFirst - Whether this is the first line (contains capabilities)
|
|
99
249
|
* @returns Parsed ref advertisement
|
|
250
|
+
*
|
|
251
|
+
* @throws {Error} If the first line is missing the NUL byte
|
|
252
|
+
* @throws {Error} If the line is missing the space between OID and refname
|
|
253
|
+
* @throws {Error} If the OID is not 40 characters (SHA-1)
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* ```typescript
|
|
257
|
+
* // Parse first line (with capabilities)
|
|
258
|
+
* const firstLine = 'abc123def456789012345678901234567890abcd refs/heads/main\0multi_ack side-band-64k\n';
|
|
259
|
+
* const firstRef = parseRefAdvertisement(firstLine, true);
|
|
260
|
+
* // {
|
|
261
|
+
* // oid: 'abc123def456789012345678901234567890abcd',
|
|
262
|
+
* // name: 'refs/heads/main',
|
|
263
|
+
* // capabilities: { version: 1, capabilities: Map {...} }
|
|
264
|
+
* // }
|
|
265
|
+
*
|
|
266
|
+
* // Parse subsequent line (no capabilities)
|
|
267
|
+
* const otherLine = 'def456789012345678901234567890abcdef12 refs/heads/feature\n';
|
|
268
|
+
* const otherRef = parseRefAdvertisement(otherLine, false);
|
|
269
|
+
* // {
|
|
270
|
+
* // oid: 'def456789012345678901234567890abcdef12',
|
|
271
|
+
* // name: 'refs/heads/feature'
|
|
272
|
+
* // }
|
|
273
|
+
* ```
|
|
100
274
|
*/
|
|
101
275
|
export function parseRefAdvertisement(line, isFirst) {
|
|
102
276
|
// Remove trailing newline if present
|
|
@@ -145,16 +319,51 @@ export function parseRefAdvertisement(line, isFirst) {
|
|
|
145
319
|
/**
|
|
146
320
|
* Parse protocol v2 capability advertisement.
|
|
147
321
|
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
322
|
+
* @description
|
|
323
|
+
* Parses the server's capability advertisement in protocol v2 format.
|
|
324
|
+
* Protocol v2 uses a line-by-line format starting with "version 2",
|
|
325
|
+
* followed by capability lines. Commands and capabilities are distinguished
|
|
326
|
+
* by whether they have values.
|
|
327
|
+
*
|
|
328
|
+
* Response format:
|
|
329
|
+
* ```
|
|
330
|
+
* version 2
|
|
331
|
+
* agent=git/2.30.0
|
|
332
|
+
* ls-refs
|
|
333
|
+
* fetch=shallow filter
|
|
334
|
+
* server-option
|
|
335
|
+
* object-format=sha1
|
|
336
|
+
* ```
|
|
155
337
|
*
|
|
156
|
-
* @param lines - Array of pkt-line data
|
|
338
|
+
* @param lines - Array of pkt-line data (without length prefixes)
|
|
157
339
|
* @returns Parsed server capabilities
|
|
340
|
+
*
|
|
341
|
+
* @throws {Error} If lines is empty or doesn't start with "version 2"
|
|
342
|
+
*
|
|
343
|
+
* @example
|
|
344
|
+
* ```typescript
|
|
345
|
+
* const lines = [
|
|
346
|
+
* 'version 2',
|
|
347
|
+
* 'agent=git/2.40.0',
|
|
348
|
+
* 'ls-refs',
|
|
349
|
+
* 'fetch=shallow filter',
|
|
350
|
+
* 'server-option',
|
|
351
|
+
* 'object-format=sha1'
|
|
352
|
+
* ];
|
|
353
|
+
*
|
|
354
|
+
* const serverCaps = parseServerCapabilitiesV2(lines);
|
|
355
|
+
* // {
|
|
356
|
+
* // version: 2,
|
|
357
|
+
* // commands: ['ls-refs', 'fetch', 'server-option'],
|
|
358
|
+
* // agent: 'git/2.40.0',
|
|
359
|
+
* // objectFormat: 'sha1',
|
|
360
|
+
* // capabilities: Map { 'ls-refs' => undefined, 'fetch' => 'shallow filter', ... }
|
|
361
|
+
* // }
|
|
362
|
+
*
|
|
363
|
+
* if (serverCaps.commands.includes('fetch')) {
|
|
364
|
+
* console.log('Server supports fetch with:', serverCaps.capabilities.get('fetch'));
|
|
365
|
+
* }
|
|
366
|
+
* ```
|
|
158
367
|
*/
|
|
159
368
|
export function parseServerCapabilitiesV2(lines) {
|
|
160
369
|
if (lines.length === 0 || lines[0] !== 'version 2') {
|
|
@@ -206,8 +415,25 @@ export function parseServerCapabilitiesV2(lines) {
|
|
|
206
415
|
/**
|
|
207
416
|
* Build a capability string for want/have request (protocol v1).
|
|
208
417
|
*
|
|
418
|
+
* @description
|
|
419
|
+
* Constructs a space-separated capability string from an array of
|
|
420
|
+
* capability entries. Capabilities with values are formatted as
|
|
421
|
+
* `name=value`, while those without are just the name.
|
|
422
|
+
*
|
|
209
423
|
* @param capabilities - Capabilities to include
|
|
210
424
|
* @returns Space-separated capability string
|
|
425
|
+
*
|
|
426
|
+
* @example
|
|
427
|
+
* ```typescript
|
|
428
|
+
* const caps: CapabilityEntry[] = [
|
|
429
|
+
* { name: 'multi_ack_detailed' },
|
|
430
|
+
* { name: 'side-band-64k' },
|
|
431
|
+
* { name: 'agent', value: 'gitdo/1.0' }
|
|
432
|
+
* ];
|
|
433
|
+
*
|
|
434
|
+
* const str = buildCapabilityString(caps);
|
|
435
|
+
* // 'multi_ack_detailed side-band-64k agent=gitdo/1.0'
|
|
436
|
+
* ```
|
|
211
437
|
*/
|
|
212
438
|
export function buildCapabilityString(capabilities) {
|
|
213
439
|
return capabilities
|
|
@@ -222,11 +448,31 @@ export function buildCapabilityString(capabilities) {
|
|
|
222
448
|
/**
|
|
223
449
|
* Build a want line with capabilities (first want only).
|
|
224
450
|
*
|
|
225
|
-
*
|
|
451
|
+
* @description
|
|
452
|
+
* Constructs a want line for a fetch request. The first want line
|
|
453
|
+
* includes capabilities, while subsequent want lines contain only
|
|
454
|
+
* the object ID.
|
|
226
455
|
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
456
|
+
* Format: `want <oid> <capabilities>\n` (first line)
|
|
457
|
+
* Format: `want <oid>\n` (subsequent lines)
|
|
458
|
+
*
|
|
459
|
+
* @param oid - The object ID to want (40-character SHA-1 hex string)
|
|
460
|
+
* @param capabilities - Capabilities to include (optional, first want only)
|
|
461
|
+
* @returns Formatted want line with trailing newline
|
|
462
|
+
*
|
|
463
|
+
* @example
|
|
464
|
+
* ```typescript
|
|
465
|
+
* // First want line with capabilities
|
|
466
|
+
* const firstWant = buildWantLine(
|
|
467
|
+
* 'abc123def456789012345678901234567890abcd',
|
|
468
|
+
* [{ name: 'multi_ack' }, { name: 'agent', value: 'gitdo/1.0' }]
|
|
469
|
+
* );
|
|
470
|
+
* // 'want abc123def456789012345678901234567890abcd multi_ack agent=gitdo/1.0\n'
|
|
471
|
+
*
|
|
472
|
+
* // Subsequent want line (no capabilities)
|
|
473
|
+
* const nextWant = buildWantLine('def456789012345678901234567890abcdef12');
|
|
474
|
+
* // 'want def456789012345678901234567890abcdef12\n'
|
|
475
|
+
* ```
|
|
230
476
|
*/
|
|
231
477
|
export function buildWantLine(oid, capabilities) {
|
|
232
478
|
if (capabilities && capabilities.length > 0) {
|
|
@@ -238,10 +484,25 @@ export function buildWantLine(oid, capabilities) {
|
|
|
238
484
|
/**
|
|
239
485
|
* Build a have line for negotiation.
|
|
240
486
|
*
|
|
241
|
-
*
|
|
487
|
+
* @description
|
|
488
|
+
* Constructs a have line used during fetch negotiation. Have lines
|
|
489
|
+
* inform the server what objects the client already has, allowing
|
|
490
|
+
* the server to determine the minimal set of objects to send.
|
|
491
|
+
*
|
|
492
|
+
* Format: `have <oid>\n`
|
|
242
493
|
*
|
|
243
|
-
* @param oid - The object ID we have
|
|
244
|
-
* @returns Formatted have line
|
|
494
|
+
* @param oid - The object ID we have (40-character SHA-1 hex string)
|
|
495
|
+
* @returns Formatted have line with trailing newline
|
|
496
|
+
*
|
|
497
|
+
* @example
|
|
498
|
+
* ```typescript
|
|
499
|
+
* const haveLine = buildHaveLine('abc123def456789012345678901234567890abcd');
|
|
500
|
+
* // 'have abc123def456789012345678901234567890abcd\n'
|
|
501
|
+
*
|
|
502
|
+
* // OID is normalized to lowercase
|
|
503
|
+
* const normalized = buildHaveLine('ABC123DEF456789012345678901234567890ABCD');
|
|
504
|
+
* // 'have abc123def456789012345678901234567890abcd\n'
|
|
505
|
+
* ```
|
|
245
506
|
*/
|
|
246
507
|
export function buildHaveLine(oid) {
|
|
247
508
|
return `have ${oid.toLowerCase()}\n`;
|
|
@@ -249,8 +510,35 @@ export function buildHaveLine(oid) {
|
|
|
249
510
|
/**
|
|
250
511
|
* Build a complete want/have request.
|
|
251
512
|
*
|
|
252
|
-
* @
|
|
253
|
-
*
|
|
513
|
+
* @description
|
|
514
|
+
* Constructs all want lines for a fetch request. The first want line
|
|
515
|
+
* includes the client's capabilities, while subsequent want lines
|
|
516
|
+
* contain only the object IDs.
|
|
517
|
+
*
|
|
518
|
+
* @param request - The want request containing object IDs and capabilities
|
|
519
|
+
* @returns Array of formatted want lines (ready for pkt-line encoding)
|
|
520
|
+
*
|
|
521
|
+
* @example
|
|
522
|
+
* ```typescript
|
|
523
|
+
* const request: WantRequest = {
|
|
524
|
+
* wants: [
|
|
525
|
+
* 'abc123def456789012345678901234567890abcd',
|
|
526
|
+
* 'def456789012345678901234567890abcdef12',
|
|
527
|
+
* '123456789012345678901234567890abcdef00'
|
|
528
|
+
* ],
|
|
529
|
+
* capabilities: [
|
|
530
|
+
* { name: 'multi_ack_detailed' },
|
|
531
|
+
* { name: 'side-band-64k' }
|
|
532
|
+
* ]
|
|
533
|
+
* };
|
|
534
|
+
*
|
|
535
|
+
* const lines = buildFetchRequest(request);
|
|
536
|
+
* // [
|
|
537
|
+
* // 'want abc123... multi_ack_detailed side-band-64k\n',
|
|
538
|
+
* // 'want def456...\n',
|
|
539
|
+
* // 'want 123456...\n'
|
|
540
|
+
* // ]
|
|
541
|
+
* ```
|
|
254
542
|
*/
|
|
255
543
|
export function buildFetchRequest(request) {
|
|
256
544
|
const lines = [];
|
|
@@ -270,18 +558,48 @@ export function buildFetchRequest(request) {
|
|
|
270
558
|
/**
|
|
271
559
|
* Build protocol v2 command request.
|
|
272
560
|
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
561
|
+
* @description
|
|
562
|
+
* Constructs a protocol v2 command request. Protocol v2 uses a structured
|
|
563
|
+
* format with command specification, capabilities, and optional arguments.
|
|
564
|
+
*
|
|
565
|
+
* Request format:
|
|
566
|
+
* ```
|
|
567
|
+
* command=<cmd>
|
|
568
|
+
* capability1
|
|
569
|
+
* capability2=value
|
|
570
|
+
* 0001 (delimiter - added by caller)
|
|
571
|
+
* <command-specific args>
|
|
572
|
+
* 0000 (flush - added by caller)
|
|
573
|
+
* ```
|
|
280
574
|
*
|
|
281
575
|
* @param command - The v2 command (e.g., 'fetch', 'ls-refs')
|
|
282
|
-
* @param capabilities - Client capabilities
|
|
283
|
-
* @param args - Command-specific arguments
|
|
284
|
-
* @returns Array of pkt-line
|
|
576
|
+
* @param capabilities - Client capabilities to advertise
|
|
577
|
+
* @param args - Command-specific arguments (optional)
|
|
578
|
+
* @returns Array of lines (ready for pkt-line encoding)
|
|
579
|
+
*
|
|
580
|
+
* @example
|
|
581
|
+
* ```typescript
|
|
582
|
+
* // ls-refs request
|
|
583
|
+
* const lsRefsLines = buildV2CommandRequest(
|
|
584
|
+
* 'ls-refs',
|
|
585
|
+
* [{ name: 'agent', value: 'gitdo/1.0' }],
|
|
586
|
+
* ['peel', 'symrefs', 'ref-prefix refs/heads/']
|
|
587
|
+
* );
|
|
588
|
+
* // [
|
|
589
|
+
* // 'command=ls-refs',
|
|
590
|
+
* // 'agent=gitdo/1.0',
|
|
591
|
+
* // 'peel',
|
|
592
|
+
* // 'symrefs',
|
|
593
|
+
* // 'ref-prefix refs/heads/'
|
|
594
|
+
* // ]
|
|
595
|
+
*
|
|
596
|
+
* // fetch request
|
|
597
|
+
* const fetchLines = buildV2CommandRequest(
|
|
598
|
+
* 'fetch',
|
|
599
|
+
* [{ name: 'agent', value: 'gitdo/1.0' }, { name: 'thin-pack' }],
|
|
600
|
+
* ['want abc123...', 'have def456...', 'done']
|
|
601
|
+
* );
|
|
602
|
+
* ```
|
|
285
603
|
*/
|
|
286
604
|
export function buildV2CommandRequest(command, capabilities, args) {
|
|
287
605
|
const lines = [];
|
|
@@ -310,9 +628,29 @@ export function buildV2CommandRequest(command, capabilities, args) {
|
|
|
310
628
|
/**
|
|
311
629
|
* Negotiate protocol version with server.
|
|
312
630
|
*
|
|
313
|
-
* @
|
|
314
|
-
*
|
|
315
|
-
*
|
|
631
|
+
* @description
|
|
632
|
+
* Determines the protocol version to use based on the server's advertisement
|
|
633
|
+
* and the client's preference. The negotiated version is the highest version
|
|
634
|
+
* supported by both parties.
|
|
635
|
+
*
|
|
636
|
+
* @param serverAdvertisement - First line from server's response
|
|
637
|
+
* @param preferredVersion - Client's preferred protocol version (default: 2)
|
|
638
|
+
* @returns Negotiation result with agreed version
|
|
639
|
+
*
|
|
640
|
+
* @example
|
|
641
|
+
* ```typescript
|
|
642
|
+
* // Server supports v2, client prefers v2
|
|
643
|
+
* const v2Result = negotiateVersion('version 2', 2);
|
|
644
|
+
* // { version: 2, serverSupportsV2: true, commonCapabilities: [] }
|
|
645
|
+
*
|
|
646
|
+
* // Server is v1 only, client prefers v2
|
|
647
|
+
* const v1Result = negotiateVersion('abc123... refs/heads/main\0multi_ack', 2);
|
|
648
|
+
* // { version: 1, serverSupportsV2: false, commonCapabilities: [] }
|
|
649
|
+
*
|
|
650
|
+
* // Client explicitly wants v1
|
|
651
|
+
* const explicitV1 = negotiateVersion('version 2', 1);
|
|
652
|
+
* // { version: 1, serverSupportsV2: true, commonCapabilities: [] }
|
|
653
|
+
* ```
|
|
316
654
|
*/
|
|
317
655
|
export function negotiateVersion(serverAdvertisement, preferredVersion = 2) {
|
|
318
656
|
const serverSupportsV2 = serverAdvertisement.startsWith('version 2');
|
|
@@ -332,9 +670,36 @@ export function negotiateVersion(serverAdvertisement, preferredVersion = 2) {
|
|
|
332
670
|
/**
|
|
333
671
|
* Find common capabilities between client and server.
|
|
334
672
|
*
|
|
335
|
-
* @
|
|
336
|
-
*
|
|
337
|
-
*
|
|
673
|
+
* @description
|
|
674
|
+
* Determines which capabilities are supported by both the client and server.
|
|
675
|
+
* This is used to select the optimal set of capabilities for the session.
|
|
676
|
+
*
|
|
677
|
+
* @param clientCaps - Client's supported capabilities
|
|
678
|
+
* @param serverCaps - Server's advertised capabilities
|
|
679
|
+
* @returns Array of capability names supported by both parties
|
|
680
|
+
*
|
|
681
|
+
* @example
|
|
682
|
+
* ```typescript
|
|
683
|
+
* const clientCaps: CapabilityEntry[] = [
|
|
684
|
+
* { name: 'multi_ack_detailed' },
|
|
685
|
+
* { name: 'side-band-64k' },
|
|
686
|
+
* { name: 'thin-pack' },
|
|
687
|
+
* { name: 'ofs-delta' }
|
|
688
|
+
* ];
|
|
689
|
+
*
|
|
690
|
+
* const serverCaps: CapabilitySet = {
|
|
691
|
+
* version: 1,
|
|
692
|
+
* capabilities: new Map([
|
|
693
|
+
* ['multi_ack', undefined],
|
|
694
|
+
* ['multi_ack_detailed', undefined],
|
|
695
|
+
* ['side-band-64k', undefined],
|
|
696
|
+
* ['shallow', undefined]
|
|
697
|
+
* ])
|
|
698
|
+
* };
|
|
699
|
+
*
|
|
700
|
+
* const common = findCommonCapabilities(clientCaps, serverCaps);
|
|
701
|
+
* // ['multi_ack_detailed', 'side-band-64k']
|
|
702
|
+
* ```
|
|
338
703
|
*/
|
|
339
704
|
export function findCommonCapabilities(clientCaps, serverCaps) {
|
|
340
705
|
const common = [];
|
|
@@ -348,9 +713,29 @@ export function findCommonCapabilities(clientCaps, serverCaps) {
|
|
|
348
713
|
/**
|
|
349
714
|
* Check if a specific capability is supported.
|
|
350
715
|
*
|
|
716
|
+
* @description
|
|
717
|
+
* Checks whether a capability is present in the capability set.
|
|
718
|
+
* This is a convenience wrapper around Map.has().
|
|
719
|
+
*
|
|
351
720
|
* @param capSet - The capability set to check
|
|
352
|
-
* @param name - The capability name
|
|
353
|
-
* @returns True if capability is
|
|
721
|
+
* @param name - The capability name to look for
|
|
722
|
+
* @returns True if the capability is present
|
|
723
|
+
*
|
|
724
|
+
* @example
|
|
725
|
+
* ```typescript
|
|
726
|
+
* const caps: CapabilitySet = {
|
|
727
|
+
* version: 1,
|
|
728
|
+
* capabilities: new Map([
|
|
729
|
+
* ['multi_ack', undefined],
|
|
730
|
+
* ['side-band-64k', undefined],
|
|
731
|
+
* ['agent', 'git/2.30.0']
|
|
732
|
+
* ])
|
|
733
|
+
* };
|
|
734
|
+
*
|
|
735
|
+
* hasCapability(caps, 'multi_ack'); // true
|
|
736
|
+
* hasCapability(caps, 'side-band-64k'); // true
|
|
737
|
+
* hasCapability(caps, 'thin-pack'); // false
|
|
738
|
+
* ```
|
|
354
739
|
*/
|
|
355
740
|
export function hasCapability(capSet, name) {
|
|
356
741
|
return capSet.capabilities.has(name);
|
|
@@ -358,9 +743,30 @@ export function hasCapability(capSet, name) {
|
|
|
358
743
|
/**
|
|
359
744
|
* Get the value of a capability (if it has one).
|
|
360
745
|
*
|
|
361
|
-
* @
|
|
746
|
+
* @description
|
|
747
|
+
* Retrieves the value associated with a capability. Returns undefined
|
|
748
|
+
* if the capability is not present or has no value.
|
|
749
|
+
*
|
|
750
|
+
* @param capSet - The capability set to query
|
|
362
751
|
* @param name - The capability name
|
|
363
|
-
* @returns The capability value or undefined
|
|
752
|
+
* @returns The capability value, or undefined if not present/no value
|
|
753
|
+
*
|
|
754
|
+
* @example
|
|
755
|
+
* ```typescript
|
|
756
|
+
* const caps: CapabilitySet = {
|
|
757
|
+
* version: 1,
|
|
758
|
+
* capabilities: new Map([
|
|
759
|
+
* ['multi_ack', undefined],
|
|
760
|
+
* ['agent', 'git/2.30.0'],
|
|
761
|
+
* ['symref', 'HEAD:refs/heads/main']
|
|
762
|
+
* ])
|
|
763
|
+
* };
|
|
764
|
+
*
|
|
765
|
+
* getCapabilityValue(caps, 'agent'); // 'git/2.30.0'
|
|
766
|
+
* getCapabilityValue(caps, 'symref'); // 'HEAD:refs/heads/main'
|
|
767
|
+
* getCapabilityValue(caps, 'multi_ack'); // undefined (present but no value)
|
|
768
|
+
* getCapabilityValue(caps, 'thin-pack'); // undefined (not present)
|
|
769
|
+
* ```
|
|
364
770
|
*/
|
|
365
771
|
export function getCapabilityValue(capSet, name) {
|
|
366
772
|
return capSet.capabilities.get(name);
|
|
@@ -368,9 +774,32 @@ export function getCapabilityValue(capSet, name) {
|
|
|
368
774
|
/**
|
|
369
775
|
* Create a capability set from entries.
|
|
370
776
|
*
|
|
371
|
-
* @
|
|
372
|
-
*
|
|
373
|
-
*
|
|
777
|
+
* @description
|
|
778
|
+
* Constructs a CapabilitySet from an array of capability entries.
|
|
779
|
+
* This is useful for creating capability sets programmatically.
|
|
780
|
+
*
|
|
781
|
+
* @param version - Protocol version (1 or 2)
|
|
782
|
+
* @param entries - Array of capability entries
|
|
783
|
+
* @returns A new CapabilitySet
|
|
784
|
+
*
|
|
785
|
+
* @example
|
|
786
|
+
* ```typescript
|
|
787
|
+
* const entries: CapabilityEntry[] = [
|
|
788
|
+
* { name: 'multi_ack_detailed' },
|
|
789
|
+
* { name: 'side-band-64k' },
|
|
790
|
+
* { name: 'agent', value: 'gitdo/1.0' }
|
|
791
|
+
* ];
|
|
792
|
+
*
|
|
793
|
+
* const capSet = createCapabilitySet(1, entries);
|
|
794
|
+
* // {
|
|
795
|
+
* // version: 1,
|
|
796
|
+
* // capabilities: Map {
|
|
797
|
+
* // 'multi_ack_detailed' => undefined,
|
|
798
|
+
* // 'side-band-64k' => undefined,
|
|
799
|
+
* // 'agent' => 'gitdo/1.0'
|
|
800
|
+
* // }
|
|
801
|
+
* // }
|
|
802
|
+
* ```
|
|
374
803
|
*/
|
|
375
804
|
export function createCapabilitySet(version, entries) {
|
|
376
805
|
const capabilities = new Map();
|
|
@@ -385,9 +814,40 @@ export function createCapabilitySet(version, entries) {
|
|
|
385
814
|
/**
|
|
386
815
|
* Select optimal capabilities for a fetch operation.
|
|
387
816
|
*
|
|
388
|
-
* @
|
|
389
|
-
*
|
|
390
|
-
*
|
|
817
|
+
* @description
|
|
818
|
+
* Filters client-preferred capabilities to only those supported by the server.
|
|
819
|
+
* The client's values are preserved (not the server's), maintaining client
|
|
820
|
+
* identification and preferences.
|
|
821
|
+
*
|
|
822
|
+
* @param serverCaps - Server's advertised capabilities
|
|
823
|
+
* @param clientPrefs - Client's preferred capabilities (in priority order)
|
|
824
|
+
* @returns Array of capabilities to use (subset of client preferences)
|
|
825
|
+
*
|
|
826
|
+
* @example
|
|
827
|
+
* ```typescript
|
|
828
|
+
* const serverCaps: CapabilitySet = {
|
|
829
|
+
* version: 1,
|
|
830
|
+
* capabilities: new Map([
|
|
831
|
+
* ['multi_ack', undefined],
|
|
832
|
+
* ['side-band-64k', undefined],
|
|
833
|
+
* ['thin-pack', undefined]
|
|
834
|
+
* ])
|
|
835
|
+
* };
|
|
836
|
+
*
|
|
837
|
+
* const clientPrefs: CapabilityEntry[] = [
|
|
838
|
+
* { name: 'multi_ack_detailed' }, // Not supported by server
|
|
839
|
+
* { name: 'multi_ack' }, // Supported
|
|
840
|
+
* { name: 'side-band-64k' }, // Supported
|
|
841
|
+
* { name: 'ofs-delta' }, // Not supported
|
|
842
|
+
* { name: 'agent', value: 'gitdo/1.0' } // Not in server caps
|
|
843
|
+
* ];
|
|
844
|
+
*
|
|
845
|
+
* const selected = selectFetchCapabilities(serverCaps, clientPrefs);
|
|
846
|
+
* // [
|
|
847
|
+
* // { name: 'multi_ack' },
|
|
848
|
+
* // { name: 'side-band-64k' }
|
|
849
|
+
* // ]
|
|
850
|
+
* ```
|
|
391
851
|
*/
|
|
392
852
|
export function selectFetchCapabilities(serverCaps, clientPrefs) {
|
|
393
853
|
const selected = [];
|
|
@@ -405,8 +865,24 @@ export function selectFetchCapabilities(serverCaps, clientPrefs) {
|
|
|
405
865
|
/**
|
|
406
866
|
* Validate that a capability name is well-formed.
|
|
407
867
|
*
|
|
868
|
+
* @description
|
|
869
|
+
* Checks that a capability name follows the Git protocol requirements.
|
|
870
|
+
* Capability names must be non-empty and cannot contain spaces, NUL bytes,
|
|
871
|
+
* or newline characters.
|
|
872
|
+
*
|
|
408
873
|
* @param name - The capability name to validate
|
|
409
|
-
* @returns True if valid
|
|
874
|
+
* @returns True if the name is valid
|
|
875
|
+
*
|
|
876
|
+
* @example
|
|
877
|
+
* ```typescript
|
|
878
|
+
* isValidCapabilityName('multi_ack'); // true
|
|
879
|
+
* isValidCapabilityName('side-band-64k'); // true
|
|
880
|
+
* isValidCapabilityName('agent'); // true
|
|
881
|
+
* isValidCapabilityName(''); // false (empty)
|
|
882
|
+
* isValidCapabilityName('multi ack'); // false (contains space)
|
|
883
|
+
* isValidCapabilityName('cap\0name'); // false (contains NUL)
|
|
884
|
+
* isValidCapabilityName('cap\nname'); // false (contains newline)
|
|
885
|
+
* ```
|
|
410
886
|
*/
|
|
411
887
|
export function isValidCapabilityName(name) {
|
|
412
888
|
if (name === '') {
|
|
@@ -421,9 +897,37 @@ export function isValidCapabilityName(name) {
|
|
|
421
897
|
/**
|
|
422
898
|
* Validate that required capabilities are present.
|
|
423
899
|
*
|
|
424
|
-
* @
|
|
425
|
-
*
|
|
426
|
-
*
|
|
900
|
+
* @description
|
|
901
|
+
* Checks a capability set for the presence of all required capabilities.
|
|
902
|
+
* Returns an array of missing capability names. An empty array indicates
|
|
903
|
+
* all requirements are satisfied.
|
|
904
|
+
*
|
|
905
|
+
* @param capSet - The capability set to validate
|
|
906
|
+
* @param required - Array of required capability names
|
|
907
|
+
* @returns Array of missing capability names (empty if all present)
|
|
908
|
+
*
|
|
909
|
+
* @example
|
|
910
|
+
* ```typescript
|
|
911
|
+
* const caps: CapabilitySet = {
|
|
912
|
+
* version: 1,
|
|
913
|
+
* capabilities: new Map([
|
|
914
|
+
* ['multi_ack', undefined],
|
|
915
|
+
* ['side-band-64k', undefined]
|
|
916
|
+
* ])
|
|
917
|
+
* };
|
|
918
|
+
*
|
|
919
|
+
* // All present
|
|
920
|
+
* const missing1 = validateRequiredCapabilities(caps, ['multi_ack']);
|
|
921
|
+
* // []
|
|
922
|
+
*
|
|
923
|
+
* // Some missing
|
|
924
|
+
* const missing2 = validateRequiredCapabilities(caps, ['multi_ack', 'thin-pack', 'ofs-delta']);
|
|
925
|
+
* // ['thin-pack', 'ofs-delta']
|
|
926
|
+
*
|
|
927
|
+
* if (missing2.length > 0) {
|
|
928
|
+
* throw new Error(`Server missing capabilities: ${missing2.join(', ')}`);
|
|
929
|
+
* }
|
|
930
|
+
* ```
|
|
427
931
|
*/
|
|
428
932
|
export function validateRequiredCapabilities(capSet, required) {
|
|
429
933
|
const missing = [];
|