@ankhorage/repository 0.4.19 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/CHANGELOG.md +143 -0
  2. package/README.md +16 -27
  3. package/dist/cli/commands/materialize/definitions/MaterializeCommandOptions.d.ts +6 -0
  4. package/dist/cli/commands/materialize/definitions/MaterializeCommandOptions.d.ts.map +1 -0
  5. package/dist/cli/commands/materialize/definitions/MaterializeCommandOptions.js +2 -0
  6. package/dist/cli/commands/materialize/definitions/MaterializeCommandOptions.js.map +1 -0
  7. package/dist/cli/commands/materialize/parseMaterializeCommandOptions.d.ts +4 -0
  8. package/dist/cli/commands/materialize/parseMaterializeCommandOptions.d.ts.map +1 -0
  9. package/dist/cli/commands/materialize/parseMaterializeCommandOptions.js +33 -0
  10. package/dist/cli/commands/materialize/parseMaterializeCommandOptions.js.map +1 -0
  11. package/dist/cli/commands/materialize/parseMaterializeCommandOptions.test.d.ts +2 -0
  12. package/dist/cli/commands/materialize/parseMaterializeCommandOptions.test.d.ts.map +1 -0
  13. package/dist/cli/commands/materialize/parseMaterializeCommandOptions.test.js +23 -0
  14. package/dist/cli/commands/materialize/parseMaterializeCommandOptions.test.js.map +1 -0
  15. package/dist/cli/commands/materialize/runMaterializeCommandAsync.d.ts +10 -0
  16. package/dist/cli/commands/materialize/runMaterializeCommandAsync.d.ts.map +1 -0
  17. package/dist/cli/commands/materialize/runMaterializeCommandAsync.js +28 -0
  18. package/dist/cli/commands/materialize/runMaterializeCommandAsync.js.map +1 -0
  19. package/dist/cli/provider/createRepositoryRuntimeProvider.d.ts +14 -2
  20. package/dist/cli/provider/createRepositoryRuntimeProvider.d.ts.map +1 -1
  21. package/dist/cli/provider/createRepositoryRuntimeProvider.js +7 -9
  22. package/dist/cli/provider/createRepositoryRuntimeProvider.js.map +1 -1
  23. package/dist/cli/provider/createRepositoryRuntimeProvider.test.js +6 -2
  24. package/dist/cli/provider/createRepositoryRuntimeProvider.test.js.map +1 -1
  25. package/dist/github/index.d.ts +3 -0
  26. package/dist/github/index.d.ts.map +1 -1
  27. package/dist/github/index.js +1 -0
  28. package/dist/github/index.js.map +1 -1
  29. package/dist/metadata/index.d.ts +1 -1
  30. package/dist/metadata/index.js +1 -1
  31. package/dist/metadata/index.js.map +1 -1
  32. package/dist/metadata/repositoryPackageMetadata.d.ts +6 -1
  33. package/dist/metadata/repositoryPackageMetadata.d.ts.map +1 -1
  34. package/dist/metadata/repositoryPackageMetadata.js +6 -1
  35. package/dist/metadata/repositoryPackageMetadata.js.map +1 -1
  36. package/dist/providers/github/adapters/createGitHubHttpRepositoryReadGateway.d.ts +4 -0
  37. package/dist/providers/github/adapters/createGitHubHttpRepositoryReadGateway.d.ts.map +1 -0
  38. package/dist/providers/github/adapters/createGitHubHttpRepositoryReadGateway.js +115 -0
  39. package/dist/providers/github/adapters/createGitHubHttpRepositoryReadGateway.js.map +1 -0
  40. package/dist/providers/github/adapters/createGitHubHttpRepositoryReadGateway.test.d.ts +2 -0
  41. package/dist/providers/github/adapters/createGitHubHttpRepositoryReadGateway.test.d.ts.map +1 -0
  42. package/dist/providers/github/adapters/createGitHubHttpRepositoryReadGateway.test.js +80 -0
  43. package/dist/providers/github/adapters/createGitHubHttpRepositoryReadGateway.test.js.map +1 -0
  44. package/dist/providers/github/definitions/GitHubRepositoryConnectionOptions.d.ts +0 -8
  45. package/dist/providers/github/definitions/GitHubRepositoryConnectionOptions.d.ts.map +1 -1
  46. package/dist/providers/github/definitions/GitHubRepositoryMaterializationOptions.d.ts +6 -0
  47. package/dist/providers/github/definitions/GitHubRepositoryMaterializationOptions.d.ts.map +1 -0
  48. package/dist/providers/github/definitions/GitHubRepositoryMaterializationOptions.js +2 -0
  49. package/dist/providers/github/definitions/GitHubRepositoryMaterializationOptions.js.map +1 -0
  50. package/dist/providers/github/definitions/GitHubRepositoryMaterializationResult.d.ts +19 -0
  51. package/dist/providers/github/definitions/GitHubRepositoryMaterializationResult.d.ts.map +1 -0
  52. package/dist/providers/github/definitions/GitHubRepositoryMaterializationResult.js +2 -0
  53. package/dist/providers/github/definitions/GitHubRepositoryMaterializationResult.js.map +1 -0
  54. package/dist/providers/github/ports/GitHubRepositoryReadGateway.d.ts +31 -0
  55. package/dist/providers/github/ports/GitHubRepositoryReadGateway.d.ts.map +1 -0
  56. package/dist/providers/github/ports/GitHubRepositoryReadGateway.js +2 -0
  57. package/dist/providers/github/ports/GitHubRepositoryReadGateway.js.map +1 -0
  58. package/dist/providers/github/services/connectGitHubRepositoryAsync.d.ts +10 -1
  59. package/dist/providers/github/services/connectGitHubRepositoryAsync.d.ts.map +1 -1
  60. package/dist/providers/github/services/connectGitHubRepositoryAsync.js.map +1 -1
  61. package/dist/providers/github/services/connectGitHubRepositoryAsync.test.js.map +1 -1
  62. package/dist/providers/github/services/materializeGitHubRepositoryAsync.d.ts +5 -0
  63. package/dist/providers/github/services/materializeGitHubRepositoryAsync.d.ts.map +1 -0
  64. package/dist/providers/github/services/materializeGitHubRepositoryAsync.js +7 -0
  65. package/dist/providers/github/services/materializeGitHubRepositoryAsync.js.map +1 -0
  66. package/dist/providers/github/services/materializeGitHubRepositoryWithGatewayAsync.d.ts +6 -0
  67. package/dist/providers/github/services/materializeGitHubRepositoryWithGatewayAsync.d.ts.map +1 -0
  68. package/dist/providers/github/services/materializeGitHubRepositoryWithGatewayAsync.js +219 -0
  69. package/dist/providers/github/services/materializeGitHubRepositoryWithGatewayAsync.js.map +1 -0
  70. package/dist/providers/github/services/materializeGitHubRepositoryWithGatewayAsync.test.d.ts +2 -0
  71. package/dist/providers/github/services/materializeGitHubRepositoryWithGatewayAsync.test.d.ts.map +1 -0
  72. package/dist/providers/github/services/materializeGitHubRepositoryWithGatewayAsync.test.js +174 -0
  73. package/dist/providers/github/services/materializeGitHubRepositoryWithGatewayAsync.test.js.map +1 -0
  74. package/package.json +9 -8
  75. package/dist/readme-usage.d.ts +0 -2
  76. package/dist/readme-usage.d.ts.map +0 -1
  77. package/dist/readme-usage.js +0 -32
  78. package/dist/readme-usage.js.map +0 -1
