authflow-cli 0.1.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/LICENSE +201 -0
- package/README.md +260 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +33 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/connect.d.ts +7 -0
- package/dist/commands/connect.js +84 -0
- package/dist/commands/connect.js.map +1 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +16 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/init.d.ts +12 -0
- package/dist/commands/init.js +182 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/mcp.d.ts +2 -0
- package/dist/commands/mcp.js +24 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/mint-header.d.ts +2 -0
- package/dist/commands/mint-header.js +69 -0
- package/dist/commands/mint-header.js.map +1 -0
- package/dist/commands/probe.d.ts +2 -0
- package/dist/commands/probe.js +49 -0
- package/dist/commands/probe.js.map +1 -0
- package/dist/commands/register.d.ts +2 -0
- package/dist/commands/register.js +78 -0
- package/dist/commands/register.js.map +1 -0
- package/dist/commands/scaffold.d.ts +2 -0
- package/dist/commands/scaffold.js +72 -0
- package/dist/commands/scaffold.js.map +1 -0
- package/dist/commands/set-origin.d.ts +6 -0
- package/dist/commands/set-origin.js +38 -0
- package/dist/commands/set-origin.js.map +1 -0
- package/dist/commands/signup.d.ts +2 -0
- package/dist/commands/signup.js +53 -0
- package/dist/commands/signup.js.map +1 -0
- package/dist/config.d.ts +47 -0
- package/dist/config.js +56 -0
- package/dist/config.js.map +1 -0
- package/dist/constants.d.ts +12 -0
- package/dist/constants.js +13 -0
- package/dist/constants.js.map +1 -0
- package/dist/doctor.d.ts +24 -0
- package/dist/doctor.js +230 -0
- package/dist/doctor.js.map +1 -0
- package/dist/integration.d.ts +44 -0
- package/dist/integration.js +247 -0
- package/dist/integration.js.map +1 -0
- package/dist/mcp/server.d.ts +3 -0
- package/dist/mcp/server.js +362 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/rail.d.ts +80 -0
- package/dist/rail.js +115 -0
- package/dist/rail.js.map +1 -0
- package/dist/secrets.d.ts +28 -0
- package/dist/secrets.js +117 -0
- package/dist/secrets.js.map +1 -0
- package/package.json +56 -0
package/dist/rail.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { type RegistrationReceipt } from "./config.js";
|
|
2
|
+
/**
|
|
3
|
+
* One typed wrapper per rail admin/Origin-Protocol call, so the CLI commands and the MCP server
|
|
4
|
+
* drive the same code. They are two front ends onto one onboarding flow; when they drift, the
|
|
5
|
+
* agent-driven path silently stops matching the documented one.
|
|
6
|
+
*/
|
|
7
|
+
export type ConnectOnboarding = {
|
|
8
|
+
slug: string;
|
|
9
|
+
connected_account_id: string;
|
|
10
|
+
charges_enabled: boolean;
|
|
11
|
+
details_submitted: boolean;
|
|
12
|
+
payouts_enabled: boolean;
|
|
13
|
+
onboarding_url?: string | null;
|
|
14
|
+
onboarding_url_expires_at?: string | null;
|
|
15
|
+
status: string;
|
|
16
|
+
pending_requirements: string[];
|
|
17
|
+
};
|
|
18
|
+
export type ConformanceCheck = {
|
|
19
|
+
name: string;
|
|
20
|
+
pass: boolean;
|
|
21
|
+
expected: string;
|
|
22
|
+
observed: string;
|
|
23
|
+
};
|
|
24
|
+
export type ConformanceReport = {
|
|
25
|
+
pass: boolean;
|
|
26
|
+
origin: string;
|
|
27
|
+
checks: ConformanceCheck[];
|
|
28
|
+
error?: string | null;
|
|
29
|
+
};
|
|
30
|
+
export type MintedHeader = {
|
|
31
|
+
header?: string;
|
|
32
|
+
identity_header?: string;
|
|
33
|
+
[key: string]: unknown;
|
|
34
|
+
};
|
|
35
|
+
export type ResourceDraft = {
|
|
36
|
+
slug: string;
|
|
37
|
+
display_name?: string;
|
|
38
|
+
origin_base_uri?: string | null;
|
|
39
|
+
connected_account_id?: string | null;
|
|
40
|
+
currency?: string;
|
|
41
|
+
price_amount_minor?: number;
|
|
42
|
+
credits_per_period?: number;
|
|
43
|
+
metering_mode?: string;
|
|
44
|
+
metering_default_units?: number;
|
|
45
|
+
tool_units?: Record<string, number>;
|
|
46
|
+
documentation_uri?: string;
|
|
47
|
+
merchant_display_name?: string;
|
|
48
|
+
};
|
|
49
|
+
export type TenantSignup = {
|
|
50
|
+
tenant_id: string;
|
|
51
|
+
email: string;
|
|
52
|
+
admin_api_key: string;
|
|
53
|
+
issuer: string;
|
|
54
|
+
};
|
|
55
|
+
export type AdminAuth = {
|
|
56
|
+
issuer: string;
|
|
57
|
+
adminKey: string;
|
|
58
|
+
};
|
|
59
|
+
export declare function signupTenant(issuer: string, email: string): Promise<TenantSignup>;
|
|
60
|
+
export declare function registerResource(auth: AdminAuth, draft: ResourceDraft): Promise<RegistrationReceipt & Record<string, unknown>>;
|
|
61
|
+
export declare function getResource(auth: AdminAuth, slug: string): Promise<RegistrationReceipt>;
|
|
62
|
+
export declare function setOrigin(auth: AdminAuth, slug: string, originBaseUri: string): Promise<RegistrationReceipt>;
|
|
63
|
+
export declare function setConnectedAccount(auth: AdminAuth, slug: string, connectedAccountId: string): Promise<RegistrationReceipt>;
|
|
64
|
+
export declare function startConnect(auth: AdminAuth, slug: string, email?: string): Promise<ConnectOnboarding>;
|
|
65
|
+
export declare function rotateOriginKey(auth: AdminAuth, slug: string): Promise<RegistrationReceipt>;
|
|
66
|
+
/** Authenticates with the origin API key, which is bound to exactly one resource. */
|
|
67
|
+
export declare function probeConformance(issuer: string, originApiKey: string): Promise<ConformanceReport>;
|
|
68
|
+
export declare function mintDevHeader(issuer: string, originApiKey: string, options?: {
|
|
69
|
+
subject?: string;
|
|
70
|
+
tier?: string;
|
|
71
|
+
ttlSeconds?: number;
|
|
72
|
+
grantCredits?: number;
|
|
73
|
+
}): Promise<MintedHeader>;
|
|
74
|
+
/**
|
|
75
|
+
* The gateway appends `/mcp` to the origin base URI, so an origin URL that already ends in `/mcp`
|
|
76
|
+
* gets called at `/mcp/mcp`. Cheap to catch here, confusing to debug once traffic is flowing.
|
|
77
|
+
*/
|
|
78
|
+
export declare function assertNotMcpSuffixed(originUrl: string): void;
|
|
79
|
+
/** Human-readable next step for each `pending_requirements` entry the receipt can carry. */
|
|
80
|
+
export declare function describePending(requirement: string, slug: string): string;
|
package/dist/rail.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { apiJson, bearer } from "./config.js";
|
|
2
|
+
const jsonHeaders = { "Content-Type": "application/json", Accept: "application/json" };
|
|
3
|
+
export async function signupTenant(issuer, email) {
|
|
4
|
+
const { body } = await apiJson(`${issuer.replace(/\/+$/, "")}/admin/tenants`, {
|
|
5
|
+
method: "POST",
|
|
6
|
+
headers: jsonHeaders,
|
|
7
|
+
body: JSON.stringify({ email }),
|
|
8
|
+
expectedStatuses: [201],
|
|
9
|
+
});
|
|
10
|
+
return body;
|
|
11
|
+
}
|
|
12
|
+
export async function registerResource(auth, draft) {
|
|
13
|
+
const { body } = await apiJson(`${auth.issuer}/admin/resources`, {
|
|
14
|
+
method: "POST",
|
|
15
|
+
headers: { ...bearer(auth.adminKey), ...jsonHeaders },
|
|
16
|
+
body: JSON.stringify(draft),
|
|
17
|
+
expectedStatuses: [201],
|
|
18
|
+
});
|
|
19
|
+
return body;
|
|
20
|
+
}
|
|
21
|
+
export async function getResource(auth, slug) {
|
|
22
|
+
const { body } = await apiJson(`${auth.issuer}/admin/resources/${encodeURIComponent(slug)}`, {
|
|
23
|
+
method: "GET",
|
|
24
|
+
headers: { ...bearer(auth.adminKey), Accept: "application/json" },
|
|
25
|
+
expectedStatuses: [200],
|
|
26
|
+
});
|
|
27
|
+
return body;
|
|
28
|
+
}
|
|
29
|
+
export async function setOrigin(auth, slug, originBaseUri) {
|
|
30
|
+
assertNotMcpSuffixed(originBaseUri);
|
|
31
|
+
const { body } = await apiJson(`${auth.issuer}/admin/resources/${encodeURIComponent(slug)}/origin`, {
|
|
32
|
+
method: "PUT",
|
|
33
|
+
headers: { ...bearer(auth.adminKey), ...jsonHeaders },
|
|
34
|
+
body: JSON.stringify({ origin_base_uri: originBaseUri }),
|
|
35
|
+
expectedStatuses: [200],
|
|
36
|
+
});
|
|
37
|
+
return body;
|
|
38
|
+
}
|
|
39
|
+
export async function setConnectedAccount(auth, slug, connectedAccountId) {
|
|
40
|
+
const { body } = await apiJson(`${auth.issuer}/admin/resources/${encodeURIComponent(slug)}/connected-account`, {
|
|
41
|
+
method: "PUT",
|
|
42
|
+
headers: { ...bearer(auth.adminKey), ...jsonHeaders },
|
|
43
|
+
body: JSON.stringify({ connected_account_id: connectedAccountId }),
|
|
44
|
+
expectedStatuses: [200],
|
|
45
|
+
});
|
|
46
|
+
return body;
|
|
47
|
+
}
|
|
48
|
+
export async function startConnect(auth, slug, email) {
|
|
49
|
+
const { body } = await apiJson(`${auth.issuer}/admin/resources/${encodeURIComponent(slug)}/connect`, {
|
|
50
|
+
method: "POST",
|
|
51
|
+
headers: { ...bearer(auth.adminKey), ...jsonHeaders },
|
|
52
|
+
body: JSON.stringify(email ? { email } : {}),
|
|
53
|
+
expectedStatuses: [200],
|
|
54
|
+
});
|
|
55
|
+
return body;
|
|
56
|
+
}
|
|
57
|
+
export async function rotateOriginKey(auth, slug) {
|
|
58
|
+
const { body } = await apiJson(`${auth.issuer}/admin/resources/${encodeURIComponent(slug)}/rotate-origin-key`, {
|
|
59
|
+
method: "POST",
|
|
60
|
+
headers: { ...bearer(auth.adminKey), Accept: "application/json" },
|
|
61
|
+
expectedStatuses: [200],
|
|
62
|
+
});
|
|
63
|
+
return body;
|
|
64
|
+
}
|
|
65
|
+
/** Authenticates with the origin API key, which is bound to exactly one resource. */
|
|
66
|
+
export async function probeConformance(issuer, originApiKey) {
|
|
67
|
+
const { body } = await apiJson(`${issuer}/origin/v1/conformance`, {
|
|
68
|
+
method: "POST",
|
|
69
|
+
headers: { ...bearer(originApiKey), Accept: "application/json" },
|
|
70
|
+
expectedStatuses: [200],
|
|
71
|
+
});
|
|
72
|
+
return body;
|
|
73
|
+
}
|
|
74
|
+
export async function mintDevHeader(issuer, originApiKey, options = {}) {
|
|
75
|
+
const payload = {};
|
|
76
|
+
if (options.subject)
|
|
77
|
+
payload.subject = options.subject;
|
|
78
|
+
if (options.tier)
|
|
79
|
+
payload.tier = options.tier;
|
|
80
|
+
if (options.ttlSeconds !== undefined)
|
|
81
|
+
payload.ttl_seconds = options.ttlSeconds;
|
|
82
|
+
if (options.grantCredits !== undefined)
|
|
83
|
+
payload.grant_credits = options.grantCredits;
|
|
84
|
+
const { body } = await apiJson(`${issuer}/origin/v1/dev/mint-header`, {
|
|
85
|
+
method: "POST",
|
|
86
|
+
headers: { ...bearer(originApiKey), ...jsonHeaders },
|
|
87
|
+
body: JSON.stringify(payload),
|
|
88
|
+
expectedStatuses: [200],
|
|
89
|
+
});
|
|
90
|
+
return body;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* The gateway appends `/mcp` to the origin base URI, so an origin URL that already ends in `/mcp`
|
|
94
|
+
* gets called at `/mcp/mcp`. Cheap to catch here, confusing to debug once traffic is flowing.
|
|
95
|
+
*/
|
|
96
|
+
export function assertNotMcpSuffixed(originUrl) {
|
|
97
|
+
if (/\/mcp\/?$/i.test(originUrl)) {
|
|
98
|
+
const trimmed = originUrl.replace(/\/$/, "");
|
|
99
|
+
throw new Error(`Origin URL must not end in /mcp. The gateway appends it, so ${originUrl} would be called at ${trimmed}/mcp.`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/** Human-readable next step for each `pending_requirements` entry the receipt can carry. */
|
|
103
|
+
export function describePending(requirement, slug) {
|
|
104
|
+
switch (requirement) {
|
|
105
|
+
case "origin_base_uri":
|
|
106
|
+
return `Deploy the origin, then: authflow set-origin --slug ${slug} --origin-url https://your-origin.example`;
|
|
107
|
+
case "connected_account_id":
|
|
108
|
+
return `Connect Stripe: authflow connect --slug ${slug}`;
|
|
109
|
+
case "stripe_onboarding_complete":
|
|
110
|
+
return `Finish Stripe KYC in the browser, then re-run: authflow connect --slug ${slug}`;
|
|
111
|
+
default:
|
|
112
|
+
return requirement;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=rail.js.map
|
package/dist/rail.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rail.js","sourceRoot":"","sources":["../src/rail.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where `register --write-secrets` puts the origin API key.
|
|
3
|
+
*
|
|
4
|
+
* The key is shown exactly once, so the default path of "write the receipt to disk and sort the
|
|
5
|
+
* secret out later" reliably ends with a plaintext credential in a JSON file next to the source —
|
|
6
|
+
* and often in git. Each target below hands it to something built to hold it.
|
|
7
|
+
*/
|
|
8
|
+
export type SecretTarget = "user-secrets" | "env-file" | "keyvault";
|
|
9
|
+
export declare const secretTargets: readonly SecretTarget[];
|
|
10
|
+
/** Config key the .NET verifier and the origin proxy both read the usage-reporting key from. */
|
|
11
|
+
export declare const originApiKeyConfigKey = "Authflow:OriginApiKey";
|
|
12
|
+
/** Environment variable form of the same setting, for non-.NET origins. */
|
|
13
|
+
export declare const originApiKeyEnvVar = "AUTHFLOW_ORIGIN_API_KEY";
|
|
14
|
+
/** Per-tenant admin key used by `init`, `register`, and `authflow mcp`. */
|
|
15
|
+
export declare const adminApiKeyEnvVar = "AUTHFLOW_ADMIN_API_KEY";
|
|
16
|
+
export type WriteSecretRequest = {
|
|
17
|
+
target: SecretTarget;
|
|
18
|
+
value: string;
|
|
19
|
+
/** Project directory for `user-secrets`, file path for `env-file`, vault name for `keyvault`. */
|
|
20
|
+
destination?: string;
|
|
21
|
+
};
|
|
22
|
+
/** Human-readable description of where the secret landed, for the receipt and console. */
|
|
23
|
+
/** Writes AUTHFLOW_ADMIN_API_KEY to an env file. Signup's default so the key is not only in stdout. */
|
|
24
|
+
export declare function writeAdminApiKey(request: {
|
|
25
|
+
value: string;
|
|
26
|
+
destination?: string;
|
|
27
|
+
}): Promise<string>;
|
|
28
|
+
export declare function writeOriginApiKey(request: WriteSecretRequest): Promise<string>;
|
package/dist/secrets.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { appendFile, chmod, readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
export const secretTargets = ["user-secrets", "env-file", "keyvault"];
|
|
5
|
+
/** Config key the .NET verifier and the origin proxy both read the usage-reporting key from. */
|
|
6
|
+
export const originApiKeyConfigKey = "Authflow:OriginApiKey";
|
|
7
|
+
/** Environment variable form of the same setting, for non-.NET origins. */
|
|
8
|
+
export const originApiKeyEnvVar = "AUTHFLOW_ORIGIN_API_KEY";
|
|
9
|
+
/** Per-tenant admin key used by `init`, `register`, and `authflow mcp`. */
|
|
10
|
+
export const adminApiKeyEnvVar = "AUTHFLOW_ADMIN_API_KEY";
|
|
11
|
+
/** Human-readable description of where the secret landed, for the receipt and console. */
|
|
12
|
+
/** Writes AUTHFLOW_ADMIN_API_KEY to an env file. Signup's default so the key is not only in stdout. */
|
|
13
|
+
export async function writeAdminApiKey(request) {
|
|
14
|
+
return writeNamedEnvVar(adminApiKeyEnvVar, request.value, request.destination);
|
|
15
|
+
}
|
|
16
|
+
export async function writeOriginApiKey(request) {
|
|
17
|
+
switch (request.target) {
|
|
18
|
+
case "user-secrets":
|
|
19
|
+
return writeUserSecret(request);
|
|
20
|
+
case "env-file":
|
|
21
|
+
return writeEnvFile(request);
|
|
22
|
+
case "keyvault":
|
|
23
|
+
return writeKeyVault(request);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async function writeUserSecret(request) {
|
|
27
|
+
const project = request.destination ?? ".";
|
|
28
|
+
await run("dotnet", ["user-secrets", "set", originApiKeyConfigKey, request.value, "--project", project]);
|
|
29
|
+
return `dotnet user-secrets (${originApiKeyConfigKey}) in ${resolve(project)}`;
|
|
30
|
+
}
|
|
31
|
+
async function writeEnvFile(request) {
|
|
32
|
+
return writeNamedEnvVar(originApiKeyEnvVar, request.value, request.destination);
|
|
33
|
+
}
|
|
34
|
+
async function writeNamedEnvVar(name, value, destination) {
|
|
35
|
+
const path = resolve(destination ?? ".env.local");
|
|
36
|
+
const line = `${name}=${value}\n`;
|
|
37
|
+
const existing = await readFileOrEmpty(path);
|
|
38
|
+
const next = existing ? `${stripVar(existing, name)}${line}` : line;
|
|
39
|
+
await writeFile(path, next, "utf8");
|
|
40
|
+
// Best-effort: a no-op on Windows, which is exactly why this is not the recommended target.
|
|
41
|
+
await chmod(path, 0o600).catch(() => undefined);
|
|
42
|
+
await ensureGitIgnored(path);
|
|
43
|
+
return path;
|
|
44
|
+
}
|
|
45
|
+
async function writeKeyVault(request) {
|
|
46
|
+
const vault = request.destination;
|
|
47
|
+
if (!vault) {
|
|
48
|
+
throw new Error("--secret-destination <vault-name> is required for --write-secrets keyvault.");
|
|
49
|
+
}
|
|
50
|
+
// Key Vault names cannot contain ':'; keep the mapping mechanical so it is guessable from config.
|
|
51
|
+
const name = originApiKeyConfigKey.replace(/:/g, "--");
|
|
52
|
+
await run("az", ["keyvault", "secret", "set", "--vault-name", vault, "--name", name, "--value", request.value]);
|
|
53
|
+
return `Azure Key Vault ${vault}/${name}`;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Adds the secret file to .gitignore if it is not already covered.
|
|
57
|
+
*
|
|
58
|
+
* Deliberately conservative: it only appends when the exact pattern is absent, because a
|
|
59
|
+
* false-negative here costs one duplicate line and a false-positive leaks a credential.
|
|
60
|
+
*/
|
|
61
|
+
async function ensureGitIgnored(secretPath) {
|
|
62
|
+
const gitignore = resolve(dirname(secretPath), ".gitignore");
|
|
63
|
+
const pattern = secretPath.split(/[/\\]/).pop();
|
|
64
|
+
if (!pattern) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const existing = await readFileOrEmpty(gitignore);
|
|
68
|
+
if (existing.split(/\r?\n/).some((line) => line.trim() === pattern)) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const prefix = existing && !existing.endsWith("\n") ? "\n" : "";
|
|
72
|
+
await appendFile(gitignore, `${prefix}${pattern}\n`, "utf8");
|
|
73
|
+
}
|
|
74
|
+
async function readFileOrEmpty(path) {
|
|
75
|
+
try {
|
|
76
|
+
return await readFile(path, "utf8");
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return "";
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function stripVar(contents, name) {
|
|
83
|
+
const kept = contents
|
|
84
|
+
.split(/\r?\n/)
|
|
85
|
+
.filter((line) => !line.startsWith(`${name}=`))
|
|
86
|
+
.join("\n")
|
|
87
|
+
.replace(/\n+$/, "");
|
|
88
|
+
return kept ? `${kept}\n` : "";
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Runs a tool with the secret in argv.
|
|
92
|
+
*
|
|
93
|
+
* `shell: false` matters: the secret is passed as a discrete argument, so no shell ever parses it
|
|
94
|
+
* and a value containing quotes or `$` cannot turn into a command.
|
|
95
|
+
*/
|
|
96
|
+
function run(command, args) {
|
|
97
|
+
return new Promise((resolvePromise, reject) => {
|
|
98
|
+
const child = spawn(command, [...args], { stdio: ["ignore", "ignore", "pipe"], shell: false });
|
|
99
|
+
let stderr = "";
|
|
100
|
+
child.stderr?.on("data", (chunk) => {
|
|
101
|
+
stderr += chunk.toString();
|
|
102
|
+
});
|
|
103
|
+
child.on("error", (err) => {
|
|
104
|
+
reject(err.code === "ENOENT"
|
|
105
|
+
? new Error(`${command} was not found on PATH. Install it or use --write-secrets env-file.`)
|
|
106
|
+
: err);
|
|
107
|
+
});
|
|
108
|
+
child.on("close", (code) => {
|
|
109
|
+
if (code === 0) {
|
|
110
|
+
resolvePromise();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
reject(new Error(`${command} exited with ${code}: ${stderr.trim().slice(0, 400)}`));
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../src/secrets.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "authflow-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Authflow Rail onboarding CLI — register, mint-header, probe, scaffold",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"authflow": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"LICENSE",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"start": "node dist/cli.js",
|
|
17
|
+
"authflow": "tsx src/cli.ts",
|
|
18
|
+
"test": "node --import tsx --test \"test/**/*.test.ts\"",
|
|
19
|
+
"typecheck": "tsc -p tsconfig.test.json",
|
|
20
|
+
"prepublishOnly": "npm run build"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=20"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
27
|
+
"commander": "^13.1.0",
|
|
28
|
+
"zod": "^4.5.4"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/node": "^22.13.10",
|
|
32
|
+
"tsx": "^4.19.3",
|
|
33
|
+
"typescript": "^5.8.2"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://docs.authflow.ai/docs/tools/cli",
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/Snyder-Technology-LLC/Authflow.Rail/issues"
|
|
38
|
+
},
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "git+https://github.com/Snyder-Technology-LLC/Authflow.Rail.git",
|
|
42
|
+
"directory": "sdk/cli"
|
|
43
|
+
},
|
|
44
|
+
"keywords": [
|
|
45
|
+
"mcp",
|
|
46
|
+
"authflow",
|
|
47
|
+
"oauth",
|
|
48
|
+
"cli",
|
|
49
|
+
"monetization"
|
|
50
|
+
],
|
|
51
|
+
"author": "Authflow LLC",
|
|
52
|
+
"license": "Apache-2.0",
|
|
53
|
+
"publishConfig": {
|
|
54
|
+
"access": "public"
|
|
55
|
+
}
|
|
56
|
+
}
|