@aigne/afs-cli 1.11.0-beta.6 → 1.11.0-beta.8
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/_virtual/rolldown_runtime.mjs +7 -0
- 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 +567 -0
- package/dist/config/afs-loader.d.cts +19 -0
- package/dist/config/afs-loader.d.cts.map +1 -0
- package/dist/config/afs-loader.d.mts +19 -0
- package/dist/config/afs-loader.d.mts.map +1 -0
- package/dist/config/afs-loader.mjs +565 -0
- package/dist/config/afs-loader.mjs.map +1 -0
- package/dist/config/loader.cjs +28 -11
- package/dist/config/loader.mjs +28 -11
- package/dist/config/loader.mjs.map +1 -1
- package/dist/config/mount-commands.cjs +208 -0
- package/dist/config/mount-commands.d.cts +14 -0
- package/dist/config/mount-commands.d.cts.map +1 -0
- package/dist/config/mount-commands.d.mts +14 -0
- package/dist/config/mount-commands.d.mts.map +1 -0
- package/dist/config/mount-commands.mjs +203 -0
- package/dist/config/mount-commands.mjs.map +1 -0
- package/dist/config/schema.cjs +10 -2
- package/dist/config/schema.mjs +10 -2
- 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 +98 -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 +99 -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 +222 -0
- package/dist/core/commands/mount.d.cts +35 -0
- package/dist/core/commands/mount.d.cts.map +1 -0
- package/dist/core/commands/mount.d.mts +35 -0
- package/dist/core/commands/mount.d.mts.map +1 -0
- package/dist/core/commands/mount.mjs +223 -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 +267 -0
- package/dist/core/commands/serve.d.mts +2 -0
- package/dist/core/commands/serve.mjs +267 -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 +18 -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 +19 -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/credential/auth-server.cjs +247 -0
- package/dist/credential/auth-server.mjs +247 -0
- package/dist/credential/auth-server.mjs.map +1 -0
- package/dist/credential/cli-auth-context.cjs +86 -0
- package/dist/credential/cli-auth-context.d.mts +1 -0
- package/dist/credential/cli-auth-context.mjs +86 -0
- package/dist/credential/cli-auth-context.mjs.map +1 -0
- package/dist/credential/index.cjs +5 -0
- package/dist/credential/index.d.mts +4 -0
- package/dist/credential/index.mjs +7 -0
- package/dist/credential/mcp-auth-context.cjs +186 -0
- package/dist/credential/mcp-auth-context.d.mts +1 -0
- package/dist/credential/mcp-auth-context.mjs +186 -0
- package/dist/credential/mcp-auth-context.mjs.map +1 -0
- package/dist/credential/resolver.cjs +125 -0
- package/dist/credential/resolver.d.mts +1 -0
- package/dist/credential/resolver.mjs +125 -0
- package/dist/credential/resolver.mjs.map +1 -0
- package/dist/credential/store.cjs +106 -0
- package/dist/credential/store.d.cts +30 -0
- package/dist/credential/store.d.cts.map +1 -0
- package/dist/credential/store.d.mts +30 -0
- package/dist/credential/store.d.mts.map +1 -0
- package/dist/credential/store.mjs +106 -0
- package/dist/credential/store.mjs.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 +10 -1
- package/dist/index.d.cts +5 -1
- package/dist/index.d.mts +6 -1
- package/dist/index.mjs +6 -1
- package/dist/mcp/http-transport.cjs +87 -0
- package/dist/mcp/http-transport.mjs +87 -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 +40 -0
- package/dist/mcp/server.mjs +39 -0
- package/dist/mcp/server.mjs.map +1 -0
- package/dist/mcp/tools.cjs +152 -0
- package/dist/mcp/tools.mjs +152 -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 +491 -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 +491 -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 +30 -17
- 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.cjs +0 -194
- package/dist/commands/mount.mjs +0 -190
- 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
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_auth_server = require('./auth-server.cjs');
|
|
3
|
+
let node_child_process = require("node:child_process");
|
|
4
|
+
|
|
5
|
+
//#region src/credential/cli-auth-context.ts
|
|
6
|
+
/**
|
|
7
|
+
* CLI AuthContext implementation.
|
|
8
|
+
*
|
|
9
|
+
* Collects credentials by launching a local HTTP form in the browser.
|
|
10
|
+
* Opens URLs via the platform `open` command.
|
|
11
|
+
* Creates callback servers via the shared auth-server module.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Create a CLI AuthContext that collects credentials via a local browser form.
|
|
15
|
+
*/
|
|
16
|
+
function createCLIAuthContext(options) {
|
|
17
|
+
const resolved = options?.resolved ?? {};
|
|
18
|
+
const output = options?.output ?? process.stderr;
|
|
19
|
+
const openURLFn = options?.openURL ?? openURL;
|
|
20
|
+
return {
|
|
21
|
+
get resolved() {
|
|
22
|
+
return { ...resolved };
|
|
23
|
+
},
|
|
24
|
+
async collect(schema) {
|
|
25
|
+
const properties = schema.properties;
|
|
26
|
+
if (!properties || typeof properties !== "object") return {};
|
|
27
|
+
if (Object.keys(properties).length === 0) return {};
|
|
28
|
+
const server = await require_auth_server.createAuthServer();
|
|
29
|
+
const formURL = `${server.baseURL}/auth?nonce=${server.nonce}`;
|
|
30
|
+
const writeOutput = (text) => new Promise((resolve) => {
|
|
31
|
+
output.write(text, () => resolve());
|
|
32
|
+
});
|
|
33
|
+
await writeOutput(`\nPlease fill in credentials in your browser:\n${formURL}\n`);
|
|
34
|
+
try {
|
|
35
|
+
await openURLFn(formURL);
|
|
36
|
+
} catch {}
|
|
37
|
+
try {
|
|
38
|
+
return await server.waitForForm(schema, { title: "AFS Credential Collection" });
|
|
39
|
+
} finally {
|
|
40
|
+
server.close();
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
async createCallbackServer() {
|
|
44
|
+
const server = await require_auth_server.createAuthServer();
|
|
45
|
+
return {
|
|
46
|
+
callbackURL: server.callbackURL,
|
|
47
|
+
waitForCallback: server.waitForCallback.bind(server),
|
|
48
|
+
close: server.close.bind(server)
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
async requestOpenURL(url, message) {
|
|
52
|
+
const writeOutput = (text) => {
|
|
53
|
+
return new Promise((resolve) => {
|
|
54
|
+
output.write(text, () => resolve());
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
await writeOutput(`\n${message}\n`);
|
|
58
|
+
await writeOutput(`${url}\n`);
|
|
59
|
+
try {
|
|
60
|
+
await openURLFn(url);
|
|
61
|
+
} catch {}
|
|
62
|
+
return "accepted";
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Open a URL in the default browser using platform-specific commands.
|
|
68
|
+
*/
|
|
69
|
+
function openURL(url) {
|
|
70
|
+
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
71
|
+
const args = process.platform === "win32" ? [
|
|
72
|
+
"/c",
|
|
73
|
+
"start",
|
|
74
|
+
"",
|
|
75
|
+
url
|
|
76
|
+
] : [url];
|
|
77
|
+
return new Promise((resolve, reject) => {
|
|
78
|
+
(0, node_child_process.execFile)(cmd, args, (err) => {
|
|
79
|
+
if (err) reject(err);
|
|
80
|
+
else resolve();
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
//#endregion
|
|
86
|
+
exports.createCLIAuthContext = createCLIAuthContext;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { AuthContext } from "@aigne/afs";
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { createAuthServer } from "./auth-server.mjs";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
|
|
4
|
+
//#region src/credential/cli-auth-context.ts
|
|
5
|
+
/**
|
|
6
|
+
* CLI AuthContext implementation.
|
|
7
|
+
*
|
|
8
|
+
* Collects credentials by launching a local HTTP form in the browser.
|
|
9
|
+
* Opens URLs via the platform `open` command.
|
|
10
|
+
* Creates callback servers via the shared auth-server module.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Create a CLI AuthContext that collects credentials via a local browser form.
|
|
14
|
+
*/
|
|
15
|
+
function createCLIAuthContext(options) {
|
|
16
|
+
const resolved = options?.resolved ?? {};
|
|
17
|
+
const output = options?.output ?? process.stderr;
|
|
18
|
+
const openURLFn = options?.openURL ?? openURL;
|
|
19
|
+
return {
|
|
20
|
+
get resolved() {
|
|
21
|
+
return { ...resolved };
|
|
22
|
+
},
|
|
23
|
+
async collect(schema) {
|
|
24
|
+
const properties = schema.properties;
|
|
25
|
+
if (!properties || typeof properties !== "object") return {};
|
|
26
|
+
if (Object.keys(properties).length === 0) return {};
|
|
27
|
+
const server = await createAuthServer();
|
|
28
|
+
const formURL = `${server.baseURL}/auth?nonce=${server.nonce}`;
|
|
29
|
+
const writeOutput = (text) => new Promise((resolve) => {
|
|
30
|
+
output.write(text, () => resolve());
|
|
31
|
+
});
|
|
32
|
+
await writeOutput(`\nPlease fill in credentials in your browser:\n${formURL}\n`);
|
|
33
|
+
try {
|
|
34
|
+
await openURLFn(formURL);
|
|
35
|
+
} catch {}
|
|
36
|
+
try {
|
|
37
|
+
return await server.waitForForm(schema, { title: "AFS Credential Collection" });
|
|
38
|
+
} finally {
|
|
39
|
+
server.close();
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
async createCallbackServer() {
|
|
43
|
+
const server = await createAuthServer();
|
|
44
|
+
return {
|
|
45
|
+
callbackURL: server.callbackURL,
|
|
46
|
+
waitForCallback: server.waitForCallback.bind(server),
|
|
47
|
+
close: server.close.bind(server)
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
async requestOpenURL(url, message) {
|
|
51
|
+
const writeOutput = (text) => {
|
|
52
|
+
return new Promise((resolve) => {
|
|
53
|
+
output.write(text, () => resolve());
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
await writeOutput(`\n${message}\n`);
|
|
57
|
+
await writeOutput(`${url}\n`);
|
|
58
|
+
try {
|
|
59
|
+
await openURLFn(url);
|
|
60
|
+
} catch {}
|
|
61
|
+
return "accepted";
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Open a URL in the default browser using platform-specific commands.
|
|
67
|
+
*/
|
|
68
|
+
function openURL(url) {
|
|
69
|
+
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
70
|
+
const args = process.platform === "win32" ? [
|
|
71
|
+
"/c",
|
|
72
|
+
"start",
|
|
73
|
+
"",
|
|
74
|
+
url
|
|
75
|
+
] : [url];
|
|
76
|
+
return new Promise((resolve, reject) => {
|
|
77
|
+
execFile(cmd, args, (err) => {
|
|
78
|
+
if (err) reject(err);
|
|
79
|
+
else resolve();
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
//#endregion
|
|
85
|
+
export { createCLIAuthContext };
|
|
86
|
+
//# sourceMappingURL=cli-auth-context.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-auth-context.mjs","names":[],"sources":["../../src/credential/cli-auth-context.ts"],"sourcesContent":["/**\n * CLI AuthContext implementation.\n *\n * Collects credentials by launching a local HTTP form in the browser.\n * Opens URLs via the platform `open` command.\n * Creates callback servers via the shared auth-server module.\n */\n\nimport { execFile } from \"node:child_process\";\nimport type { AuthContext, CallbackServer, JSONSchema7 } from \"@aigne/afs\";\nimport { createAuthServer } from \"./auth-server.js\";\n\nexport interface CLIAuthContextOptions {\n /** Pre-resolved fields from Step 2 (env/store/config) */\n resolved?: Record<string, unknown>;\n /** Output stream (for testing). Default: process.stderr */\n output?: NodeJS.WritableStream;\n /** Custom URL opener (for testing). Default: platform `open` command. */\n openURL?: (url: string) => Promise<void>;\n}\n\n/**\n * Create a CLI AuthContext that collects credentials via a local browser form.\n */\nexport function createCLIAuthContext(options?: CLIAuthContextOptions): AuthContext {\n const resolved = options?.resolved ?? {};\n const output = options?.output ?? process.stderr;\n const openURLFn = options?.openURL ?? openURL;\n\n return {\n get resolved() {\n return { ...resolved };\n },\n\n async collect(schema: JSONSchema7): Promise<Record<string, unknown> | null> {\n const properties = (schema as any).properties;\n if (!properties || typeof properties !== \"object\") return {};\n if (Object.keys(properties).length === 0) return {};\n\n // Start auth server and open form in browser\n const server = await createAuthServer();\n const formURL = `${server.baseURL}/auth?nonce=${server.nonce}`;\n\n const writeOutput = (text: string) =>\n new Promise<void>((resolve) => {\n (output as NodeJS.WritableStream).write(text, () => resolve());\n });\n\n await writeOutput(`\\nPlease fill in credentials in your browser:\\n${formURL}\\n`);\n\n try {\n await openURLFn(formURL);\n } catch {\n // Browser failed to open; URL is already printed above\n }\n\n try {\n const result = await server.waitForForm(schema as Record<string, any>, {\n title: \"AFS Credential Collection\",\n });\n return result;\n } finally {\n server.close();\n }\n },\n\n async createCallbackServer(): Promise<CallbackServer> {\n const server = await createAuthServer();\n return {\n callbackURL: server.callbackURL,\n waitForCallback: server.waitForCallback.bind(server),\n close: server.close.bind(server),\n };\n },\n\n async requestOpenURL(\n url: string,\n message: string,\n ): Promise<\"accepted\" | \"declined\" | \"cancelled\"> {\n const writeOutput = (text: string) => {\n return new Promise<void>((resolve) => {\n (output as NodeJS.WritableStream).write(text, () => resolve());\n });\n };\n\n await writeOutput(`\\n${message}\\n`);\n\n await writeOutput(`${url}\\n`);\n\n try {\n await openURLFn(url);\n } catch {\n // Browser failed to open; URL is already printed above\n }\n\n return \"accepted\";\n },\n };\n}\n\n/**\n * Open a URL in the default browser using platform-specific commands.\n */\nfunction openURL(url: string): Promise<void> {\n const cmd =\n process.platform === \"darwin\" ? \"open\" : process.platform === \"win32\" ? \"cmd\" : \"xdg-open\";\n\n const args = process.platform === \"win32\" ? [\"/c\", \"start\", \"\", url] : [url];\n\n return new Promise((resolve, reject) => {\n execFile(cmd, args, (err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n}\n"],"mappings":";;;;;;;;;;;;;;AAwBA,SAAgB,qBAAqB,SAA8C;CACjF,MAAM,WAAW,SAAS,YAAY,EAAE;CACxC,MAAM,SAAS,SAAS,UAAU,QAAQ;CAC1C,MAAM,YAAY,SAAS,WAAW;AAEtC,QAAO;EACL,IAAI,WAAW;AACb,UAAO,EAAE,GAAG,UAAU;;EAGxB,MAAM,QAAQ,QAA8D;GAC1E,MAAM,aAAc,OAAe;AACnC,OAAI,CAAC,cAAc,OAAO,eAAe,SAAU,QAAO,EAAE;AAC5D,OAAI,OAAO,KAAK,WAAW,CAAC,WAAW,EAAG,QAAO,EAAE;GAGnD,MAAM,SAAS,MAAM,kBAAkB;GACvC,MAAM,UAAU,GAAG,OAAO,QAAQ,cAAc,OAAO;GAEvD,MAAM,eAAe,SACnB,IAAI,SAAe,YAAY;AAC7B,IAAC,OAAiC,MAAM,YAAY,SAAS,CAAC;KAC9D;AAEJ,SAAM,YAAY,kDAAkD,QAAQ,IAAI;AAEhF,OAAI;AACF,UAAM,UAAU,QAAQ;WAClB;AAIR,OAAI;AAIF,WAHe,MAAM,OAAO,YAAY,QAA+B,EACrE,OAAO,6BACR,CAAC;aAEM;AACR,WAAO,OAAO;;;EAIlB,MAAM,uBAAgD;GACpD,MAAM,SAAS,MAAM,kBAAkB;AACvC,UAAO;IACL,aAAa,OAAO;IACpB,iBAAiB,OAAO,gBAAgB,KAAK,OAAO;IACpD,OAAO,OAAO,MAAM,KAAK,OAAO;IACjC;;EAGH,MAAM,eACJ,KACA,SACgD;GAChD,MAAM,eAAe,SAAiB;AACpC,WAAO,IAAI,SAAe,YAAY;AACpC,KAAC,OAAiC,MAAM,YAAY,SAAS,CAAC;MAC9D;;AAGJ,SAAM,YAAY,KAAK,QAAQ,IAAI;AAEnC,SAAM,YAAY,GAAG,IAAI,IAAI;AAE7B,OAAI;AACF,UAAM,UAAU,IAAI;WACd;AAIR,UAAO;;EAEV;;;;;AAMH,SAAS,QAAQ,KAA4B;CAC3C,MAAM,MACJ,QAAQ,aAAa,WAAW,SAAS,QAAQ,aAAa,UAAU,QAAQ;CAElF,MAAM,OAAO,QAAQ,aAAa,UAAU;EAAC;EAAM;EAAS;EAAI;EAAI,GAAG,CAAC,IAAI;AAE5E,QAAO,IAAI,SAAS,SAAS,WAAW;AACtC,WAAS,KAAK,OAAO,QAAQ;AAC3B,OAAI,IAAK,QAAO,IAAI;OACf,UAAS;IACd;GACF"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
const require_auth_server = require('./auth-server.cjs');
|
|
2
|
+
const require_cli_auth_context = require('./cli-auth-context.cjs');
|
|
3
|
+
const require_mcp_auth_context = require('./mcp-auth-context.cjs');
|
|
4
|
+
const require_resolver = require('./resolver.cjs');
|
|
5
|
+
const require_store = require('./store.cjs');
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createAuthServer } from "./auth-server.mjs";
|
|
2
|
+
import { createCLIAuthContext } from "./cli-auth-context.mjs";
|
|
3
|
+
import { createMCPAuthContext } from "./mcp-auth-context.mjs";
|
|
4
|
+
import { resolveCredentials } from "./resolver.mjs";
|
|
5
|
+
import { createCredentialStore } from "./store.mjs";
|
|
6
|
+
|
|
7
|
+
export { };
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_auth_server = require('./auth-server.cjs');
|
|
3
|
+
let node_crypto = require("node:crypto");
|
|
4
|
+
let node_child_process = require("node:child_process");
|
|
5
|
+
let _aigne_afs_utils_schema = require("@aigne/afs/utils/schema");
|
|
6
|
+
|
|
7
|
+
//#region src/credential/mcp-auth-context.ts
|
|
8
|
+
/**
|
|
9
|
+
* MCP AuthContext implementation.
|
|
10
|
+
*
|
|
11
|
+
* Uses MCP elicitation protocol to collect credentials:
|
|
12
|
+
* - Non-sensitive fields: form mode (Client renders UI)
|
|
13
|
+
* - Sensitive fields: URL mode (local HTTP server, data never passes through Client/LLM)
|
|
14
|
+
*
|
|
15
|
+
* Requires an MCP Server instance that supports elicitation.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Create an MCP AuthContext for MCP-based credential collection.
|
|
19
|
+
*/
|
|
20
|
+
function createMCPAuthContext(options) {
|
|
21
|
+
const { server } = options;
|
|
22
|
+
const resolved = options.resolved ?? {};
|
|
23
|
+
const openURLFn = options.openURL;
|
|
24
|
+
return {
|
|
25
|
+
get resolved() {
|
|
26
|
+
return { ...resolved };
|
|
27
|
+
},
|
|
28
|
+
async collect(schema) {
|
|
29
|
+
const properties = schema.properties;
|
|
30
|
+
if (!properties || typeof properties !== "object") return {};
|
|
31
|
+
if (new Set((0, _aigne_afs_utils_schema.getSensitiveFields)(schema)).size > 0) {
|
|
32
|
+
try {
|
|
33
|
+
return await collectViaURLMode(server, schema);
|
|
34
|
+
} catch (err) {
|
|
35
|
+
if (!(err instanceof ElicitationUnsupportedError)) throw err;
|
|
36
|
+
}
|
|
37
|
+
return collectViaBrowser(schema, openURLFn);
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
return await collectViaFormMode(server, schema);
|
|
41
|
+
} catch (err) {
|
|
42
|
+
if (!(err instanceof ElicitationUnsupportedError)) throw err;
|
|
43
|
+
}
|
|
44
|
+
return collectViaBrowser(schema, openURLFn);
|
|
45
|
+
},
|
|
46
|
+
async createCallbackServer() {
|
|
47
|
+
const authServer = await require_auth_server.createAuthServer();
|
|
48
|
+
return {
|
|
49
|
+
callbackURL: authServer.callbackURL,
|
|
50
|
+
waitForCallback: authServer.waitForCallback.bind(authServer),
|
|
51
|
+
close: authServer.close.bind(authServer)
|
|
52
|
+
};
|
|
53
|
+
},
|
|
54
|
+
async requestOpenURL(url, message) {
|
|
55
|
+
try {
|
|
56
|
+
const elicitationId = (0, node_crypto.randomBytes)(16).toString("hex");
|
|
57
|
+
const result = await server.elicitInput({
|
|
58
|
+
mode: "url",
|
|
59
|
+
message,
|
|
60
|
+
url,
|
|
61
|
+
elicitationId
|
|
62
|
+
});
|
|
63
|
+
if (result.action === "accept") return "accepted";
|
|
64
|
+
if (result.action === "decline") return "declined";
|
|
65
|
+
return "cancelled";
|
|
66
|
+
} catch {
|
|
67
|
+
return "cancelled";
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/** Sentinel error: elicitation mode not supported by client */
|
|
73
|
+
var ElicitationUnsupportedError = class extends Error {
|
|
74
|
+
constructor(mode) {
|
|
75
|
+
super(`Client does not support ${mode} elicitation`);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Collect non-sensitive fields via MCP form mode elicitation.
|
|
80
|
+
*
|
|
81
|
+
* @throws ElicitationUnsupportedError if client doesn't support form mode
|
|
82
|
+
* @returns collected values, or null if user declined/cancelled
|
|
83
|
+
*/
|
|
84
|
+
async function collectViaFormMode(server, schema) {
|
|
85
|
+
const properties = schema.properties || {};
|
|
86
|
+
const required = schema.required || [];
|
|
87
|
+
const formProperties = {};
|
|
88
|
+
for (const [key, prop] of Object.entries(properties)) formProperties[key] = {
|
|
89
|
+
type: "string",
|
|
90
|
+
...prop.description ? { description: prop.description } : {},
|
|
91
|
+
...prop.title ? { title: prop.title } : {},
|
|
92
|
+
...prop.default != null ? { default: prop.default } : {}
|
|
93
|
+
};
|
|
94
|
+
try {
|
|
95
|
+
const result = await server.elicitInput({
|
|
96
|
+
mode: "form",
|
|
97
|
+
message: "Please provide the required configuration:",
|
|
98
|
+
requestedSchema: {
|
|
99
|
+
type: "object",
|
|
100
|
+
properties: formProperties,
|
|
101
|
+
required
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
if (result.action === "accept" && result.content) return result.content;
|
|
105
|
+
return null;
|
|
106
|
+
} catch {
|
|
107
|
+
throw new ElicitationUnsupportedError("form");
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Collect fields containing sensitive data via URL mode.
|
|
112
|
+
* Starts a local HTTP server, sends URL mode elicitation so Client opens the browser.
|
|
113
|
+
* Form data goes directly from browser to local server (never through Client/LLM).
|
|
114
|
+
*
|
|
115
|
+
* @throws ElicitationUnsupportedError if client doesn't support URL mode
|
|
116
|
+
* @returns collected values, or null if user declined/cancelled
|
|
117
|
+
*/
|
|
118
|
+
async function collectViaURLMode(server, schema) {
|
|
119
|
+
const authServer = await require_auth_server.createAuthServer();
|
|
120
|
+
try {
|
|
121
|
+
const elicitationId = (0, node_crypto.randomBytes)(16).toString("hex");
|
|
122
|
+
const formURL = `${authServer.baseURL}/auth?nonce=${authServer.nonce}`;
|
|
123
|
+
let elicitResult;
|
|
124
|
+
try {
|
|
125
|
+
elicitResult = await server.elicitInput({
|
|
126
|
+
mode: "url",
|
|
127
|
+
message: "Please fill in the credential form in your browser:",
|
|
128
|
+
url: formURL,
|
|
129
|
+
elicitationId
|
|
130
|
+
});
|
|
131
|
+
} catch {
|
|
132
|
+
throw new ElicitationUnsupportedError("url");
|
|
133
|
+
}
|
|
134
|
+
if (elicitResult.action !== "accept") return null;
|
|
135
|
+
const result = await authServer.waitForForm(schema, {
|
|
136
|
+
title: "AFS Credential Collection",
|
|
137
|
+
timeout: 12e4
|
|
138
|
+
});
|
|
139
|
+
try {
|
|
140
|
+
await server.createElicitationCompletionNotifier(elicitationId)();
|
|
141
|
+
} catch {}
|
|
142
|
+
return result;
|
|
143
|
+
} finally {
|
|
144
|
+
authServer.close();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Fallback: collect credentials by opening a browser directly.
|
|
149
|
+
* Used when MCP client doesn't support elicitation protocol.
|
|
150
|
+
*/
|
|
151
|
+
async function collectViaBrowser(schema, openURLFn) {
|
|
152
|
+
const properties = schema.properties || {};
|
|
153
|
+
if (Object.keys(properties).length === 0) return {};
|
|
154
|
+
const authServer = await require_auth_server.createAuthServer();
|
|
155
|
+
const formURL = `${authServer.baseURL}/auth?nonce=${authServer.nonce}`;
|
|
156
|
+
console.error(`\nPlease fill in credentials in your browser:\n${formURL}`);
|
|
157
|
+
try {
|
|
158
|
+
await (openURLFn ?? openURL)(formURL);
|
|
159
|
+
} catch {}
|
|
160
|
+
try {
|
|
161
|
+
return await authServer.waitForForm(schema, { title: "AFS Credential Collection" });
|
|
162
|
+
} finally {
|
|
163
|
+
authServer.close();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Open a URL in the default browser.
|
|
168
|
+
*/
|
|
169
|
+
function openURL(url) {
|
|
170
|
+
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
171
|
+
const args = process.platform === "win32" ? [
|
|
172
|
+
"/c",
|
|
173
|
+
"start",
|
|
174
|
+
"",
|
|
175
|
+
url
|
|
176
|
+
] : [url];
|
|
177
|
+
return new Promise((resolve, reject) => {
|
|
178
|
+
(0, node_child_process.execFile)(cmd, args, (err) => {
|
|
179
|
+
if (err) reject(err);
|
|
180
|
+
else resolve();
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
//#endregion
|
|
186
|
+
exports.createMCPAuthContext = createMCPAuthContext;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { AuthContext } from "@aigne/afs";
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { createAuthServer } from "./auth-server.mjs";
|
|
2
|
+
import { randomBytes } from "node:crypto";
|
|
3
|
+
import { execFile } from "node:child_process";
|
|
4
|
+
import { getSensitiveFields } from "@aigne/afs/utils/schema";
|
|
5
|
+
|
|
6
|
+
//#region src/credential/mcp-auth-context.ts
|
|
7
|
+
/**
|
|
8
|
+
* MCP AuthContext implementation.
|
|
9
|
+
*
|
|
10
|
+
* Uses MCP elicitation protocol to collect credentials:
|
|
11
|
+
* - Non-sensitive fields: form mode (Client renders UI)
|
|
12
|
+
* - Sensitive fields: URL mode (local HTTP server, data never passes through Client/LLM)
|
|
13
|
+
*
|
|
14
|
+
* Requires an MCP Server instance that supports elicitation.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Create an MCP AuthContext for MCP-based credential collection.
|
|
18
|
+
*/
|
|
19
|
+
function createMCPAuthContext(options) {
|
|
20
|
+
const { server } = options;
|
|
21
|
+
const resolved = options.resolved ?? {};
|
|
22
|
+
const openURLFn = options.openURL;
|
|
23
|
+
return {
|
|
24
|
+
get resolved() {
|
|
25
|
+
return { ...resolved };
|
|
26
|
+
},
|
|
27
|
+
async collect(schema) {
|
|
28
|
+
const properties = schema.properties;
|
|
29
|
+
if (!properties || typeof properties !== "object") return {};
|
|
30
|
+
if (new Set(getSensitiveFields(schema)).size > 0) {
|
|
31
|
+
try {
|
|
32
|
+
return await collectViaURLMode(server, schema);
|
|
33
|
+
} catch (err) {
|
|
34
|
+
if (!(err instanceof ElicitationUnsupportedError)) throw err;
|
|
35
|
+
}
|
|
36
|
+
return collectViaBrowser(schema, openURLFn);
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
return await collectViaFormMode(server, schema);
|
|
40
|
+
} catch (err) {
|
|
41
|
+
if (!(err instanceof ElicitationUnsupportedError)) throw err;
|
|
42
|
+
}
|
|
43
|
+
return collectViaBrowser(schema, openURLFn);
|
|
44
|
+
},
|
|
45
|
+
async createCallbackServer() {
|
|
46
|
+
const authServer = await createAuthServer();
|
|
47
|
+
return {
|
|
48
|
+
callbackURL: authServer.callbackURL,
|
|
49
|
+
waitForCallback: authServer.waitForCallback.bind(authServer),
|
|
50
|
+
close: authServer.close.bind(authServer)
|
|
51
|
+
};
|
|
52
|
+
},
|
|
53
|
+
async requestOpenURL(url, message) {
|
|
54
|
+
try {
|
|
55
|
+
const elicitationId = randomBytes(16).toString("hex");
|
|
56
|
+
const result = await server.elicitInput({
|
|
57
|
+
mode: "url",
|
|
58
|
+
message,
|
|
59
|
+
url,
|
|
60
|
+
elicitationId
|
|
61
|
+
});
|
|
62
|
+
if (result.action === "accept") return "accepted";
|
|
63
|
+
if (result.action === "decline") return "declined";
|
|
64
|
+
return "cancelled";
|
|
65
|
+
} catch {
|
|
66
|
+
return "cancelled";
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/** Sentinel error: elicitation mode not supported by client */
|
|
72
|
+
var ElicitationUnsupportedError = class extends Error {
|
|
73
|
+
constructor(mode) {
|
|
74
|
+
super(`Client does not support ${mode} elicitation`);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Collect non-sensitive fields via MCP form mode elicitation.
|
|
79
|
+
*
|
|
80
|
+
* @throws ElicitationUnsupportedError if client doesn't support form mode
|
|
81
|
+
* @returns collected values, or null if user declined/cancelled
|
|
82
|
+
*/
|
|
83
|
+
async function collectViaFormMode(server, schema) {
|
|
84
|
+
const properties = schema.properties || {};
|
|
85
|
+
const required = schema.required || [];
|
|
86
|
+
const formProperties = {};
|
|
87
|
+
for (const [key, prop] of Object.entries(properties)) formProperties[key] = {
|
|
88
|
+
type: "string",
|
|
89
|
+
...prop.description ? { description: prop.description } : {},
|
|
90
|
+
...prop.title ? { title: prop.title } : {},
|
|
91
|
+
...prop.default != null ? { default: prop.default } : {}
|
|
92
|
+
};
|
|
93
|
+
try {
|
|
94
|
+
const result = await server.elicitInput({
|
|
95
|
+
mode: "form",
|
|
96
|
+
message: "Please provide the required configuration:",
|
|
97
|
+
requestedSchema: {
|
|
98
|
+
type: "object",
|
|
99
|
+
properties: formProperties,
|
|
100
|
+
required
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
if (result.action === "accept" && result.content) return result.content;
|
|
104
|
+
return null;
|
|
105
|
+
} catch {
|
|
106
|
+
throw new ElicitationUnsupportedError("form");
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Collect fields containing sensitive data via URL mode.
|
|
111
|
+
* Starts a local HTTP server, sends URL mode elicitation so Client opens the browser.
|
|
112
|
+
* Form data goes directly from browser to local server (never through Client/LLM).
|
|
113
|
+
*
|
|
114
|
+
* @throws ElicitationUnsupportedError if client doesn't support URL mode
|
|
115
|
+
* @returns collected values, or null if user declined/cancelled
|
|
116
|
+
*/
|
|
117
|
+
async function collectViaURLMode(server, schema) {
|
|
118
|
+
const authServer = await createAuthServer();
|
|
119
|
+
try {
|
|
120
|
+
const elicitationId = randomBytes(16).toString("hex");
|
|
121
|
+
const formURL = `${authServer.baseURL}/auth?nonce=${authServer.nonce}`;
|
|
122
|
+
let elicitResult;
|
|
123
|
+
try {
|
|
124
|
+
elicitResult = await server.elicitInput({
|
|
125
|
+
mode: "url",
|
|
126
|
+
message: "Please fill in the credential form in your browser:",
|
|
127
|
+
url: formURL,
|
|
128
|
+
elicitationId
|
|
129
|
+
});
|
|
130
|
+
} catch {
|
|
131
|
+
throw new ElicitationUnsupportedError("url");
|
|
132
|
+
}
|
|
133
|
+
if (elicitResult.action !== "accept") return null;
|
|
134
|
+
const result = await authServer.waitForForm(schema, {
|
|
135
|
+
title: "AFS Credential Collection",
|
|
136
|
+
timeout: 12e4
|
|
137
|
+
});
|
|
138
|
+
try {
|
|
139
|
+
await server.createElicitationCompletionNotifier(elicitationId)();
|
|
140
|
+
} catch {}
|
|
141
|
+
return result;
|
|
142
|
+
} finally {
|
|
143
|
+
authServer.close();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Fallback: collect credentials by opening a browser directly.
|
|
148
|
+
* Used when MCP client doesn't support elicitation protocol.
|
|
149
|
+
*/
|
|
150
|
+
async function collectViaBrowser(schema, openURLFn) {
|
|
151
|
+
const properties = schema.properties || {};
|
|
152
|
+
if (Object.keys(properties).length === 0) return {};
|
|
153
|
+
const authServer = await createAuthServer();
|
|
154
|
+
const formURL = `${authServer.baseURL}/auth?nonce=${authServer.nonce}`;
|
|
155
|
+
console.error(`\nPlease fill in credentials in your browser:\n${formURL}`);
|
|
156
|
+
try {
|
|
157
|
+
await (openURLFn ?? openURL)(formURL);
|
|
158
|
+
} catch {}
|
|
159
|
+
try {
|
|
160
|
+
return await authServer.waitForForm(schema, { title: "AFS Credential Collection" });
|
|
161
|
+
} finally {
|
|
162
|
+
authServer.close();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Open a URL in the default browser.
|
|
167
|
+
*/
|
|
168
|
+
function openURL(url) {
|
|
169
|
+
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
170
|
+
const args = process.platform === "win32" ? [
|
|
171
|
+
"/c",
|
|
172
|
+
"start",
|
|
173
|
+
"",
|
|
174
|
+
url
|
|
175
|
+
] : [url];
|
|
176
|
+
return new Promise((resolve, reject) => {
|
|
177
|
+
execFile(cmd, args, (err) => {
|
|
178
|
+
if (err) reject(err);
|
|
179
|
+
else resolve();
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
//#endregion
|
|
185
|
+
export { createMCPAuthContext };
|
|
186
|
+
//# sourceMappingURL=mcp-auth-context.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-auth-context.mjs","names":[],"sources":["../../src/credential/mcp-auth-context.ts"],"sourcesContent":["/**\n * MCP AuthContext implementation.\n *\n * Uses MCP elicitation protocol to collect credentials:\n * - Non-sensitive fields: form mode (Client renders UI)\n * - Sensitive fields: URL mode (local HTTP server, data never passes through Client/LLM)\n *\n * Requires an MCP Server instance that supports elicitation.\n */\n\nimport { execFile } from \"node:child_process\";\nimport { randomBytes } from \"node:crypto\";\nimport type { AuthContext, CallbackServer, JSONSchema7 } from \"@aigne/afs\";\nimport { getSensitiveFields } from \"@aigne/afs/utils/schema\";\nimport type { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { createAuthServer } from \"./auth-server.js\";\n\nexport interface MCPAuthContextOptions {\n /** The MCP Server instance (for sending elicitation requests) */\n server: Server;\n /** Pre-resolved fields from Step 2 (env/store/config) */\n resolved?: Record<string, unknown>;\n /** Override browser URL opener (for testing). Falls back to platform-default open. */\n openURL?: (url: string) => Promise<void>;\n}\n\n/**\n * Create an MCP AuthContext for MCP-based credential collection.\n */\nexport function createMCPAuthContext(options: MCPAuthContextOptions): AuthContext {\n const { server } = options;\n const resolved = options.resolved ?? {};\n const openURLFn = options.openURL;\n\n return {\n get resolved() {\n return { ...resolved };\n },\n\n async collect(schema: JSONSchema7): Promise<Record<string, unknown> | null> {\n const properties = (schema as any).properties;\n if (!properties || typeof properties !== \"object\") return {};\n\n const sensitiveFields = new Set(getSensitiveFields(schema));\n const hasSensitive = sensitiveFields.size > 0;\n\n // Strategy: try elicitation first, fall back to browser if client doesn't support it.\n // ElicitationUnsupportedError means \"not supported\" → try next mode.\n // null means \"user declined/cancelled\" → stop and return null.\n\n if (hasSensitive) {\n // Sensitive fields: try URL mode (data stays local, never through Client/LLM)\n try {\n return await collectViaURLMode(server, schema);\n } catch (err) {\n if (!(err instanceof ElicitationUnsupportedError)) throw err;\n }\n // URL mode not supported — browser fallback (also keeps data local)\n return collectViaBrowser(schema, openURLFn);\n }\n\n // Non-sensitive only: try form mode (Client renders UI)\n try {\n return await collectViaFormMode(server, schema);\n } catch (err) {\n if (!(err instanceof ElicitationUnsupportedError)) throw err;\n }\n\n // Form mode not supported — browser fallback\n return collectViaBrowser(schema, openURLFn);\n },\n\n async createCallbackServer(): Promise<CallbackServer> {\n const authServer = await createAuthServer();\n return {\n callbackURL: authServer.callbackURL,\n waitForCallback: authServer.waitForCallback.bind(authServer),\n close: authServer.close.bind(authServer),\n };\n },\n\n async requestOpenURL(\n url: string,\n message: string,\n ): Promise<\"accepted\" | \"declined\" | \"cancelled\"> {\n try {\n const elicitationId = randomBytes(16).toString(\"hex\");\n const result = await server.elicitInput({\n mode: \"url\",\n message,\n url,\n elicitationId,\n });\n\n if (result.action === \"accept\") return \"accepted\";\n if (result.action === \"decline\") return \"declined\";\n return \"cancelled\";\n } catch {\n // Client doesn't support elicitation — try direct open\n return \"cancelled\";\n }\n },\n };\n}\n\n/** Sentinel error: elicitation mode not supported by client */\nclass ElicitationUnsupportedError extends Error {\n constructor(mode: string) {\n super(`Client does not support ${mode} elicitation`);\n }\n}\n\n/**\n * Collect non-sensitive fields via MCP form mode elicitation.\n *\n * @throws ElicitationUnsupportedError if client doesn't support form mode\n * @returns collected values, or null if user declined/cancelled\n */\nasync function collectViaFormMode(\n server: Server,\n schema: JSONSchema7,\n): Promise<Record<string, unknown> | null> {\n const properties = (schema as any).properties || {};\n const required = (schema as any).required || [];\n\n // Build elicitation form schema (simplified for MCP form mode)\n const formProperties: Record<string, any> = {};\n for (const [key, prop] of Object.entries(properties) as [string, any][]) {\n formProperties[key] = {\n type: \"string\",\n ...(prop.description ? { description: prop.description } : {}),\n ...(prop.title ? { title: prop.title } : {}),\n ...(prop.default != null ? { default: prop.default } : {}),\n };\n }\n\n try {\n const result = await server.elicitInput({\n mode: \"form\",\n message: \"Please provide the required configuration:\",\n requestedSchema: {\n type: \"object\" as const,\n properties: formProperties,\n required,\n },\n });\n\n if (result.action === \"accept\" && result.content) {\n return result.content as Record<string, unknown>;\n }\n\n // User declined or cancelled\n return null;\n } catch {\n // Client doesn't support form elicitation\n throw new ElicitationUnsupportedError(\"form\");\n }\n}\n\n/**\n * Collect fields containing sensitive data via URL mode.\n * Starts a local HTTP server, sends URL mode elicitation so Client opens the browser.\n * Form data goes directly from browser to local server (never through Client/LLM).\n *\n * @throws ElicitationUnsupportedError if client doesn't support URL mode\n * @returns collected values, or null if user declined/cancelled\n */\nasync function collectViaURLMode(\n server: Server,\n schema: JSONSchema7,\n): Promise<Record<string, unknown> | null> {\n const authServer = await createAuthServer();\n\n try {\n const elicitationId = randomBytes(16).toString(\"hex\");\n const formURL = `${authServer.baseURL}/auth?nonce=${authServer.nonce}`;\n\n // Send URL mode elicitation to client — let errors propagate\n let elicitResult: { action: string };\n try {\n elicitResult = await server.elicitInput({\n mode: \"url\",\n message: \"Please fill in the credential form in your browser:\",\n url: formURL,\n elicitationId,\n });\n } catch {\n // Client doesn't support URL elicitation\n throw new ElicitationUnsupportedError(\"url\");\n }\n\n if (elicitResult.action !== \"accept\") {\n // User declined or cancelled\n return null;\n }\n\n // Client accepted — wait for form submission with timeout\n const result = await authServer.waitForForm(schema as Record<string, any>, {\n title: \"AFS Credential Collection\",\n timeout: 120_000, // 2-minute safety timeout\n });\n\n // Notify client that elicitation is complete\n try {\n const notifyComplete = server.createElicitationCompletionNotifier(elicitationId);\n await notifyComplete();\n } catch {\n // Notification failure is non-critical\n }\n\n return result;\n } finally {\n authServer.close();\n }\n}\n\n/**\n * Fallback: collect credentials by opening a browser directly.\n * Used when MCP client doesn't support elicitation protocol.\n */\nasync function collectViaBrowser(\n schema: JSONSchema7,\n openURLFn?: (url: string) => Promise<void>,\n): Promise<Record<string, unknown> | null> {\n const properties = (schema as any).properties || {};\n if (Object.keys(properties).length === 0) return {};\n\n const authServer = await createAuthServer();\n const formURL = `${authServer.baseURL}/auth?nonce=${authServer.nonce}`;\n\n console.error(`\\nPlease fill in credentials in your browser:\\n${formURL}`);\n\n try {\n await (openURLFn ?? openURL)(formURL);\n } catch {\n // Browser failed to open; URL is already printed above\n }\n\n try {\n const result = await authServer.waitForForm(schema as Record<string, any>, {\n title: \"AFS Credential Collection\",\n });\n return result;\n } finally {\n authServer.close();\n }\n}\n\n/**\n * Open a URL in the default browser.\n */\nfunction openURL(url: string): Promise<void> {\n const cmd =\n process.platform === \"darwin\" ? \"open\" : process.platform === \"win32\" ? \"cmd\" : \"xdg-open\";\n\n const args = process.platform === \"win32\" ? [\"/c\", \"start\", \"\", url] : [url];\n\n return new Promise((resolve, reject) => {\n execFile(cmd, args, (err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n}\n"],"mappings":"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"}
|