@@ -0,0 +1,219 @@
1
+ import { chmod, mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
2
+ import { tmpdir } from 'node:os';
3
+ import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
4
+ /*** Materialize a GitHub repository through an injected read gateway for deterministic testing. */
5
+ export async function materializeGitHubRepositoryWithGatewayAsync(options, gateway) {
6
+ const parsed = parseGitHubRepositoryUrl(options.url);
7
+ const repository = await gateway.inspectRepositoryAsync(parsed.target);
8
+ const explicitRef = normalizeRef(options.ref);
9
+ const revision = explicitRef === undefined
10
+ ? await resolveUrlRevisionAsync(gateway, parsed, repository.defaultBranch)
11
+ : await gateway.resolveRevisionAsync(parsed.target, explicitRef);
12
+ const tree = await gateway.readTreeAsync(parsed.target, revision.treeSha);
13
+ const validated = validateTree(tree.entries, tree.truncated);
14
+ const rootPath = await createMaterializationRootAsync(options.destinationPath);
15
+ try {
16
+ await writeFileBatchesAsync(gateway, parsed.target, revision.commitSha, rootPath, validated.files);
17
+ }
18
+ catch (error) {
19
+ await rm(rootPath, { force: true, recursive: true });
20
+ throw error;
21
+ }
22
+ return {
23
+ rootPath,
24
+ revision: revision.commitSha,
25
+ diagnostics: validated.diagnostics,
26
+ repository: {
27
+ owner: parsed.target.owner,
28
+ name: parsed.target.name,
29
+ url: repository.url,
30
+ defaultBranch: repository.defaultBranch,
31
+ },
32
+ cleanupAsync: () => rm(rootPath, { force: true, recursive: true }),
33
+ };
34
+ }
35
+ const MAX_FILE_COUNT = 20_000;
36
+ const MAX_TOTAL_BYTES = 256 * 1024 * 1024;
37
+ const WRITE_BATCH_SIZE = 8;
38
+ /*** Parse a normal GitHub repository, tree, blob, or commit URL into repository and ref intent. */
39
+ function parseGitHubRepositoryUrl(value) {
40
+ const url = parseRepositoryUrl(value);
41
+ assertGitHubRepositoryUrl(url);
42
+ const segments = decodePathSegments(url);
43
+ if (segments.length < 2) {
44
+ throw invalidRepositoryUrl();
45
+ }
46
+ const [owner = '', repositorySegment = '', route] = segments;
47
+ const name = repositorySegment.endsWith('.git')
48
+ ? repositorySegment.slice(0, -4)
49
+ : repositorySegment;
50
+ assertRepositoryIdentity(owner, name);
51
+ const routeSegments = segments.slice(3);
52
+ if (route === undefined) {
53
+ return {
54
+ target: { owner, name, url: `https://github.com/${owner}/${name}` },
55
+ refCandidates: [],
56
+ };
57
+ }
58
+ if (route === 'commit') {
59
+ if (routeSegments.length !== 1)
60
+ throw invalidRepositoryUrl();
61
+ return {
62
+ target: { owner, name, url: `https://github.com/${owner}/${name}` },
63
+ refCandidates: [routeSegments[0] ?? ''],
64
+ };
65
+ }
66
+ if (route !== 'tree' && route !== 'blob')
67
+ throw invalidRepositoryUrl();
68
+ if (routeSegments.length === 0)
69
+ throw invalidRepositoryUrl();
70
+ return {
71
+ target: { owner, name, url: `https://github.com/${owner}/${name}` },
72
+ refCandidates: createRefCandidates(routeSegments),
73
+ };
74
+ }
75
+ /*** Parse a repository URL while preserving the original parsing failure as the cause. */
76
+ function parseRepositoryUrl(value) {
77
+ try {
78
+ return new URL(value);
79
+ }
80
+ catch (error) {
81
+ throw new Error('Repository URL must be a valid GitHub HTTPS URL.', { cause: error });
82
+ }
83
+ }
84
+ /*** Reject non-GitHub origins and embedded credentials while ignoring normal page query/anchor state. */
85
+ function assertGitHubRepositoryUrl(url) {
86
+ if (url.protocol !== 'https:' ||
87
+ url.hostname.toLowerCase() !== 'github.com' ||
88
+ url.username !== '' ||
89
+ url.password !== '') {
90
+ throw invalidRepositoryUrl();
91
+ }
92
+ }
93
+ /*** Decode normal GitHub path segments and reject malformed encoded paths. */
94
+ function decodePathSegments(url) {
95
+ try {
96
+ return url.pathname
97
+ .split('/')
98
+ .filter(Boolean)
99
+ .map((segment) => decodeURIComponent(segment));
100
+ }
101
+ catch (error) {
102
+ throw new Error('Repository URL contains an invalid encoded path.', { cause: error });
103
+ }
104
+ }
105
+ /*** Build longest-first ref candidates so slash-containing branch/tag names resolve like GitHub URLs. */
106
+ function createRefCandidates(segments) {
107
+ return Array.from({ length: segments.length }, (_, index) => segments.slice(0, segments.length - index).join('/'));
108
+ }
109
+ /*** Resolve URL-derived ref candidates, falling back to the repository default branch. */
110
+ async function resolveUrlRevisionAsync(gateway, parsed, defaultBranch) {
111
+ if (parsed.refCandidates.length === 0) {
112
+ return gateway.resolveRevisionAsync(parsed.target, defaultBranch);
113
+ }
114
+ for (const candidate of parsed.refCandidates) {
115
+ try {
116
+ return await gateway.resolveRevisionAsync(parsed.target, candidate);
117
+ }
118
+ catch {
119
+ // GitHub tree/blob URLs can contain both slash-containing refs and trailing repository paths.
120
+ }
121
+ }
122
+ throw new Error('GitHub repository URL does not resolve to a branch, tag, or commit.');
123
+ }
124
+ /*** Create the consistent public error for unsupported GitHub URL shapes. */
125
+ function invalidRepositoryUrl() {
126
+ return new Error('Repository URL must be a GitHub repository, tree, blob, or commit HTTPS URL.');
127
+ }
128
+ /*** Validate canonical GitHub owner and repository path segments. */
129
+ function assertRepositoryIdentity(owner, name) {
130
+ if (!/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,98}[A-Za-z0-9])?$/u.test(owner)) {
131
+ throw new Error('GitHub repository owner is invalid.');
132
+ }
133
+ if (!/^[A-Za-z0-9._-]{1,100}$/u.test(name) || name === '.' || name === '..') {
134
+ throw new Error('GitHub repository name is invalid.');
135
+ }
136
+ }
137
+ /*** Normalize an optional requested ref while rejecting an explicitly empty value. */
138
+ function normalizeRef(value) {
139
+ if (value === undefined)
140
+ return undefined;
141
+ const normalized = value.trim();
142
+ if (normalized === '')
143
+ throw new Error('GitHub repository ref must not be empty.');
144
+ return normalized;
145
+ }
146
+ /*** Reject incomplete or unexpectedly large remote trees while safely omitting symbolic links. */
147
+ function validateTree(entries, truncated) {
148
+ if (truncated) {
149
+ throw new Error('GitHub repository tree is truncated and cannot be materialized safely.');
150
+ }
151
+ const symlinks = entries.filter((entry) => entry.type === 'blob' && entry.mode === '120000');
152
+ const files = entries.filter((entry) => entry.type === 'blob' && entry.mode !== '120000');
153
+ if (files.length > MAX_FILE_COUNT) {
154
+ throw new Error(`GitHub repository exceeds the ${MAX_FILE_COUNT} file materialization limit.`);
155
+ }
156
+ const totalBytes = files.reduce((sum, entry) => {
157
+ if (entry.size === undefined) {
158
+ throw new Error(`GitHub repository file size is missing for ${entry.path}.`);
159
+ }
160
+ return sum + entry.size;
161
+ }, 0);
162
+ if (totalBytes > MAX_TOTAL_BYTES) {
163
+ throw new Error('GitHub repository exceeds the 256 MiB materialization limit.');
164
+ }
165
+ return {
166
+ files,
167
+ diagnostics: symlinks.map((entry) => ({
168
+ code: 'symlink-skipped',
169
+ severity: 'warning',
170
+ path: entry.path,
171
+ message: 'Symbolic link skipped during safe GitHub repository materialization.',
172
+ })),
173
+ };
174
+ }
175
+ /*** Create either an isolated temporary root or one explicitly requested empty destination. */
176
+ async function createMaterializationRootAsync(destinationPath) {
177
+ if (destinationPath === undefined) {
178
+ return mkdtemp(join(tmpdir(), 'ankhorage-repository-'));
179
+ }
180
+ const rootPath = resolve(destinationPath);
181
+ await mkdir(dirname(rootPath), { recursive: true });
182
+ await mkdir(rootPath);
183
+ return rootPath;
184
+ }
185
+ /*** Download and write bounded groups so large repositories do not fan out unbounded requests. */
186
+ async function writeFileBatchesAsync(gateway, target, revision, rootPath, entries) {
187
+ const batches = Array.from({ length: Math.ceil(entries.length / WRITE_BATCH_SIZE) }, (_, index) => entries.slice(index * WRITE_BATCH_SIZE, (index + 1) * WRITE_BATCH_SIZE));
188
+ for (const batch of batches) {
189
+ await Promise.all(batch.map((entry) => materializeFileAsync(gateway, target, revision, rootPath, entry)));
190
+ }
191
+ }
192
+ /*** Materialize one ordinary Git blob beneath the isolated root and preserve executable mode. */
193
+ async function materializeFileAsync(gateway, target, revision, rootPath, entry) {
194
+ const destination = resolveMaterializationPath(rootPath, entry.path);
195
+ const content = await gateway.readFileAsync(target, revision, entry.path);
196
+ if (entry.size !== content.byteLength) {
197
+ throw new Error(`GitHub repository file size changed while reading ${entry.path}.`);
198
+ }
199
+ await mkdir(dirname(destination), { recursive: true });
200
+ await writeFile(destination, content);
201
+ if (entry.mode === '100755')
202
+ await chmod(destination, 0o755);
203
+ }
204
+ /*** Resolve one provider path while rejecting traversal outside the materialization root. */
205
+ function resolveMaterializationPath(rootPath, repositoryPath) {
206
+ if (repositoryPath.trim() === '' ||
207
+ repositoryPath.includes('\\') ||
208
+ repositoryPath.startsWith('/') ||
209
+ repositoryPath.split('/').some((segment) => segment === '..' || segment === '')) {
210
+ throw new Error(`Unsafe GitHub repository path: ${repositoryPath}.`);
211
+ }
212
+ const destination = resolve(rootPath, ...repositoryPath.split('/'));
213
+ const child = relative(rootPath, destination);
214
+ if (child === '' || child === '..' || child.startsWith(`..${sep}`) || isAbsolute(child)) {
215
+ throw new Error(`Unsafe GitHub repository path: ${repositoryPath}.`);
216
+ }
217
+ return destination;
218
+ }
219
+ //# sourceMappingURL=materializeGitHubRepositoryWithGatewayAsync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"materializeGitHubRepositoryWithGatewayAsync.js","sourceRoot":"","sources":["../../../../src/providers/github/services/materializeGitHubRepositoryWithGatewayAsync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=materializeGitHubRepositoryWithGatewayAsync.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"materializeGitHubRepositoryWithGatewayAsync.test.d.ts","sourceRoot":"","sources":["../../../../src/providers/github/services/materializeGitHubRepositoryWithGatewayAsync.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,174 @@
1
+ import { access, readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { expect, test } from 'bun:test';
4
+ import { materializeGitHubRepositoryWithGatewayAsync } from './materializeGitHubRepositoryWithGatewayAsync.js';
5
+ test('materializes an exact explicit GitHub revision and cleans up the isolated root', async () => {
6
+ const requestedRefs = [];
7
+ const gateway = createGateway({
8
+ requestedRefs,
9
+ files: {
10
+ 'package.json': '{"name":"demo"}\n',
11
+ 'src/index.ts': 'export const demo = true;\n',
12
+ },
13
+ });
14
+ const result = await materializeGitHubRepositoryWithGatewayAsync({ url: 'https://github.com/ankhorage/demo', ref: 'feature/read' }, gateway);
15
+ expect(requestedRefs).toEqual(['feature/read']);
16
+ expect(result.revision).toBe('commit-sha');
17
+ expect(result.diagnostics).toEqual([]);
18
+ expect(result.repository).toEqual({
19
+ owner: 'ankhorage',
20
+ name: 'demo',
21
+ url: 'https://github.com/ankhorage/demo',
22
+ defaultBranch: 'main',
23
+ });
24
+ expect(await readFile(join(result.rootPath, 'src/index.ts'), 'utf8')).toBe('export const demo = true;\n');
25
+ await result.cleanupAsync();
26
+ await expectMissingPathAsync(result.rootPath);
27
+ });
28
+ test('uses the remote default branch for a normal repository URL', async () => {
29
+ const requestedRefs = [];
30
+ const result = await materializeGitHubRepositoryWithGatewayAsync({ url: 'https://github.com/ankhorage/demo.git?tab=readme-ov-file#readme' }, createGateway({ requestedRefs, defaultBranch: 'develop', files: {} }));
31
+ expect(requestedRefs).toEqual(['develop']);
32
+ await result.cleanupAsync();
33
+ });
34
+ test('resolves slash-containing refs from normal GitHub tree URLs', async () => {
35
+ const requestedRefs = [];
36
+ const result = await materializeGitHubRepositoryWithGatewayAsync({ url: 'https://github.com/ankhorage/demo/tree/feature/read' }, createGateway({
37
+ requestedRefs,
38
+ acceptedRefs: ['feature/read'],
39
+ files: { 'src/index.ts': 'export {};\n' },
40
+ }));
41
+ expect(requestedRefs).toEqual(['feature/read']);
42
+ await result.cleanupAsync();
43
+ });
44
+ test('resolves a ref from normal GitHub blob URLs while ignoring the file path', async () => {
45
+ const requestedRefs = [];
46
+ const result = await materializeGitHubRepositoryWithGatewayAsync({ url: 'https://github.com/ankhorage/demo/blob/main/src/index.ts#L1' }, createGateway({
47
+ requestedRefs,
48
+ acceptedRefs: ['main'],
49
+ files: { 'src/index.ts': 'export {};\n' },
50
+ }));
51
+ expect(requestedRefs).toEqual(['main/src/index.ts', 'main/src', 'main']);
52
+ await result.cleanupAsync();
53
+ });
54
+ test('resolves normal GitHub commit URLs directly', async () => {
55
+ const requestedRefs = [];
56
+ const result = await materializeGitHubRepositoryWithGatewayAsync({ url: 'https://github.com/ankhorage/demo/commit/deadbeef' }, createGateway({
57
+ requestedRefs,
58
+ acceptedRefs: ['deadbeef'],
59
+ files: {},
60
+ }));
61
+ expect(requestedRefs).toEqual(['deadbeef']);
62
+ await result.cleanupAsync();
63
+ });
64
+ test('rejects traversal before downloading an unsafe repository file', async () => {
65
+ let reads = 0;
66
+ const gateway = createGateway({
67
+ files: { '../escape.ts': 'escape' },
68
+ onRead: () => {
69
+ reads += 1;
70
+ },
71
+ });
72
+ await expectFailureAsync(() => materializeGitHubRepositoryWithGatewayAsync({ url: 'https://github.com/ankhorage/demo' }, gateway), 'Unsafe GitHub repository path');
73
+ expect(reads).toBe(0);
74
+ });
75
+ test('rejects truncated GitHub trees before materialization', async () => {
76
+ const gateway = createGateway({ files: {}, truncated: true });
77
+ await expectFailureAsync(() => materializeGitHubRepositoryWithGatewayAsync({ url: 'https://github.com/ankhorage/demo' }, gateway), 'repository tree is truncated');
78
+ });
79
+ test('skips symbolic links with warnings without reading their target bytes', async () => {
80
+ const reads = [];
81
+ const gateway = {
82
+ ...createGateway({
83
+ files: { 'src/index.ts': 'export {};\n' },
84
+ onReadPath: (path) => reads.push(path),
85
+ }),
86
+ readTreeAsync: () => Promise.resolve({
87
+ truncated: false,
88
+ entries: [
89
+ {
90
+ mode: '120000',
91
+ path: 'CLAUDE.md',
92
+ sha: 'link-sha',
93
+ size: 9,
94
+ type: 'blob',
95
+ },
96
+ {
97
+ mode: '100644',
98
+ path: 'src/index.ts',
99
+ sha: 'file-sha',
100
+ size: 11,
101
+ type: 'blob',
102
+ },
103
+ ],
104
+ }),
105
+ };
106
+ const result = await materializeGitHubRepositoryWithGatewayAsync({ url: 'https://github.com/ankhorage/demo' }, gateway);
107
+ expect(reads).toEqual(['src/index.ts']);
108
+ expect(await readFile(join(result.rootPath, 'src/index.ts'), 'utf8')).toBe('export {};\n');
109
+ expect(result.diagnostics).toEqual([
110
+ {
111
+ code: 'symlink-skipped',
112
+ severity: 'warning',
113
+ path: 'CLAUDE.md',
114
+ message: 'Symbolic link skipped during safe GitHub repository materialization.',
115
+ },
116
+ ]);
117
+ await expectMissingPathAsync(join(result.rootPath, 'CLAUDE.md'));
118
+ await result.cleanupAsync();
119
+ });
120
+ function createGateway(options) {
121
+ const files = new Map(Object.entries(options.files));
122
+ const entries = [...files].map(([path, fileContent], index) => ({
123
+ mode: '100644',
124
+ path,
125
+ sha: `blob-${index}`,
126
+ size: Buffer.byteLength(fileContent),
127
+ type: 'blob',
128
+ }));
129
+ return {
130
+ inspectRepositoryAsync: (target) => Promise.resolve({
131
+ defaultBranch: options.defaultBranch ?? 'main',
132
+ url: target.url,
133
+ }),
134
+ resolveRevisionAsync: (_target, ref) => {
135
+ options.requestedRefs?.push(ref);
136
+ if (options.acceptedRefs !== undefined && !options.acceptedRefs.includes(ref)) {
137
+ return Promise.reject(new Error(`Unknown fixture ref: ${ref}`));
138
+ }
139
+ return Promise.resolve({ commitSha: 'commit-sha', treeSha: 'tree-sha' });
140
+ },
141
+ readTreeAsync: () => Promise.resolve({
142
+ entries,
143
+ truncated: options.truncated ?? false,
144
+ }),
145
+ readFileAsync: (_target, _revision, path) => {
146
+ options.onRead?.();
147
+ options.onReadPath?.(path);
148
+ const fileContent = files.get(path);
149
+ if (fileContent === undefined)
150
+ throw new Error(`Missing fixture: ${path}`);
151
+ return Promise.resolve(Buffer.from(fileContent));
152
+ },
153
+ };
154
+ }
155
+ async function expectFailureAsync(operation, message) {
156
+ try {
157
+ await operation();
158
+ throw new Error('Expected operation to fail.');
159
+ }
160
+ catch (error) {
161
+ expect(error).toBeInstanceOf(Error);
162
+ expect(error.message).toContain(message);
163
+ }
164
+ }
165
+ async function expectMissingPathAsync(path) {
166
+ try {
167
+ await access(path);
168
+ throw new Error('Expected path to be missing.');
169
+ }
170
+ catch (error) {
171
+ expect(error).toBeInstanceOf(Error);
172
+ }
173
+ }
174
+ //# sourceMappingURL=materializeGitHubRepositoryWithGatewayAsync.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"materializeGitHubRepositoryWithGatewayAsync.test.js","sourceRoot":"","sources":["../../../../src/providers/github/services/materializeGitHubRepositoryWithGatewayAsync.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ankhorage/repository",
3
- "version": "0.4.19",
3
+ "version": "0.5.1",
4
4
  "description": "Standalone repository capability for connecting and managing an app project's source repository.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -54,7 +54,8 @@
54
54
  "category": "repository",
55
55
  "provider": "./dist/cli/index.js",
56
56
  "capabilities": [
57
- "repository.connect"
57
+ "repository.connect",
58
+ "repository.materialize"
58
59
  ]
59
60
  },
