@stripe/link-cli 0.15.0 → 0.16.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 +18 -0
- package/dist/cli.js +38 -19
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -310,6 +310,24 @@ card SpendRequest instead; do not create an LPT request.
|
|
|
310
310
|
| Rolling creation rate | 200 per 60 days |
|
|
311
311
|
|
|
312
312
|
|
|
313
|
+
Use `mpp pay` to complete purchases on merchants that use the [Machine Payments Protocol](https://mpp.dev). The spend request must use `credential_type: "shared_payment_token"` and you must approve it before paying. The SPT is one-time-use — if payment fails, create a new spend request.
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
|
+
link-cli mpp pay https://climate.stripe.dev/api/contribute \
|
|
317
|
+
--spend-request-id lsrq_001 \
|
|
318
|
+
--method POST \
|
|
319
|
+
--data '{"amount":100}' \
|
|
320
|
+
--header "X-Custom: value"
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
In agent mode (`--format json`), the full flow returns the payment continuation twice: as `_next.pay_argv` (`{ "command": "mpp", "args": [...] }`) and as `_next.pay_command`. Prefer `pay_argv` and invoke it directly, passing each `args` entry as its own process argument. The URL, body and headers can carry merchant-controlled text, so `pay_command` is shell-quoted for callers that must go through a shell — pass it to the shell verbatim, without unquoting or re-splitting it.
|
|
324
|
+
|
|
325
|
+
Use `mpp decode` to validate a raw `WWW-Authenticate` header and extract the `network_id` needed for `shared_payment_token` spend requests:
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
link-cli mpp decode \
|
|
329
|
+
--challenge 'Payment id="ch_001", realm="merchant.example", method="stripe", intent="charge", request="..."'
|
|
330
|
+
```
|
|
313
331
|
|
|
314
332
|
### Report outcomes
|
|
315
333
|
|
package/dist/cli.js
CHANGED
|
@@ -593,7 +593,9 @@ var BalancesResource = class extends BaseResource {
|
|
|
593
593
|
var paymentMethodSchema = z2.looseObject({
|
|
594
594
|
id: z2.string(),
|
|
595
595
|
type: z2.string(),
|
|
596
|
-
is_default: z2.boolean()
|
|
596
|
+
is_default: z2.boolean(),
|
|
597
|
+
name: z2.string(),
|
|
598
|
+
nickname: z2.optional(z2.string().nullable())
|
|
597
599
|
});
|
|
598
600
|
var paymentMethodsResponseSchema = z2.looseObject({
|
|
599
601
|
payment_details: z2.array(paymentMethodSchema)
|
|
@@ -649,7 +651,7 @@ var ReportResource = class extends BaseResource {
|
|
|
649
651
|
var shippingAddressSchema = z4.looseObject({
|
|
650
652
|
id: z4.string(),
|
|
651
653
|
is_default: z4.boolean(),
|
|
652
|
-
nickname: z4.string().nullable(),
|
|
654
|
+
nickname: z4.optional(z4.string().nullable()),
|
|
653
655
|
address: z4.looseObject({}).nullable()
|
|
654
656
|
});
|
|
655
657
|
var shippingAddressesResponseSchema = z4.looseObject({
|
|
@@ -2799,7 +2801,7 @@ function buildHeaders(data, headers) {
|
|
|
2799
2801
|
if (key) result[key] = value;
|
|
2800
2802
|
}
|
|
2801
2803
|
if (!Object.keys(result).some((key) => key.toLowerCase() === "user-agent")) {
|
|
2802
|
-
result["User-Agent"] = `link-cli/${"0.
|
|
2804
|
+
result["User-Agent"] = `link-cli/${"0.16.0"}`;
|
|
2803
2805
|
}
|
|
2804
2806
|
return result;
|
|
2805
2807
|
}
|
|
@@ -3658,6 +3660,21 @@ function createDemoCli(authRepo2, spendRequestRepo2, createPaymentMethodsResourc
|
|
|
3658
3660
|
// src/commands/mpp/index.tsx
|
|
3659
3661
|
import { Cli as Cli4, z as z14 } from "incur";
|
|
3660
3662
|
|
|
3663
|
+
// src/utils/shell-quote.ts
|
|
3664
|
+
var SAFE_RE = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
3665
|
+
function shellQuote(value) {
|
|
3666
|
+
if (value === "") {
|
|
3667
|
+
return "''";
|
|
3668
|
+
}
|
|
3669
|
+
if (SAFE_RE.test(value)) {
|
|
3670
|
+
return value;
|
|
3671
|
+
}
|
|
3672
|
+
return `'${value.replaceAll("'", `'\\''`)}'`;
|
|
3673
|
+
}
|
|
3674
|
+
function shellCommand(parts) {
|
|
3675
|
+
return parts.map(shellQuote).join(" ");
|
|
3676
|
+
}
|
|
3677
|
+
|
|
3661
3678
|
// src/commands/mpp/decode-view.tsx
|
|
3662
3679
|
import { Box as Box10, Text as Text12 } from "ink";
|
|
3663
3680
|
import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
@@ -3829,20 +3846,22 @@ function createMppCli(repository, paymentMethodsFactory, authStorage2, envAccess
|
|
|
3829
3846
|
request_approval: true,
|
|
3830
3847
|
test: opts.test || void 0
|
|
3831
3848
|
});
|
|
3832
|
-
const
|
|
3833
|
-
if (method)
|
|
3834
|
-
if (data)
|
|
3849
|
+
const nextArgs = ["pay", url, "--spend-request-id", spendRequest.id];
|
|
3850
|
+
if (method) nextArgs.push("-X", method);
|
|
3851
|
+
if (data) nextArgs.push("-d", data);
|
|
3835
3852
|
if (headers) {
|
|
3836
|
-
for (const h of headers)
|
|
3853
|
+
for (const h of headers) nextArgs.push("-H", h);
|
|
3837
3854
|
}
|
|
3838
|
-
const nextCommand = `mpp
|
|
3855
|
+
const nextCommand = `mpp ${shellCommand(nextArgs)}`;
|
|
3856
|
+
const pollCommand = `spend-request retrieve ${shellQuote(spendRequest.id)} --interval 2 --max-attempts 300`;
|
|
3839
3857
|
yield {
|
|
3840
3858
|
...spendRequest,
|
|
3841
|
-
instruction: `Present the approval_url to the user and ask them to approve in the Link app. Then call
|
|
3859
|
+
instruction: `Present the approval_url to the user and ask them to approve in the Link app. Then call \`${pollCommand}\` to poll until approved. Once approved, run _next.pay_argv (preferred \u2014 invoke it directly without a shell) or _next.pay_command to complete payment. Do not wait for the user to reply \u2014 start polling immediately.`,
|
|
3842
3860
|
_next: {
|
|
3843
|
-
poll_command:
|
|
3861
|
+
poll_command: pollCommand,
|
|
3844
3862
|
pay_command: nextCommand,
|
|
3845
|
-
|
|
3863
|
+
pay_argv: { command: "mpp", args: nextArgs },
|
|
3864
|
+
until: "status changes from pending_approval, then run pay_argv"
|
|
3846
3865
|
}
|
|
3847
3866
|
};
|
|
3848
3867
|
}
|
|
@@ -4094,7 +4113,7 @@ var PaymentMethodsList = ({
|
|
|
4094
4113
|
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
|
|
4095
4114
|
/* @__PURE__ */ jsx19(Text15, { bold: true, children: "Payment Methods" }),
|
|
4096
4115
|
/* @__PURE__ */ jsx19(Box13, { flexDirection: "column", marginTop: 1, children: methods.map((pm) => {
|
|
4097
|
-
const label = pm.card_details?.brand ?? pm.bank_account_details?.bank_name ?? "Bank account";
|
|
4116
|
+
const label = pm.name ?? pm.card_details?.brand ?? pm.bank_account_details?.bank_name ?? "Bank account";
|
|
4098
4117
|
const last4 = pm.card_details?.last4 ?? pm.bank_account_details?.last4;
|
|
4099
4118
|
const suffix = pm.nickname ? `(${pm.nickname})` : "";
|
|
4100
4119
|
const agenticCap = pm.capabilities?.agentic_payments;
|
|
@@ -6243,9 +6262,9 @@ function buildRequiresActionResult(request) {
|
|
|
6243
6262
|
const isAutoResume2 = nextAction?.resolution === "auto_resume";
|
|
6244
6263
|
return {
|
|
6245
6264
|
...request,
|
|
6246
|
-
instruction: isAutoResume2 ? `The spend request requires 3D Secure verification. Present action_url (${nextAction?.action_url}) to the user, then call \`spend-request retrieve ${request.id} --interval 2 --max-attempts 300\` to poll until it resolves. Do not create a new spend request \u2014 this one resumes automatically once the challenge is completed.` : `The spend request requires action (${nextAction?.type}): ${nextAction?.display_message}${nextAction?.action_url ? ` URL: ${nextAction.action_url}` : ""} Have the user complete this, then create a new spend request.`,
|
|
6265
|
+
instruction: isAutoResume2 ? `The spend request requires 3D Secure verification. Present action_url (${nextAction?.action_url}) to the user, then call \`spend-request retrieve ${shellQuote(request.id)} --interval 2 --max-attempts 300\` to poll until it resolves. Do not create a new spend request \u2014 this one resumes automatically once the challenge is completed.` : `The spend request requires action (${nextAction?.type}): ${nextAction?.display_message}${nextAction?.action_url ? ` URL: ${nextAction.action_url}` : ""} Have the user complete this, then create a new spend request.`,
|
|
6247
6266
|
_next: isAutoResume2 ? {
|
|
6248
|
-
command: `spend-request retrieve ${request.id} --interval 2 --max-attempts 300`,
|
|
6267
|
+
command: `spend-request retrieve ${shellQuote(request.id)} --interval 2 --max-attempts 300`,
|
|
6249
6268
|
until: "status changes from requires_action"
|
|
6250
6269
|
} : void 0
|
|
6251
6270
|
};
|
|
@@ -6503,9 +6522,9 @@ function createSpendRequestCli(repository, authStorage2, envAccessToken2) {
|
|
|
6503
6522
|
}
|
|
6504
6523
|
yield {
|
|
6505
6524
|
...created,
|
|
6506
|
-
instruction: `Present the approval_url to the user and ask them to approve in the Link app. Then call \`spend-request retrieve ${created.id} --interval 2 --max-attempts 300\` to poll until approved. Do not wait for the user to reply \u2014 start polling immediately.`,
|
|
6525
|
+
instruction: `Present the approval_url to the user and ask them to approve in the Link app. Then call \`spend-request retrieve ${shellQuote(created.id)} --interval 2 --max-attempts 300\` to poll until approved. Do not wait for the user to reply \u2014 start polling immediately.`,
|
|
6507
6526
|
_next: {
|
|
6508
|
-
command: `spend-request retrieve ${created.id} --interval 2 --max-attempts 300`,
|
|
6527
|
+
command: `spend-request retrieve ${shellQuote(created.id)} --interval 2 --max-attempts 300`,
|
|
6509
6528
|
until: "status changes from pending_approval"
|
|
6510
6529
|
}
|
|
6511
6530
|
};
|
|
@@ -6616,9 +6635,9 @@ function createSpendRequestCli(repository, authStorage2, envAccessToken2) {
|
|
|
6616
6635
|
}
|
|
6617
6636
|
yield {
|
|
6618
6637
|
...approval,
|
|
6619
|
-
instruction: `Present the approval_url to the user and ask them to approve in the Link app. Then call \`spend-request retrieve ${id} --interval 2 --max-attempts 300\` to poll until approved. Do not wait for the user to reply \u2014 start polling immediately.`,
|
|
6638
|
+
instruction: `Present the approval_url to the user and ask them to approve in the Link app. Then call \`spend-request retrieve ${shellQuote(id)} --interval 2 --max-attempts 300\` to poll until approved. Do not wait for the user to reply \u2014 start polling immediately.`,
|
|
6620
6639
|
_next: {
|
|
6621
|
-
command: `spend-request retrieve ${id} --interval 2 --max-attempts 300`,
|
|
6640
|
+
command: `spend-request retrieve ${shellQuote(id)} --interval 2 --max-attempts 300`,
|
|
6622
6641
|
until: "status changes from pending_approval"
|
|
6623
6642
|
}
|
|
6624
6643
|
};
|
|
@@ -7580,7 +7599,7 @@ function cacheUpdateInfo(value, ttlMs = UPDATE_CACHE_TTL_MS) {
|
|
|
7580
7599
|
}
|
|
7581
7600
|
|
|
7582
7601
|
// src/cli.tsx
|
|
7583
|
-
var cliVersion = "0.
|
|
7602
|
+
var cliVersion = "0.16.0";
|
|
7584
7603
|
var cliName = "@stripe/link-cli";
|
|
7585
7604
|
var defaultHeaders = {
|
|
7586
7605
|
"User-Agent": `link-cli/${cliVersion}`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stripe/link-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"link-cli": "./dist/cli.js"
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"tsx": "^4.23.5",
|
|
46
46
|
"typescript": "^5.9.3",
|
|
47
47
|
"vitest": "^4.1.10",
|
|
48
|
-
"@stripe/link-sdk": "0.2.
|
|
48
|
+
"@stripe/link-sdk": "0.2.1",
|
|
49
49
|
"@stripe/link-typescript-config": "0.0.0"
|
|
50
50
|
},
|
|
51
51
|
"scripts": {
|