authflow-cli 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -492
- package/dist/commands/account.d.ts +2 -0
- package/dist/commands/account.js +105 -0
- package/dist/commands/account.js.map +1 -0
- package/dist/commands/mcp.js +11 -6
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/plan.js +7 -7
- package/dist/commands/plan.js.map +1 -1
- package/dist/commands/signup.d.ts +1 -0
- package/dist/commands/signup.js +4 -50
- package/dist/commands/signup.js.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/credentials.d.ts +22 -0
- package/dist/credentials.js +206 -0
- package/dist/credentials.js.map +1 -0
- package/dist/integration-plans.json +80 -0
- package/dist/integration.d.ts +17 -23
- package/dist/integration.js +29 -236
- package/dist/integration.js.map +1 -1
- package/dist/login.d.ts +11 -0
- package/dist/login.js +181 -0
- package/dist/login.js.map +1 -0
- package/dist/management.d.ts +17 -0
- package/dist/management.js +67 -0
- package/dist/management.js.map +1 -0
- package/dist/mcp/management-server.d.ts +4 -0
- package/dist/mcp/management-server.js +103 -0
- package/dist/mcp/management-server.js.map +1 -0
- package/dist/program.js +2 -0
- package/dist/program.js.map +1 -1
- package/dist/rail.js +4 -0
- package/dist/rail.js.map +1 -1
- package/dist/secrets.d.ts +29 -14
- package/dist/secrets.js +201 -90
- package/dist/secrets.js.map +1 -1
- package/dist/status.js +10 -2
- package/dist/status.js.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { requireIssuer } from "../config.js";
|
|
3
|
+
import { login, logout } from "../login.js";
|
|
4
|
+
import { currentWorkspacePath, managementRequest, managementResourceActions, redactToolSecrets } from "../management.js";
|
|
5
|
+
import { secretDelivery, secretTargets } from "../secrets.js";
|
|
6
|
+
const print = (value) => { process.stdout.write(`${JSON.stringify(value, null, 2)}\n`); };
|
|
7
|
+
export function accountCommands(program) {
|
|
8
|
+
program.command("login").description("Sign in in the browser and store a workspace login in your OS credential store")
|
|
9
|
+
.option("--issuer <url>", "Authflow issuer (default: AUTHFLOW_ISSUER)")
|
|
10
|
+
.option("--workspace <id>", "Workspace to authorize; otherwise choose in the browser")
|
|
11
|
+
.option("--no-browser", "Print the login URL without opening a browser")
|
|
12
|
+
.action(async (options) => print(await login(requireIssuer(options.issuer), options.workspace, options.browser !== false)));
|
|
13
|
+
program.command("logout").description("Revoke and remove the saved Authflow login")
|
|
14
|
+
.option("--issuer <url>", "Authflow issuer")
|
|
15
|
+
.option("--local-only", "Clear this device only; server authorization is not revoked")
|
|
16
|
+
.action(async (options) => { await logout(requireIssuer(options.issuer), { localOnly: options.localOnly }); print({ signed_out: true, authorization_revoked: !options.localOnly }); });
|
|
17
|
+
const workspace = program.command("workspace").description("Manage your verified workspace");
|
|
18
|
+
workspace.command("list").option("--issuer <url>").action(async (options) => print(await managementRequest(requireIssuer(options.issuer), "/workspaces")));
|
|
19
|
+
for (const operation of ["overview", "usage", "earnings"])
|
|
20
|
+
workspace.command(operation).option("--issuer <url>").option("--workspace <id>").action(async (options) => {
|
|
21
|
+
const issuer = requireIssuer(options.issuer);
|
|
22
|
+
print(await managementRequest(issuer, `${await currentWorkspacePath(issuer, options.workspace)}/${operation}`));
|
|
23
|
+
});
|
|
24
|
+
workspace.command("rename <name>").option("--issuer <url>").option("--workspace <id>").action(async (name, options) => {
|
|
25
|
+
const issuer = requireIssuer(options.issuer);
|
|
26
|
+
print(await managementRequest(issuer, await currentWorkspacePath(issuer, options.workspace), "PATCH", { name }));
|
|
27
|
+
});
|
|
28
|
+
const docs = program.command("docs").description("Search and read Authflow's indexed public documentation");
|
|
29
|
+
docs.command("search <query>").option("--issuer <url>").action(async (query, options) => {
|
|
30
|
+
print(await managementRequest(requireIssuer(options.issuer), "/docs/search", "GET", undefined, { q: query }));
|
|
31
|
+
});
|
|
32
|
+
docs.command("get <path>").option("--issuer <url>").action(async (path, options) => {
|
|
33
|
+
print(await managementRequest(requireIssuer(options.issuer), "/docs/page", "GET", undefined, { path }));
|
|
34
|
+
});
|
|
35
|
+
const resource = program.command("resource").description("Create, configure, verify, and explicitly publish an MCP");
|
|
36
|
+
for (const operation of ["list", "get", "create", "update", "origin", "domain", ...managementResourceActions, "rotate-key"]) {
|
|
37
|
+
const command = resource.command(operation.replace("/", "-"));
|
|
38
|
+
if (!["list", "create"].includes(operation))
|
|
39
|
+
command.argument("<slug>");
|
|
40
|
+
command.option("--issuer <url>").option("--workspace <id>");
|
|
41
|
+
if (["create", "update", "origin", "domain"].includes(operation))
|
|
42
|
+
command.requiredOption("--file <path>", "Resource input JSON");
|
|
43
|
+
if (["create", "rotate-key"].includes(operation))
|
|
44
|
+
command.option("--write-secrets <target>", secretTargets.join(" | ")).option("--secret-destination <value>", "Explicit project, env-file path, or vault for origin-reported usage");
|
|
45
|
+
command.action(async (...args) => {
|
|
46
|
+
const hasSlug = !["list", "create"].includes(operation);
|
|
47
|
+
const slug = hasSlug ? String(args[0]) : undefined;
|
|
48
|
+
const options = args[hasSlug ? 1 : 0];
|
|
49
|
+
const issuer = requireIssuer(options.issuer);
|
|
50
|
+
const workspacePath = await currentWorkspacePath(issuer, options.workspace);
|
|
51
|
+
const path = `${workspacePath}/resources${slug ? `/${encodeURIComponent(slug)}` : ""}`;
|
|
52
|
+
const body = options.file ? JSON.parse((await readFile(options.file, "utf8")).replace(/^\uFEFF/, "")) : undefined;
|
|
53
|
+
let prepared;
|
|
54
|
+
if (operation === "create" || operation === "rotate-key") {
|
|
55
|
+
// Resolve ownership and the actual metering policy before rotating or touching a destination.
|
|
56
|
+
const resource = operation === "rotate-key" ? await managementRequest(issuer, path) : body;
|
|
57
|
+
if (requiresOriginCredential(resource)) {
|
|
58
|
+
if (operation === "rotate-key" || options.writeSecrets || options.secretDestination) {
|
|
59
|
+
if (!options.writeSecrets || !secretTargets.includes(options.writeSecrets) || !options.secretDestination?.trim())
|
|
60
|
+
throw new Error("Choose both --write-secrets <target> and --secret-destination <destination>. The origin key is never printed.");
|
|
61
|
+
const resourceSlug = slug ?? resource.slug;
|
|
62
|
+
prepared = await secretDelivery.prepare({ target: options.writeSecrets, destination: options.secretDestination,
|
|
63
|
+
resource: { issuer, workspaceId: decodeURIComponent(workspacePath.split("/")[2]), slug: resourceSlug } });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else if (operation === "rotate-key") {
|
|
67
|
+
print({ result: redactToolSecrets(resource), origin_key_delivery: { status: "not_required" } });
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const method = ["get", "list"].includes(operation) ? "GET" : operation === "update" ? "PATCH" : "POST";
|
|
72
|
+
const suffix = ["get", "list", "create", "update"].includes(operation) ? "" : `/${operation}`;
|
|
73
|
+
const result = await managementRequest(issuer, path + suffix, method, body);
|
|
74
|
+
let storedAt;
|
|
75
|
+
if (prepared) {
|
|
76
|
+
if (!result || typeof result !== "object" || !("origin_api_key" in result) || typeof result.origin_api_key !== "string")
|
|
77
|
+
throw new Error("The resource operation completed without a deliverable origin key. Inspect the resource before explicitly requesting another rotation.");
|
|
78
|
+
try {
|
|
79
|
+
await prepared.write(result.origin_api_key);
|
|
80
|
+
storedAt = prepared.description;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
throw new Error("The resource operation completed, but origin-key delivery failed. The previous key may already be revoked. Check the destination and explicitly run resource rotate-key when ready; no mutation was retried.");
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
print({ result: redactToolSecrets(result), ...(storedAt ? { origin_key_stored_at: storedAt, deployment_updated: false } : {}),
|
|
87
|
+
...(operation === "create" && !storedAt ? { origin_key_delivery: { status: requiresOriginCredential(result) ? "required" : "not_required" } } : {}) });
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
const stripe = program.command("stripe").description("Inspect payout readiness or open signed-in Stripe setup");
|
|
91
|
+
for (const operation of ["status", "onboard", "connect-existing"]) {
|
|
92
|
+
stripe.command(operation).option("--issuer <url>").option("--workspace <id>").action(async (options) => {
|
|
93
|
+
const issuer = requireIssuer(options.issuer);
|
|
94
|
+
const path = `${await currentWorkspacePath(issuer, options.workspace)}/stripe`;
|
|
95
|
+
print(await managementRequest(issuer, operation === "status" ? path : `${path}/actions`, operation === "status" ? "GET" : "POST", operation === "status" ? undefined : { kind: operation === "onboard" ? "onboard" : "connect_existing" }));
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function requiresOriginCredential(value) {
|
|
100
|
+
if (!value || typeof value !== "object")
|
|
101
|
+
return false;
|
|
102
|
+
const resource = value;
|
|
103
|
+
return resource.access_mode === "paid" && resource.metering_mode === "origin_reported";
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=account.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account.js","sourceRoot":"","sources":["../../src/commands/account.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/mcp.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { runStdioServer } from "../mcp/server.js";
|
|
2
|
+
import { runManagementStdioServer } from "../mcp/management-server.js";
|
|
2
3
|
export function mcpCommand(program) {
|
|
3
4
|
program
|
|
4
5
|
.command("mcp")
|
|
5
|
-
.description("Run
|
|
6
|
+
.description("Run workspace-scoped Authflow management using your OS-stored login")
|
|
7
|
+
.option("--legacy-admin", "Use the legacy operator-admin adapter for migration and recovery")
|
|
6
8
|
.addHelpText("after", [
|
|
7
9
|
"",
|
|
8
10
|
"Add to an MCP client (Cursor, Claude Desktop) so a coding agent can onboard a server",
|
|
@@ -10,15 +12,18 @@ export function mcpCommand(program) {
|
|
|
10
12
|
"",
|
|
11
13
|
' { "mcpServers": { "authflow": {',
|
|
12
14
|
' "command": "npx", "args": ["-y", "-p", "authflow-cli", "authflow", "mcp"],',
|
|
13
|
-
' "env": { "AUTHFLOW_ISSUER": "https://…"
|
|
15
|
+
' "env": { "AUTHFLOW_ISSUER": "https://…" } } } }',
|
|
14
16
|
"",
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
+
"Run authflow login first. The credential stays in your operating system's keyring.",
|
|
18
|
+
"You can also connect a remote MCP client directly to <issuer>/management/mcp.",
|
|
17
19
|
"",
|
|
18
20
|
"stdout is the MCP transport, so this command writes nothing else to it.",
|
|
19
21
|
].join("\n"))
|
|
20
|
-
.action(async () => {
|
|
21
|
-
|
|
22
|
+
.action(async (options) => {
|
|
23
|
+
if (options.legacyAdmin)
|
|
24
|
+
await runStdioServer();
|
|
25
|
+
else
|
|
26
|
+
await runManagementStdioServer();
|
|
22
27
|
});
|
|
23
28
|
}
|
|
24
29
|
//# sourceMappingURL=mcp.js.map
|
package/dist/commands/mcp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAEvE,MAAM,UAAU,UAAU,CAAC,OAAgB;IACzC,OAAO;SACJ,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,qEAAqE,CAAC;SAClF,MAAM,CAAC,gBAAgB,EAAE,kEAAkE,CAAC;SAC5F,WAAW,CACV,OAAO,EACP;QACE,EAAE;QACF,sFAAsF;QACtF,2CAA2C;QAC3C,EAAE;QACF,mCAAmC;QACnC,kFAAkF;QAClF,uDAAuD;QACvD,EAAE;QACF,oFAAoF;QACpF,+EAA+E;QAC/E,EAAE;QACF,yEAAyE;KAC1E,CAAC,IAAI,CAAC,IAAI,CAAC,CACb;SACA,MAAM,CAAC,KAAK,EAAE,OAAkC,EAAE,EAAE;QACnD,IAAI,OAAO,CAAC,WAAW;YAAE,MAAM,cAAc,EAAE,CAAC;;YAC3C,MAAM,wBAAwB,EAAE,CAAC;IACxC,CAAC,CAAC,CAAC;AACP,CAAC"}
|
package/dist/commands/plan.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { requireIssuer } from "../config.js";
|
|
2
|
+
import { integrationFrameworks, isIntegrationFramework, } from "../integration.js";
|
|
3
|
+
import { currentWorkspacePath, managementRequest } from "../management.js";
|
|
4
4
|
/**
|
|
5
5
|
* CLI twin of `authflow_integration_plan`. The MCP tool is how an agent usually gets this; the
|
|
6
6
|
* command exists so the two surfaces stay the same size.
|
|
@@ -12,14 +12,14 @@ export function planCommand(program) {
|
|
|
12
12
|
.requiredOption("--slug <slug>", "Resource slug")
|
|
13
13
|
.requiredOption("--framework <kind>", `Origin implementation (${integrationFrameworks.join(" | ")})`)
|
|
14
14
|
.option("--issuer <url>", "Authflow issuer (default: AUTHFLOW_ISSUER)")
|
|
15
|
-
.option("--
|
|
15
|
+
.option("--workspace <id>", "Workspace selected by authflow login")
|
|
16
16
|
.action(async (opts) => {
|
|
17
17
|
if (!isIntegrationFramework(opts.framework)) {
|
|
18
18
|
throw new Error(`--framework must be one of: ${integrationFrameworks.join(", ")}. Got '${opts.framework}'.`);
|
|
19
19
|
}
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const plan =
|
|
20
|
+
const issuer = requireIssuer(opts.issuer);
|
|
21
|
+
const workspace = await currentWorkspacePath(issuer, opts.workspace);
|
|
22
|
+
const plan = await managementRequest(issuer, `${workspace}/resources/${encodeURIComponent(opts.slug)}/integration-plan`, "GET", undefined, { framework: opts.framework });
|
|
23
23
|
console.log(JSON.stringify(plan, null, 2));
|
|
24
24
|
});
|
|
25
25
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../src/commands/plan.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../src/commands/plan.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE3E;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,OAAgB;IAC1C,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,qEAAqE,CAAC;SAClF,cAAc,CAAC,eAAe,EAAE,eAAe,CAAC;SAChD,cAAc,CACb,oBAAoB,EACpB,0BAA0B,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAC/D;SACA,MAAM,CAAC,gBAAgB,EAAE,4CAA4C,CAAC;SACtE,MAAM,CAAC,kBAAkB,EAAE,sCAAsC,CAAC;SAClE,MAAM,CAAC,KAAK,EAAE,IAA8E,EAAE,EAAE;QAC/F,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YAC5C,MAAM,IAAI,KAAK,CACb,+BAA+B,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,SAAS,IAAI,CAC5F,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,SAAS,GAAG,MAAM,oBAAoB,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QACrE,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,MAAM,EAAE,GAAG,SAAS,cAAc,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QAC1K,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACP,CAAC"}
|
package/dist/commands/signup.js
CHANGED
|
@@ -1,53 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
import { signupTenant } from "../rail.js";
|
|
3
|
-
import { writeAdminApiKey } from "../secrets.js";
|
|
1
|
+
/** Compatibility command: an email address is not proof of account ownership. */
|
|
4
2
|
export function signupCommand(program) {
|
|
5
|
-
program
|
|
6
|
-
.
|
|
7
|
-
.
|
|
8
|
-
.requiredOption("--email <address>", "Email that owns the tenant")
|
|
9
|
-
.option("--issuer <url>", "Authflow issuer (default: AUTHFLOW_ISSUER)")
|
|
10
|
-
.option("--write-secrets", "Write the key to an env file (default: .env.local)", true)
|
|
11
|
-
.option("--no-write-secrets", "Print the key only; do not write it to disk")
|
|
12
|
-
.option("--secret-destination <path>", "Env-file path for --write-secrets")
|
|
13
|
-
.addHelpText("after", [
|
|
14
|
-
"",
|
|
15
|
-
"The key is scoped to slugs you register with it. Paste it into Cursor as",
|
|
16
|
-
"AUTHFLOW_ADMIN_API_KEY, then run `authflow mcp` or `authflow init`.",
|
|
17
|
-
].join("\n"))
|
|
18
|
-
.action(async (opts) => {
|
|
19
|
-
const issuer = requireIssuer(opts.issuer);
|
|
20
|
-
const receipt = await signupTenant(issuer, opts.email);
|
|
21
|
-
let storedAt;
|
|
22
|
-
if (opts.writeSecrets !== false) {
|
|
23
|
-
storedAt = await writeAdminApiKey({
|
|
24
|
-
value: receipt.admin_api_key,
|
|
25
|
-
destination: opts.secretDestination,
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
const mcpConfig = {
|
|
29
|
-
mcpServers: {
|
|
30
|
-
authflow: {
|
|
31
|
-
command: "npx",
|
|
32
|
-
args: ["-y", "-p", "authflow-cli", "authflow", "mcp"],
|
|
33
|
-
env: {
|
|
34
|
-
AUTHFLOW_ISSUER: receipt.issuer,
|
|
35
|
-
AUTHFLOW_ADMIN_API_KEY: storedAt ? `<from ${storedAt}>` : receipt.admin_api_key,
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
};
|
|
40
|
-
process.stdout.write(JSON.stringify({
|
|
41
|
-
...receipt,
|
|
42
|
-
admin_api_key: storedAt ? `<stored in ${storedAt}>` : receipt.admin_api_key,
|
|
43
|
-
mcp_config: mcpConfig,
|
|
44
|
-
next_steps: [
|
|
45
|
-
storedAt
|
|
46
|
-
? `Load ${storedAt} (or copy the key into Cursor's MCP env) and run: npx -y -p authflow-cli authflow init --slug <your-slug>`
|
|
47
|
-
: "Store the admin_api_key, then: npx -y -p authflow-cli authflow init --slug <your-slug>",
|
|
48
|
-
"Or paste mcp_config into Cursor and let the agent finish onboarding.",
|
|
49
|
-
],
|
|
50
|
-
}, null, 2) + "\n");
|
|
51
|
-
});
|
|
3
|
+
program.command("signup").description("Moved: use verified browser sign-in with authflow login")
|
|
4
|
+
.option("--email <address>").option("--issuer <url>").option("--write-secrets").option("--no-write-secrets").option("--secret-destination <path>")
|
|
5
|
+
.action(() => { throw new Error("Email-only signup has been retired. Create a workspace in the Authflow portal, then run authflow login --issuer <issuer>. Existing tenant owners can claim their workspace in the portal with their current admin credential."); });
|
|
52
6
|
}
|
|
53
7
|
//# sourceMappingURL=signup.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signup.js","sourceRoot":"","sources":["../../src/commands/signup.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"signup.js","sourceRoot":"","sources":["../../src/commands/signup.ts"],"names":[],"mappings":"AAEA,iFAAiF;AACjF,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,yDAAyD,CAAC;SAC7F,MAAM,CAAC,mBAAmB,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,MAAM,CAAC,6BAA6B,CAAC;SACjJ,MAAM,CAAC,GAAG,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,+NAA+N,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzQ,CAAC"}
|
package/dist/config.d.ts
CHANGED
|
@@ -54,12 +54,16 @@ export type RegistrationReceipt = {
|
|
|
54
54
|
origin_api_key?: string;
|
|
55
55
|
gateway_egress_cidrs?: string[];
|
|
56
56
|
status?: string;
|
|
57
|
+
access_mode?: "free" | "paid";
|
|
57
58
|
metering_mode?: string;
|
|
59
|
+
metering_default_units?: number;
|
|
60
|
+
tool_units?: Record<string, number>;
|
|
58
61
|
/**
|
|
59
62
|
* What still blocks go-live: origin_base_uri, connected_account_id, stripe_onboarding_complete,
|
|
60
63
|
* and custom_domain_dns while a custom host is set but not yet ready.
|
|
61
64
|
*/
|
|
62
65
|
pending_requirements?: string[];
|
|
66
|
+
allowed_actions?: string[];
|
|
63
67
|
last_probe_at_utc?: string | null;
|
|
64
68
|
last_probe_passed?: boolean | null;
|
|
65
69
|
};
|
package/dist/config.js
CHANGED
|
@@ -9,7 +9,7 @@ export function requireIssuer(flag) {
|
|
|
9
9
|
export function requireAdminKey(flag) {
|
|
10
10
|
const key = (flag ?? process.env.AUTHFLOW_ADMIN_API_KEY ?? "").trim();
|
|
11
11
|
if (!key) {
|
|
12
|
-
throw new Error("
|
|
12
|
+
throw new Error("This legacy operator command requires AUTHFLOW_ADMIN_API_KEY or --admin-key. For creator onboarding, run authflow login and use authflow resource commands. Claim an existing workspace in the portal with its current tenant key.");
|
|
13
13
|
}
|
|
14
14
|
return key;
|
|
15
15
|
}
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAU5C,MAAM,UAAU,aAAa,CAAC,IAAa;IACzC,MAAM,MAAM,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACtF,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAa;IAC3C,MAAM,GAAG,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACtE,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type LoginCredential = {
|
|
2
|
+
issuer: string;
|
|
3
|
+
client_id: string;
|
|
4
|
+
access_token: string;
|
|
5
|
+
refresh_token?: string;
|
|
6
|
+
expires_at: number;
|
|
7
|
+
workspace_id: string;
|
|
8
|
+
};
|
|
9
|
+
/** Credentials never enter the checkout, environment files, or tool results. */
|
|
10
|
+
export declare function credentialEntry(issuer: string, suffix?: string): Promise<import("@napi-rs/keyring").Entry>;
|
|
11
|
+
export declare function readCredential(issuer: string): Promise<LoginCredential | undefined>;
|
|
12
|
+
export declare function saveCredential(credential: LoginCredential): Promise<void>;
|
|
13
|
+
export declare function deleteCredential(issuer: string): Promise<void>;
|
|
14
|
+
/** Serialize refresh-token rotation across CLI/MCP processes. The lock contains no secrets. */
|
|
15
|
+
export declare function withCredentialLock<T>(issuer: string, action: () => Promise<T>): Promise<T>;
|
|
16
|
+
/** One storage boundary also lets protocol tests use an isolated in-memory credential store. */
|
|
17
|
+
export declare const credentialStore: {
|
|
18
|
+
read: typeof readCredential;
|
|
19
|
+
save: typeof saveCredential;
|
|
20
|
+
delete: typeof deleteCredential;
|
|
21
|
+
withLock: typeof withCredentialLock;
|
|
22
|
+
};
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, rmdir, stat, unlink, utimes, writeFile } from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
6
|
+
/** Credentials never enter the checkout, environment files, or tool results. */
|
|
7
|
+
export async function credentialEntry(issuer, suffix = "") {
|
|
8
|
+
try {
|
|
9
|
+
const { Entry } = await import("@napi-rs/keyring");
|
|
10
|
+
return new Entry("authflow-cli", issuer + suffix, { linux: { store: "secret-service" } });
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
throw new Error("The operating system credential store is unavailable. Enable your desktop keyring and retry; Authflow does not fall back to plaintext credentials.");
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export async function readCredential(issuer) {
|
|
17
|
+
const entry = await credentialEntry(issuer);
|
|
18
|
+
let value;
|
|
19
|
+
try {
|
|
20
|
+
value = entry.getPassword();
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
throw new Error("Unable to read the OS credential store. Unlock it and retry authflow login.");
|
|
24
|
+
}
|
|
25
|
+
if (!value)
|
|
26
|
+
return undefined;
|
|
27
|
+
const manifest = parseManifest(value);
|
|
28
|
+
const chunks = [];
|
|
29
|
+
for (let i = 0; i < manifest.count; i++) {
|
|
30
|
+
const chunk = (await credentialEntry(issuer, `:${manifest.generation}:${i}`)).getPassword();
|
|
31
|
+
if (chunk === null)
|
|
32
|
+
throw new Error("Stored Authflow login is incomplete; run authflow login again.");
|
|
33
|
+
chunks.push(chunk);
|
|
34
|
+
}
|
|
35
|
+
let parsed;
|
|
36
|
+
try {
|
|
37
|
+
parsed = JSON.parse(chunks.join(""));
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
throw new Error("Stored Authflow login is invalid; run authflow login again.");
|
|
41
|
+
}
|
|
42
|
+
if (!parsed || typeof parsed !== "object")
|
|
43
|
+
throw new Error("Stored Authflow login is invalid; run authflow login again.");
|
|
44
|
+
const credential = parsed;
|
|
45
|
+
if (credential.issuer !== issuer || typeof credential.client_id !== "string" || !credential.client_id
|
|
46
|
+
|| typeof credential.access_token !== "string" || !credential.access_token || typeof credential.workspace_id !== "string" || !credential.workspace_id
|
|
47
|
+
|| credential.refresh_token !== undefined && typeof credential.refresh_token !== "string" || !Number.isFinite(credential.expires_at)) {
|
|
48
|
+
throw new Error("Stored Authflow login is invalid; run authflow login again.");
|
|
49
|
+
}
|
|
50
|
+
return credential;
|
|
51
|
+
}
|
|
52
|
+
export async function saveCredential(credential) {
|
|
53
|
+
// Windows limits each credential blob. Publish one small manifest only after every
|
|
54
|
+
// protected chunk is written; interrupted writes leave the previous login readable.
|
|
55
|
+
const entry = await credentialEntry(credential.issuer);
|
|
56
|
+
const previous = entry.getPassword();
|
|
57
|
+
const serialized = JSON.stringify(credential);
|
|
58
|
+
const generation = randomBytes(16).toString("hex");
|
|
59
|
+
const count = Math.ceil(serialized.length / 1000);
|
|
60
|
+
if (count > 64)
|
|
61
|
+
throw new Error("The issuer returned an unexpectedly large login credential.");
|
|
62
|
+
let written = 0;
|
|
63
|
+
try {
|
|
64
|
+
for (; written < count; written++) {
|
|
65
|
+
(await credentialEntry(credential.issuer, `:${generation}:${written}`)).setPassword(serialized.slice(written * 1000, (written + 1) * 1000));
|
|
66
|
+
}
|
|
67
|
+
entry.setPassword(JSON.stringify({ generation, count }));
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
await removeChunks(credential.issuer, { generation, count: written });
|
|
71
|
+
throw new Error("Unable to save the login in your OS credential store. Unlock it and retry authflow login.");
|
|
72
|
+
}
|
|
73
|
+
if (previous) {
|
|
74
|
+
try {
|
|
75
|
+
await removeChunks(credential.issuer, parseManifest(previous));
|
|
76
|
+
}
|
|
77
|
+
catch { /* Replacing an invalid manifest still successfully repairs the login. */ }
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export async function deleteCredential(issuer) {
|
|
81
|
+
const entry = await credentialEntry(issuer);
|
|
82
|
+
const previous = entry.getPassword();
|
|
83
|
+
entry.deletePassword();
|
|
84
|
+
if (previous) {
|
|
85
|
+
try {
|
|
86
|
+
await removeChunks(issuer, parseManifest(previous));
|
|
87
|
+
}
|
|
88
|
+
catch { /* An invalid old manifest cannot make removal of the login fail. */ }
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function parseManifest(value) {
|
|
92
|
+
let parsed;
|
|
93
|
+
try {
|
|
94
|
+
parsed = JSON.parse(value);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
throw new Error("Stored Authflow login is invalid; run authflow login again.");
|
|
98
|
+
}
|
|
99
|
+
if (!parsed || typeof parsed !== "object" || !/^[a-f0-9]{32}$/.test(parsed.generation) || !Number.isInteger(parsed.count) || parsed.count < 1 || parsed.count > 64) {
|
|
100
|
+
throw new Error("Stored Authflow login is invalid; run authflow login again.");
|
|
101
|
+
}
|
|
102
|
+
return parsed;
|
|
103
|
+
}
|
|
104
|
+
async function removeChunks(issuer, manifest) {
|
|
105
|
+
for (let i = 0; i < manifest.count; i++) {
|
|
106
|
+
try {
|
|
107
|
+
(await credentialEntry(issuer, `:${manifest.generation}:${i}`)).deletePassword();
|
|
108
|
+
}
|
|
109
|
+
catch { /* A revoked orphan remains OS-protected. */ }
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/** Serialize refresh-token rotation across CLI/MCP processes. The lock contains no secrets. */
|
|
113
|
+
export async function withCredentialLock(issuer, action) {
|
|
114
|
+
const directory = join(homedir(), ".authflow", "locks");
|
|
115
|
+
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
116
|
+
const lock = join(directory, createHash("sha256").update(issuer).digest("hex"));
|
|
117
|
+
const ownerPath = join(lock, "owner.json");
|
|
118
|
+
const owner = { pid: process.pid, id: randomBytes(16).toString("hex") };
|
|
119
|
+
const deadline = Date.now() + 45_000;
|
|
120
|
+
while (true) {
|
|
121
|
+
try {
|
|
122
|
+
await mkdir(lock, { mode: 0o700 });
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
if (error.code !== "EEXIST")
|
|
127
|
+
throw error;
|
|
128
|
+
const info = await stat(lock).catch(() => undefined);
|
|
129
|
+
// A suspended process can miss its heartbeat while still holding a rotating refresh
|
|
130
|
+
// token. Never steal its lock merely because a timer elapsed.
|
|
131
|
+
if (info && Date.now() - info.mtimeMs > 60_000) {
|
|
132
|
+
await recoverAbandonedLock(lock, ownerPath);
|
|
133
|
+
}
|
|
134
|
+
if (Date.now() >= deadline)
|
|
135
|
+
throw new Error("Another Authflow login is busy. Retry shortly.");
|
|
136
|
+
await delay(200);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
await writeFile(ownerPath, JSON.stringify(owner), { mode: 0o600 });
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
await rmdir(lock).catch(() => undefined);
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
const heartbeat = setInterval(() => { const now = new Date(); void utimes(lock, now, now).catch(() => undefined); }, 10_000);
|
|
147
|
+
heartbeat.unref();
|
|
148
|
+
try {
|
|
149
|
+
return await action();
|
|
150
|
+
}
|
|
151
|
+
finally {
|
|
152
|
+
clearInterval(heartbeat);
|
|
153
|
+
if ((await lockOwner(ownerPath))?.id === owner.id) {
|
|
154
|
+
await unlink(ownerPath);
|
|
155
|
+
await rmdir(lock);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
async function lockOwner(path) {
|
|
160
|
+
try {
|
|
161
|
+
const owner = JSON.parse(await readFile(path, "utf8"));
|
|
162
|
+
if (owner && typeof owner === "object" && "pid" in owner && "id" in owner
|
|
163
|
+
&& Number.isInteger(owner.pid) && Number(owner.pid) > 0 && typeof owner.id === "string")
|
|
164
|
+
return owner;
|
|
165
|
+
}
|
|
166
|
+
catch { /* An interrupted acquisition can leave an empty legacy lock. */ }
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
function processIsAlive(pid) {
|
|
170
|
+
try {
|
|
171
|
+
process.kill(pid, 0);
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
return error.code !== "ESRCH";
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
async function recoverAbandonedLock(lock, ownerPath) {
|
|
179
|
+
// Serialize stale cleanup. Recheck the owner after acquiring this marker: another
|
|
180
|
+
// waiter may already have recovered the directory and acquired a fresh login lock.
|
|
181
|
+
const recovery = join(lock, "recovering");
|
|
182
|
+
try {
|
|
183
|
+
await mkdir(recovery, { mode: 0o700 });
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
let abandoned = false;
|
|
189
|
+
try {
|
|
190
|
+
const previous = await lockOwner(ownerPath);
|
|
191
|
+
if (previous && processIsAlive(previous.pid))
|
|
192
|
+
return;
|
|
193
|
+
abandoned = true;
|
|
194
|
+
await unlink(ownerPath).catch(() => undefined);
|
|
195
|
+
}
|
|
196
|
+
finally {
|
|
197
|
+
await rmdir(recovery).catch(() => undefined);
|
|
198
|
+
}
|
|
199
|
+
// A new owner writes owner.json before entering its action, so a delayed cleanup
|
|
200
|
+
// cannot delete an acquired lock: rmdir refuses any nonempty directory.
|
|
201
|
+
if (abandoned)
|
|
202
|
+
await rmdir(lock).catch(() => undefined);
|
|
203
|
+
}
|
|
204
|
+
/** One storage boundary also lets protocol tests use an isolated in-memory credential store. */
|
|
205
|
+
export const credentialStore = { read: readCredential, save: saveCredential, delete: deleteCredential, withLock: withCredentialLock };
|
|
206
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"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"}
|