60
61
  "publishConfig": {
@@ -75,15 +76,15 @@
75
76
  "knip:check": "ankhorage-knip"
76
77
  },
77
78
  "devDependencies": {
78
- "@ankhorage/devtools": "^1.18.5",
79
- "@ankhorage/paradox": "^0.1.26",
80
- "@types/bun": "^1.4.1",
81
- "@types/node": "^24.13.3",
79
+ "@ankhorage/devtools": "^2.1.6",
80
+ "@ankhorage/paradox": "^0.2.27",
81
+ "@types/bun": "^1.4.2",
82
+ "@types/node": "^26.6.4",
82
83
  "typescript": "~6.0.3"
83
84
  },
84
85
  "packageManager": "bun@1.4.2",
85
86
  "dependencies": {
86
- "@ankhorage/contracts": "^22.8.2",
87
- "ignore": "^7.0.8"
87
+ "@ankhorage/contracts": "^22.8.99",
88
+ "ignore": "^7.0.12"
88
89
  }
89
90
  }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=readme-usage.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"readme-usage.d.ts","sourceRoot":"","sources":["../src/readme-usage.ts"],"names":[],"mappings":""}
@@ -1,32 +0,0 @@
1
- /***
2
- * Connect a project folder to its source repository
3
- *
4
- * `@ankhorage/repository` consumes only the project's `RepositoryManifest` slice and delegates
5
- * GitHub operations to the local authenticated `gh` adapter. It creates a missing repository,
6
- * publishes the project snapshot to `main`, stores only the repository slice in
7
- * `.ankhorage/repository.json`, and refuses unrelated existing repositories.
8
- *
9
- * See [`examples/basic-usage.ts`](../examples/basic-usage.ts) for a complete programmatic example.
10
- *
11
- * @usage
12
- */
13
- import { connectRepositoryAsync } from '@ankhorage/repository';
14
- const result = await connectRepositoryAsync({
15
- projectPath: './my-project',
16
- repository: {
17
- provider: 'github',
18
- owner: 'ankhorage',
19
- name: 'my-project',
20
- url: 'https://github.com/ankhorage/my-project',
21
- defaultBranch: 'main',
22
- },
23
- visibility: 'private',
24
- });
25
- if (result.status === 'conflict' || result.status === 'recoverable-failure') {
26
- console.error(`${result.status}: ${result.message}`);
27
- process.exitCode = 1;
28
- }
29
- else {
30
- console.log(JSON.stringify(result));
31
- }
32
- //# sourceMappingURL=readme-usage.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"readme-usage.js","sourceRoot":"","sources":["../src/readme-usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC;IAC1C,WAAW,EAAE,cAAc;IAC3B,UAAU,EAAE;QACV,QAAQ,EAAE,QAAQ;QAClB,KAAK,EAAE,WAAW;QAClB,IAAI,EAAE,YAAY;QAClB,GAAG,EAAE,yCAAyC;QAC9C,aAAa,EAAE,MAAM;KACtB;IACD,UAAU,EAAE,SAAS;CACtB,CAAC,CAAC;AAEH,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,IAAI,MAAM,CAAC,MAAM,KAAK,qBAAqB,EAAE,CAAC;IAC5E,OAAO,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IACrD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC;KAAM,CAAC;IACN,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;AACtC,CAAC"}