@xodn348/clawpay 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.
@@ -0,0 +1,42 @@
1
+ import { appendFileSync, mkdirSync, existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { homedir } from "node:os";
4
+ const AUDIT_DIR = join(homedir(), ".clawpay");
5
+ const AUDIT_FILE = join(AUDIT_DIR, "audit.log");
6
+ export function auditLog(entry) {
7
+ if (!existsSync(AUDIT_DIR)) {
8
+ mkdirSync(AUDIT_DIR, { recursive: true });
9
+ }
10
+ const line = JSON.stringify({ ...entry, timestamp: new Date().toISOString() });
11
+ appendFileSync(AUDIT_FILE, line + "\n", "utf-8");
12
+ }
13
+ export function auditPayment(opts) {
14
+ auditLog({
15
+ timestamp: new Date().toISOString(),
16
+ action: "pay",
17
+ amount: opts.amount,
18
+ currency: opts.currency,
19
+ paymentIntentId: opts.paymentIntentId,
20
+ status: opts.status,
21
+ reason: opts.reason,
22
+ });
23
+ }
24
+ export function auditRefund(opts) {
25
+ auditLog({
26
+ timestamp: new Date().toISOString(),
27
+ action: "refund",
28
+ refundId: opts.refundId,
29
+ amount: opts.amount,
30
+ status: opts.status,
31
+ reason: opts.reason,
32
+ });
33
+ }
34
+ export function auditSetup(status, reason) {
35
+ auditLog({
36
+ timestamp: new Date().toISOString(),
37
+ action: "setup_payment",
38
+ status,
39
+ reason,
40
+ });
41
+ }
42
+ //# sourceMappingURL=guardrails.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guardrails.js","sourceRoot":"","sources":["../src/guardrails.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;AAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;AAehD,MAAM,UAAU,QAAQ,CAAC,KAAiB;IACxC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IAC/E,cAAc,CAAC,UAAU,EAAE,IAAI,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAM5B;IACC,QAAQ,CAAC;QACP,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,MAAM,EAAE,KAAK;QACb,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,eAAe,EAAE,IAAI,CAAC,eAAe;QACrC,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,MAAM,EAAE,IAAI,CAAC,MAAM;KACpB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAK3B;IACC,QAAQ,CAAC;QACP,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,MAAM,EAAE,QAAQ;QAChB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,MAAM,EAAE,IAAI,CAAC,MAAM;KACpB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAA4B,EAAE,MAAe;IACtE,QAAQ,CAAC;QACP,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,MAAM,EAAE,eAAe;QACvB,MAAM;QACN,MAAM;KACP,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,222 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from "node:module";
3
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
6
+ import { isConfigured } from "./config.js";
7
+ import { createPayment, getBalance, listTransactions, refundPayment } from "./stripe.js";
8
+ const require = createRequire(import.meta.url);
9
+ const packageJson = require("../package.json");
10
+ const VERSION = typeof packageJson.version === "string" ? packageJson.version : "0.0.0";
11
+ function successResult(result) {
12
+ return {
13
+ content: [{ type: "text", text: JSON.stringify(result) }],
14
+ };
15
+ }
16
+ function errorResult(error) {
17
+ const message = error instanceof Error ? error.message : "Unknown error";
18
+ return {
19
+ content: [{ type: "text", text: message }],
20
+ isError: true,
21
+ };
22
+ }
23
+ function asObject(value) {
24
+ return value !== null && typeof value === "object" ? value : {};
25
+ }
26
+ function requireString(value, field) {
27
+ if (typeof value !== "string" || value.trim().length === 0) {
28
+ throw new Error(`Invalid or missing '${field}'.`);
29
+ }
30
+ return value;
31
+ }
32
+ function requireNumber(value, field) {
33
+ if (typeof value !== "number" || !Number.isFinite(value)) {
34
+ throw new Error(`Invalid or missing '${field}'.`);
35
+ }
36
+ return value;
37
+ }
38
+ function optionalPositiveInt(value, field) {
39
+ if (value === undefined) {
40
+ return undefined;
41
+ }
42
+ if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
43
+ throw new Error(`Invalid '${field}'. Expected a positive integer.`);
44
+ }
45
+ return value;
46
+ }
47
+ async function getRunSetup() {
48
+ const setupModule = (await import("./setup.js"));
49
+ const runSetup = setupModule["runSetup"];
50
+ if (typeof runSetup !== "function") {
51
+ throw new Error("setup_payment is not available: runSetup() is not implemented in ./setup.js.");
52
+ }
53
+ return runSetup;
54
+ }
55
+ async function runInstallerAction(action) {
56
+ const installerModule = (await import("./installer.js"));
57
+ const candidates = action === "install"
58
+ ? ["install", "runInstall", "runInstaller", "setup", "default"]
59
+ : ["uninstall", "runUninstall", "remove", "teardown", "default"];
60
+ for (const candidate of candidates) {
61
+ const fn = installerModule[candidate];
62
+ if (typeof fn === "function") {
63
+ await Promise.resolve(fn());
64
+ return;
65
+ }
66
+ }
67
+ throw new Error(`'${action}' is not available: missing function export in ./installer.js.`);
68
+ }
69
+ async function runServer() {
70
+ if (!process.env["STRIPE_SECRET_KEY"]) {
71
+ console.error("STRIPE_SECRET_KEY environment variable is required to run the MCP server.");
72
+ process.exit(1);
73
+ }
74
+ const server = new Server({ name: "clawpay", version: VERSION }, { capabilities: { tools: {} } });
75
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
76
+ tools: [
77
+ {
78
+ name: "setup_payment",
79
+ description: "Set up Stripe payment method for ClawPay.",
80
+ inputSchema: {
81
+ type: "object",
82
+ properties: {},
83
+ additionalProperties: false,
84
+ },
85
+ },
86
+ {
87
+ name: "pay",
88
+ description: "Create and confirm a payment in cents.",
89
+ inputSchema: {
90
+ type: "object",
91
+ properties: {
92
+ amount: { type: "number", description: "Amount in cents." },
93
+ currency: { type: "string", description: "Currency code (for example: usd)." },
94
+ description: { type: "string", description: "Payment description." },
95
+ },
96
+ required: ["amount", "currency", "description"],
97
+ additionalProperties: false,
98
+ },
99
+ },
100
+ {
101
+ name: "get_balance",
102
+ description: "Get Stripe account balance.",
103
+ inputSchema: {
104
+ type: "object",
105
+ properties: {},
106
+ additionalProperties: false,
107
+ },
108
+ },
109
+ {
110
+ name: "list_transactions",
111
+ description: "List recent payment transactions.",
112
+ inputSchema: {
113
+ type: "object",
114
+ properties: {
115
+ limit: {
116
+ type: "number",
117
+ description: "Optional max items to return.",
118
+ },
119
+ },
120
+ additionalProperties: false,
121
+ },
122
+ },
123
+ {
124
+ name: "refund",
125
+ description: "Refund a payment intent.",
126
+ inputSchema: {
127
+ type: "object",
128
+ properties: {
129
+ payment_intent_id: { type: "string", description: "Stripe payment intent ID." },
130
+ },
131
+ required: ["payment_intent_id"],
132
+ additionalProperties: false,
133
+ },
134
+ },
135
+ ],
136
+ }));
137
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
138
+ const name = request.params.name;
139
+ const args = asObject(request.params.arguments);
140
+ switch (name) {
141
+ case "setup_payment": {
142
+ try {
143
+ const runSetup = await getRunSetup();
144
+ const result = await runSetup();
145
+ return successResult({ result, configured: isConfigured() });
146
+ }
147
+ catch (error) {
148
+ return errorResult(error);
149
+ }
150
+ }
151
+ case "pay": {
152
+ try {
153
+ const amount = requireNumber(args["amount"], "amount");
154
+ const currency = requireString(args["currency"], "currency");
155
+ const description = requireString(args["description"], "description");
156
+ const result = await createPayment({ amount, currency, description });
157
+ return successResult(result);
158
+ }
159
+ catch (error) {
160
+ return errorResult(error);
161
+ }
162
+ }
163
+ case "get_balance": {
164
+ try {
165
+ const result = await getBalance();
166
+ return successResult(result);
167
+ }
168
+ catch (error) {
169
+ return errorResult(error);
170
+ }
171
+ }
172
+ case "list_transactions": {
173
+ try {
174
+ const limit = optionalPositiveInt(args["limit"], "limit");
175
+ const result = await listTransactions(limit);
176
+ return successResult(result);
177
+ }
178
+ catch (error) {
179
+ return errorResult(error);
180
+ }
181
+ }
182
+ case "refund": {
183
+ try {
184
+ const paymentIntentId = requireString(args["payment_intent_id"], "payment_intent_id");
185
+ const result = await refundPayment(paymentIntentId);
186
+ return successResult(result);
187
+ }
188
+ catch (error) {
189
+ return errorResult(error);
190
+ }
191
+ }
192
+ default:
193
+ return errorResult(new Error(`Unknown tool: ${name}`));
194
+ }
195
+ });
196
+ const transport = new StdioServerTransport();
197
+ await server.connect(transport);
198
+ }
199
+ async function main() {
200
+ const command = process.argv[2];
201
+ if (command === "install") {
202
+ await runInstallerAction("install");
203
+ return;
204
+ }
205
+ if (command === "uninstall") {
206
+ await runInstallerAction("uninstall");
207
+ return;
208
+ }
209
+ if (command !== undefined) {
210
+ console.error(`Unknown command: ${command}`);
211
+ console.error("Usage: clawpay [install|uninstall]");
212
+ process.exitCode = 1;
213
+ return;
214
+ }
215
+ await runServer();
216
+ }
217
+ main().catch((error) => {
218
+ const message = error instanceof Error ? error.message : String(error);
219
+ console.error(message);
220
+ process.exit(1);
221
+ });
222
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function runInstall(): Promise<void>;
2
+ export declare function runUninstall(): Promise<void>;
3
+ //# sourceMappingURL=installer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"AA6GA,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CA6FhD;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAiClD"}
@@ -0,0 +1,168 @@
1
+ import { createInterface } from "node:readline";
2
+ import { promises as fs } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { join, dirname } from "node:path";
5
+ async function pathExists(filePath) {
6
+ try {
7
+ await fs.stat(filePath);
8
+ return true;
9
+ }
10
+ catch {
11
+ return false;
12
+ }
13
+ }
14
+ async function isDirectory(dirPath) {
15
+ try {
16
+ const stat = await fs.stat(dirPath);
17
+ return stat.isDirectory();
18
+ }
19
+ catch {
20
+ return false;
21
+ }
22
+ }
23
+ async function readJsonSafe(filePath) {
24
+ try {
25
+ const content = await fs.readFile(filePath, "utf-8");
26
+ return JSON.parse(content);
27
+ }
28
+ catch {
29
+ return {};
30
+ }
31
+ }
32
+ function askQuestion(question) {
33
+ return new Promise((resolve) => {
34
+ const rl = createInterface({
35
+ input: process.stdin,
36
+ output: process.stdout,
37
+ });
38
+ rl.question(question, (answer) => {
39
+ rl.close();
40
+ resolve(answer.trim());
41
+ });
42
+ });
43
+ }
44
+ function getMcpClients() {
45
+ const home = homedir();
46
+ return [
47
+ {
48
+ name: "OpenCode",
49
+ configPath: join(home, ".config", "opencode", "config.json"),
50
+ mcpKey: "mcp",
51
+ },
52
+ {
53
+ name: "Claude Desktop (macOS)",
54
+ configPath: join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json"),
55
+ mcpKey: "mcpServers",
56
+ },
57
+ {
58
+ name: "Claude Desktop (Linux)",
59
+ configPath: join(home, ".config", "Claude", "claude_desktop_config.json"),
60
+ mcpKey: "mcpServers",
61
+ },
62
+ {
63
+ name: "Cursor",
64
+ configPath: join(home, ".cursor", "mcp.json"),
65
+ mcpKey: "mcpServers",
66
+ },
67
+ ];
68
+ }
69
+ function buildClawPayEntry(stripeKey, mcpKey) {
70
+ if (mcpKey === "mcp") {
71
+ return {
72
+ clawpay: {
73
+ type: "local",
74
+ command: ["clawpay"],
75
+ environment: {
76
+ STRIPE_SECRET_KEY: stripeKey,
77
+ },
78
+ },
79
+ };
80
+ }
81
+ return {
82
+ clawpay: {
83
+ command: "clawpay",
84
+ args: [],
85
+ env: {
86
+ STRIPE_SECRET_KEY: stripeKey,
87
+ },
88
+ },
89
+ };
90
+ }
91
+ export async function runInstall() {
92
+ const stripeKey = await askQuestion("Enter your Stripe Secret Key (sk_test_... or sk_live_...): ");
93
+ if (!stripeKey.startsWith("sk_test_") && !stripeKey.startsWith("sk_live_")) {
94
+ console.error("Error: Invalid Stripe key. Must start with sk_test_ or sk_live_.");
95
+ process.exit(1);
96
+ }
97
+ // Never log the full key — show a masked version only
98
+ const maskedKey = `sk_...${stripeKey.slice(-4)}`;
99
+ console.log(`\nConfiguring MCP clients with key ${maskedKey}...`);
100
+ const clients = getMcpClients();
101
+ let configuredCount = 0;
102
+ for (const client of clients) {
103
+ const configDir = dirname(client.configPath);
104
+ const configFileExists = await pathExists(client.configPath);
105
+ const configDirExists = await isDirectory(configDir);
106
+ if (!configFileExists && !configDirExists) {
107
+ continue;
108
+ }
109
+ const config = await readJsonSafe(client.configPath);
110
+ const mcpSection = config[client.mcpKey] ?? {};
111
+ if (mcpSection["clawpay"] !== undefined) {
112
+ console.log(` clawpay already configured in ${client.name} — skipping`);
113
+ configuredCount++;
114
+ continue;
115
+ }
116
+ const entry = buildClawPayEntry(stripeKey, client.mcpKey);
117
+ config[client.mcpKey] = { ...mcpSection, ...entry };
118
+ await fs.writeFile(client.configPath, JSON.stringify(config, null, 2), "utf-8");
119
+ console.log(` ✓ ${client.name} configured`);
120
+ configuredCount++;
121
+ }
122
+ if (configuredCount === 0) {
123
+ console.log("\nNo MCP client config files found. Add clawpay manually:");
124
+ console.log("\nOpenCode (~/.config/opencode/config.json):");
125
+ console.log(JSON.stringify({
126
+ mcp: {
127
+ clawpay: {
128
+ type: "local",
129
+ command: ["clawpay"],
130
+ environment: { STRIPE_SECRET_KEY: maskedKey },
131
+ },
132
+ },
133
+ }, null, 2));
134
+ console.log("\nClaude Desktop (~/.../claude_desktop_config.json) / Cursor (~/.cursor/mcp.json):");
135
+ console.log(JSON.stringify({
136
+ mcpServers: {
137
+ clawpay: {
138
+ command: "clawpay",
139
+ args: [],
140
+ env: { STRIPE_SECRET_KEY: maskedKey },
141
+ },
142
+ },
143
+ }, null, 2));
144
+ }
145
+ console.log('\nInstallation complete! Ask your AI: "set up payment method"');
146
+ }
147
+ export async function runUninstall() {
148
+ const clients = getMcpClients();
149
+ for (const client of clients) {
150
+ const exists = await pathExists(client.configPath);
151
+ if (!exists) {
152
+ continue;
153
+ }
154
+ const config = await readJsonSafe(client.configPath);
155
+ const mcpSection = config[client.mcpKey];
156
+ if (mcpSection === undefined || mcpSection["clawpay"] === undefined) {
157
+ console.log(` ${client.name} — not configured, skipping`);
158
+ continue;
159
+ }
160
+ const updated = { ...mcpSection };
161
+ delete updated["clawpay"];
162
+ config[client.mcpKey] = updated;
163
+ await fs.writeFile(client.configPath, JSON.stringify(config, null, 2), "utf-8");
164
+ console.log(` ✓ ${client.name} — clawpay removed`);
165
+ }
166
+ console.log("\nUninstallation complete.");
167
+ }
168
+ //# sourceMappingURL=installer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installer.js","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function runSetup(): Promise<{
2
+ success: boolean;
3
+ message: string;
4
+ }>;
5
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AA4BA,wBAAsB,QAAQ,IAAI,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAsJ/E"}
package/dist/setup.js ADDED
@@ -0,0 +1,163 @@
1
+ import http from "node:http";
2
+ import { exec } from "node:child_process";
3
+ import qrcode from "qrcode-terminal";
4
+ import { getStripe } from "./stripe.js";
5
+ import { loadConfig, saveConfig, isConfigured } from "./config.js";
6
+ import { auditSetup } from "./guardrails.js";
7
+ const SETUP_PORT = 3100;
8
+ const SETUP_HOST = "127.0.0.1";
9
+ const TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
10
+ function openBrowser(url) {
11
+ const platform = process.platform;
12
+ let command;
13
+ if (platform === "darwin") {
14
+ command = `open "${url}"`;
15
+ }
16
+ else if (platform === "win32") {
17
+ command = `start "" "${url}"`;
18
+ }
19
+ else {
20
+ command = `xdg-open "${url}"`;
21
+ }
22
+ exec(command, (err) => {
23
+ if (err) {
24
+ process.stderr.write(`Failed to open browser: ${err.message}\n`);
25
+ }
26
+ });
27
+ }
28
+ export async function runSetup() {
29
+ if (isConfigured()) {
30
+ return {
31
+ success: true,
32
+ message: "Payment method already configured. Run setup again to replace.",
33
+ };
34
+ }
35
+ const stripe = getStripe();
36
+ let checkoutUrl;
37
+ try {
38
+ const session = await stripe.checkout.sessions.create({
39
+ mode: "setup",
40
+ payment_method_types: ["card"],
41
+ success_url: `http://${SETUP_HOST}:${SETUP_PORT}/success?session_id={CHECKOUT_SESSION_ID}`,
42
+ cancel_url: `http://${SETUP_HOST}:${SETUP_PORT}/cancel`,
43
+ });
44
+ if (!session.url) {
45
+ throw new Error("Stripe did not return a Checkout URL.");
46
+ }
47
+ checkoutUrl = session.url;
48
+ }
49
+ catch (err) {
50
+ const message = err instanceof Error ? err.message : "Failed to create Stripe Checkout Session.";
51
+ auditSetup("failed", message);
52
+ return { success: false, message };
53
+ }
54
+ return new Promise((resolve) => {
55
+ let settled = false;
56
+ const timeoutHandle = setTimeout(() => {
57
+ finish({ success: false, message: "Setup timed out after 5 minutes." });
58
+ }, TIMEOUT_MS);
59
+ function finish(result) {
60
+ if (settled)
61
+ return;
62
+ settled = true;
63
+ clearTimeout(timeoutHandle);
64
+ server.close();
65
+ if (result.success) {
66
+ auditSetup("success");
67
+ }
68
+ else {
69
+ auditSetup("failed", result.message);
70
+ }
71
+ resolve(result);
72
+ }
73
+ const server = http.createServer((req, res) => {
74
+ const rawUrl = req.url ?? "/";
75
+ const parsedUrl = new URL(rawUrl, `http://${SETUP_HOST}:${SETUP_PORT}`);
76
+ if (parsedUrl.pathname === "/success") {
77
+ const sessionId = parsedUrl.searchParams.get("session_id");
78
+ if (!sessionId) {
79
+ res.writeHead(400, { "Content-Type": "text/plain" });
80
+ res.end("Missing session_id parameter.");
81
+ finish({ success: false, message: "Missing session_id in success callback." });
82
+ return;
83
+ }
84
+ // Async work inside a synchronous request handler — explicitly void the promise.
85
+ void (async () => {
86
+ try {
87
+ const completedSession = await stripe.checkout.sessions.retrieve(sessionId);
88
+ // setup_intent is string | Stripe.SetupIntent | null depending on expansion.
89
+ const rawSetupIntent = completedSession.setup_intent;
90
+ const setupIntentId = typeof rawSetupIntent === "string"
91
+ ? rawSetupIntent
92
+ : (rawSetupIntent?.id ?? null);
93
+ if (!setupIntentId) {
94
+ throw new Error("No setup_intent on completed Checkout Session.");
95
+ }
96
+ const setupIntent = await stripe.setupIntents.retrieve(setupIntentId);
97
+ // payment_method is string | Stripe.PaymentMethod | null depending on expansion.
98
+ const rawPaymentMethod = setupIntent.payment_method;
99
+ const paymentMethodId = typeof rawPaymentMethod === "string"
100
+ ? rawPaymentMethod
101
+ : (rawPaymentMethod?.id ?? null);
102
+ // customer is string | Stripe.Customer | Stripe.DeletedCustomer | null.
103
+ const rawCustomer = setupIntent.customer;
104
+ let customerId;
105
+ if (typeof rawCustomer === "string") {
106
+ customerId = rawCustomer;
107
+ }
108
+ else if (rawCustomer != null) {
109
+ customerId = rawCustomer.id;
110
+ }
111
+ else {
112
+ customerId = null;
113
+ }
114
+ if (!paymentMethodId) {
115
+ throw new Error("No payment_method on SetupIntent.");
116
+ }
117
+ if (!customerId) {
118
+ throw new Error("No customer on SetupIntent.");
119
+ }
120
+ // Never store raw card data — only Stripe IDs are persisted.
121
+ const config = loadConfig();
122
+ config.stripe.customerId = customerId;
123
+ config.stripe.paymentMethodId = paymentMethodId;
124
+ saveConfig(config);
125
+ res.writeHead(200, { "Content-Type": "text/html" });
126
+ res.end("<!DOCTYPE html><html><body>" +
127
+ "<h1>Payment method saved!</h1>" +
128
+ "<p>You may close this tab and return to your terminal.</p>" +
129
+ "</body></html>");
130
+ finish({ success: true, message: "Payment method configured successfully." });
131
+ }
132
+ catch (err) {
133
+ const message = err instanceof Error ? err.message : "Failed to save payment method.";
134
+ res.writeHead(500, { "Content-Type": "text/plain" });
135
+ res.end(message);
136
+ finish({ success: false, message });
137
+ }
138
+ })();
139
+ }
140
+ else if (parsedUrl.pathname === "/cancel") {
141
+ res.writeHead(200, { "Content-Type": "text/html" });
142
+ res.end("<!DOCTYPE html><html><body>" +
143
+ "<h1>Setup cancelled.</h1>" +
144
+ "<p>You may close this tab and return to your terminal.</p>" +
145
+ "</body></html>");
146
+ finish({ success: false, message: "Setup was cancelled by the user." });
147
+ }
148
+ else {
149
+ res.writeHead(404, { "Content-Type": "text/plain" });
150
+ res.end("Not found.");
151
+ }
152
+ });
153
+ server.on("error", (err) => {
154
+ finish({ success: false, message: `Server error: ${err.message}` });
155
+ });
156
+ server.listen(SETUP_PORT, SETUP_HOST, () => {
157
+ process.stderr.write(`Setup URL: ${checkoutUrl}\n`);
158
+ qrcode.generate(checkoutUrl, { small: true });
159
+ openBrowser(checkoutUrl);
160
+ });
161
+ });
162
+ }
163
+ //# sourceMappingURL=setup.js.map