authflow-cli 0.4.1 → 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 +62 -341
- package/dist/checks.d.ts +30 -0
- package/dist/checks.js +36 -0
- package/dist/checks.js.map +1 -0
- package/dist/client-conformance.d.ts +5 -1
- package/dist/client-conformance.js +9 -1
- package/dist/client-conformance.js.map +1 -1
- 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/doctor.js +5 -1
- package/dist/commands/doctor.js.map +1 -1
- 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/register.js +30 -2
- package/dist/commands/register.js.map +1 -1
- package/dist/commands/set-domain.d.ts +34 -0
- package/dist/commands/set-domain.js +162 -0
- package/dist/commands/set-domain.js.map +1 -0
- 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 +36 -1
- 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/custom-domain.d.ts +96 -0
- package/dist/custom-domain.js +289 -0
- package/dist/custom-domain.js.map +1 -0
- package/dist/doctor.d.ts +31 -23
- package/dist/doctor.js +271 -57
- package/dist/doctor.js.map +1 -1
- package/dist/google-redirect.d.ts +5 -1
- package/dist/google-redirect.js +11 -5
- package/dist/google-redirect.js.map +1 -1
- 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/mcp/server.d.ts +8 -1
- package/dist/mcp/server.js +137 -7
- package/dist/mcp/server.js.map +1 -1
- package/dist/program.js +6 -1
- package/dist/program.js.map +1 -1
- package/dist/rail.d.ts +16 -0
- package/dist/rail.js +43 -0
- package/dist/rail.js.map +1 -1
- package/dist/resource-urls.d.ts +27 -0
- package/dist/resource-urls.js +56 -0
- package/dist/resource-urls.js.map +1 -0
- package/dist/secrets.d.ts +29 -14
- package/dist/secrets.js +201 -90
- package/dist/secrets.js.map +1 -1
- package/dist/status.d.ts +15 -1
- package/dist/status.js +68 -6
- package/dist/status.js.map +1 -1
- package/dist/surface.d.ts +1 -0
- package/dist/surface.js +1 -0
- package/dist/surface.js.map +1 -1
- package/dist/tenant-host.d.ts +49 -0
- package/dist/tenant-host.js +367 -0
- package/dist/tenant-host.js.map +1 -0
- package/dist/version.d.ts +10 -0
- package/dist/version.js +27 -0
- package/dist/version.js.map +1 -0
- package/package.json +6 -5
|
@@ -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/doctor.js
CHANGED
|
@@ -6,7 +6,9 @@ export function doctorCommand(program) {
|
|
|
6
6
|
.command("doctor")
|
|
7
7
|
.description("Check that the rail is reachable, serving a consistent Origin Protocol surface, and (with --client) accepts real MCP client OAuth registration. With --client and --slug (not --dry-run), also drive authorize through login and ask Google whether the rail's redirect_uri is registered")
|
|
8
8
|
.option("--issuer <url>", "Authflow issuer (default: AUTHFLOW_ISSUER)")
|
|
9
|
-
.option("--slug <slug>", "Also check this resource's PRM document and gateway 401 challenge")
|
|
9
|
+
.option("--slug <slug>", "Also check this resource's PRM document and gateway 401 challenge (read from the receipt when an admin key is available, so a resource on its own hostname is probed there)")
|
|
10
|
+
.option("--host <host>", "Also verify a tenant's own hostname end to end: the three DNS records, TLS certificate issuer and expiry, http to https redirect, PRM at both well-known paths, and the 401's resource_metadata. With an admin key, DNS is compared against the receipt (found by --slug, or by the host)")
|
|
11
|
+
.option("--admin-key <key>", "Admin API key (default: AUTHFLOW_ADMIN_API_KEY). Distinguishes a draft 404 from an unknown slug, and catches a stale key after a sandbox reset.")
|
|
10
12
|
.option("--client <name>", "Replay MCP client OAuth registration: cursor, claude, chatgpt, or all")
|
|
11
13
|
.option("--dry-run", "With --client: discovery only, do not POST DCR registrations")
|
|
12
14
|
.option("--json", "Emit the report as JSON")
|
|
@@ -16,8 +18,10 @@ export function doctorCommand(program) {
|
|
|
16
18
|
}
|
|
17
19
|
const report = await runDoctorAndConnect(requireIssuer(opts.issuer), {
|
|
18
20
|
slug: opts.slug,
|
|
21
|
+
host: opts.host,
|
|
19
22
|
client: opts.client,
|
|
20
23
|
dryRun: opts.dryRun,
|
|
24
|
+
adminKey: opts.adminKey,
|
|
21
25
|
});
|
|
22
26
|
console.log(opts.json ? JSON.stringify(report, null, 2) : formatDoctorReport(report));
|
|
23
27
|
process.exitCode = report.pass ? 0 : 1;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CACV,2RAA2R,CAC5R;SACA,MAAM,CAAC,gBAAgB,EAAE,4CAA4C,CAAC;SACtE,MAAM,
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CACV,2RAA2R,CAC5R;SACA,MAAM,CAAC,gBAAgB,EAAE,4CAA4C,CAAC;SACtE,MAAM,CACL,eAAe,EACf,6KAA6K,CAC9K;SACA,MAAM,CACL,eAAe,EACf,2RAA2R,CAC5R;SACA,MAAM,CAAC,mBAAmB,EAAE,iJAAiJ,CAAC;SAC9K,MAAM,CAAC,iBAAiB,EAAE,uEAAuE,CAAC;SAClG,MAAM,CAAC,WAAW,EAAE,8DAA8D,CAAC;SACnF,MAAM,CAAC,QAAQ,EAAE,yBAAyB,CAAC;SAC3C,MAAM,CACL,KAAK,EAAE,IAQN,EAAE,EAAE;QACH,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAC3D,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;YACnE,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxB,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;QACtF,OAAO,CAAC,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzC,CAAC,CACF,CAAC;AACN,CAAC"}
|
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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { apiJson, bearer, requireAdminKey, requireIssuer } from "../config.js";
|
|
3
|
+
import { parsePublicHost, parsePublicPath } from "../custom-domain.js";
|
|
3
4
|
import { secretTargets, writeOriginApiKey } from "../secrets.js";
|
|
4
5
|
import { formatCursorMcpConfig, formatReadiness, resourceReadiness } from "../status.js";
|
|
5
6
|
export function registerCommand(program) {
|
|
@@ -13,18 +14,21 @@ export function registerCommand(program) {
|
|
|
13
14
|
.option("--write-secrets <target>", `Store the origin API key and redact it from the receipt (${secretTargets.join(" | ")})`)
|
|
14
15
|
.option("--secret-destination <value>", "user-secrets: project dir (default .) · env-file: path (default .env.local) · keyvault: vault name")
|
|
15
16
|
.option("--keep-secret-in-receipt", "Leave the origin API key in the receipt file as plaintext (not recommended)")
|
|
17
|
+
.option("--public-host <host>", "Serve the resource on your own hostname (a subdomain) instead of the gateway's slug URL. Sent as public_host; the receipt then lists the DNS records to add")
|
|
18
|
+
.option("--public-path <path>", "Public MCP path on that host (default /mcp). Sent as public_path")
|
|
16
19
|
.action(async (opts) => {
|
|
17
20
|
const issuer = requireIssuer(opts.issuer);
|
|
18
21
|
const adminKey = requireAdminKey(opts.adminKey);
|
|
19
22
|
const target = parseTarget(opts.writeSecrets);
|
|
20
23
|
const draftRaw = (await readFile(opts.file, "utf8")).replace(/^\uFEFF/, "");
|
|
21
|
-
let
|
|
24
|
+
let parsed;
|
|
22
25
|
try {
|
|
23
|
-
|
|
26
|
+
parsed = JSON.parse(draftRaw);
|
|
24
27
|
}
|
|
25
28
|
catch {
|
|
26
29
|
throw new Error(`--file ${opts.file} is not valid JSON.`);
|
|
27
30
|
}
|
|
31
|
+
const draft = withPublicHost(parsed, opts);
|
|
28
32
|
const { body, status } = await apiJson(`${issuer}/admin/resources`, {
|
|
29
33
|
method: "POST",
|
|
30
34
|
headers: {
|
|
@@ -89,6 +93,30 @@ export function registerCommand(program) {
|
|
|
89
93
|
}
|
|
90
94
|
});
|
|
91
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* --public-host and --public-path are shorthand for the same two fields in the file, and win over
|
|
98
|
+
* it. A path with no host is refused here: the rail would have nothing to apply it to, and the
|
|
99
|
+
* silent outcome is a resource on the slug URL that the tenant believes is on their own.
|
|
100
|
+
*/
|
|
101
|
+
function withPublicHost(draft, opts) {
|
|
102
|
+
if (opts.publicHost === undefined && opts.publicPath === undefined) {
|
|
103
|
+
return draft;
|
|
104
|
+
}
|
|
105
|
+
if (draft === null || typeof draft !== "object" || Array.isArray(draft)) {
|
|
106
|
+
throw new Error(`--file ${opts.file} must hold a JSON object to combine it with --public-host / --public-path.`);
|
|
107
|
+
}
|
|
108
|
+
const merged = { ...draft };
|
|
109
|
+
if (opts.publicHost !== undefined) {
|
|
110
|
+
merged.public_host = parsePublicHost(opts.publicHost, "--public-host", "--public-path");
|
|
111
|
+
}
|
|
112
|
+
if (opts.publicPath !== undefined) {
|
|
113
|
+
merged.public_path = parsePublicPath(opts.publicPath, "--public-path");
|
|
114
|
+
}
|
|
115
|
+
if (merged.public_path !== undefined && merged.public_host === undefined) {
|
|
116
|
+
throw new Error("--public-path needs a host: pass --public-host (or set public_host in the file).");
|
|
117
|
+
}
|
|
118
|
+
return merged;
|
|
119
|
+
}
|
|
92
120
|
function parseTarget(raw) {
|
|
93
121
|
if (raw === undefined) {
|
|
94
122
|
return undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register.js","sourceRoot":"","sources":["../../src/commands/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,OAAO,EAAE,MAAM,EAA4B,eAAe,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACzG,OAAO,EAAqB,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACpF,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"register.js","sourceRoot":"","sources":["../../src/commands/register.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
export type SetDomainOptions = {
|
|
3
|
+
slug: string;
|
|
4
|
+
/** Omit to re-verify the host already set on the resource. */
|
|
5
|
+
host?: string;
|
|
6
|
+
path?: string;
|
|
7
|
+
wait?: boolean;
|
|
8
|
+
timeout?: string;
|
|
9
|
+
issuer?: string;
|
|
10
|
+
adminKey?: string;
|
|
11
|
+
};
|
|
12
|
+
/** Injectable so tests can drive the wait without real time or a real terminal. */
|
|
13
|
+
export type SetDomainEnvironment = {
|
|
14
|
+
sleep?: (ms: number) => Promise<void>;
|
|
15
|
+
now?: () => number;
|
|
16
|
+
log?: (line: string) => void;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Serve a resource on the tenant's own hostname: the "bring your existing MCP URL" step.
|
|
20
|
+
*
|
|
21
|
+
* Setting the host is the easy half. The rail answers with the DNS records the tenant has to create
|
|
22
|
+
* at a registrar this CLI cannot reach, so the command's job is to put those records on screen
|
|
23
|
+
* exactly as the rail issued them and then, with --wait, to confirm they took.
|
|
24
|
+
*
|
|
25
|
+
* There is no separate verify command, so this is also how a tenant re-checks after adding the
|
|
26
|
+
* records: with no --host it verifies the host already set on the resource instead of setting one.
|
|
27
|
+
*/
|
|
28
|
+
export declare function setDomainCommand(program: Command, env?: SetDomainEnvironment): void;
|
|
29
|
+
/**
|
|
30
|
+
* Returns the exit code instead of setting it: 0 when the domain is ready (or, without --wait,
|
|
31
|
+
* when it was set or re-checked and is not in a failure state), 1 when it timed out or is blocked,
|
|
32
|
+
* moved, or removed.
|
|
33
|
+
*/
|
|
34
|
+
export declare function runSetDomain(opts: SetDomainOptions, env?: SetDomainEnvironment): Promise<number>;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { requireAdminKey, requireIssuer } from "../config.js";
|
|
2
|
+
import { assertCustomDomainReturned, assertCustomDomainSet, customDomainState, defaultPublicPath, defaultWaitTimeoutSeconds, describeCustomDomainState, dnsInstructions, formatDuration, isCustomDomainFailure, parsePublicHost, parsePublicPath, setDomainCommandLine, summarizeCustomDomain, waitForCustomDomain, waitIntervalMs, } from "../custom-domain.js";
|
|
3
|
+
import { describePending, getResource, setCustomDomain, verifyCustomDomain } from "../rail.js";
|
|
4
|
+
import { formatCursorMcpConfig } from "../status.js";
|
|
5
|
+
/**
|
|
6
|
+
* Serve a resource on the tenant's own hostname: the "bring your existing MCP URL" step.
|
|
7
|
+
*
|
|
8
|
+
* Setting the host is the easy half. The rail answers with the DNS records the tenant has to create
|
|
9
|
+
* at a registrar this CLI cannot reach, so the command's job is to put those records on screen
|
|
10
|
+
* exactly as the rail issued them and then, with --wait, to confirm they took.
|
|
11
|
+
*
|
|
12
|
+
* There is no separate verify command, so this is also how a tenant re-checks after adding the
|
|
13
|
+
* records: with no --host it verifies the host already set on the resource instead of setting one.
|
|
14
|
+
*/
|
|
15
|
+
export function setDomainCommand(program, env = {}) {
|
|
16
|
+
program
|
|
17
|
+
.command("set-domain")
|
|
18
|
+
.description("Serve a resource on your own hostname, or re-verify the one already set: print the DNS records to add and, with --wait, poll until the domain is ready")
|
|
19
|
+
.requiredOption("--slug <slug>", "Resource slug")
|
|
20
|
+
.option("--host <host>", "Your hostname, e.g. mcp.example.com (a subdomain; no scheme, path or port). Omit it to re-verify the host already set on the resource")
|
|
21
|
+
.option("--path <path>", "Public MCP path on that host. Sent only when given: the rail uses /mcp the first time and keeps the stored path afterwards. Needs --host")
|
|
22
|
+
.option("--wait", "Poll verification until the domain is ready, fails, or --timeout passes")
|
|
23
|
+
.option("--timeout <seconds>", `With --wait: how long to keep polling before giving up (default ${defaultWaitTimeoutSeconds})`)
|
|
24
|
+
.option("--issuer <url>", "Authflow issuer (default: AUTHFLOW_ISSUER)")
|
|
25
|
+
.option("--admin-key <key>", "Admin API key (default: AUTHFLOW_ADMIN_API_KEY)")
|
|
26
|
+
.action(async (opts) => {
|
|
27
|
+
process.exitCode = await runSetDomain(opts, env);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Returns the exit code instead of setting it: 0 when the domain is ready (or, without --wait,
|
|
32
|
+
* when it was set or re-checked and is not in a failure state), 1 when it timed out or is blocked,
|
|
33
|
+
* moved, or removed.
|
|
34
|
+
*/
|
|
35
|
+
export async function runSetDomain(opts, env = {}) {
|
|
36
|
+
const log = env.log ?? ((line) => console.log(line));
|
|
37
|
+
const timeoutMs = resolveTimeoutMs(opts);
|
|
38
|
+
// A path belongs to a host being set. Re-verifying sends nothing, so a --path there would be
|
|
39
|
+
// silently ignored, and someone who typed it believes they changed the path.
|
|
40
|
+
if (opts.host === undefined && opts.path !== undefined) {
|
|
41
|
+
throw new Error("--path only applies with --host. Without a host this re-verifies the one already set, and the " +
|
|
42
|
+
"rail keeps its stored path.");
|
|
43
|
+
}
|
|
44
|
+
const host = opts.host === undefined ? undefined : parsePublicHost(opts.host);
|
|
45
|
+
const path = opts.path === undefined ? undefined : parsePublicPath(opts.path);
|
|
46
|
+
const auth = { issuer: requireIssuer(opts.issuer), adminKey: requireAdminKey(opts.adminKey) };
|
|
47
|
+
// Both routes end with a receipt to show and, with --wait, to poll from.
|
|
48
|
+
let receipt;
|
|
49
|
+
let hostName;
|
|
50
|
+
if (host !== undefined) {
|
|
51
|
+
receipt = await setCustomDomain(auth, opts.slug, host, path);
|
|
52
|
+
hostName = host;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
// Ask the receipt first. Verifying a resource with no host would fail with an error that does
|
|
56
|
+
// not say how to fix it; this says to pass --host.
|
|
57
|
+
hostName = assertCustomDomainSet(await getResource(auth, opts.slug), opts.slug);
|
|
58
|
+
receipt = await verifyCustomDomain(auth, opts.slug);
|
|
59
|
+
}
|
|
60
|
+
assertCustomDomainReturned(receipt, hostName, opts.slug);
|
|
61
|
+
const url = receipt.gateway_url ??
|
|
62
|
+
receipt.resource ??
|
|
63
|
+
`https://${hostName}${receipt.public_path ?? path ?? defaultPublicPath}`;
|
|
64
|
+
log(`${receipt.slug ?? opts.slug} -> ${url}`);
|
|
65
|
+
log(`state: ${summarizeCustomDomain(receipt)}`);
|
|
66
|
+
const instructions = dnsInstructions(receipt);
|
|
67
|
+
if (instructions.length > 0) {
|
|
68
|
+
log("");
|
|
69
|
+
for (const line of instructions) {
|
|
70
|
+
log(line);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const state = customDomainState(receipt);
|
|
74
|
+
if (state === "ready") {
|
|
75
|
+
return reportReady(receipt, opts.slug, log);
|
|
76
|
+
}
|
|
77
|
+
if (isCustomDomainFailure(state)) {
|
|
78
|
+
return reportFailure(receipt, opts.slug, log);
|
|
79
|
+
}
|
|
80
|
+
if (!opts.wait) {
|
|
81
|
+
log("");
|
|
82
|
+
log(host === undefined
|
|
83
|
+
? `Still not ready. To keep checking (now, then every ${formatDuration(waitIntervalMs)} until ready):`
|
|
84
|
+
: `Once the records are in place, verify (re-checks now, then every ${formatDuration(waitIntervalMs)} until ready):`);
|
|
85
|
+
log(` ${setDomainCommandLine(opts.slug)}`);
|
|
86
|
+
return 0;
|
|
87
|
+
}
|
|
88
|
+
log("");
|
|
89
|
+
log("Add the records above. This keeps checking and says when the domain is ready.");
|
|
90
|
+
const result = await waitForCustomDomain(receipt, {
|
|
91
|
+
verify: () => verifyCustomDomain(auth, opts.slug),
|
|
92
|
+
timeoutMs,
|
|
93
|
+
sleep: env.sleep,
|
|
94
|
+
now: env.now,
|
|
95
|
+
onProgress: (line) => log(` ${line}`),
|
|
96
|
+
});
|
|
97
|
+
switch (result.outcome) {
|
|
98
|
+
case "ready":
|
|
99
|
+
return reportReady(result.receipt, opts.slug, log);
|
|
100
|
+
case "failed":
|
|
101
|
+
return reportFailure(result.receipt, opts.slug, log);
|
|
102
|
+
case "timeout":
|
|
103
|
+
return reportTimeout(result.receipt, opts.slug, timeoutMs, log);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function resolveTimeoutMs(opts) {
|
|
107
|
+
if (opts.timeout === undefined) {
|
|
108
|
+
return defaultWaitTimeoutSeconds * 1000;
|
|
109
|
+
}
|
|
110
|
+
if (!opts.wait) {
|
|
111
|
+
throw new Error("--timeout only applies with --wait.");
|
|
112
|
+
}
|
|
113
|
+
const seconds = Number(opts.timeout);
|
|
114
|
+
if (!Number.isFinite(seconds) || seconds <= 0) {
|
|
115
|
+
throw new Error(`--timeout must be a positive number of seconds (got '${opts.timeout}').`);
|
|
116
|
+
}
|
|
117
|
+
return seconds * 1000;
|
|
118
|
+
}
|
|
119
|
+
function reportReady(receipt, slug, log) {
|
|
120
|
+
log("");
|
|
121
|
+
log(`Ready. ${receipt.gateway_url ?? receipt.resource ?? "The hostname"} is serving this resource.`);
|
|
122
|
+
const config = formatCursorMcpConfig(receipt);
|
|
123
|
+
if (config.length > 0) {
|
|
124
|
+
log("");
|
|
125
|
+
for (const line of config) {
|
|
126
|
+
log(line);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// A ready hostname is one requirement, not the whole go-live. Say what is left rather than let
|
|
130
|
+
// "Ready" read as "live".
|
|
131
|
+
const pending = receipt.pending_requirements ?? [];
|
|
132
|
+
if (pending.length > 0) {
|
|
133
|
+
log("");
|
|
134
|
+
log("Still pending before go-live:");
|
|
135
|
+
for (const requirement of pending) {
|
|
136
|
+
log(` ${requirement}`);
|
|
137
|
+
log(` ${describePending(requirement, slug)}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return 0;
|
|
141
|
+
}
|
|
142
|
+
function reportFailure(receipt, slug, log) {
|
|
143
|
+
const state = customDomainState(receipt);
|
|
144
|
+
log("");
|
|
145
|
+
log(`The custom domain is ${state}: ${describeCustomDomainState(state)}.`);
|
|
146
|
+
log(`last error: ${receipt.custom_domain?.last_error?.trim() || "(the rail gave no detail)"}`);
|
|
147
|
+
log("");
|
|
148
|
+
log(`Fix the cause, then re-run: ${setDomainCommandLine(slug)}`);
|
|
149
|
+
return 1;
|
|
150
|
+
}
|
|
151
|
+
function reportTimeout(receipt, slug, timeoutMs, log) {
|
|
152
|
+
log("");
|
|
153
|
+
log(`Still ${customDomainState(receipt) ?? "unknown"} after ${formatDuration(timeoutMs)}.`);
|
|
154
|
+
const error = receipt.custom_domain?.last_error?.trim();
|
|
155
|
+
if (error) {
|
|
156
|
+
log(`last error: ${error}`);
|
|
157
|
+
}
|
|
158
|
+
log("Nothing is lost. Add or fix the records above, then re-run:");
|
|
159
|
+
log(` ${setDomainCommandLine(slug)}`);
|
|
160
|
+
return 1;
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=set-domain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"set-domain.js","sourceRoot":"","sources":["../../src/commands/set-domain.ts"],"names":[],"mappings":"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"}
|
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"}
|