dsh-gitnexus-plus 0.1.3 → 0.1.4
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/README-CN.md +22 -7
- package/README.md +41 -8
- package/lib/bin/graph-helper.d.ts +21 -0
- package/lib/bin/graph-helper.d.ts.map +1 -0
- package/lib/bin/graph-helper.js +71 -0
- package/lib/bin/graph-helper.js.map +1 -0
- package/lib/client.js +4081 -2370
- package/lib/gitnexus/analyze.d.ts +48 -8
- package/lib/gitnexus/analyze.d.ts.map +1 -1
- package/lib/gitnexus/analyze.js +345 -84
- package/lib/gitnexus/analyze.js.map +1 -1
- package/lib/gitnexus/commands.d.ts +8 -1
- package/lib/gitnexus/commands.d.ts.map +1 -1
- package/lib/gitnexus/commands.js +19 -0
- package/lib/gitnexus/commands.js.map +1 -1
- package/lib/gitnexus/delta.d.ts +144 -0
- package/lib/gitnexus/delta.d.ts.map +1 -0
- package/lib/gitnexus/delta.js +347 -0
- package/lib/gitnexus/delta.js.map +1 -0
- package/lib/gitnexus/git-activity.d.ts +13 -21
- package/lib/gitnexus/git-activity.d.ts.map +1 -1
- package/lib/gitnexus/git-activity.js +60 -26
- package/lib/gitnexus/git-activity.js.map +1 -1
- package/lib/gitnexus/graph.d.ts +126 -0
- package/lib/gitnexus/graph.d.ts.map +1 -0
- package/lib/gitnexus/graph.js +472 -0
- package/lib/gitnexus/graph.js.map +1 -0
- package/lib/gitnexus/root.d.ts +0 -3
- package/lib/gitnexus/root.d.ts.map +1 -1
- package/lib/gitnexus/root.js +64 -5
- package/lib/gitnexus/root.js.map +1 -1
- package/lib/gitnexus/search.d.ts +21 -8
- package/lib/gitnexus/search.d.ts.map +1 -1
- package/lib/gitnexus/search.js +87 -13
- package/lib/gitnexus/search.js.map +1 -1
- package/lib/index.d.ts +6 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +165 -3
- package/lib/index.js.map +1 -1
- package/lib/routes/analyze.d.ts +3 -2
- package/lib/routes/analyze.d.ts.map +1 -1
- package/lib/routes/analyze.js +8 -2
- package/lib/routes/analyze.js.map +1 -1
- package/lib/routes/delta.d.ts +22 -0
- package/lib/routes/delta.d.ts.map +1 -0
- package/lib/routes/delta.js +50 -0
- package/lib/routes/delta.js.map +1 -0
- package/lib/routes/file-diff.d.ts +19 -0
- package/lib/routes/file-diff.d.ts.map +1 -0
- package/lib/routes/file-diff.js +69 -0
- package/lib/routes/file-diff.js.map +1 -0
- package/lib/routes/graph.d.ts +22 -0
- package/lib/routes/graph.d.ts.map +1 -0
- package/lib/routes/graph.js +71 -0
- package/lib/routes/graph.js.map +1 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/routes/analyze.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3F;;;GAGG;AACH,MAAM,eAAe,GAAwB,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;AAaxF;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,SAA2B,EAAE,IAAsB;IACnF,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QAC9C,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,eAAe,CAAC;YAAE,OAAO;QAElD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAC;QACxD,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACxC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,kCAAkC,EAAE,CAAC,CAAC;YACrG,OAAO;QACT,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAEnC,IAAI,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC;YAAE,OAAO;QAEjC,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC1B,6EAA6E;YAC7E,+EAA+E;YAC/E,6BAA6B;YAC7B,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC;gBAAE,OAAO;YACtC,4EAA4E;YAC5E,8EAA8E;YAC9E,oEAAoE;YACpE,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,GAAG,CAAC;
|
|
1
|
+
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/routes/analyze.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `GET /api/gitnexus/delta?repo=<project>` — "is a refresh worth running?"
|
|
3
|
+
*
|
|
4
|
+
* Read-only on purpose, and separated from the analyze route for the same reason that
|
|
5
|
+
* one is separate from coverage: the two halves have different method policies. This
|
|
6
|
+
* route answers a question about the working tree; it never starts, cancels or writes
|
|
7
|
+
* anything, so it takes only the read guard.
|
|
8
|
+
*
|
|
9
|
+
* The panel calls it before offering the refresh control, which is why it has to be
|
|
10
|
+
* fast. It is: on a clean working tree the candidate set is empty and no file is read.
|
|
11
|
+
* The engine's own bound is a candidate cap, not a time budget — see `gitnexus/delta.ts`.
|
|
12
|
+
*/
|
|
13
|
+
import type { WebServerService } from '@deepseek-ai/cordis';
|
|
14
|
+
import type { DeltaReport } from '../gitnexus/delta.js';
|
|
15
|
+
export interface DeltaRouteDeps {
|
|
16
|
+
read: (repoPath: string) => Promise<DeltaReport>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* @returns disposer that unregisters the route
|
|
20
|
+
*/
|
|
21
|
+
export declare function mountDeltaRoute(webServer: WebServerService, deps: DeltaRouteDeps): () => void;
|
|
22
|
+
//# sourceMappingURL=delta.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delta.d.ts","sourceRoot":"","sources":["../../src/routes/delta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAIxD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;CAClD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,gBAAgB,EAAE,IAAI,EAAE,cAAc,GAAG,MAAM,IAAI,CAgC7F"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `GET /api/gitnexus/delta?repo=<project>` — "is a refresh worth running?"
|
|
3
|
+
*
|
|
4
|
+
* Read-only on purpose, and separated from the analyze route for the same reason that
|
|
5
|
+
* one is separate from coverage: the two halves have different method policies. This
|
|
6
|
+
* route answers a question about the working tree; it never starts, cancels or writes
|
|
7
|
+
* anything, so it takes only the read guard.
|
|
8
|
+
*
|
|
9
|
+
* The panel calls it before offering the refresh control, which is why it has to be
|
|
10
|
+
* fast. It is: on a clean working tree the candidate set is empty and no file is read.
|
|
11
|
+
* The engine's own bound is a candidate cap, not a time budget — see `gitnexus/delta.ts`.
|
|
12
|
+
*/
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
import { isProjectRoot } from '../gitnexus/index-meta.js';
|
|
15
|
+
import { guardHandler, passGuard, answerHead, sendJson } from './guard.js';
|
|
16
|
+
const DELTA_METHODS = new Set(['GET', 'HEAD']);
|
|
17
|
+
/**
|
|
18
|
+
* @returns disposer that unregisters the route
|
|
19
|
+
*/
|
|
20
|
+
export function mountDeltaRoute(webServer, deps) {
|
|
21
|
+
const handler = guardHandler(async (req, res) => {
|
|
22
|
+
if (!passGuard(req, res, DELTA_METHODS))
|
|
23
|
+
return;
|
|
24
|
+
const url = new URL(req.url ?? '/', 'http://127.0.0.1');
|
|
25
|
+
const repo = url.searchParams.get('repo');
|
|
26
|
+
if (repo === null || repo.trim() === '') {
|
|
27
|
+
sendJson(res, 400, { ok: false, code: 'missing-repo', message: 'repo query parameter is required' });
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const absRepo = path.resolve(repo);
|
|
31
|
+
// Same bound as the coverage route: a project root, so this cannot be used to
|
|
32
|
+
// probe arbitrary directories. A project without an index is *not* refused here:
|
|
33
|
+
// "no index yet" is an answer the panel renders, and the engine reports it as
|
|
34
|
+
// `comparable: false` with the reason.
|
|
35
|
+
if (!(await isProjectRoot(absRepo))) {
|
|
36
|
+
sendJson(res, 404, {
|
|
37
|
+
ok: false,
|
|
38
|
+
code: 'not-a-project',
|
|
39
|
+
message: 'directory is neither a GitNexus index nor a git repository root',
|
|
40
|
+
});
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (answerHead(req, res))
|
|
44
|
+
return;
|
|
45
|
+
const report = await deps.read(absRepo);
|
|
46
|
+
sendJson(res, 200, { ok: true, delta: report, readAt: new Date().toISOString() });
|
|
47
|
+
});
|
|
48
|
+
return webServer.register({ kind: 'prefix', path: '/api/gitnexus/delta', handler });
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=delta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delta.js","sourceRoot":"","sources":["../../src/routes/delta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3E,MAAM,aAAa,GAAwB,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;AAMpE;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,SAA2B,EAAE,IAAoB;IAC/E,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QAC9C,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,aAAa,CAAC;YAAE,OAAO;QAEhD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAC;QACxD,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACxC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,kCAAkC,EAAE,CAAC,CAAC;YACrG,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACnC,8EAA8E;QAC9E,iFAAiF;QACjF,8EAA8E;QAC9E,uCAAuC;QACvC,IAAI,CAAC,CAAC,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;YACpC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;gBACjB,EAAE,EAAE,KAAK;gBACT,IAAI,EAAE,eAAe;gBACrB,OAAO,EAAE,iEAAiE;aAC3E,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,IAAI,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC;YAAE,OAAO;QAEjC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IACpF,CAAC,CAAC,CAAC;IAEH,OAAO,SAAS,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,qBAAqB,EAAE,OAAO,EAAE,CAAC,CAAC;AACtF,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `GET /api/gitnexus/file-diff?repo=<project>&path=<file>&sha=<commit>`
|
|
3
|
+
*
|
|
4
|
+
* The patch behind one commit's effect on one file. Split from file-history because the
|
|
5
|
+
* two cost differently: the timeline is a `git log`, and the patch is a `git show` that
|
|
6
|
+
* can carry a whole minified file. The client asks for it only when the reader expands a
|
|
7
|
+
* commit.
|
|
8
|
+
*
|
|
9
|
+
* Read-only. The path is resolved inside the project root and the sha is checked against
|
|
10
|
+
* a hash shape before it reaches git.
|
|
11
|
+
*/
|
|
12
|
+
import type { WebServerService } from '@deepseek-ai/cordis';
|
|
13
|
+
import type { CommitDiff } from '../gitnexus/git-activity.js';
|
|
14
|
+
export interface FileDiffRouteDeps {
|
|
15
|
+
read: (repoPath: string, filePath: string, sha: string) => Promise<CommitDiff>;
|
|
16
|
+
}
|
|
17
|
+
/** @returns disposer that unregisters the route */
|
|
18
|
+
export declare function mountFileDiffRoute(webServer: WebServerService, deps: FileDiffRouteDeps): () => void;
|
|
19
|
+
//# sourceMappingURL=file-diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-diff.d.ts","sourceRoot":"","sources":["../../src/routes/file-diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CAChF;AAED,mDAAmD;AACnD,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,gBAAgB,EAC3B,IAAI,EAAE,iBAAiB,GACtB,MAAM,IAAI,CA2DZ"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `GET /api/gitnexus/file-diff?repo=<project>&path=<file>&sha=<commit>`
|
|
3
|
+
*
|
|
4
|
+
* The patch behind one commit's effect on one file. Split from file-history because the
|
|
5
|
+
* two cost differently: the timeline is a `git log`, and the patch is a `git show` that
|
|
6
|
+
* can carry a whole minified file. The client asks for it only when the reader expands a
|
|
7
|
+
* commit.
|
|
8
|
+
*
|
|
9
|
+
* Read-only. The path is resolved inside the project root and the sha is checked against
|
|
10
|
+
* a hash shape before it reaches git.
|
|
11
|
+
*/
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import { isProjectRoot } from '../gitnexus/index-meta.js';
|
|
14
|
+
import { guardHandler, passGuard, answerHead, sendJson } from './guard.js';
|
|
15
|
+
/** @returns disposer that unregisters the route */
|
|
16
|
+
export function mountFileDiffRoute(webServer, deps) {
|
|
17
|
+
const handler = guardHandler(async (req, res) => {
|
|
18
|
+
if (!passGuard(req, res))
|
|
19
|
+
return;
|
|
20
|
+
const url = new URL(req.url ?? '/', 'http://127.0.0.1');
|
|
21
|
+
const repo = url.searchParams.get('repo');
|
|
22
|
+
const file = url.searchParams.get('path');
|
|
23
|
+
const sha = url.searchParams.get('sha');
|
|
24
|
+
if (repo === null ||
|
|
25
|
+
repo.trim() === '' ||
|
|
26
|
+
file === null ||
|
|
27
|
+
file.trim() === '' ||
|
|
28
|
+
sha === null ||
|
|
29
|
+
!/^[0-9a-fA-F]{7,40}$/.test(sha.trim())) {
|
|
30
|
+
sendJson(res, 400, {
|
|
31
|
+
ok: false,
|
|
32
|
+
code: 'missing-params',
|
|
33
|
+
message: 'repo, path and a 7–40 character hex sha are required',
|
|
34
|
+
});
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const absRepo = path.resolve(repo);
|
|
38
|
+
if (!(await isProjectRoot(absRepo))) {
|
|
39
|
+
sendJson(res, 404, {
|
|
40
|
+
ok: false,
|
|
41
|
+
code: 'not-a-project',
|
|
42
|
+
message: 'directory is neither a GitNexus index nor a git repository root',
|
|
43
|
+
});
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const relative = file.trim();
|
|
47
|
+
const prefix = absRepo.endsWith(path.sep) ? absRepo : `${absRepo}${path.sep}`;
|
|
48
|
+
const absolute = path.resolve(absRepo, relative);
|
|
49
|
+
// Windows paths compare case-insensitively; normalising both sides avoids a
|
|
50
|
+
// false "outside project" for a path the caller spelled with another drive case.
|
|
51
|
+
const inside = process.platform === 'win32'
|
|
52
|
+
? absolute.toLowerCase().startsWith(prefix.toLowerCase())
|
|
53
|
+
: absolute.startsWith(prefix);
|
|
54
|
+
if (!inside) {
|
|
55
|
+
sendJson(res, 400, {
|
|
56
|
+
ok: false,
|
|
57
|
+
code: 'invalid-path',
|
|
58
|
+
message: 'path must resolve inside the project root',
|
|
59
|
+
});
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (answerHead(req, res))
|
|
63
|
+
return;
|
|
64
|
+
const diff = await deps.read(absRepo, relative, sha.trim());
|
|
65
|
+
sendJson(res, 200, { ok: true, ...diff, readAt: new Date().toISOString() });
|
|
66
|
+
});
|
|
67
|
+
return webServer.register({ kind: 'prefix', path: '/api/gitnexus/file-diff', handler });
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=file-diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-diff.js","sourceRoot":"","sources":["../../src/routes/file-diff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `GET /api/gitnexus/graph?repo=<project>&view=communities|community&id=<community>`
|
|
3
|
+
*
|
|
4
|
+
* The read-only endpoint behind the panel's graph view. Two views, both bounded on the
|
|
5
|
+
* server: the browser never sends Cypher and never chooses how much of the graph to
|
|
6
|
+
* load — it picks one of two projections and the budgets are applied here.
|
|
7
|
+
*
|
|
8
|
+
* `view` defaults to `communities` rather than erroring when absent: the overview is the
|
|
9
|
+
* only sensible default, and the panel's first request has no scope yet. An unknown view
|
|
10
|
+
* is a 400, not a silent fallback — a typo must not render a different graph than the
|
|
11
|
+
* caller asked for.
|
|
12
|
+
*/
|
|
13
|
+
import { type GraphProjection, type GraphView } from '../gitnexus/graph.js';
|
|
14
|
+
import type { WebServerService } from '@deepseek-ai/cordis';
|
|
15
|
+
export interface GraphRouteDeps {
|
|
16
|
+
project: (repoPath: string, view: GraphView, id: string | null) => Promise<GraphProjection>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* @returns disposer that unregisters the route
|
|
20
|
+
*/
|
|
21
|
+
export declare function mountGraphRoute(webServer: WebServerService, deps: GraphRouteDeps): () => void;
|
|
22
|
+
//# sourceMappingURL=graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/routes/graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EAA2B,KAAK,eAAe,EAAE,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAErG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAI5D,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;CAC7F;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,gBAAgB,EAAE,IAAI,EAAE,cAAc,GAAG,MAAM,IAAI,CAqD7F"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `GET /api/gitnexus/graph?repo=<project>&view=communities|community&id=<community>`
|
|
3
|
+
*
|
|
4
|
+
* The read-only endpoint behind the panel's graph view. Two views, both bounded on the
|
|
5
|
+
* server: the browser never sends Cypher and never chooses how much of the graph to
|
|
6
|
+
* load — it picks one of two projections and the budgets are applied here.
|
|
7
|
+
*
|
|
8
|
+
* `view` defaults to `communities` rather than erroring when absent: the overview is the
|
|
9
|
+
* only sensible default, and the panel's first request has no scope yet. An unknown view
|
|
10
|
+
* is a 400, not a silent fallback — a typo must not render a different graph than the
|
|
11
|
+
* caller asked for.
|
|
12
|
+
*/
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
import { isProjectRoot } from '../gitnexus/index-meta.js';
|
|
15
|
+
import { GraphError, isGraphView } from '../gitnexus/graph.js';
|
|
16
|
+
import { guardHandler, passGuard, answerHead, sendJson } from './guard.js';
|
|
17
|
+
const GRAPH_METHODS = new Set(['GET', 'HEAD']);
|
|
18
|
+
/**
|
|
19
|
+
* @returns disposer that unregisters the route
|
|
20
|
+
*/
|
|
21
|
+
export function mountGraphRoute(webServer, deps) {
|
|
22
|
+
const handler = guardHandler(async (req, res) => {
|
|
23
|
+
if (!passGuard(req, res, GRAPH_METHODS))
|
|
24
|
+
return;
|
|
25
|
+
const url = new URL(req.url ?? '/', 'http://127.0.0.1');
|
|
26
|
+
const repo = url.searchParams.get('repo');
|
|
27
|
+
if (repo === null || repo.trim() === '') {
|
|
28
|
+
sendJson(res, 400, { ok: false, code: 'missing-repo', message: 'repo query parameter is required' });
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const rawView = url.searchParams.get('view');
|
|
32
|
+
const view = rawView === null || rawView === '' ? 'communities' : rawView;
|
|
33
|
+
if (!isGraphView(view)) {
|
|
34
|
+
sendJson(res, 400, {
|
|
35
|
+
ok: false,
|
|
36
|
+
code: 'invalid-view',
|
|
37
|
+
message: 'view must be one of: communities, community',
|
|
38
|
+
});
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const absRepo = path.resolve(repo);
|
|
42
|
+
// Same bound as every other read route: a project root, so this cannot be used to
|
|
43
|
+
// probe arbitrary directories.
|
|
44
|
+
if (!(await isProjectRoot(absRepo))) {
|
|
45
|
+
sendJson(res, 404, {
|
|
46
|
+
ok: false,
|
|
47
|
+
code: 'not-a-project',
|
|
48
|
+
message: 'directory is neither a GitNexus index nor a git repository root',
|
|
49
|
+
});
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (answerHead(req, res))
|
|
53
|
+
return;
|
|
54
|
+
const id = url.searchParams.get('id');
|
|
55
|
+
try {
|
|
56
|
+
const projection = await deps.project(absRepo, view, id === null || id === '' ? null : id);
|
|
57
|
+
sendJson(res, 200, { ok: true, projection, readAt: new Date().toISOString() });
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
if (error instanceof GraphError) {
|
|
61
|
+
sendJson(res, error.status, { ok: false, code: error.code, message: error.message });
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
// `guardHandler` turns anything else into a 500; rethrow so its single error
|
|
65
|
+
// path stays the only place that formats an unexpected failure.
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
return webServer.register({ kind: 'prefix', path: '/api/gitnexus/graph', handler });
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.js","sourceRoot":"","sources":["../../src/routes/graph.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-gitnexus-plus",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "DSH plugin: visualize a GitNexus project index, search
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"description": "DSH plugin: visualize a GitNexus project index and its communities, decide whether a refresh would change anything before running it, search symbols by keyword, report what the index left out, and run incremental or FTS-repair maintenance from a sidebar panel.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|