@aigne/afs-cli 1.11.0-beta.6 → 1.11.0-beta.7
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.cjs +27 -353
- package/dist/cli.d.cts +2 -1
- package/dist/cli.d.mts +2 -1
- package/dist/cli.mjs +28 -353
- package/dist/cli.mjs.map +1 -1
- package/dist/config/afs-loader.cjs +123 -0
- package/dist/config/afs-loader.d.cts +14 -0
- package/dist/config/afs-loader.d.cts.map +1 -0
- package/dist/config/afs-loader.d.mts +14 -0
- package/dist/config/afs-loader.d.mts.map +1 -0
- package/dist/config/afs-loader.mjs +122 -0
- package/dist/config/afs-loader.mjs.map +1 -0
- package/dist/config/loader.cjs +2 -2
- package/dist/config/loader.mjs +2 -2
- package/dist/{commands/mount.cjs → config/mount-commands.cjs} +13 -49
- package/dist/config/mount-commands.d.cts +20 -0
- package/dist/config/mount-commands.d.cts.map +1 -0
- package/dist/config/mount-commands.d.mts +20 -0
- package/dist/config/mount-commands.d.mts.map +1 -0
- package/dist/{commands/mount.mjs → config/mount-commands.mjs} +14 -49
- package/dist/config/mount-commands.mjs.map +1 -0
- package/dist/config/schema.cjs +9 -1
- package/dist/config/schema.mjs +9 -1
- package/dist/config/schema.mjs.map +1 -1
- package/dist/core/commands/delete.cjs +41 -0
- package/dist/core/commands/delete.d.cts +18 -0
- package/dist/core/commands/delete.d.cts.map +1 -0
- package/dist/core/commands/delete.d.mts +18 -0
- package/dist/core/commands/delete.d.mts.map +1 -0
- package/dist/core/commands/delete.mjs +42 -0
- package/dist/core/commands/delete.mjs.map +1 -0
- package/dist/core/commands/exec.cjs +95 -0
- package/dist/core/commands/exec.d.cts +26 -0
- package/dist/core/commands/exec.d.cts.map +1 -0
- package/dist/core/commands/exec.d.mts +26 -0
- package/dist/core/commands/exec.d.mts.map +1 -0
- package/dist/core/commands/exec.mjs +96 -0
- package/dist/core/commands/exec.mjs.map +1 -0
- package/dist/core/commands/explain.cjs +254 -0
- package/dist/core/commands/explain.d.cts +25 -0
- package/dist/core/commands/explain.d.cts.map +1 -0
- package/dist/core/commands/explain.d.mts +25 -0
- package/dist/core/commands/explain.d.mts.map +1 -0
- package/dist/core/commands/explain.mjs +255 -0
- package/dist/core/commands/explain.mjs.map +1 -0
- package/dist/core/commands/explore.cjs +30 -0
- package/dist/core/commands/explore.d.mts +2 -0
- package/dist/core/commands/explore.mjs +31 -0
- package/dist/core/commands/explore.mjs.map +1 -0
- package/dist/core/commands/index.cjs +36 -0
- package/dist/core/commands/index.d.cts +21 -0
- package/dist/core/commands/index.d.cts.map +1 -0
- package/dist/core/commands/index.d.mts +24 -0
- package/dist/core/commands/index.d.mts.map +1 -0
- package/dist/core/commands/index.mjs +37 -0
- package/dist/core/commands/index.mjs.map +1 -0
- package/dist/core/commands/ls.cjs +57 -0
- package/dist/core/commands/ls.d.cts +21 -0
- package/dist/core/commands/ls.d.cts.map +1 -0
- package/dist/core/commands/ls.d.mts +21 -0
- package/dist/core/commands/ls.d.mts.map +1 -0
- package/dist/core/commands/ls.mjs +58 -0
- package/dist/core/commands/ls.mjs.map +1 -0
- package/dist/core/commands/mount.cjs +139 -0
- package/dist/core/commands/mount.d.cts +33 -0
- package/dist/core/commands/mount.d.cts.map +1 -0
- package/dist/core/commands/mount.d.mts +33 -0
- package/dist/core/commands/mount.d.mts.map +1 -0
- package/dist/core/commands/mount.mjs +140 -0
- package/dist/core/commands/mount.mjs.map +1 -0
- package/dist/core/commands/read.cjs +48 -0
- package/dist/core/commands/read.d.cts +17 -0
- package/dist/core/commands/read.d.cts.map +1 -0
- package/dist/core/commands/read.d.mts +17 -0
- package/dist/core/commands/read.d.mts.map +1 -0
- package/dist/core/commands/read.mjs +49 -0
- package/dist/core/commands/read.mjs.map +1 -0
- package/dist/core/commands/search.cjs +40 -0
- package/dist/core/commands/search.d.mts +2 -0
- package/dist/core/commands/search.mjs +41 -0
- package/dist/core/commands/search.mjs.map +1 -0
- package/dist/core/commands/serve.cjs +242 -0
- package/dist/core/commands/serve.d.mts +2 -0
- package/dist/core/commands/serve.mjs +242 -0
- package/dist/core/commands/serve.mjs.map +1 -0
- package/dist/core/commands/stat.cjs +53 -0
- package/dist/core/commands/stat.d.cts +17 -0
- package/dist/core/commands/stat.d.cts.map +1 -0
- package/dist/core/commands/stat.d.mts +17 -0
- package/dist/core/commands/stat.d.mts.map +1 -0
- package/dist/core/commands/stat.mjs +54 -0
- package/dist/core/commands/stat.mjs.map +1 -0
- package/dist/core/commands/types.cjs +13 -0
- package/dist/core/commands/types.d.cts +54 -0
- package/dist/core/commands/types.d.cts.map +1 -0
- package/dist/core/commands/types.d.mts +54 -0
- package/dist/core/commands/types.d.mts.map +1 -0
- package/dist/core/commands/types.mjs +14 -0
- package/dist/core/commands/types.mjs.map +1 -0
- package/dist/core/commands/write.cjs +70 -0
- package/dist/core/commands/write.d.cts +20 -0
- package/dist/core/commands/write.d.cts.map +1 -0
- package/dist/core/commands/write.d.mts +20 -0
- package/dist/core/commands/write.d.mts.map +1 -0
- package/dist/core/commands/write.mjs +71 -0
- package/dist/core/commands/write.mjs.map +1 -0
- package/dist/core/executor/index.cjs +196 -0
- package/dist/core/executor/index.d.cts +77 -0
- package/dist/core/executor/index.d.cts.map +1 -0
- package/dist/core/executor/index.d.mts +77 -0
- package/dist/core/executor/index.d.mts.map +1 -0
- package/dist/core/executor/index.mjs +195 -0
- package/dist/core/executor/index.mjs.map +1 -0
- package/dist/core/formatters/delete.cjs +37 -0
- package/dist/core/formatters/delete.d.cts +18 -0
- package/dist/core/formatters/delete.d.cts.map +1 -0
- package/dist/core/formatters/delete.d.mts +18 -0
- package/dist/core/formatters/delete.d.mts.map +1 -0
- package/dist/core/formatters/delete.mjs +37 -0
- package/dist/core/formatters/delete.mjs.map +1 -0
- package/dist/core/formatters/exec.cjs +60 -0
- package/dist/core/formatters/exec.d.cts +18 -0
- package/dist/core/formatters/exec.d.cts.map +1 -0
- package/dist/core/formatters/exec.d.mts +18 -0
- package/dist/core/formatters/exec.d.mts.map +1 -0
- package/dist/core/formatters/exec.mjs +60 -0
- package/dist/core/formatters/exec.mjs.map +1 -0
- package/dist/core/formatters/explain.cjs +97 -0
- package/dist/core/formatters/explain.d.cts +11 -0
- package/dist/core/formatters/explain.d.cts.map +1 -0
- package/dist/core/formatters/explain.d.mts +11 -0
- package/dist/core/formatters/explain.d.mts.map +1 -0
- package/dist/core/formatters/explain.mjs +96 -0
- package/dist/core/formatters/explain.mjs.map +1 -0
- package/dist/core/formatters/index.d.mts +9 -0
- package/dist/core/formatters/ls.cjs +179 -0
- package/dist/core/formatters/ls.d.cts +20 -0
- package/dist/core/formatters/ls.d.cts.map +1 -0
- package/dist/core/formatters/ls.d.mts +20 -0
- package/dist/core/formatters/ls.d.mts.map +1 -0
- package/dist/core/formatters/ls.mjs +179 -0
- package/dist/core/formatters/ls.mjs.map +1 -0
- package/dist/core/formatters/mount.cjs +55 -0
- package/dist/core/formatters/mount.d.cts +15 -0
- package/dist/core/formatters/mount.d.cts.map +1 -0
- package/dist/core/formatters/mount.d.mts +15 -0
- package/dist/core/formatters/mount.d.mts.map +1 -0
- package/dist/core/formatters/mount.mjs +55 -0
- package/dist/core/formatters/mount.mjs.map +1 -0
- package/dist/core/formatters/read.cjs +100 -0
- package/dist/core/formatters/read.d.cts +22 -0
- package/dist/core/formatters/read.d.cts.map +1 -0
- package/dist/core/formatters/read.d.mts +22 -0
- package/dist/core/formatters/read.d.mts.map +1 -0
- package/dist/core/formatters/read.mjs +100 -0
- package/dist/core/formatters/read.mjs.map +1 -0
- package/dist/core/formatters/search.cjs +44 -0
- package/dist/core/formatters/search.d.mts +1 -0
- package/dist/core/formatters/search.mjs +44 -0
- package/dist/core/formatters/search.mjs.map +1 -0
- package/dist/core/formatters/stat.cjs +155 -0
- package/dist/core/formatters/stat.d.cts +15 -0
- package/dist/core/formatters/stat.d.cts.map +1 -0
- package/dist/core/formatters/stat.d.mts +15 -0
- package/dist/core/formatters/stat.d.mts.map +1 -0
- package/dist/core/formatters/stat.mjs +155 -0
- package/dist/core/formatters/stat.mjs.map +1 -0
- package/dist/core/formatters/write.cjs +51 -0
- package/dist/core/formatters/write.d.cts +22 -0
- package/dist/core/formatters/write.d.cts.map +1 -0
- package/dist/core/formatters/write.d.mts +22 -0
- package/dist/core/formatters/write.d.mts.map +1 -0
- package/dist/core/formatters/write.mjs +51 -0
- package/dist/core/formatters/write.mjs.map +1 -0
- package/dist/core/helpers/exec-args.cjs +142 -0
- package/dist/core/helpers/exec-args.d.cts +46 -0
- package/dist/core/helpers/exec-args.d.cts.map +1 -0
- package/dist/core/helpers/exec-args.d.mts +46 -0
- package/dist/core/helpers/exec-args.d.mts.map +1 -0
- package/dist/core/helpers/exec-args.mjs +139 -0
- package/dist/core/helpers/exec-args.mjs.map +1 -0
- package/dist/core/helpers/stdin.cjs +41 -0
- package/dist/core/helpers/stdin.d.cts +15 -0
- package/dist/core/helpers/stdin.d.cts.map +1 -0
- package/dist/core/helpers/stdin.d.mts +15 -0
- package/dist/core/helpers/stdin.d.mts.map +1 -0
- package/dist/core/helpers/stdin.mjs +41 -0
- package/dist/core/helpers/stdin.mjs.map +1 -0
- package/dist/core/index.cjs +49 -0
- package/dist/core/index.d.cts +24 -0
- package/dist/core/index.d.mts +25 -0
- package/dist/core/index.mjs +24 -0
- package/dist/core/path-utils.cjs +1 -0
- package/dist/core/path-utils.mjs +3 -0
- package/dist/core/types.d.cts +24 -0
- package/dist/core/types.d.cts.map +1 -0
- package/dist/core/types.d.mts +24 -0
- package/dist/core/types.d.mts.map +1 -0
- package/dist/errors.cjs +0 -11
- package/dist/errors.mjs +1 -11
- package/dist/errors.mjs.map +1 -1
- package/dist/explorer/actions.cjs +67 -32
- package/dist/explorer/actions.mjs +66 -32
- package/dist/explorer/actions.mjs.map +1 -1
- package/dist/explorer/components/dialog.cjs +170 -46
- package/dist/explorer/components/dialog.mjs +170 -46
- package/dist/explorer/components/dialog.mjs.map +1 -1
- package/dist/explorer/components/metadata-panel.cjs +86 -3
- package/dist/explorer/components/metadata-panel.mjs +86 -3
- package/dist/explorer/components/metadata-panel.mjs.map +1 -1
- package/dist/explorer/screen.cjs +63 -27
- package/dist/explorer/screen.d.cts +23 -0
- package/dist/explorer/screen.d.cts.map +1 -0
- package/dist/explorer/screen.d.mts +23 -0
- package/dist/explorer/screen.d.mts.map +1 -0
- package/dist/explorer/screen.mjs +63 -27
- package/dist/explorer/screen.mjs.map +1 -1
- package/dist/explorer/theme.cjs +1 -1
- package/dist/explorer/theme.mjs +1 -1
- package/dist/explorer/theme.mjs.map +1 -1
- package/dist/index.cjs +7 -1
- package/dist/index.d.cts +4 -1
- package/dist/index.d.mts +4 -1
- package/dist/index.mjs +4 -1
- package/dist/mcp/http-transport.cjs +68 -0
- package/dist/mcp/http-transport.mjs +68 -0
- package/dist/mcp/http-transport.mjs.map +1 -0
- package/dist/mcp/prompts.cjs +48 -0
- package/dist/mcp/prompts.mjs +48 -0
- package/dist/mcp/prompts.mjs.map +1 -0
- package/dist/mcp/resources.cjs +25 -0
- package/dist/mcp/resources.mjs +25 -0
- package/dist/mcp/resources.mjs.map +1 -0
- package/dist/mcp/server.cjs +30 -0
- package/dist/mcp/server.mjs +30 -0
- package/dist/mcp/server.mjs.map +1 -0
- package/dist/mcp/tools.cjs +196 -0
- package/dist/mcp/tools.mjs +196 -0
- package/dist/mcp/tools.mjs.map +1 -0
- package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/index.d.cts +10 -0
- package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/index.d.cts.map +1 -0
- package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/index.d.mts +10 -0
- package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/index.d.mts.map +1 -0
- package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/types.d.cts +46 -0
- package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/types.d.cts.map +1 -0
- package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/types.d.mts +46 -0
- package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/types.d.mts.map +1 -0
- package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/urlpattern.cjs +902 -0
- package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/urlpattern.mjs +902 -0
- package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/urlpattern.mjs.map +1 -0
- package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/index.cjs +6 -0
- package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/index.mjs +8 -0
- package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/index.mjs.map +1 -0
- package/dist/path-utils.d.cts +50 -0
- package/dist/path-utils.d.cts.map +1 -0
- package/dist/path-utils.d.mts +50 -0
- package/dist/path-utils.d.mts.map +1 -0
- package/dist/repl.cjs +485 -0
- package/dist/repl.d.cts +15 -0
- package/dist/repl.d.cts.map +1 -0
- package/dist/repl.d.mts +16 -0
- package/dist/repl.d.mts.map +1 -0
- package/dist/repl.mjs +485 -0
- package/dist/repl.mjs.map +1 -0
- package/dist/serve.cjs +146 -0
- package/dist/serve.d.cts +41 -0
- package/dist/serve.d.cts.map +1 -0
- package/dist/serve.d.mts +41 -0
- package/dist/serve.d.mts.map +1 -0
- package/dist/serve.mjs +146 -0
- package/dist/serve.mjs.map +1 -0
- package/dist/ui/header.cjs +1 -40
- package/dist/ui/header.mjs +1 -39
- package/dist/ui/header.mjs.map +1 -1
- package/dist/ui/index.cjs +2 -9
- package/dist/ui/index.mjs +2 -7
- package/dist/ui/index.mjs.map +1 -1
- package/dist/ui/terminal.cjs +1 -10
- package/dist/ui/terminal.mjs +1 -8
- package/dist/ui/terminal.mjs.map +1 -1
- package/package.json +29 -16
- package/dist/commands/exec.cjs +0 -164
- package/dist/commands/exec.mjs +0 -160
- package/dist/commands/exec.mjs.map +0 -1
- package/dist/commands/explain.cjs +0 -244
- package/dist/commands/explain.mjs +0 -242
- package/dist/commands/explain.mjs.map +0 -1
- package/dist/commands/index.cjs +0 -8
- package/dist/commands/index.mjs +0 -10
- package/dist/commands/ls.cjs +0 -242
- package/dist/commands/ls.mjs +0 -242
- package/dist/commands/ls.mjs.map +0 -1
- package/dist/commands/mount.mjs.map +0 -1
- package/dist/commands/read.cjs +0 -264
- package/dist/commands/read.mjs +0 -263
- package/dist/commands/read.mjs.map +0 -1
- package/dist/commands/serve.cjs +0 -144
- package/dist/commands/serve.mjs +0 -143
- package/dist/commands/serve.mjs.map +0 -1
- package/dist/commands/stat.cjs +0 -195
- package/dist/commands/stat.mjs +0 -195
- package/dist/commands/stat.mjs.map +0 -1
- package/dist/commands/write.cjs +0 -85
- package/dist/commands/write.mjs +0 -85
- package/dist/commands/write.mjs.map +0 -1
- package/dist/config/provider-factory.cjs +0 -400
- package/dist/config/provider-factory.mjs +0 -401
- package/dist/config/provider-factory.mjs.map +0 -1
- package/dist/config/uri-parser.cjs +0 -285
- package/dist/config/uri-parser.mjs +0 -285
- package/dist/config/uri-parser.mjs.map +0 -1
- package/dist/runtime.cjs +0 -120
- package/dist/runtime.mjs +0 -120
- package/dist/runtime.mjs.map +0 -1
- package/dist/utils/meta.cjs +0 -51
- package/dist/utils/meta.mjs +0 -49
- package/dist/utils/meta.mjs.map +0 -1
|
@@ -1,285 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
//#region src/config/uri-parser.ts
|
|
3
|
-
const SUPPORTED_SCHEMES = new Set([
|
|
4
|
-
"fs",
|
|
5
|
-
"git",
|
|
6
|
-
"github",
|
|
7
|
-
"sqlite",
|
|
8
|
-
"json",
|
|
9
|
-
"toml",
|
|
10
|
-
"s3",
|
|
11
|
-
"gs",
|
|
12
|
-
"ec2",
|
|
13
|
-
"gce",
|
|
14
|
-
"dns",
|
|
15
|
-
"sandbox",
|
|
16
|
-
"http",
|
|
17
|
-
"https",
|
|
18
|
-
"mcp",
|
|
19
|
-
"mcp+stdio",
|
|
20
|
-
"mcp+http",
|
|
21
|
-
"mcp+sse"
|
|
22
|
-
]);
|
|
23
|
-
/**
|
|
24
|
-
* Parse an AFS URI into components
|
|
25
|
-
*
|
|
26
|
-
* Supported formats:
|
|
27
|
-
* - fs:///path/to/dir
|
|
28
|
-
* - git:///path/to/repo?branch=main
|
|
29
|
-
* - git@github.com:user/repo.git (SSH-style)
|
|
30
|
-
* - sqlite:///path/to/db.sqlite
|
|
31
|
-
* - json:///path/to/config.json
|
|
32
|
-
* - http://host:port/path
|
|
33
|
-
* - https://host:port/path
|
|
34
|
-
*/
|
|
35
|
-
function parseURI(uri) {
|
|
36
|
-
if (!uri || uri.trim() === "") throw new Error("URI cannot be empty");
|
|
37
|
-
const sshGitMatch = uri.match(/^git@([^:]+):(.+)$/);
|
|
38
|
-
if (sshGitMatch?.[1] && sshGitMatch[2]) return {
|
|
39
|
-
scheme: "git",
|
|
40
|
-
host: sshGitMatch[1],
|
|
41
|
-
path: sshGitMatch[2],
|
|
42
|
-
params: {}
|
|
43
|
-
};
|
|
44
|
-
const schemeMatch = uri.match(/^([a-z0-9+]+):\/\//i);
|
|
45
|
-
if (!schemeMatch?.[1]) throw new Error(`Invalid URI format: ${uri}`);
|
|
46
|
-
const scheme = schemeMatch[1].toLowerCase();
|
|
47
|
-
if (!SUPPORTED_SCHEMES.has(scheme)) throw new Error(`Unknown URI scheme: ${scheme}`);
|
|
48
|
-
if (scheme === "http" || scheme === "https") return parseHttpURI(uri, scheme);
|
|
49
|
-
if (scheme.startsWith("mcp")) return parseMCPURI(uri, scheme);
|
|
50
|
-
if (scheme === "s3") return parseS3URI(uri);
|
|
51
|
-
if (scheme === "gs") return parseGCSURI(uri);
|
|
52
|
-
if (scheme === "ec2") return parseEC2URI(uri);
|
|
53
|
-
if (scheme === "gce") return parseGCEURI(uri);
|
|
54
|
-
if (scheme === "dns") return parseDNSURI(uri);
|
|
55
|
-
return parseLocalURI(uri, scheme);
|
|
56
|
-
}
|
|
57
|
-
function parseHttpURI(uri, scheme) {
|
|
58
|
-
const url = new URL(uri);
|
|
59
|
-
const params = {};
|
|
60
|
-
url.searchParams.forEach((value, key) => {
|
|
61
|
-
params[key] = value;
|
|
62
|
-
});
|
|
63
|
-
return {
|
|
64
|
-
scheme,
|
|
65
|
-
host: url.hostname,
|
|
66
|
-
port: url.port ? Number.parseInt(url.port, 10) : void 0,
|
|
67
|
-
path: url.pathname || "/",
|
|
68
|
-
params
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
function parseLocalURI(uri, scheme) {
|
|
72
|
-
const withoutScheme = uri.slice(scheme.length + 3);
|
|
73
|
-
if (scheme === "git") {
|
|
74
|
-
const sshMatch = withoutScheme.match(/^([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+):(.+)$/);
|
|
75
|
-
if (sshMatch?.[1] && sshMatch[2]) {
|
|
76
|
-
const atIndex = sshMatch[1].indexOf("@");
|
|
77
|
-
return {
|
|
78
|
-
scheme: "git",
|
|
79
|
-
host: sshMatch[1].slice(atIndex + 1),
|
|
80
|
-
path: sshMatch[2],
|
|
81
|
-
params: {}
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
if (withoutScheme.startsWith("https://") || withoutScheme.startsWith("http://")) return {
|
|
85
|
-
scheme: "git",
|
|
86
|
-
path: withoutScheme,
|
|
87
|
-
params: {}
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
const queryIndex = withoutScheme.indexOf("?");
|
|
91
|
-
let path;
|
|
92
|
-
let queryString;
|
|
93
|
-
if (queryIndex >= 0) {
|
|
94
|
-
path = withoutScheme.slice(0, queryIndex);
|
|
95
|
-
queryString = withoutScheme.slice(queryIndex + 1);
|
|
96
|
-
} else path = withoutScheme;
|
|
97
|
-
path = decodeURIComponent(path);
|
|
98
|
-
const params = {};
|
|
99
|
-
if (queryString) new URLSearchParams(queryString).forEach((value, key) => {
|
|
100
|
-
params[key] = value;
|
|
101
|
-
});
|
|
102
|
-
return {
|
|
103
|
-
scheme,
|
|
104
|
-
path,
|
|
105
|
-
params
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Parse MCP URI preserving URL encoding in path
|
|
110
|
-
*
|
|
111
|
-
* For MCP URIs, we don't decode the path to allow %2F to represent
|
|
112
|
-
* literal / in arguments (e.g., @playwright%2Fmcp -> @playwright/mcp after split)
|
|
113
|
-
*/
|
|
114
|
-
function parseMCPURI(uri, scheme) {
|
|
115
|
-
const withoutScheme = uri.slice(scheme.length + 3);
|
|
116
|
-
const queryIndex = withoutScheme.indexOf("?");
|
|
117
|
-
let path;
|
|
118
|
-
let queryString;
|
|
119
|
-
if (queryIndex >= 0) {
|
|
120
|
-
path = withoutScheme.slice(0, queryIndex);
|
|
121
|
-
queryString = withoutScheme.slice(queryIndex + 1);
|
|
122
|
-
} else path = withoutScheme;
|
|
123
|
-
const params = {};
|
|
124
|
-
if (queryString) new URLSearchParams(queryString).forEach((value, key) => {
|
|
125
|
-
params[key] = value;
|
|
126
|
-
});
|
|
127
|
-
return {
|
|
128
|
-
scheme,
|
|
129
|
-
path,
|
|
130
|
-
params
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Parse S3 URI into bucket and prefix
|
|
135
|
-
*
|
|
136
|
-
* Format: s3://bucket/prefix
|
|
137
|
-
*/
|
|
138
|
-
function parseS3URI(uri) {
|
|
139
|
-
const withoutScheme = uri.slice(5);
|
|
140
|
-
const queryIndex = withoutScheme.indexOf("?");
|
|
141
|
-
let pathPart;
|
|
142
|
-
let queryString;
|
|
143
|
-
if (queryIndex >= 0) {
|
|
144
|
-
pathPart = withoutScheme.slice(0, queryIndex);
|
|
145
|
-
queryString = withoutScheme.slice(queryIndex + 1);
|
|
146
|
-
} else pathPart = withoutScheme;
|
|
147
|
-
const parts = pathPart.split("/").filter(Boolean);
|
|
148
|
-
const bucket = parts[0] || "";
|
|
149
|
-
const prefix = parts.slice(1).join("/");
|
|
150
|
-
if (!bucket) throw new Error("S3 URI requires a bucket name: s3://bucket/prefix");
|
|
151
|
-
const params = {};
|
|
152
|
-
if (queryString) new URLSearchParams(queryString).forEach((value, key) => {
|
|
153
|
-
params[key] = value;
|
|
154
|
-
});
|
|
155
|
-
return {
|
|
156
|
-
scheme: "s3",
|
|
157
|
-
path: prefix ? `${bucket}/${prefix}` : bucket,
|
|
158
|
-
params,
|
|
159
|
-
host: bucket
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Parse EC2 URI into region(s)
|
|
164
|
-
*
|
|
165
|
-
* Formats:
|
|
166
|
-
* - ec2://us-east-1 (single region)
|
|
167
|
-
* - ec2://us-east-1,us-west-2 (multi-region)
|
|
168
|
-
* - ec2://?profile=myprofile (use default region from profile)
|
|
169
|
-
*
|
|
170
|
-
* Query params:
|
|
171
|
-
* - profile: AWS profile name
|
|
172
|
-
* - endpoint: Custom endpoint (for LocalStack)
|
|
173
|
-
*/
|
|
174
|
-
function parseEC2URI(uri) {
|
|
175
|
-
const withoutScheme = uri.slice(6);
|
|
176
|
-
const queryIndex = withoutScheme.indexOf("?");
|
|
177
|
-
let pathPart;
|
|
178
|
-
let queryString;
|
|
179
|
-
if (queryIndex >= 0) {
|
|
180
|
-
pathPart = withoutScheme.slice(0, queryIndex);
|
|
181
|
-
queryString = withoutScheme.slice(queryIndex + 1);
|
|
182
|
-
} else pathPart = withoutScheme;
|
|
183
|
-
const params = {};
|
|
184
|
-
if (queryString) new URLSearchParams(queryString).forEach((value, key) => {
|
|
185
|
-
params[key] = value;
|
|
186
|
-
});
|
|
187
|
-
return {
|
|
188
|
-
scheme: "ec2",
|
|
189
|
-
path: pathPart.trim(),
|
|
190
|
-
params
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
/**
|
|
194
|
-
* Parse DNS URI into zone domain
|
|
195
|
-
*
|
|
196
|
-
* Format: dns://zone.domain.com
|
|
197
|
-
*
|
|
198
|
-
* Query params:
|
|
199
|
-
* - provider: DNS provider (route53, cloudflare, etc.)
|
|
200
|
-
*/
|
|
201
|
-
function parseDNSURI(uri) {
|
|
202
|
-
const withoutScheme = uri.slice(6);
|
|
203
|
-
const queryIndex = withoutScheme.indexOf("?");
|
|
204
|
-
let pathPart;
|
|
205
|
-
let queryString;
|
|
206
|
-
if (queryIndex >= 0) {
|
|
207
|
-
pathPart = withoutScheme.slice(0, queryIndex);
|
|
208
|
-
queryString = withoutScheme.slice(queryIndex + 1);
|
|
209
|
-
} else pathPart = withoutScheme;
|
|
210
|
-
const params = {};
|
|
211
|
-
if (queryString) new URLSearchParams(queryString).forEach((value, key) => {
|
|
212
|
-
params[key] = value;
|
|
213
|
-
});
|
|
214
|
-
const path = pathPart.trim();
|
|
215
|
-
if (!path) throw new Error("DNS URI requires a zone domain: dns://example.com");
|
|
216
|
-
return {
|
|
217
|
-
scheme: "dns",
|
|
218
|
-
path,
|
|
219
|
-
params
|
|
220
|
-
};
|
|
221
|
-
}
|
|
222
|
-
/**
|
|
223
|
-
* Parse GCS URI into bucket and prefix
|
|
224
|
-
*
|
|
225
|
-
* Format: gs://bucket/prefix
|
|
226
|
-
*/
|
|
227
|
-
function parseGCSURI(uri) {
|
|
228
|
-
const withoutScheme = uri.slice(5);
|
|
229
|
-
const queryIndex = withoutScheme.indexOf("?");
|
|
230
|
-
let pathPart;
|
|
231
|
-
let queryString;
|
|
232
|
-
if (queryIndex >= 0) {
|
|
233
|
-
pathPart = withoutScheme.slice(0, queryIndex);
|
|
234
|
-
queryString = withoutScheme.slice(queryIndex + 1);
|
|
235
|
-
} else pathPart = withoutScheme;
|
|
236
|
-
const parts = pathPart.split("/").filter(Boolean);
|
|
237
|
-
const bucket = parts[0] || "";
|
|
238
|
-
const prefix = parts.slice(1).join("/");
|
|
239
|
-
if (!bucket) throw new Error("GCS URI requires a bucket name: gs://bucket/prefix");
|
|
240
|
-
const params = {};
|
|
241
|
-
if (queryString) new URLSearchParams(queryString).forEach((value, key) => {
|
|
242
|
-
params[key] = value;
|
|
243
|
-
});
|
|
244
|
-
return {
|
|
245
|
-
scheme: "gs",
|
|
246
|
-
path: prefix ? `${bucket}/${prefix}` : bucket,
|
|
247
|
-
params,
|
|
248
|
-
host: bucket
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* Parse GCE URI into project and zone
|
|
253
|
-
*
|
|
254
|
-
* Formats:
|
|
255
|
-
* - gce://project-id/zone (project and zone)
|
|
256
|
-
* - gce://project-id (project only, zone from options)
|
|
257
|
-
*
|
|
258
|
-
* Query params:
|
|
259
|
-
* - zone: GCE zone (alternative to path)
|
|
260
|
-
* - keyFilename: Path to service account key file
|
|
261
|
-
*/
|
|
262
|
-
function parseGCEURI(uri) {
|
|
263
|
-
const withoutScheme = uri.slice(6);
|
|
264
|
-
const queryIndex = withoutScheme.indexOf("?");
|
|
265
|
-
let pathPart;
|
|
266
|
-
let queryString;
|
|
267
|
-
if (queryIndex >= 0) {
|
|
268
|
-
pathPart = withoutScheme.slice(0, queryIndex);
|
|
269
|
-
queryString = withoutScheme.slice(queryIndex + 1);
|
|
270
|
-
} else pathPart = withoutScheme;
|
|
271
|
-
const params = {};
|
|
272
|
-
if (queryString) new URLSearchParams(queryString).forEach((value, key) => {
|
|
273
|
-
params[key] = value;
|
|
274
|
-
});
|
|
275
|
-
const path = pathPart.trim();
|
|
276
|
-
if (!path) throw new Error("GCE URI requires a project ID: gce://project-id/zone");
|
|
277
|
-
return {
|
|
278
|
-
scheme: "gce",
|
|
279
|
-
path,
|
|
280
|
-
params
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
//#endregion
|
|
285
|
-
exports.parseURI = parseURI;
|
|
@@ -1,285 +0,0 @@
|
|
|
1
|
-
//#region src/config/uri-parser.ts
|
|
2
|
-
const SUPPORTED_SCHEMES = new Set([
|
|
3
|
-
"fs",
|
|
4
|
-
"git",
|
|
5
|
-
"github",
|
|
6
|
-
"sqlite",
|
|
7
|
-
"json",
|
|
8
|
-
"toml",
|
|
9
|
-
"s3",
|
|
10
|
-
"gs",
|
|
11
|
-
"ec2",
|
|
12
|
-
"gce",
|
|
13
|
-
"dns",
|
|
14
|
-
"sandbox",
|
|
15
|
-
"http",
|
|
16
|
-
"https",
|
|
17
|
-
"mcp",
|
|
18
|
-
"mcp+stdio",
|
|
19
|
-
"mcp+http",
|
|
20
|
-
"mcp+sse"
|
|
21
|
-
]);
|
|
22
|
-
/**
|
|
23
|
-
* Parse an AFS URI into components
|
|
24
|
-
*
|
|
25
|
-
* Supported formats:
|
|
26
|
-
* - fs:///path/to/dir
|
|
27
|
-
* - git:///path/to/repo?branch=main
|
|
28
|
-
* - git@github.com:user/repo.git (SSH-style)
|
|
29
|
-
* - sqlite:///path/to/db.sqlite
|
|
30
|
-
* - json:///path/to/config.json
|
|
31
|
-
* - http://host:port/path
|
|
32
|
-
* - https://host:port/path
|
|
33
|
-
*/
|
|
34
|
-
function parseURI(uri) {
|
|
35
|
-
if (!uri || uri.trim() === "") throw new Error("URI cannot be empty");
|
|
36
|
-
const sshGitMatch = uri.match(/^git@([^:]+):(.+)$/);
|
|
37
|
-
if (sshGitMatch?.[1] && sshGitMatch[2]) return {
|
|
38
|
-
scheme: "git",
|
|
39
|
-
host: sshGitMatch[1],
|
|
40
|
-
path: sshGitMatch[2],
|
|
41
|
-
params: {}
|
|
42
|
-
};
|
|
43
|
-
const schemeMatch = uri.match(/^([a-z0-9+]+):\/\//i);
|
|
44
|
-
if (!schemeMatch?.[1]) throw new Error(`Invalid URI format: ${uri}`);
|
|
45
|
-
const scheme = schemeMatch[1].toLowerCase();
|
|
46
|
-
if (!SUPPORTED_SCHEMES.has(scheme)) throw new Error(`Unknown URI scheme: ${scheme}`);
|
|
47
|
-
if (scheme === "http" || scheme === "https") return parseHttpURI(uri, scheme);
|
|
48
|
-
if (scheme.startsWith("mcp")) return parseMCPURI(uri, scheme);
|
|
49
|
-
if (scheme === "s3") return parseS3URI(uri);
|
|
50
|
-
if (scheme === "gs") return parseGCSURI(uri);
|
|
51
|
-
if (scheme === "ec2") return parseEC2URI(uri);
|
|
52
|
-
if (scheme === "gce") return parseGCEURI(uri);
|
|
53
|
-
if (scheme === "dns") return parseDNSURI(uri);
|
|
54
|
-
return parseLocalURI(uri, scheme);
|
|
55
|
-
}
|
|
56
|
-
function parseHttpURI(uri, scheme) {
|
|
57
|
-
const url = new URL(uri);
|
|
58
|
-
const params = {};
|
|
59
|
-
url.searchParams.forEach((value, key) => {
|
|
60
|
-
params[key] = value;
|
|
61
|
-
});
|
|
62
|
-
return {
|
|
63
|
-
scheme,
|
|
64
|
-
host: url.hostname,
|
|
65
|
-
port: url.port ? Number.parseInt(url.port, 10) : void 0,
|
|
66
|
-
path: url.pathname || "/",
|
|
67
|
-
params
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
function parseLocalURI(uri, scheme) {
|
|
71
|
-
const withoutScheme = uri.slice(scheme.length + 3);
|
|
72
|
-
if (scheme === "git") {
|
|
73
|
-
const sshMatch = withoutScheme.match(/^([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+):(.+)$/);
|
|
74
|
-
if (sshMatch?.[1] && sshMatch[2]) {
|
|
75
|
-
const atIndex = sshMatch[1].indexOf("@");
|
|
76
|
-
return {
|
|
77
|
-
scheme: "git",
|
|
78
|
-
host: sshMatch[1].slice(atIndex + 1),
|
|
79
|
-
path: sshMatch[2],
|
|
80
|
-
params: {}
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
if (withoutScheme.startsWith("https://") || withoutScheme.startsWith("http://")) return {
|
|
84
|
-
scheme: "git",
|
|
85
|
-
path: withoutScheme,
|
|
86
|
-
params: {}
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
const queryIndex = withoutScheme.indexOf("?");
|
|
90
|
-
let path;
|
|
91
|
-
let queryString;
|
|
92
|
-
if (queryIndex >= 0) {
|
|
93
|
-
path = withoutScheme.slice(0, queryIndex);
|
|
94
|
-
queryString = withoutScheme.slice(queryIndex + 1);
|
|
95
|
-
} else path = withoutScheme;
|
|
96
|
-
path = decodeURIComponent(path);
|
|
97
|
-
const params = {};
|
|
98
|
-
if (queryString) new URLSearchParams(queryString).forEach((value, key) => {
|
|
99
|
-
params[key] = value;
|
|
100
|
-
});
|
|
101
|
-
return {
|
|
102
|
-
scheme,
|
|
103
|
-
path,
|
|
104
|
-
params
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Parse MCP URI preserving URL encoding in path
|
|
109
|
-
*
|
|
110
|
-
* For MCP URIs, we don't decode the path to allow %2F to represent
|
|
111
|
-
* literal / in arguments (e.g., @playwright%2Fmcp -> @playwright/mcp after split)
|
|
112
|
-
*/
|
|
113
|
-
function parseMCPURI(uri, scheme) {
|
|
114
|
-
const withoutScheme = uri.slice(scheme.length + 3);
|
|
115
|
-
const queryIndex = withoutScheme.indexOf("?");
|
|
116
|
-
let path;
|
|
117
|
-
let queryString;
|
|
118
|
-
if (queryIndex >= 0) {
|
|
119
|
-
path = withoutScheme.slice(0, queryIndex);
|
|
120
|
-
queryString = withoutScheme.slice(queryIndex + 1);
|
|
121
|
-
} else path = withoutScheme;
|
|
122
|
-
const params = {};
|
|
123
|
-
if (queryString) new URLSearchParams(queryString).forEach((value, key) => {
|
|
124
|
-
params[key] = value;
|
|
125
|
-
});
|
|
126
|
-
return {
|
|
127
|
-
scheme,
|
|
128
|
-
path,
|
|
129
|
-
params
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Parse S3 URI into bucket and prefix
|
|
134
|
-
*
|
|
135
|
-
* Format: s3://bucket/prefix
|
|
136
|
-
*/
|
|
137
|
-
function parseS3URI(uri) {
|
|
138
|
-
const withoutScheme = uri.slice(5);
|
|
139
|
-
const queryIndex = withoutScheme.indexOf("?");
|
|
140
|
-
let pathPart;
|
|
141
|
-
let queryString;
|
|
142
|
-
if (queryIndex >= 0) {
|
|
143
|
-
pathPart = withoutScheme.slice(0, queryIndex);
|
|
144
|
-
queryString = withoutScheme.slice(queryIndex + 1);
|
|
145
|
-
} else pathPart = withoutScheme;
|
|
146
|
-
const parts = pathPart.split("/").filter(Boolean);
|
|
147
|
-
const bucket = parts[0] || "";
|
|
148
|
-
const prefix = parts.slice(1).join("/");
|
|
149
|
-
if (!bucket) throw new Error("S3 URI requires a bucket name: s3://bucket/prefix");
|
|
150
|
-
const params = {};
|
|
151
|
-
if (queryString) new URLSearchParams(queryString).forEach((value, key) => {
|
|
152
|
-
params[key] = value;
|
|
153
|
-
});
|
|
154
|
-
return {
|
|
155
|
-
scheme: "s3",
|
|
156
|
-
path: prefix ? `${bucket}/${prefix}` : bucket,
|
|
157
|
-
params,
|
|
158
|
-
host: bucket
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Parse EC2 URI into region(s)
|
|
163
|
-
*
|
|
164
|
-
* Formats:
|
|
165
|
-
* - ec2://us-east-1 (single region)
|
|
166
|
-
* - ec2://us-east-1,us-west-2 (multi-region)
|
|
167
|
-
* - ec2://?profile=myprofile (use default region from profile)
|
|
168
|
-
*
|
|
169
|
-
* Query params:
|
|
170
|
-
* - profile: AWS profile name
|
|
171
|
-
* - endpoint: Custom endpoint (for LocalStack)
|
|
172
|
-
*/
|
|
173
|
-
function parseEC2URI(uri) {
|
|
174
|
-
const withoutScheme = uri.slice(6);
|
|
175
|
-
const queryIndex = withoutScheme.indexOf("?");
|
|
176
|
-
let pathPart;
|
|
177
|
-
let queryString;
|
|
178
|
-
if (queryIndex >= 0) {
|
|
179
|
-
pathPart = withoutScheme.slice(0, queryIndex);
|
|
180
|
-
queryString = withoutScheme.slice(queryIndex + 1);
|
|
181
|
-
} else pathPart = withoutScheme;
|
|
182
|
-
const params = {};
|
|
183
|
-
if (queryString) new URLSearchParams(queryString).forEach((value, key) => {
|
|
184
|
-
params[key] = value;
|
|
185
|
-
});
|
|
186
|
-
return {
|
|
187
|
-
scheme: "ec2",
|
|
188
|
-
path: pathPart.trim(),
|
|
189
|
-
params
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* Parse DNS URI into zone domain
|
|
194
|
-
*
|
|
195
|
-
* Format: dns://zone.domain.com
|
|
196
|
-
*
|
|
197
|
-
* Query params:
|
|
198
|
-
* - provider: DNS provider (route53, cloudflare, etc.)
|
|
199
|
-
*/
|
|
200
|
-
function parseDNSURI(uri) {
|
|
201
|
-
const withoutScheme = uri.slice(6);
|
|
202
|
-
const queryIndex = withoutScheme.indexOf("?");
|
|
203
|
-
let pathPart;
|
|
204
|
-
let queryString;
|
|
205
|
-
if (queryIndex >= 0) {
|
|
206
|
-
pathPart = withoutScheme.slice(0, queryIndex);
|
|
207
|
-
queryString = withoutScheme.slice(queryIndex + 1);
|
|
208
|
-
} else pathPart = withoutScheme;
|
|
209
|
-
const params = {};
|
|
210
|
-
if (queryString) new URLSearchParams(queryString).forEach((value, key) => {
|
|
211
|
-
params[key] = value;
|
|
212
|
-
});
|
|
213
|
-
const path = pathPart.trim();
|
|
214
|
-
if (!path) throw new Error("DNS URI requires a zone domain: dns://example.com");
|
|
215
|
-
return {
|
|
216
|
-
scheme: "dns",
|
|
217
|
-
path,
|
|
218
|
-
params
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* Parse GCS URI into bucket and prefix
|
|
223
|
-
*
|
|
224
|
-
* Format: gs://bucket/prefix
|
|
225
|
-
*/
|
|
226
|
-
function parseGCSURI(uri) {
|
|
227
|
-
const withoutScheme = uri.slice(5);
|
|
228
|
-
const queryIndex = withoutScheme.indexOf("?");
|
|
229
|
-
let pathPart;
|
|
230
|
-
let queryString;
|
|
231
|
-
if (queryIndex >= 0) {
|
|
232
|
-
pathPart = withoutScheme.slice(0, queryIndex);
|
|
233
|
-
queryString = withoutScheme.slice(queryIndex + 1);
|
|
234
|
-
} else pathPart = withoutScheme;
|
|
235
|
-
const parts = pathPart.split("/").filter(Boolean);
|
|
236
|
-
const bucket = parts[0] || "";
|
|
237
|
-
const prefix = parts.slice(1).join("/");
|
|
238
|
-
if (!bucket) throw new Error("GCS URI requires a bucket name: gs://bucket/prefix");
|
|
239
|
-
const params = {};
|
|
240
|
-
if (queryString) new URLSearchParams(queryString).forEach((value, key) => {
|
|
241
|
-
params[key] = value;
|
|
242
|
-
});
|
|
243
|
-
return {
|
|
244
|
-
scheme: "gs",
|
|
245
|
-
path: prefix ? `${bucket}/${prefix}` : bucket,
|
|
246
|
-
params,
|
|
247
|
-
host: bucket
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* Parse GCE URI into project and zone
|
|
252
|
-
*
|
|
253
|
-
* Formats:
|
|
254
|
-
* - gce://project-id/zone (project and zone)
|
|
255
|
-
* - gce://project-id (project only, zone from options)
|
|
256
|
-
*
|
|
257
|
-
* Query params:
|
|
258
|
-
* - zone: GCE zone (alternative to path)
|
|
259
|
-
* - keyFilename: Path to service account key file
|
|
260
|
-
*/
|
|
261
|
-
function parseGCEURI(uri) {
|
|
262
|
-
const withoutScheme = uri.slice(6);
|
|
263
|
-
const queryIndex = withoutScheme.indexOf("?");
|
|
264
|
-
let pathPart;
|
|
265
|
-
let queryString;
|
|
266
|
-
if (queryIndex >= 0) {
|
|
267
|
-
pathPart = withoutScheme.slice(0, queryIndex);
|
|
268
|
-
queryString = withoutScheme.slice(queryIndex + 1);
|
|
269
|
-
} else pathPart = withoutScheme;
|
|
270
|
-
const params = {};
|
|
271
|
-
if (queryString) new URLSearchParams(queryString).forEach((value, key) => {
|
|
272
|
-
params[key] = value;
|
|
273
|
-
});
|
|
274
|
-
const path = pathPart.trim();
|
|
275
|
-
if (!path) throw new Error("GCE URI requires a project ID: gce://project-id/zone");
|
|
276
|
-
return {
|
|
277
|
-
scheme: "gce",
|
|
278
|
-
path,
|
|
279
|
-
params
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
//#endregion
|
|
284
|
-
export { parseURI };
|
|
285
|
-
//# sourceMappingURL=uri-parser.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"uri-parser.mjs","names":[],"sources":["../../src/config/uri-parser.ts"],"sourcesContent":["/**\n * Supported URI schemes\n */\nexport type URIScheme =\n | \"fs\"\n | \"git\"\n | \"github\"\n | \"sqlite\"\n | \"json\"\n | \"toml\"\n | \"s3\"\n | \"gs\"\n | \"ec2\"\n | \"gce\"\n | \"dns\"\n | \"sandbox\"\n | \"http\"\n | \"https\"\n | \"mcp\"\n | \"mcp+stdio\"\n | \"mcp+http\"\n | \"mcp+sse\";\n\n/**\n * Parsed URI result\n */\nexport interface ParsedURI {\n /** URI scheme */\n scheme: URIScheme;\n /** Path component (decoded) */\n path: string;\n /** Query parameters */\n params: Record<string, string>;\n /** Host (for http/https only) */\n host?: string;\n /** Port (for http/https only) */\n port?: number;\n}\n\nconst SUPPORTED_SCHEMES = new Set<string>([\n \"fs\",\n \"git\",\n \"github\",\n \"sqlite\",\n \"json\",\n \"toml\",\n \"s3\",\n \"gs\",\n \"ec2\",\n \"gce\",\n \"dns\",\n \"sandbox\",\n \"http\",\n \"https\",\n \"mcp\",\n \"mcp+stdio\",\n \"mcp+http\",\n \"mcp+sse\",\n]);\n\n/**\n * Parse an AFS URI into components\n *\n * Supported formats:\n * - fs:///path/to/dir\n * - git:///path/to/repo?branch=main\n * - git@github.com:user/repo.git (SSH-style)\n * - sqlite:///path/to/db.sqlite\n * - json:///path/to/config.json\n * - http://host:port/path\n * - https://host:port/path\n */\nexport function parseURI(uri: string): ParsedURI {\n if (!uri || uri.trim() === \"\") {\n throw new Error(\"URI cannot be empty\");\n }\n\n // Handle SSH-style git URLs: git@host:path\n const sshGitMatch = uri.match(/^git@([^:]+):(.+)$/);\n if (sshGitMatch?.[1] && sshGitMatch[2]) {\n return {\n scheme: \"git\",\n host: sshGitMatch[1],\n path: sshGitMatch[2],\n params: {},\n };\n }\n\n // Extract scheme (supports mcp+stdio, mcp+http, mcp+sse, s3)\n const schemeMatch = uri.match(/^([a-z0-9+]+):\\/\\//i);\n if (!schemeMatch?.[1]) {\n throw new Error(`Invalid URI format: ${uri}`);\n }\n\n const scheme = schemeMatch[1].toLowerCase();\n if (!SUPPORTED_SCHEMES.has(scheme)) {\n throw new Error(`Unknown URI scheme: ${scheme}`);\n }\n\n // For http/https, use URL API for proper parsing\n if (scheme === \"http\" || scheme === \"https\") {\n return parseHttpURI(uri, scheme as \"http\" | \"https\");\n }\n\n // For MCP schemes, preserve URL encoding in path\n // This allows %2F to represent literal / in arguments\n if (scheme.startsWith(\"mcp\")) {\n return parseMCPURI(uri, scheme as URIScheme);\n }\n\n // For S3 scheme, parse bucket and prefix from path\n if (scheme === \"s3\") {\n return parseS3URI(uri);\n }\n\n // For GCS scheme, parse bucket and prefix from path\n if (scheme === \"gs\") {\n return parseGCSURI(uri);\n }\n\n // For EC2 scheme, parse region from path\n if (scheme === \"ec2\") {\n return parseEC2URI(uri);\n }\n\n // For GCE scheme, parse project and zone from path\n if (scheme === \"gce\") {\n return parseGCEURI(uri);\n }\n\n // For DNS scheme, parse zone domain from path\n if (scheme === \"dns\") {\n return parseDNSURI(uri);\n }\n\n // For local schemes (fs, git, github, sqlite, json, toml, sandbox)\n return parseLocalURI(\n uri,\n scheme as \"fs\" | \"git\" | \"github\" | \"sqlite\" | \"json\" | \"toml\" | \"sandbox\",\n );\n}\n\nfunction parseHttpURI(uri: string, scheme: \"http\" | \"https\"): ParsedURI {\n const url = new URL(uri);\n\n const params: Record<string, string> = {};\n url.searchParams.forEach((value, key) => {\n params[key] = value;\n });\n\n return {\n scheme,\n host: url.hostname,\n port: url.port ? Number.parseInt(url.port, 10) : undefined,\n path: url.pathname || \"/\",\n params,\n };\n}\n\nfunction parseLocalURI(\n uri: string,\n scheme: \"fs\" | \"git\" | \"github\" | \"sqlite\" | \"json\" | \"toml\" | \"sandbox\",\n): ParsedURI {\n // Remove scheme prefix (e.g., \"fs://\")\n const withoutScheme = uri.slice(scheme.length + 3);\n\n // For git:// scheme, check if the path is actually an SSH-style URL (git@host:path)\n if (scheme === \"git\") {\n const sshMatch = withoutScheme.match(/^([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+):(.+)$/);\n if (sshMatch?.[1] && sshMatch[2]) {\n // Extract host from user@host format\n const atIndex = sshMatch[1].indexOf(\"@\");\n const host = sshMatch[1].slice(atIndex + 1);\n return {\n scheme: \"git\",\n host,\n path: sshMatch[2],\n params: {},\n };\n }\n\n // Also handle embedded https:// URLs (git://https://github.com/user/repo.git)\n if (withoutScheme.startsWith(\"https://\") || withoutScheme.startsWith(\"http://\")) {\n return {\n scheme: \"git\",\n path: withoutScheme, // Store full URL as path, provider will handle it\n params: {},\n };\n }\n }\n\n // Split path and query\n const queryIndex = withoutScheme.indexOf(\"?\");\n let path: string;\n let queryString: string | undefined;\n\n if (queryIndex >= 0) {\n path = withoutScheme.slice(0, queryIndex);\n queryString = withoutScheme.slice(queryIndex + 1);\n } else {\n path = withoutScheme;\n }\n\n // Decode URI components\n path = decodeURIComponent(path);\n\n // Parse query params\n const params: Record<string, string> = {};\n if (queryString) {\n const searchParams = new URLSearchParams(queryString);\n searchParams.forEach((value, key) => {\n params[key] = value;\n });\n }\n\n return {\n scheme,\n path,\n params,\n };\n}\n\n/**\n * Parse MCP URI preserving URL encoding in path\n *\n * For MCP URIs, we don't decode the path to allow %2F to represent\n * literal / in arguments (e.g., @playwright%2Fmcp -> @playwright/mcp after split)\n */\nfunction parseMCPURI(uri: string, scheme: URIScheme): ParsedURI {\n // Remove scheme prefix (e.g., \"mcp+stdio://\")\n const withoutScheme = uri.slice(scheme.length + 3);\n\n // Split path and query without decoding\n const queryIndex = withoutScheme.indexOf(\"?\");\n let path: string;\n let queryString: string | undefined;\n\n if (queryIndex >= 0) {\n path = withoutScheme.slice(0, queryIndex);\n queryString = withoutScheme.slice(queryIndex + 1);\n } else {\n path = withoutScheme;\n }\n\n // Parse query params\n const params: Record<string, string> = {};\n if (queryString) {\n const searchParams = new URLSearchParams(queryString);\n searchParams.forEach((value, key) => {\n params[key] = value;\n });\n }\n\n return {\n scheme,\n path,\n params,\n };\n}\n\n/**\n * Parse S3 URI into bucket and prefix\n *\n * Format: s3://bucket/prefix\n */\nfunction parseS3URI(uri: string): ParsedURI {\n // Remove scheme prefix (s3://)\n const withoutScheme = uri.slice(5);\n\n // Split path and query\n const queryIndex = withoutScheme.indexOf(\"?\");\n let pathPart: string;\n let queryString: string | undefined;\n\n if (queryIndex >= 0) {\n pathPart = withoutScheme.slice(0, queryIndex);\n queryString = withoutScheme.slice(queryIndex + 1);\n } else {\n pathPart = withoutScheme;\n }\n\n // Parse bucket and prefix from path: bucket/prefix/path\n const parts = pathPart.split(\"/\").filter(Boolean);\n const bucket = parts[0] || \"\";\n const prefix = parts.slice(1).join(\"/\"); // Already trimmed trailing slash\n\n if (!bucket) {\n throw new Error(\"S3 URI requires a bucket name: s3://bucket/prefix\");\n }\n\n // Parse query params\n const params: Record<string, string> = {};\n if (queryString) {\n const searchParams = new URLSearchParams(queryString);\n searchParams.forEach((value, key) => {\n params[key] = value;\n });\n }\n\n // Store bucket and prefix in path format for provider-factory\n // Path will be: bucket/prefix (or just bucket if no prefix)\n const path = prefix ? `${bucket}/${prefix}` : bucket;\n\n return {\n scheme: \"s3\",\n path,\n params,\n host: bucket, // Store bucket in host for convenience\n };\n}\n\n/**\n * Parse EC2 URI into region(s)\n *\n * Formats:\n * - ec2://us-east-1 (single region)\n * - ec2://us-east-1,us-west-2 (multi-region)\n * - ec2://?profile=myprofile (use default region from profile)\n *\n * Query params:\n * - profile: AWS profile name\n * - endpoint: Custom endpoint (for LocalStack)\n */\nfunction parseEC2URI(uri: string): ParsedURI {\n // Remove scheme prefix (ec2://)\n const withoutScheme = uri.slice(6);\n\n // Split path and query\n const queryIndex = withoutScheme.indexOf(\"?\");\n let pathPart: string;\n let queryString: string | undefined;\n\n if (queryIndex >= 0) {\n pathPart = withoutScheme.slice(0, queryIndex);\n queryString = withoutScheme.slice(queryIndex + 1);\n } else {\n pathPart = withoutScheme;\n }\n\n // Parse query params\n const params: Record<string, string> = {};\n if (queryString) {\n const searchParams = new URLSearchParams(queryString);\n searchParams.forEach((value, key) => {\n params[key] = value;\n });\n }\n\n // Path contains region(s), comma-separated for multi-region\n const path = pathPart.trim();\n\n return {\n scheme: \"ec2\",\n path,\n params,\n };\n}\n\n/**\n * Parse DNS URI into zone domain\n *\n * Format: dns://zone.domain.com\n *\n * Query params:\n * - provider: DNS provider (route53, cloudflare, etc.)\n */\nfunction parseDNSURI(uri: string): ParsedURI {\n // Remove scheme prefix (dns://)\n const withoutScheme = uri.slice(6);\n\n // Split path and query\n const queryIndex = withoutScheme.indexOf(\"?\");\n let pathPart: string;\n let queryString: string | undefined;\n\n if (queryIndex >= 0) {\n pathPart = withoutScheme.slice(0, queryIndex);\n queryString = withoutScheme.slice(queryIndex + 1);\n } else {\n pathPart = withoutScheme;\n }\n\n // Parse query params\n const params: Record<string, string> = {};\n if (queryString) {\n const searchParams = new URLSearchParams(queryString);\n searchParams.forEach((value, key) => {\n params[key] = value;\n });\n }\n\n // Path contains zone domain\n const path = pathPart.trim();\n\n if (!path) {\n throw new Error(\"DNS URI requires a zone domain: dns://example.com\");\n }\n\n return {\n scheme: \"dns\",\n path,\n params,\n };\n}\n\n/**\n * Parse GCS URI into bucket and prefix\n *\n * Format: gs://bucket/prefix\n */\nfunction parseGCSURI(uri: string): ParsedURI {\n // Remove scheme prefix (gs://)\n const withoutScheme = uri.slice(5);\n\n // Split path and query\n const queryIndex = withoutScheme.indexOf(\"?\");\n let pathPart: string;\n let queryString: string | undefined;\n\n if (queryIndex >= 0) {\n pathPart = withoutScheme.slice(0, queryIndex);\n queryString = withoutScheme.slice(queryIndex + 1);\n } else {\n pathPart = withoutScheme;\n }\n\n // Parse bucket and prefix from path: bucket/prefix/path\n const parts = pathPart.split(\"/\").filter(Boolean);\n const bucket = parts[0] || \"\";\n const prefix = parts.slice(1).join(\"/\");\n\n if (!bucket) {\n throw new Error(\"GCS URI requires a bucket name: gs://bucket/prefix\");\n }\n\n // Parse query params\n const params: Record<string, string> = {};\n if (queryString) {\n const searchParams = new URLSearchParams(queryString);\n searchParams.forEach((value, key) => {\n params[key] = value;\n });\n }\n\n // Store bucket and prefix in path format for provider-factory\n const path = prefix ? `${bucket}/${prefix}` : bucket;\n\n return {\n scheme: \"gs\",\n path,\n params,\n host: bucket,\n };\n}\n\n/**\n * Parse GCE URI into project and zone\n *\n * Formats:\n * - gce://project-id/zone (project and zone)\n * - gce://project-id (project only, zone from options)\n *\n * Query params:\n * - zone: GCE zone (alternative to path)\n * - keyFilename: Path to service account key file\n */\nfunction parseGCEURI(uri: string): ParsedURI {\n // Remove scheme prefix (gce://)\n const withoutScheme = uri.slice(6);\n\n // Split path and query\n const queryIndex = withoutScheme.indexOf(\"?\");\n let pathPart: string;\n let queryString: string | undefined;\n\n if (queryIndex >= 0) {\n pathPart = withoutScheme.slice(0, queryIndex);\n queryString = withoutScheme.slice(queryIndex + 1);\n } else {\n pathPart = withoutScheme;\n }\n\n // Parse query params\n const params: Record<string, string> = {};\n if (queryString) {\n const searchParams = new URLSearchParams(queryString);\n searchParams.forEach((value, key) => {\n params[key] = value;\n });\n }\n\n // Path contains project/zone\n const path = pathPart.trim();\n\n if (!path) {\n throw new Error(\"GCE URI requires a project ID: gce://project-id/zone\");\n }\n\n return {\n scheme: \"gce\",\n path,\n params,\n };\n}\n"],"mappings":"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"}
|