@stripe/link-cli 0.2.3 → 0.3.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.
Files changed (3) hide show
  1. package/README.md +19 -1
  2. package/dist/cli.js +1748 -422
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -8704,19 +8704,19 @@ var require_range = __commonJS({
8704
8704
  var replaceCaret = (comp, options) => {
8705
8705
  debug("caret", comp, options);
8706
8706
  const r = options.loose ? re[t.CARETLOOSE] : re[t.CARET];
8707
- const z7 = options.includePrerelease ? "-0" : "";
8707
+ const z8 = options.includePrerelease ? "-0" : "";
8708
8708
  return comp.replace(r, (_, M, m, p, pr) => {
8709
8709
  debug("caret", comp, _, M, m, p, pr);
8710
8710
  let ret;
8711
8711
  if (isX(M)) {
8712
8712
  ret = "";
8713
8713
  } else if (isX(m)) {
8714
- ret = `>=${M}.0.0${z7} <${+M + 1}.0.0-0`;
8714
+ ret = `>=${M}.0.0${z8} <${+M + 1}.0.0-0`;
8715
8715
  } else if (isX(p)) {
8716
8716
  if (M === "0") {
8717
- ret = `>=${M}.${m}.0${z7} <${M}.${+m + 1}.0-0`;
8717
+ ret = `>=${M}.${m}.0${z8} <${M}.${+m + 1}.0-0`;
8718
8718
  } else {
8719
- ret = `>=${M}.${m}.0${z7} <${+M + 1}.0.0-0`;
8719
+ ret = `>=${M}.${m}.0${z8} <${+M + 1}.0.0-0`;
8720
8720
  }
8721
8721
  } else if (pr) {
8722
8722
  debug("replaceCaret pr", pr);
@@ -8733,9 +8733,9 @@ var require_range = __commonJS({
8733
8733
  debug("no pr");
8734
8734
  if (M === "0") {
8735
8735
  if (m === "0") {
8736
- ret = `>=${M}.${m}.${p}${z7} <${M}.${m}.${+p + 1}-0`;
8736
+ ret = `>=${M}.${m}.${p}${z8} <${M}.${m}.${+p + 1}-0`;
8737
8737
  } else {
8738
- ret = `>=${M}.${m}.${p}${z7} <${M}.${+m + 1}.0-0`;
8738
+ ret = `>=${M}.${m}.${p}${z8} <${M}.${+m + 1}.0-0`;
8739
8739
  }
8740
8740
  } else {
8741
8741
  ret = `>=${M}.${m}.${p} <${+M + 1}.0.0-0`;
@@ -9549,7 +9549,7 @@ var require_semver2 = __commonJS({
9549
9549
  });
9550
9550
 
9551
9551
  // src/cli.tsx
9552
- import { Cli as Cli5 } from "incur";
9552
+ import { Cli as Cli7 } from "incur";
9553
9553
  import updateNotifier from "update-notifier";
9554
9554
 
9555
9555
  // ../sdk/dist/index.js
@@ -11580,10 +11580,686 @@ function createAuthCli(authResource, updateInfo) {
11580
11580
  return cli2;
11581
11581
  }
11582
11582
 
11583
- // src/commands/mpp/index.tsx
11584
- import { Cli as Cli2, z as z3 } from "incur";
11583
+ // src/commands/demo/index.tsx
11584
+ import { Cli as Cli2, z as z2 } from "incur";
11585
11585
  import { render as render2 } from "ink";
11586
11586
 
11587
+ // src/commands/demo/demo-runner.tsx
11588
+ import { Box as Box8, Text as Text9, useInput as useInput4 } from "ink";
11589
+ import { useCallback, useState as useState6 } from "react";
11590
+
11591
+ // src/utils/markdown-text.tsx
11592
+ import { Text as Text3 } from "ink";
11593
+ import { jsx as jsx4 } from "react/jsx-runtime";
11594
+ var MarkdownText = ({
11595
+ children,
11596
+ dimColor
11597
+ }) => {
11598
+ const parts = tokenize(children);
11599
+ return /* @__PURE__ */ jsx4(Text3, { dimColor, children: parts.map((part) => {
11600
+ if (part.type === "bold") {
11601
+ return /* @__PURE__ */ jsx4(Text3, { bold: true, children: part.text }, part.key);
11602
+ }
11603
+ if (part.type === "code") {
11604
+ return /* @__PURE__ */ jsx4(Text3, { color: "yellow", children: part.text }, part.key);
11605
+ }
11606
+ return /* @__PURE__ */ jsx4(Text3, { children: part.text }, part.key);
11607
+ }) });
11608
+ };
11609
+ function tokenize(input) {
11610
+ const tokens = [];
11611
+ const re = /\*\*([^*]+)\*\*|`([^`]+)`/g;
11612
+ let last = 0;
11613
+ for (; ; ) {
11614
+ const match = re.exec(input);
11615
+ if (match === null) break;
11616
+ if (match.index > last) {
11617
+ tokens.push({
11618
+ type: "text",
11619
+ key: `t${last}`,
11620
+ text: input.slice(last, match.index)
11621
+ });
11622
+ }
11623
+ if (match[1] !== void 0) {
11624
+ tokens.push({ type: "bold", key: `b${match.index}`, text: match[1] });
11625
+ } else if (match[2] !== void 0) {
11626
+ tokens.push({
11627
+ type: "code",
11628
+ key: `c${match.index}`,
11629
+ text: `\`${match[2]}\``
11630
+ });
11631
+ }
11632
+ last = match.index + match[0].length;
11633
+ }
11634
+ if (last < input.length) {
11635
+ tokens.push({ type: "text", key: `t${last}`, text: input.slice(last) });
11636
+ }
11637
+ return tokens;
11638
+ }
11639
+
11640
+ // src/commands/spend-request/app-download-qr-codes.tsx
11641
+ import { Box as Box3, Text as Text4 } from "ink";
11642
+ import { useMemo } from "react";
11643
+
11644
+ // src/utils/render-qr-matrix.ts
11645
+ import QRCode from "qrcode";
11646
+ function renderQrMatrix(url) {
11647
+ const qr = QRCode.create(url, { errorCorrectionLevel: "L" });
11648
+ const size = qr.modules.size;
11649
+ const data = qr.modules.data;
11650
+ const quiet = 1;
11651
+ const total = size + quiet * 2;
11652
+ const matrix = Array.from(
11653
+ { length: total },
11654
+ (_, r) => Array.from({ length: total }, (_2, c) => {
11655
+ if (r < quiet || r >= size + quiet || c < quiet || c >= size + quiet) {
11656
+ return false;
11657
+ }
11658
+ return data[(r - quiet) * size + (c - quiet)] === 1;
11659
+ })
11660
+ );
11661
+ const lines = [];
11662
+ for (let r = 0; r < total; r += 2) {
11663
+ let line = "";
11664
+ for (let c = 0; c < total; c++) {
11665
+ const top = matrix[r][c];
11666
+ const bottom = r + 1 < total ? matrix[r + 1][c] : false;
11667
+ if (top && bottom) line += "\u2588";
11668
+ else if (top) line += "\u2580";
11669
+ else if (bottom) line += "\u2584";
11670
+ else line += " ";
11671
+ }
11672
+ lines.push(line);
11673
+ }
11674
+ return lines;
11675
+ }
11676
+
11677
+ // src/commands/spend-request/app-download-qr-codes.tsx
11678
+ import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
11679
+ var DOWNLOAD_URL = "https://link.com/download";
11680
+ var AppDownloadQrCodes = () => {
11681
+ const qrLines = useMemo(() => renderQrMatrix(DOWNLOAD_URL), []);
11682
+ return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", marginTop: 1, children: [
11683
+ /* @__PURE__ */ jsx5(Text4, { dimColor: true, children: "Get the Link app to approve spend requests from your phone" }),
11684
+ /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", alignItems: "flex-start", marginTop: 1, children: [
11685
+ qrLines.map((line, i) => (
11686
+ // biome-ignore lint/suspicious/noArrayIndexKey: stable static array
11687
+ /* @__PURE__ */ jsx5(Text4, { children: line }, i)
11688
+ )),
11689
+ /* @__PURE__ */ jsx5(Text4, { dimColor: true, children: DOWNLOAD_URL })
11690
+ ] })
11691
+ ] });
11692
+ };
11693
+
11694
+ // src/commands/demo/card-flow.tsx
11695
+ import { Box as Box5, Text as Text6, useInput as useInput2 } from "ink";
11696
+ import { useEffect as useEffect3, useRef, useState as useState3 } from "react";
11697
+
11698
+ // src/utils/poll-until-approved.ts
11699
+ function pollUntilApproved(repository, id, options = {}) {
11700
+ const pollIntervalMs = options.pollIntervalMs ?? 2e3;
11701
+ const timeoutMs = options.timeoutMs ?? 3e5;
11702
+ const startTime = Date.now();
11703
+ const poll = async () => {
11704
+ const elapsed = Date.now() - startTime;
11705
+ if (elapsed > timeoutMs) {
11706
+ throw new Error("Approval polling timed out");
11707
+ }
11708
+ const request = await repository.getSpendRequest(id);
11709
+ if (!request) {
11710
+ throw new Error(`Spend request ${id} not found`);
11711
+ }
11712
+ if (request.status !== "created" && request.status !== "pending_approval") {
11713
+ return request;
11714
+ }
11715
+ options.onProgress?.(Math.floor(elapsed / 1e3));
11716
+ await new Promise((r) => setTimeout(r, pollIntervalMs));
11717
+ return poll();
11718
+ };
11719
+ return poll();
11720
+ }
11721
+
11722
+ // src/commands/demo/constants.ts
11723
+ var DEMO_MERCHANT_NAME = "Galtee Outdoor";
11724
+ var DEMO_MERCHANT_URL = "https://galtee.stripedemos.com/";
11725
+ var DEMO_MPP_DEV_URL = "https://mpp.dev";
11726
+ var DEMO_CLIMATE_API_URL = "https://climate.stripe.dev/api/test/contribute";
11727
+ var DEMO_CARD_AMOUNT = 12900;
11728
+ var DEMO_SPT_AMOUNT = 100;
11729
+ var DEMO_CARD_CONTEXT = "Link CLI onboarding demo: Merino Trail Jacket (size M, Forest) from Galtee Outdoor. Agent completing checkout using a virtual card credential.";
11730
+ var DEMO_SPT_CONTEXT = "Demo purchase: Testing the Link CLI machine payment flow by making an automated HTTP 402 payment to Stripe Climate. This demonstrates the shared payment token credential and machine payment protocol.";
11731
+
11732
+ // src/commands/demo/content.ts
11733
+ var cardAmount = `$${(DEMO_CARD_AMOUNT / 100).toFixed(2)}`;
11734
+ var sptAmount = `$${(DEMO_SPT_AMOUNT / 100).toFixed(2)}`;
11735
+ var CARD_FLOW = {
11736
+ title: "Flow 1: Virtual Card",
11737
+ intro: {
11738
+ description: `An agent buys a Merino Trail Jacket (${cardAmount}) from Galtee Outdoor using a **virtual card** \u2014 a one-time card number issued from your Link wallet. Your real payment details are never shared with the agent or the business.`,
11739
+ steps: [
11740
+ `The agent calls \`spend-request create\` to request ${cardAmount} at Galtee Outdoor`,
11741
+ "You approve in the Link app",
11742
+ "Link issues a one-time virtual card",
11743
+ "Open the checkout page and enter the card details"
11744
+ ],
11745
+ prompt: "Press [Enter] to start"
11746
+ },
11747
+ createSpend: {
11748
+ description: `\`spend-request create\` sends the business name, URL, amount (${cardAmount}), and purchase description to Link. No credentials are issued until you approve.`,
11749
+ loading: "Creating spend request..."
11750
+ },
11751
+ approval: {
11752
+ description: "Open the URL to approve the spend request. The CLI polls and continues once approved.",
11753
+ loading: "Waiting for approval...",
11754
+ browserHint: "Press [Enter] to open in browser"
11755
+ },
11756
+ showCard: {
11757
+ description: "Link issued a one-time virtual card. An agent fills these into the checkout form. Single-use \u2014 expires in minutes:",
11758
+ openUrl: "Open Galtee Outdoor and enter these details at checkout.",
11759
+ prompt: "Press [Enter] to open Galtee Outdoor"
11760
+ },
11761
+ done: {
11762
+ success: "Opened Galtee Outdoor in your browser",
11763
+ detail: "Enter the card details above at checkout. Galtee Outdoor runs in testmode \u2014 no real charge."
11764
+ }
11765
+ };
11766
+ var SPT_FLOW = {
11767
+ title: "Flow 2: Machine Payment (SPT)",
11768
+ intro: {
11769
+ description: "Some APIs accept payment without a checkout form. When called without credentials, the server responds with **HTTP 402** and a payment challenge. The agent signs that challenge with a **shared payment token** (SPT) and retries \u2014 this is the Machine Payment Protocol (MPP).",
11770
+ preamble: `A ${sptAmount} donation to Stripe Climate (climate.stripe.dev) demonstrates:`,
11771
+ steps: [
11772
+ "Probe the API \u2014 server responds HTTP 402 with a challenge",
11773
+ "Decode the challenge to extract the `network_id`",
11774
+ "Call `spend-request create` for an SPT credential",
11775
+ "Approve the spend request",
11776
+ "`mpp pay` signs the challenge and retries with an Authorization header"
11777
+ ],
11778
+ prompt: "Press [Enter] to start"
11779
+ },
11780
+ probe: {
11781
+ description: `The agent POSTs to ${DEMO_CLIMATE_API_URL}. Without a payment credential, the server returns HTTP 402 with a \`WWW-Authenticate\` challenge header.`,
11782
+ loading: "Probing...",
11783
+ detail: "The challenge contains a **network_id** \u2014 the business identifier on the Stripe network. The agent uses it to request the matching SPT credential."
11784
+ },
11785
+ createSpend: {
11786
+ description: `\`spend-request create\` with \`credential_type: "shared_payment_token"\`, the decoded \`network_id\`, and amount (${sptAmount}). The \`network_id\` identifies the business \u2014 no name or URL needed.`,
11787
+ loading: "Creating spend request..."
11788
+ },
11789
+ approval: {
11790
+ description: "Approve the spend request. Once approved, Link issues an SPT the agent uses to sign the 402 challenge.",
11791
+ loading: "Waiting for approval...",
11792
+ browserHint: "Press [Enter] to open in browser"
11793
+ },
11794
+ mppPay: {
11795
+ description: "`mpp pay` retrieves the SPT, re-probes the API, signs the 402 challenge, and retries with an `Authorization: Payment` header.",
11796
+ loading: "Completing payment...",
11797
+ prompt: "Press [Enter] to pay"
11798
+ },
11799
+ done: {
11800
+ success: "Payment complete",
11801
+ detail: `The ${sptAmount} donation went through entirely via API \u2014 no forms, no browser.`
11802
+ }
11803
+ };
11804
+ var DEMO_MENU = {
11805
+ title: "Link CLI Demo",
11806
+ subtitle: "Two flows showing how agents request and use payment credentials with Link.",
11807
+ question: "Which flow would you like to run?",
11808
+ hint: "Use \u2191\u2193 to select, [Enter] to confirm",
11809
+ options: [
11810
+ {
11811
+ key: "both",
11812
+ label: "Both flows",
11813
+ description: "Walk through both flows end-to-end."
11814
+ },
11815
+ {
11816
+ key: "card",
11817
+ label: "Virtual card",
11818
+ description: "The agent requests a one-time card number and fills it into a checkout form."
11819
+ },
11820
+ {
11821
+ key: "spt",
11822
+ label: "Machine payment (SPT)",
11823
+ description: "The agent pays via API using the Machine Payment Protocol \u2014 no browser, no forms."
11824
+ }
11825
+ ],
11826
+ transition: "Virtual card flow done. Next: **machine payment** \u2014 the agent pays an API directly, no checkout form needed.",
11827
+ transitionPrompt: "Press [Enter] to continue to Flow 2"
11828
+ };
11829
+ var ONBOARD = {
11830
+ title: "Welcome to Link CLI",
11831
+ subtitle: "Set up Link CLI to let agents make secure payments on your behalf.",
11832
+ auth: {
11833
+ alreadyLoggedIn: "Already logged in",
11834
+ authenticated: "Authenticated",
11835
+ clientName: "Link CLI Onboard"
11836
+ },
11837
+ paymentMethods: {
11838
+ loading: "Checking payment methods...",
11839
+ pickPrompt: "Which payment method should we use for the demo?",
11840
+ pickHint: "Use \u2191\u2193 to select, [Enter] to confirm",
11841
+ missing: "No payment methods found in your Link wallet.",
11842
+ missingSteps: [
11843
+ "Open the Link app or visit link.com",
11844
+ "Add a payment method",
11845
+ "Come back here and press [Enter] to retry"
11846
+ ],
11847
+ retryPrompt: "Press [Enter] to retry"
11848
+ },
11849
+ appTip: {
11850
+ title: "Get the Link app",
11851
+ description: "Approve spend requests from your phone. Push notifications let you approve or deny instantly.",
11852
+ url: "https://link.com/download"
11853
+ }
11854
+ };
11855
+
11856
+ // src/commands/demo/step-data.tsx
11857
+ import { Box as Box4, Text as Text5 } from "ink";
11858
+ import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
11859
+ var StepData = ({ data }) => {
11860
+ const entries = Object.entries(data).filter(
11861
+ ([, v]) => v !== void 0 && v !== null
11862
+ );
11863
+ const maxKeyLen = Math.max(...entries.map(([k]) => k.length));
11864
+ return /* @__PURE__ */ jsx6(
11865
+ Box4,
11866
+ {
11867
+ flexDirection: "column",
11868
+ paddingX: 2,
11869
+ marginTop: 1,
11870
+ borderStyle: "single",
11871
+ borderColor: "gray",
11872
+ children: entries.map(([key, value]) => /* @__PURE__ */ jsxs3(Text5, { children: [
11873
+ /* @__PURE__ */ jsx6(Text5, { dimColor: true, children: key.padEnd(maxKeyLen) }),
11874
+ " ",
11875
+ /* @__PURE__ */ jsx6(Text5, { children: typeof value === "object" ? JSON.stringify(value) : String(value) })
11876
+ ] }, key))
11877
+ }
11878
+ );
11879
+ };
11880
+
11881
+ // src/commands/demo/card-flow.tsx
11882
+ import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
11883
+ function formatPmLabel(pm) {
11884
+ return `${pm.card_details?.brand ?? pm.type} ****${pm.card_details?.last4 ?? ""}`;
11885
+ }
11886
+ function formatCardNumber(num) {
11887
+ return num.replace(/(.{4})/g, "$1 ").trim();
11888
+ }
11889
+ function formatExpiry(month, year) {
11890
+ return `${String(month).padStart(2, "0")}/${String(year).slice(-2)}`;
11891
+ }
11892
+ var CardFlow = ({
11893
+ spendRequestRepo: spendRequestRepo2,
11894
+ paymentMethodsResource,
11895
+ paymentMethodId: initialPaymentMethodId,
11896
+ onComplete
11897
+ }) => {
11898
+ const [step, setStep] = useState3("intro");
11899
+ const [paymentMethod, setPaymentMethod] = useState3(
11900
+ null
11901
+ );
11902
+ const [paymentMethods, setPaymentMethods] = useState3([]);
11903
+ const [selectedPmIndex, setSelectedPmIndex] = useState3(0);
11904
+ const [spendRequest, setSpendRequest] = useState3(null);
11905
+ const [spendRequestPayload, setSpendRequestPayload] = useState3(null);
11906
+ const [error, setError] = useState3("");
11907
+ const approvalUrl = spendRequest?.approval_url ?? "";
11908
+ const enterResolver = useRef(null);
11909
+ const pmResolver = useRef(null);
11910
+ const retryChoiceResolver = useRef(null);
11911
+ function waitForEnter() {
11912
+ return new Promise((resolve) => {
11913
+ enterResolver.current = resolve;
11914
+ });
11915
+ }
11916
+ function waitForPmSelection() {
11917
+ return new Promise((resolve) => {
11918
+ pmResolver.current = resolve;
11919
+ });
11920
+ }
11921
+ function waitForRetryChoice() {
11922
+ return new Promise((resolve) => {
11923
+ retryChoiceResolver.current = resolve;
11924
+ });
11925
+ }
11926
+ useInput2((input, key) => {
11927
+ if (step === "pick-pm") {
11928
+ if (key.upArrow) {
11929
+ setSelectedPmIndex((i) => i > 0 ? i - 1 : paymentMethods.length - 1);
11930
+ } else if (key.downArrow) {
11931
+ setSelectedPmIndex((i) => i < paymentMethods.length - 1 ? i + 1 : 0);
11932
+ } else if (key.return && pmResolver.current) {
11933
+ const pm = paymentMethods[selectedPmIndex];
11934
+ const resolve = pmResolver.current;
11935
+ pmResolver.current = null;
11936
+ resolve(pm.id);
11937
+ }
11938
+ } else if (step === "approval-timeout" && retryChoiceResolver.current) {
11939
+ if (input === "r") {
11940
+ const resolve = retryChoiceResolver.current;
11941
+ retryChoiceResolver.current = null;
11942
+ resolve("retry");
11943
+ } else if (input === "q") {
11944
+ const resolve = retryChoiceResolver.current;
11945
+ retryChoiceResolver.current = null;
11946
+ resolve("exit");
11947
+ }
11948
+ } else if (key.return) {
11949
+ if (enterResolver.current) {
11950
+ const resolve = enterResolver.current;
11951
+ enterResolver.current = null;
11952
+ resolve();
11953
+ } else if ((step === "await-approval" || step === "approval-timeout") && approvalUrl) {
11954
+ openUrl(approvalUrl);
11955
+ }
11956
+ }
11957
+ });
11958
+ const started = useRef(false);
11959
+ useEffect3(() => {
11960
+ if (started.current) return;
11961
+ started.current = true;
11962
+ const run = async () => {
11963
+ try {
11964
+ await waitForEnter();
11965
+ let pmId = initialPaymentMethodId;
11966
+ if (!pmId) {
11967
+ setStep("fetch-pm");
11968
+ const methods = await paymentMethodsResource.listPaymentMethods();
11969
+ if (methods.length === 0) {
11970
+ setError(
11971
+ "No payment methods found. Open the Link app (link.com) and add a card to your wallet, then run the demo again."
11972
+ );
11973
+ setStep("error");
11974
+ onComplete({ paymentMethodId: "", success: false });
11975
+ return;
11976
+ }
11977
+ if (methods.length === 1) {
11978
+ const pm = methods[0];
11979
+ setPaymentMethod(pm);
11980
+ setPaymentMethods(methods);
11981
+ pmId = pm.id;
11982
+ } else {
11983
+ setPaymentMethods(methods);
11984
+ const defaultIdx = methods.findIndex((m) => m.is_default);
11985
+ setSelectedPmIndex(defaultIdx >= 0 ? defaultIdx : 0);
11986
+ setStep("pick-pm");
11987
+ pmId = await waitForPmSelection();
11988
+ const pm = methods.find((m) => m.id === pmId) ?? methods[0];
11989
+ setPaymentMethod(pm);
11990
+ }
11991
+ setStep("explain-pm");
11992
+ await waitForEnter();
11993
+ }
11994
+ setStep("create-spend");
11995
+ const payload = {
11996
+ payment_details: pmId,
11997
+ credential_type: "card",
11998
+ amount: DEMO_CARD_AMOUNT,
11999
+ context: DEMO_CARD_CONTEXT,
12000
+ merchant_name: DEMO_MERCHANT_NAME,
12001
+ merchant_url: DEMO_MERCHANT_URL,
12002
+ request_approval: true,
12003
+ test: true
12004
+ };
12005
+ setSpendRequestPayload(payload);
12006
+ const result = await spendRequestRepo2.createSpendRequest(payload);
12007
+ setSpendRequest(result);
12008
+ setStep("await-approval");
12009
+ for (; ; ) {
12010
+ try {
12011
+ await pollUntilApproved(spendRequestRepo2, result.id);
12012
+ break;
12013
+ } catch (err) {
12014
+ if (err.message === "Approval polling timed out") {
12015
+ setStep("approval-timeout");
12016
+ const choice = await waitForRetryChoice();
12017
+ if (choice === "exit") {
12018
+ onComplete({ paymentMethodId: pmId ?? "", success: false });
12019
+ return;
12020
+ }
12021
+ setStep("await-approval");
12022
+ } else {
12023
+ throw err;
12024
+ }
12025
+ }
12026
+ }
12027
+ const approved = await spendRequestRepo2.getSpendRequest(result.id, {
12028
+ include: ["card"]
12029
+ });
12030
+ if (approved) setSpendRequest(approved);
12031
+ setStep("show-card");
12032
+ await waitForEnter();
12033
+ setStep("open-url");
12034
+ openUrl(DEMO_MERCHANT_URL);
12035
+ setStep("done");
12036
+ onComplete({ paymentMethodId: pmId, success: true });
12037
+ } catch (err) {
12038
+ setError(err.message);
12039
+ setStep("error");
12040
+ onComplete({
12041
+ paymentMethodId: paymentMethod?.id ?? "",
12042
+ success: false
12043
+ });
12044
+ }
12045
+ };
12046
+ run();
12047
+ }, []);
12048
+ const pmLabel = paymentMethod ? formatPmLabel(paymentMethod) : "";
12049
+ const card = spendRequest?.card;
12050
+ const pastStep = (target) => {
12051
+ const order = [
12052
+ "intro",
12053
+ "fetch-pm",
12054
+ "pick-pm",
12055
+ "explain-pm",
12056
+ "create-spend",
12057
+ "await-approval",
12058
+ "show-card",
12059
+ "open-url",
12060
+ "done"
12061
+ ];
12062
+ return order.indexOf(step) > order.indexOf(target);
12063
+ };
12064
+ const prompt = (label = "Press [Enter] to continue") => /* @__PURE__ */ jsxs4(Text6, { dimColor: true, children: [
12065
+ "\n",
12066
+ ">",
12067
+ " ",
12068
+ label
12069
+ ] });
12070
+ return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", gap: 1, children: [
12071
+ /* @__PURE__ */ jsx7(Text6, { bold: true, color: "cyan", children: CARD_FLOW.title }),
12072
+ /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
12073
+ /* @__PURE__ */ jsxs4(Box5, { flexDirection: "row", gap: 1, children: [
12074
+ /* @__PURE__ */ jsx7(Text6, { color: "yellow", children: "[testmode]" }),
12075
+ /* @__PURE__ */ jsx7(Text6, { dimColor: true, children: DEMO_MERCHANT_URL })
12076
+ ] }),
12077
+ /* @__PURE__ */ jsx7(MarkdownText, { children: CARD_FLOW.intro.description }),
12078
+ /* @__PURE__ */ jsx7(Box5, { marginTop: 1, children: /* @__PURE__ */ jsxs4(Text6, { children: [
12079
+ "What happens:",
12080
+ "\n",
12081
+ CARD_FLOW.intro.steps.map((s, i) => ` ${i + 1}. ${s}`).join("\n")
12082
+ ] }) }),
12083
+ step === "intro" && prompt(CARD_FLOW.intro.prompt)
12084
+ ] }),
12085
+ step === "fetch-pm" && /* @__PURE__ */ jsx7(Box5, { flexDirection: "column", children: /* @__PURE__ */ jsx7(Text6, { dimColor: true, children: "Fetching payment methods from your Link wallet..." }) }),
12086
+ step === "pick-pm" && paymentMethods.length > 1 && /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
12087
+ /* @__PURE__ */ jsx7(Text6, { children: "Which payment method should we use for the demo?" }),
12088
+ /* @__PURE__ */ jsx7(Box5, { flexDirection: "column", marginTop: 1, children: paymentMethods.map((pm, i) => /* @__PURE__ */ jsx7(Text6, { children: i === selectedPmIndex ? /* @__PURE__ */ jsxs4(Text6, { color: "cyan", bold: true, children: [
12089
+ ">",
12090
+ " ",
12091
+ formatPmLabel(pm),
12092
+ pm.is_default ? " (default)" : ""
12093
+ ] }) : /* @__PURE__ */ jsxs4(Text6, { dimColor: true, children: [
12094
+ " ",
12095
+ formatPmLabel(pm),
12096
+ pm.is_default ? " (default)" : ""
12097
+ ] }) }, pm.id)) }),
12098
+ /* @__PURE__ */ jsx7(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text6, { dimColor: true, children: "Use \u2191\u2193 to select, [Enter] to confirm" }) })
12099
+ ] }),
12100
+ pastStep("fetch-pm") && paymentMethod && /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
12101
+ /* @__PURE__ */ jsxs4(Text6, { color: "green", children: [
12102
+ "\u2713 Using ",
12103
+ /* @__PURE__ */ jsx7(Text6, { bold: true, children: pmLabel }),
12104
+ paymentMethod.is_default ? " (default)" : ""
12105
+ ] }),
12106
+ step === "explain-pm" && prompt()
12107
+ ] }),
12108
+ pastStep("explain-pm") && /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
12109
+ /* @__PURE__ */ jsx7(MarkdownText, { children: CARD_FLOW.createSpend.description }),
12110
+ spendRequestPayload && /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", marginTop: 1, children: [
12111
+ /* @__PURE__ */ jsx7(Text6, { dimColor: true, children: "spend-request create" }),
12112
+ /* @__PURE__ */ jsx7(
12113
+ Box5,
12114
+ {
12115
+ flexDirection: "column",
12116
+ borderStyle: "single",
12117
+ borderColor: "gray",
12118
+ paddingX: 2,
12119
+ children: /* @__PURE__ */ jsx7(Text6, { children: JSON.stringify(
12120
+ spendRequestPayload,
12121
+ null,
12122
+ 2
12123
+ ) })
12124
+ }
12125
+ )
12126
+ ] }),
12127
+ step === "create-spend" && /* @__PURE__ */ jsx7(Box5, { marginY: 1, children: /* @__PURE__ */ jsx7(Text6, { color: "cyan", children: CARD_FLOW.createSpend.loading }) })
12128
+ ] }),
12129
+ (step === "await-approval" || step === "approval-timeout" || pastStep("await-approval")) && spendRequest && /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
12130
+ /* @__PURE__ */ jsxs4(Text6, { color: "green", children: [
12131
+ "\u2713 Spend request created (ID: ",
12132
+ /* @__PURE__ */ jsx7(Text6, { bold: true, children: spendRequest.id }),
12133
+ ")"
12134
+ ] }),
12135
+ /* @__PURE__ */ jsx7(
12136
+ StepData,
12137
+ {
12138
+ data: {
12139
+ id: spendRequest.id,
12140
+ status: spendRequest.status,
12141
+ credential_type: spendRequest.credential_type,
12142
+ amount: spendRequest.amount,
12143
+ merchant_name: spendRequest.merchant_name,
12144
+ merchant_url: spendRequest.merchant_url,
12145
+ context: spendRequest.context,
12146
+ approval_url: spendRequest.approval_url
12147
+ }
12148
+ }
12149
+ )
12150
+ ] }),
12151
+ step === "await-approval" && /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
12152
+ /* @__PURE__ */ jsx7(Text6, { children: CARD_FLOW.approval.description }),
12153
+ /* @__PURE__ */ jsxs4(
12154
+ Box5,
12155
+ {
12156
+ flexDirection: "column",
12157
+ borderStyle: "round",
12158
+ borderColor: "cyan",
12159
+ paddingX: 2,
12160
+ paddingY: 1,
12161
+ marginTop: 1,
12162
+ children: [
12163
+ /* @__PURE__ */ jsxs4(Text6, { children: [
12164
+ "Approve at:",
12165
+ " ",
12166
+ /* @__PURE__ */ jsx7(Text6, { bold: true, color: "cyan", children: approvalUrl })
12167
+ ] }),
12168
+ /* @__PURE__ */ jsx7(Text6, { dimColor: true, children: CARD_FLOW.approval.browserHint })
12169
+ ]
12170
+ }
12171
+ ),
12172
+ /* @__PURE__ */ jsx7(Box5, { marginY: 1, children: /* @__PURE__ */ jsx7(Text6, { color: "cyan", children: CARD_FLOW.approval.loading }) })
12173
+ ] }),
12174
+ step === "approval-timeout" && /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
12175
+ /* @__PURE__ */ jsx7(Text6, { color: "yellow", children: "\u26A0 Approval timed out (5 min). The spend request is still pending \u2014 you can still approve it." }),
12176
+ /* @__PURE__ */ jsxs4(
12177
+ Box5,
12178
+ {
12179
+ flexDirection: "column",
12180
+ borderStyle: "round",
12181
+ borderColor: "yellow",
12182
+ paddingX: 2,
12183
+ paddingY: 1,
12184
+ marginTop: 1,
12185
+ children: [
12186
+ /* @__PURE__ */ jsxs4(Text6, { children: [
12187
+ "Approve at:",
12188
+ " ",
12189
+ /* @__PURE__ */ jsx7(Text6, { bold: true, color: "cyan", children: approvalUrl })
12190
+ ] }),
12191
+ /* @__PURE__ */ jsx7(Text6, { dimColor: true, children: "Press [Enter] to open in browser" })
12192
+ ]
12193
+ }
12194
+ ),
12195
+ /* @__PURE__ */ jsx7(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text6, { dimColor: true, children: "r Retry polling q Quit demo" }) })
12196
+ ] }),
12197
+ pastStep("await-approval") && card && /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
12198
+ /* @__PURE__ */ jsx7(Text6, { color: "green", children: "\u2713 Approved!" }),
12199
+ /* @__PURE__ */ jsx7(MarkdownText, { children: CARD_FLOW.showCard.description }),
12200
+ /* @__PURE__ */ jsxs4(
12201
+ Box5,
12202
+ {
12203
+ flexDirection: "column",
12204
+ borderStyle: "round",
12205
+ borderColor: "green",
12206
+ paddingX: 2,
12207
+ paddingY: 1,
12208
+ marginTop: 1,
12209
+ children: [
12210
+ /* @__PURE__ */ jsx7(Text6, { color: "yellow", dimColor: true, children: "[testmode card]" }),
12211
+ /* @__PURE__ */ jsxs4(Text6, { children: [
12212
+ "Number: ",
12213
+ /* @__PURE__ */ jsx7(Text6, { bold: true, children: formatCardNumber(card.number) })
12214
+ ] }),
12215
+ /* @__PURE__ */ jsxs4(Text6, { children: [
12216
+ "Exp:",
12217
+ " ",
12218
+ /* @__PURE__ */ jsx7(Text6, { bold: true, children: formatExpiry(card.exp_month, card.exp_year) })
12219
+ ] }),
12220
+ /* @__PURE__ */ jsxs4(Text6, { children: [
12221
+ "CVC: ",
12222
+ /* @__PURE__ */ jsx7(Text6, { bold: true, children: card.cvc })
12223
+ ] }),
12224
+ card.billing_address?.postal_code && /* @__PURE__ */ jsxs4(Text6, { children: [
12225
+ "Zip: ",
12226
+ /* @__PURE__ */ jsx7(Text6, { bold: true, children: card.billing_address.postal_code })
12227
+ ] }),
12228
+ card.valid_until && /* @__PURE__ */ jsxs4(Text6, { dimColor: true, children: [
12229
+ "Expires:",
12230
+ " ",
12231
+ new Date(card.valid_until).toLocaleTimeString([], {
12232
+ hour: "2-digit",
12233
+ minute: "2-digit"
12234
+ })
12235
+ ] })
12236
+ ]
12237
+ }
12238
+ ),
12239
+ /* @__PURE__ */ jsx7(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx7(MarkdownText, { children: CARD_FLOW.showCard.openUrl }) }),
12240
+ step === "show-card" && prompt(CARD_FLOW.showCard.prompt)
12241
+ ] }),
12242
+ step === "done" && /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
12243
+ /* @__PURE__ */ jsxs4(Box5, { flexDirection: "row", gap: 1, children: [
12244
+ /* @__PURE__ */ jsx7(Text6, { color: "yellow", children: "[testmode]" }),
12245
+ /* @__PURE__ */ jsxs4(Text6, { color: "green", children: [
12246
+ "\u2713 ",
12247
+ CARD_FLOW.done.success
12248
+ ] })
12249
+ ] }),
12250
+ /* @__PURE__ */ jsx7(Text6, { children: CARD_FLOW.done.detail })
12251
+ ] }),
12252
+ step === "error" && /* @__PURE__ */ jsxs4(Text6, { color: "red", children: [
12253
+ "Error: ",
12254
+ error
12255
+ ] })
12256
+ ] });
12257
+ };
12258
+
12259
+ // src/commands/demo/spt-flow.tsx
12260
+ import { Box as Box7, Text as Text8, useInput as useInput3 } from "ink";
12261
+ import { useEffect as useEffect5, useRef as useRef2, useState as useState5 } from "react";
12262
+
11587
12263
  // src/commands/mpp/decode.ts
11588
12264
  import { Challenge } from "mppx";
11589
12265
  function getString(value, path5, required = true) {
@@ -11662,41 +12338,14 @@ function decodeStripeChallenge(challengeHeader) {
11662
12338
  };
11663
12339
  }
11664
12340
 
11665
- // src/commands/mpp/decode-view.tsx
11666
- import { Box as Box3, Text as Text3 } from "ink";
11667
- import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
11668
- function DecodeChallengeView({
11669
- decoded
11670
- }) {
11671
- return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", children: [
11672
- /* @__PURE__ */ jsx4(Text3, { color: "green", children: "\u2713 Stripe challenge decoded" }),
11673
- /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
11674
- /* @__PURE__ */ jsxs2(Text3, { children: [
11675
- "ID: ",
11676
- /* @__PURE__ */ jsx4(Text3, { bold: true, children: decoded.id })
11677
- ] }),
11678
- /* @__PURE__ */ jsxs2(Text3, { children: [
11679
- "Realm: ",
11680
- /* @__PURE__ */ jsx4(Text3, { bold: true, children: decoded.realm })
11681
- ] }),
11682
- /* @__PURE__ */ jsxs2(Text3, { children: [
11683
- "Network ID: ",
11684
- /* @__PURE__ */ jsx4(Text3, { bold: true, children: decoded.network_id })
11685
- ] }),
11686
- /* @__PURE__ */ jsx4(Text3, { children: "Request JSON:" }),
11687
- /* @__PURE__ */ jsx4(Text3, { children: JSON.stringify(decoded.request_json, null, 2) })
11688
- ] })
11689
- ] });
11690
- }
11691
-
11692
12341
  // src/commands/mpp/pay.tsx
11693
- import { Box as Box4, Text as Text4 } from "ink";
12342
+ import { Box as Box6, Text as Text7 } from "ink";
11694
12343
  import Spinner2 from "ink-spinner";
11695
12344
  import { Credential, Method } from "mppx";
11696
12345
  import { Mppx, Transport } from "mppx/client";
11697
12346
  import { Methods as StripeMethods } from "mppx/stripe";
11698
- import { useEffect as useEffect3, useState as useState3 } from "react";
11699
- import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
12347
+ import { useEffect as useEffect4, useState as useState4 } from "react";
12348
+ import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
11700
12349
  function buildHeaders(data, headers) {
11701
12350
  const result = {};
11702
12351
  if (data !== void 0) {
@@ -11801,10 +12450,10 @@ function MppPay({
11801
12450
  repository,
11802
12451
  onComplete
11803
12452
  }) {
11804
- const [step, setStep] = useState3("retrieving");
11805
- const [result, setResult] = useState3(null);
11806
- const [error, setError] = useState3(null);
11807
- useEffect3(() => {
12453
+ const [step, setStep] = useState4("retrieving");
12454
+ const [result, setResult] = useState4(null);
12455
+ const [error, setError] = useState4(null);
12456
+ useEffect4(() => {
11808
12457
  (async () => {
11809
12458
  try {
11810
12459
  setStep("retrieving");
@@ -11873,54 +12522,640 @@ function MppPay({
11873
12522
  done: "Done"
11874
12523
  };
11875
12524
  if (error) {
11876
- return /* @__PURE__ */ jsxs3(Text4, { color: "red", children: [
12525
+ return /* @__PURE__ */ jsxs5(Text7, { color: "red", children: [
11877
12526
  "Error: ",
11878
12527
  error
11879
12528
  ] });
11880
12529
  }
11881
- return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", children: [
11882
- step !== "done" && /* @__PURE__ */ jsx5(Box4, { children: /* @__PURE__ */ jsxs3(Text4, { color: "cyan", children: [
11883
- /* @__PURE__ */ jsx5(Spinner2, { type: "dots" }),
12530
+ return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
12531
+ step !== "done" && /* @__PURE__ */ jsx8(Box6, { children: /* @__PURE__ */ jsxs5(Text7, { color: "cyan", children: [
12532
+ /* @__PURE__ */ jsx8(Spinner2, { type: "dots" }),
11884
12533
  " ",
11885
12534
  stepLabels[step],
11886
12535
  "..."
11887
12536
  ] }) }),
11888
- result && /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", children: [
11889
- /* @__PURE__ */ jsxs3(Text4, { color: "green", children: [
12537
+ result && /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
12538
+ /* @__PURE__ */ jsxs5(Text7, { color: "green", children: [
11890
12539
  "HTTP ",
11891
12540
  result.status
11892
12541
  ] }),
11893
- /* @__PURE__ */ jsx5(Text4, { children: result.body })
12542
+ /* @__PURE__ */ jsx8(Text7, { children: result.body })
12543
+ ] })
12544
+ ] });
12545
+ }
12546
+
12547
+ // src/commands/demo/spt-flow.tsx
12548
+ import { Fragment, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
12549
+ var SptFlow = ({
12550
+ spendRequestRepo: spendRequestRepo2,
12551
+ paymentMethodsResource,
12552
+ paymentMethodId: initialPaymentMethodId,
12553
+ onComplete
12554
+ }) => {
12555
+ const [step, setStep] = useState5("intro");
12556
+ const [networkId, setNetworkId] = useState5("");
12557
+ const [paymentMethods, setPaymentMethods] = useState5([]);
12558
+ const [selectedPmIndex, setSelectedPmIndex] = useState5(0);
12559
+ const [spendRequest, setSpendRequest] = useState5(null);
12560
+ const [spendRequestPayload, setSpendRequestPayload] = useState5(null);
12561
+ const [payResult, setPayResult] = useState5(null);
12562
+ const [challengeData, setChallengeData] = useState5(null);
12563
+ const [error, setError] = useState5("");
12564
+ const approvalUrl = spendRequest?.approval_url ?? "";
12565
+ const enterResolver = useRef2(null);
12566
+ const pmResolver = useRef2(null);
12567
+ const retryChoiceResolver = useRef2(null);
12568
+ function waitForEnter() {
12569
+ return new Promise((resolve) => {
12570
+ enterResolver.current = resolve;
12571
+ });
12572
+ }
12573
+ function waitForPmSelection() {
12574
+ return new Promise((resolve) => {
12575
+ pmResolver.current = resolve;
12576
+ });
12577
+ }
12578
+ function waitForRetryChoice() {
12579
+ return new Promise((resolve) => {
12580
+ retryChoiceResolver.current = resolve;
12581
+ });
12582
+ }
12583
+ useInput3((input, key) => {
12584
+ if (step === "pick-pm") {
12585
+ if (key.upArrow) {
12586
+ setSelectedPmIndex((i) => i > 0 ? i - 1 : paymentMethods.length - 1);
12587
+ } else if (key.downArrow) {
12588
+ setSelectedPmIndex((i) => i < paymentMethods.length - 1 ? i + 1 : 0);
12589
+ } else if (key.return && pmResolver.current) {
12590
+ const pm = paymentMethods[selectedPmIndex];
12591
+ const resolve = pmResolver.current;
12592
+ pmResolver.current = null;
12593
+ resolve(pm.id);
12594
+ }
12595
+ } else if (step === "approval-timeout" && retryChoiceResolver.current) {
12596
+ if (input === "r") {
12597
+ const resolve = retryChoiceResolver.current;
12598
+ retryChoiceResolver.current = null;
12599
+ resolve("retry");
12600
+ } else if (input === "q") {
12601
+ const resolve = retryChoiceResolver.current;
12602
+ retryChoiceResolver.current = null;
12603
+ resolve("exit");
12604
+ }
12605
+ } else if (key.return) {
12606
+ if (enterResolver.current) {
12607
+ const resolve = enterResolver.current;
12608
+ enterResolver.current = null;
12609
+ resolve();
12610
+ } else if ((step === "await-approval" || step === "approval-timeout") && approvalUrl) {
12611
+ openUrl(approvalUrl);
12612
+ }
12613
+ }
12614
+ });
12615
+ const started = useRef2(false);
12616
+ useEffect5(() => {
12617
+ if (started.current) return;
12618
+ started.current = true;
12619
+ const run = async () => {
12620
+ try {
12621
+ await waitForEnter();
12622
+ let pmId = initialPaymentMethodId;
12623
+ if (!pmId) {
12624
+ setStep("fetch-pm");
12625
+ const methods = await paymentMethodsResource.listPaymentMethods();
12626
+ if (methods.length === 0) {
12627
+ throw new Error(
12628
+ "No payment methods found. Open the Link app (link.com) and add a card to your wallet, then run the demo again."
12629
+ );
12630
+ }
12631
+ if (methods.length === 1) {
12632
+ pmId = methods[0].id;
12633
+ } else {
12634
+ setPaymentMethods(methods);
12635
+ const defaultIdx = methods.findIndex((m) => m.is_default);
12636
+ setSelectedPmIndex(defaultIdx >= 0 ? defaultIdx : 0);
12637
+ setStep("pick-pm");
12638
+ pmId = await waitForPmSelection();
12639
+ }
12640
+ }
12641
+ setStep("probe");
12642
+ const probeResponse = await fetch(DEMO_CLIMATE_API_URL, {
12643
+ method: "POST",
12644
+ headers: { "Content-Type": "application/json" },
12645
+ body: JSON.stringify({ amount: DEMO_SPT_AMOUNT })
12646
+ });
12647
+ if (probeResponse.status !== 402) {
12648
+ throw new Error(
12649
+ `Expected 402 from ${DEMO_CLIMATE_API_URL}, got ${probeResponse.status}`
12650
+ );
12651
+ }
12652
+ const wwwAuth = probeResponse.headers.get("www-authenticate") ?? "";
12653
+ const decoded = decodeStripeChallenge(wwwAuth);
12654
+ setNetworkId(decoded.network_id);
12655
+ setChallengeData({
12656
+ status: probeResponse.status,
12657
+ method: decoded.method,
12658
+ intent: decoded.intent,
12659
+ network_id: decoded.network_id,
12660
+ realm: decoded.realm
12661
+ });
12662
+ setStep("explain-402");
12663
+ await waitForEnter();
12664
+ setStep("create-spend");
12665
+ const payload = {
12666
+ payment_details: pmId,
12667
+ credential_type: "shared_payment_token",
12668
+ network_id: decoded.network_id,
12669
+ amount: DEMO_SPT_AMOUNT,
12670
+ context: DEMO_SPT_CONTEXT,
12671
+ request_approval: true,
12672
+ test: true
12673
+ };
12674
+ setSpendRequestPayload(payload);
12675
+ const result = await spendRequestRepo2.createSpendRequest(payload);
12676
+ setSpendRequest(result);
12677
+ setStep("await-approval");
12678
+ for (; ; ) {
12679
+ try {
12680
+ const approved = await pollUntilApproved(
12681
+ spendRequestRepo2,
12682
+ result.id
12683
+ );
12684
+ setSpendRequest(approved);
12685
+ break;
12686
+ } catch (err) {
12687
+ if (err.message === "Approval polling timed out") {
12688
+ setStep("approval-timeout");
12689
+ const choice = await waitForRetryChoice();
12690
+ if (choice === "exit") {
12691
+ onComplete(false);
12692
+ return;
12693
+ }
12694
+ setStep("await-approval");
12695
+ } else {
12696
+ throw err;
12697
+ }
12698
+ }
12699
+ }
12700
+ setStep("mpp-pay-gate");
12701
+ await waitForEnter();
12702
+ setStep("mpp-pay");
12703
+ const payResponse = await runMppPay(
12704
+ DEMO_CLIMATE_API_URL,
12705
+ result.id,
12706
+ "POST",
12707
+ JSON.stringify({ amount: DEMO_SPT_AMOUNT }),
12708
+ void 0,
12709
+ spendRequestRepo2
12710
+ );
12711
+ setPayResult(payResponse);
12712
+ setStep("done");
12713
+ onComplete(true);
12714
+ } catch (err) {
12715
+ setError(err.message);
12716
+ setStep("error");
12717
+ onComplete(false);
12718
+ }
12719
+ };
12720
+ run();
12721
+ }, []);
12722
+ const pastStep = (target) => {
12723
+ const order = [
12724
+ "intro",
12725
+ "fetch-pm",
12726
+ "pick-pm",
12727
+ "probe",
12728
+ "explain-402",
12729
+ "create-spend",
12730
+ "await-approval",
12731
+ "mpp-pay-gate",
12732
+ "mpp-pay",
12733
+ "done"
12734
+ ];
12735
+ return order.indexOf(step) > order.indexOf(target);
12736
+ };
12737
+ const prompt = (label = "Press [Enter] to continue") => /* @__PURE__ */ jsxs6(Text8, { dimColor: true, children: [
12738
+ "\n",
12739
+ ">",
12740
+ " ",
12741
+ label
12742
+ ] });
12743
+ return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", gap: 1, children: [
12744
+ /* @__PURE__ */ jsx9(Text8, { bold: true, color: "cyan", children: SPT_FLOW.title }),
12745
+ /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", children: [
12746
+ /* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", gap: 1, children: [
12747
+ /* @__PURE__ */ jsx9(Text8, { color: "yellow", children: "[testmode]" }),
12748
+ /* @__PURE__ */ jsxs6(Text8, { dimColor: true, children: [
12749
+ DEMO_CLIMATE_API_URL,
12750
+ " ",
12751
+ DEMO_MPP_DEV_URL
12752
+ ] })
12753
+ ] }),
12754
+ /* @__PURE__ */ jsx9(MarkdownText, { children: SPT_FLOW.intro.description }),
12755
+ /* @__PURE__ */ jsxs6(Box7, { marginTop: 1, flexDirection: "column", children: [
12756
+ /* @__PURE__ */ jsx9(Text8, { children: SPT_FLOW.intro.preamble }),
12757
+ SPT_FLOW.intro.steps.map((s, i) => /* @__PURE__ */ jsx9(MarkdownText, { children: ` ${i + 1}. ${s}` }, s))
12758
+ ] }),
12759
+ step === "intro" && prompt(SPT_FLOW.intro.prompt)
12760
+ ] }),
12761
+ step === "fetch-pm" && /* @__PURE__ */ jsx9(Box7, { marginY: 1, children: /* @__PURE__ */ jsx9(Text8, { color: "cyan", children: "Fetching payment methods..." }) }),
12762
+ step === "pick-pm" && paymentMethods.length > 1 && /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", children: [
12763
+ /* @__PURE__ */ jsx9(Text8, { children: "Which payment method should we use for the demo?" }),
12764
+ /* @__PURE__ */ jsx9(Box7, { flexDirection: "column", marginTop: 1, children: paymentMethods.map((pm, i) => /* @__PURE__ */ jsx9(Text8, { children: i === selectedPmIndex ? /* @__PURE__ */ jsxs6(Text8, { color: "cyan", bold: true, children: [
12765
+ ">",
12766
+ " ",
12767
+ pm.card_details ? `${pm.card_details.brand} ****${pm.card_details.last4}` : pm.type,
12768
+ pm.is_default ? " (default)" : ""
12769
+ ] }) : /* @__PURE__ */ jsxs6(Text8, { dimColor: true, children: [
12770
+ " ",
12771
+ pm.card_details ? `${pm.card_details.brand} ****${pm.card_details.last4}` : pm.type,
12772
+ pm.is_default ? " (default)" : ""
12773
+ ] }) }, pm.id)) }),
12774
+ /* @__PURE__ */ jsx9(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text8, { dimColor: true, children: "Use \u2191\u2193 to select, [Enter] to confirm" }) })
12775
+ ] }),
12776
+ pastStep("fetch-pm") && /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", children: [
12777
+ /* @__PURE__ */ jsx9(MarkdownText, { children: SPT_FLOW.probe.description }),
12778
+ step === "probe" && /* @__PURE__ */ jsx9(Box7, { marginY: 1, children: /* @__PURE__ */ jsx9(Text8, { color: "cyan", children: SPT_FLOW.probe.loading }) })
12779
+ ] }),
12780
+ pastStep("probe") && networkId && /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", children: [
12781
+ /* @__PURE__ */ jsxs6(Text8, { color: "green", children: [
12782
+ "\u2713 Got HTTP 402 with a ",
12783
+ /* @__PURE__ */ jsx9(Text8, { bold: true, children: "WWW-Authenticate" }),
12784
+ " challenge"
12785
+ ] }),
12786
+ challengeData && /* @__PURE__ */ jsx9(StepData, { data: challengeData }),
12787
+ /* @__PURE__ */ jsx9(MarkdownText, { children: SPT_FLOW.probe.detail }),
12788
+ step === "explain-402" && prompt()
12789
+ ] }),
12790
+ pastStep("explain-402") && /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", children: [
12791
+ /* @__PURE__ */ jsx9(MarkdownText, { children: SPT_FLOW.createSpend.description }),
12792
+ spendRequestPayload && /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", marginTop: 1, children: [
12793
+ /* @__PURE__ */ jsx9(Text8, { dimColor: true, children: "spend-request create" }),
12794
+ /* @__PURE__ */ jsx9(
12795
+ Box7,
12796
+ {
12797
+ flexDirection: "column",
12798
+ borderStyle: "single",
12799
+ borderColor: "gray",
12800
+ paddingX: 2,
12801
+ children: /* @__PURE__ */ jsx9(Text8, { children: JSON.stringify(
12802
+ spendRequestPayload,
12803
+ null,
12804
+ 2
12805
+ ) })
12806
+ }
12807
+ )
12808
+ ] }),
12809
+ step === "create-spend" && /* @__PURE__ */ jsx9(Box7, { marginY: 1, children: /* @__PURE__ */ jsx9(Text8, { color: "cyan", children: SPT_FLOW.createSpend.loading }) })
12810
+ ] }),
12811
+ (step === "await-approval" || step === "approval-timeout" || pastStep("await-approval")) && spendRequest && /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", children: [
12812
+ /* @__PURE__ */ jsxs6(Text8, { color: "green", children: [
12813
+ "\u2713 Spend request created (ID: ",
12814
+ /* @__PURE__ */ jsx9(Text8, { bold: true, children: spendRequest.id }),
12815
+ ")"
12816
+ ] }),
12817
+ /* @__PURE__ */ jsx9(
12818
+ StepData,
12819
+ {
12820
+ data: {
12821
+ id: spendRequest.id,
12822
+ status: spendRequest.status,
12823
+ credential_type: spendRequest.credential_type,
12824
+ network_id: spendRequest.network_id,
12825
+ amount: spendRequest.amount,
12826
+ context: spendRequest.context,
12827
+ approval_url: spendRequest.approval_url
12828
+ }
12829
+ }
12830
+ )
12831
+ ] }),
12832
+ step === "await-approval" && /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", children: [
12833
+ /* @__PURE__ */ jsx9(Text8, { children: SPT_FLOW.approval.description }),
12834
+ /* @__PURE__ */ jsxs6(
12835
+ Box7,
12836
+ {
12837
+ flexDirection: "column",
12838
+ borderStyle: "round",
12839
+ borderColor: "cyan",
12840
+ paddingX: 2,
12841
+ paddingY: 1,
12842
+ marginTop: 1,
12843
+ children: [
12844
+ /* @__PURE__ */ jsxs6(Text8, { children: [
12845
+ "Approve at:",
12846
+ " ",
12847
+ /* @__PURE__ */ jsx9(Text8, { bold: true, color: "cyan", children: approvalUrl })
12848
+ ] }),
12849
+ /* @__PURE__ */ jsx9(Text8, { dimColor: true, children: SPT_FLOW.approval.browserHint })
12850
+ ]
12851
+ }
12852
+ ),
12853
+ /* @__PURE__ */ jsx9(Box7, { marginY: 1, children: /* @__PURE__ */ jsx9(Text8, { color: "cyan", children: SPT_FLOW.approval.loading }) })
12854
+ ] }),
12855
+ step === "approval-timeout" && /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", children: [
12856
+ /* @__PURE__ */ jsx9(Text8, { color: "yellow", children: "\u26A0 Approval timed out (5 min). The spend request is still pending \u2014 you can still approve it." }),
12857
+ /* @__PURE__ */ jsxs6(
12858
+ Box7,
12859
+ {
12860
+ flexDirection: "column",
12861
+ borderStyle: "round",
12862
+ borderColor: "yellow",
12863
+ paddingX: 2,
12864
+ paddingY: 1,
12865
+ marginTop: 1,
12866
+ children: [
12867
+ /* @__PURE__ */ jsxs6(Text8, { children: [
12868
+ "Approve at:",
12869
+ " ",
12870
+ /* @__PURE__ */ jsx9(Text8, { bold: true, color: "cyan", children: approvalUrl })
12871
+ ] }),
12872
+ /* @__PURE__ */ jsx9(Text8, { dimColor: true, children: "Press [Enter] to open in browser" })
12873
+ ]
12874
+ }
12875
+ ),
12876
+ /* @__PURE__ */ jsx9(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text8, { dimColor: true, children: "r Retry polling q Quit demo" }) })
12877
+ ] }),
12878
+ pastStep("await-approval") && step !== "error" && /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", children: [
12879
+ (step === "mpp-pay-gate" || pastStep("mpp-pay-gate")) && /* @__PURE__ */ jsxs6(Fragment, { children: [
12880
+ /* @__PURE__ */ jsx9(Text8, { color: "green", children: "\u2713 Approved!" }),
12881
+ /* @__PURE__ */ jsx9(MarkdownText, { children: SPT_FLOW.mppPay.description })
12882
+ ] }),
12883
+ step === "mpp-pay-gate" && prompt(SPT_FLOW.mppPay.prompt),
12884
+ step === "mpp-pay" && /* @__PURE__ */ jsx9(Box7, { marginY: 1, children: /* @__PURE__ */ jsx9(Text8, { color: "cyan", children: SPT_FLOW.mppPay.loading }) })
12885
+ ] }),
12886
+ step === "done" && payResult && /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", children: [
12887
+ /* @__PURE__ */ jsxs6(
12888
+ Box7,
12889
+ {
12890
+ flexDirection: "column",
12891
+ borderStyle: "round",
12892
+ borderColor: "green",
12893
+ paddingX: 2,
12894
+ paddingY: 1,
12895
+ children: [
12896
+ /* @__PURE__ */ jsx9(Text8, { bold: true, color: "green", children: SPT_FLOW.done.success }),
12897
+ /* @__PURE__ */ jsxs6(Text8, { children: [
12898
+ "Status: ",
12899
+ /* @__PURE__ */ jsxs6(Text8, { bold: true, children: [
12900
+ "HTTP ",
12901
+ payResult.status
12902
+ ] })
12903
+ ] }),
12904
+ payResult.body && (() => {
12905
+ const body = payResult.body;
12906
+ try {
12907
+ return /* @__PURE__ */ jsx9(Text8, { children: JSON.stringify(JSON.parse(body), null, 2) });
12908
+ } catch {
12909
+ return /* @__PURE__ */ jsx9(Text8, { children: body });
12910
+ }
12911
+ })()
12912
+ ]
12913
+ }
12914
+ ),
12915
+ /* @__PURE__ */ jsx9(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx9(MarkdownText, { children: SPT_FLOW.done.detail }) })
12916
+ ] }),
12917
+ step === "error" && /* @__PURE__ */ jsxs6(Text8, { color: "red", children: [
12918
+ "Error: ",
12919
+ error
12920
+ ] })
12921
+ ] });
12922
+ };
12923
+
12924
+ // src/commands/demo/demo-runner.tsx
12925
+ import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
12926
+ var DemoRunner = ({
12927
+ authRepo: authRepo2,
12928
+ spendRequestRepo: spendRequestRepo2,
12929
+ paymentMethodsResource,
12930
+ paymentMethodId: preselectedPmId,
12931
+ onlyCard,
12932
+ onlySpt,
12933
+ onComplete
12934
+ }) => {
12935
+ const preselected = onlyCard ? "card" : onlySpt ? "spt" : null;
12936
+ const [choice, setChoice] = useState6(preselected);
12937
+ const [menuIndex, setMenuIndex] = useState6(0);
12938
+ const postAuthPhase = preselected === "spt" ? "spt-flow" : preselected ? "card-flow" : "menu";
12939
+ const [phase, setPhase] = useState6(
12940
+ storage.isAuthenticated() ? postAuthPhase : "auth"
12941
+ );
12942
+ const [paymentMethodId, setPaymentMethodId] = useState6(
12943
+ preselectedPmId ?? ""
12944
+ );
12945
+ const [cardSuccess, setCardSuccess] = useState6(null);
12946
+ const [sptSuccess, setSptSuccess] = useState6(null);
12947
+ const runCard = choice === "card" || choice === "both";
12948
+ const runSpt = choice === "spt" || choice === "both";
12949
+ useInput4((_input, key) => {
12950
+ if (phase === "menu") {
12951
+ if (key.upArrow) {
12952
+ setMenuIndex((i) => i > 0 ? i - 1 : DEMO_MENU.options.length - 1);
12953
+ } else if (key.downArrow) {
12954
+ setMenuIndex((i) => i < DEMO_MENU.options.length - 1 ? i + 1 : 0);
12955
+ } else if (key.return) {
12956
+ const selected = DEMO_MENU.options[menuIndex].key;
12957
+ setChoice(selected);
12958
+ setPhase(selected === "spt" ? "spt-flow" : "card-flow");
12959
+ }
12960
+ } else if (phase === "card-done" && key.return) {
12961
+ setPhase("spt-flow");
12962
+ }
12963
+ });
12964
+ const onCardComplete = useCallback(
12965
+ (result) => {
12966
+ setPaymentMethodId(result.paymentMethodId);
12967
+ setCardSuccess(result.success);
12968
+ if (!runSpt) {
12969
+ setPhase("summary");
12970
+ setTimeout(onComplete, 1500);
12971
+ } else {
12972
+ setPhase("card-done");
12973
+ }
12974
+ },
12975
+ [runSpt, onComplete]
12976
+ );
12977
+ const onSptComplete = useCallback(
12978
+ (success) => {
12979
+ setSptSuccess(success);
12980
+ setPhase("summary");
12981
+ setTimeout(onComplete, 1500);
12982
+ },
12983
+ [onComplete]
12984
+ );
12985
+ return /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", gap: 1, children: [
12986
+ /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
12987
+ /* @__PURE__ */ jsx10(Text9, { bold: true, children: DEMO_MENU.title }),
12988
+ /* @__PURE__ */ jsx10(Text9, { children: DEMO_MENU.subtitle })
12989
+ ] }),
12990
+ phase === "auth" && /* @__PURE__ */ jsx10(
12991
+ Login,
12992
+ {
12993
+ authResource: authRepo2,
12994
+ clientName: ONBOARD.auth.clientName,
12995
+ onComplete: () => setPhase(postAuthPhase)
12996
+ }
12997
+ ),
12998
+ phase === "menu" && /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
12999
+ /* @__PURE__ */ jsx10(Text9, { children: DEMO_MENU.question }),
13000
+ /* @__PURE__ */ jsx10(Box8, { flexDirection: "column", marginTop: 1, gap: 1, children: DEMO_MENU.options.map((opt, i) => /* @__PURE__ */ jsx10(Box8, { flexDirection: "column", children: i === menuIndex ? /* @__PURE__ */ jsxs7(Fragment2, { children: [
13001
+ /* @__PURE__ */ jsxs7(Text9, { color: "cyan", bold: true, children: [
13002
+ ">",
13003
+ " ",
13004
+ opt.label
13005
+ ] }),
13006
+ /* @__PURE__ */ jsxs7(Text9, { color: "cyan", children: [
13007
+ " ",
13008
+ opt.description
13009
+ ] })
13010
+ ] }) : /* @__PURE__ */ jsxs7(Text9, { dimColor: true, children: [
13011
+ " ",
13012
+ opt.label
13013
+ ] }) }, opt.key)) }),
13014
+ /* @__PURE__ */ jsx10(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text9, { dimColor: true, children: DEMO_MENU.hint }) })
13015
+ ] }),
13016
+ runCard && phase !== "menu" && /* @__PURE__ */ jsx10(
13017
+ CardFlow,
13018
+ {
13019
+ spendRequestRepo: spendRequestRepo2,
13020
+ paymentMethodsResource,
13021
+ paymentMethodId: preselectedPmId,
13022
+ onComplete: onCardComplete
13023
+ }
13024
+ ),
13025
+ phase === "card-done" && /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
13026
+ /* @__PURE__ */ jsx10(Text9, { dimColor: true, children: "\u2500\u2500\u2500" }),
13027
+ /* @__PURE__ */ jsx10(MarkdownText, { children: DEMO_MENU.transition }),
13028
+ /* @__PURE__ */ jsxs7(Text9, { dimColor: true, children: [
13029
+ "\n",
13030
+ ">",
13031
+ " ",
13032
+ DEMO_MENU.transitionPrompt
13033
+ ] })
13034
+ ] }),
13035
+ runSpt && (phase === "spt-flow" || phase === "summary") && /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
13036
+ runCard && /* @__PURE__ */ jsx10(Text9, { dimColor: true, children: "\u2500\u2500\u2500" }),
13037
+ /* @__PURE__ */ jsx10(
13038
+ SptFlow,
13039
+ {
13040
+ spendRequestRepo: spendRequestRepo2,
13041
+ paymentMethodsResource,
13042
+ paymentMethodId: paymentMethodId || void 0,
13043
+ onComplete: onSptComplete
13044
+ }
13045
+ )
13046
+ ] }),
13047
+ phase === "summary" && /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
13048
+ /* @__PURE__ */ jsx10(Text9, { dimColor: true, children: "\u2500\u2500\u2500" }),
13049
+ /* @__PURE__ */ jsx10(Text9, { bold: true, children: "Done!" }),
13050
+ cardSuccess !== null && /* @__PURE__ */ jsxs7(Text9, { color: cardSuccess ? "green" : "red", children: [
13051
+ cardSuccess ? "\u2713" : "\u2717",
13052
+ " Virtual card flow"
13053
+ ] }),
13054
+ sptSuccess !== null && /* @__PURE__ */ jsxs7(Text9, { color: sptSuccess ? "green" : "red", children: [
13055
+ sptSuccess ? "\u2713" : "\u2717",
13056
+ " Machine payment flow"
13057
+ ] }),
13058
+ /* @__PURE__ */ jsx10(AppDownloadQrCodes, {})
13059
+ ] })
13060
+ ] });
13061
+ };
13062
+
13063
+ // src/commands/demo/index.tsx
13064
+ import { jsx as jsx11 } from "react/jsx-runtime";
13065
+ var demoOptions = z2.object({
13066
+ onlyCard: z2.boolean().default(false).describe("Run only the virtual card flow"),
13067
+ onlySpt: z2.boolean().default(false).describe("Run only the machine payment (SPT) flow")
13068
+ });
13069
+ function createDemoCli(authRepo2, spendRequestRepo2, createPaymentMethodsResource) {
13070
+ return Cli2.create("demo", {
13071
+ description: "Run an interactive demo of both Link payment flows (virtual card + machine payment)",
13072
+ options: demoOptions,
13073
+ outputPolicy: "agent-only",
13074
+ async run(c) {
13075
+ if (c.agent || c.formatExplicit) {
13076
+ return c.error({
13077
+ code: "REQUIRES_TTY",
13078
+ message: "The demo command requires an interactive terminal."
13079
+ });
13080
+ }
13081
+ const paymentMethodsResource = createPaymentMethodsResource();
13082
+ return new Promise((resolve) => {
13083
+ const { waitUntilExit, unmount } = render2(
13084
+ /* @__PURE__ */ jsx11(
13085
+ DemoRunner,
13086
+ {
13087
+ authRepo: authRepo2,
13088
+ spendRequestRepo: spendRequestRepo2,
13089
+ paymentMethodsResource,
13090
+ onlyCard: c.options.onlyCard,
13091
+ onlySpt: c.options.onlySpt,
13092
+ onComplete: () => unmount()
13093
+ }
13094
+ )
13095
+ );
13096
+ waitUntilExit().then(() => resolve({}));
13097
+ });
13098
+ }
13099
+ });
13100
+ }
13101
+
13102
+ // src/commands/mpp/index.tsx
13103
+ import { Cli as Cli3, z as z4 } from "incur";
13104
+ import { render as render3 } from "ink";
13105
+
13106
+ // src/commands/mpp/decode-view.tsx
13107
+ import { Box as Box9, Text as Text10 } from "ink";
13108
+ import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
13109
+ function DecodeChallengeView({
13110
+ decoded
13111
+ }) {
13112
+ return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "column", children: [
13113
+ /* @__PURE__ */ jsx12(Text10, { color: "green", children: "\u2713 Stripe challenge decoded" }),
13114
+ /* @__PURE__ */ jsxs8(Box9, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
13115
+ /* @__PURE__ */ jsxs8(Text10, { children: [
13116
+ "ID: ",
13117
+ /* @__PURE__ */ jsx12(Text10, { bold: true, children: decoded.id })
13118
+ ] }),
13119
+ /* @__PURE__ */ jsxs8(Text10, { children: [
13120
+ "Realm: ",
13121
+ /* @__PURE__ */ jsx12(Text10, { bold: true, children: decoded.realm })
13122
+ ] }),
13123
+ /* @__PURE__ */ jsxs8(Text10, { children: [
13124
+ "Network ID: ",
13125
+ /* @__PURE__ */ jsx12(Text10, { bold: true, children: decoded.network_id })
13126
+ ] }),
13127
+ /* @__PURE__ */ jsx12(Text10, { children: "Request JSON:" }),
13128
+ /* @__PURE__ */ jsx12(Text10, { children: JSON.stringify(decoded.request_json, null, 2) })
11894
13129
  ] })
11895
13130
  ] });
11896
13131
  }
11897
13132
 
11898
13133
  // src/commands/mpp/schema.ts
11899
- import { z as z2 } from "incur";
11900
- var payOptions = z2.object({
11901
- spendRequestId: z2.string().describe(
13134
+ import { z as z3 } from "incur";
13135
+ var payOptions = z3.object({
13136
+ spendRequestId: z3.string().describe(
11902
13137
  'Approved spend request ID with credential_type "shared_payment_token"'
11903
13138
  ),
11904
- method: z2.string().optional().describe("HTTP method (default: GET, or POST if --data is provided)"),
11905
- data: z2.string().optional().describe("Request body (implies POST if --method is not set)"),
11906
- header: z2.array(z2.string()).default([]).describe('Request header in "Name: Value" format (repeatable)')
13139
+ method: z3.string().optional().describe("HTTP method (default: GET, or POST if --data is provided)"),
13140
+ data: z3.string().optional().describe("Request body (implies POST if --method is not set)"),
13141
+ header: z3.array(z3.string()).default([]).describe('Request header in "Name: Value" format (repeatable)')
11907
13142
  });
11908
- var decodeOptions = z2.object({
11909
- challenge: z2.string().describe(
13143
+ var decodeOptions = z3.object({
13144
+ challenge: z3.string().describe(
11910
13145
  "Raw WWW-Authenticate header value; may include multiple payment challenges"
11911
13146
  )
11912
13147
  });
11913
13148
 
11914
13149
  // src/commands/mpp/index.tsx
11915
- import { jsx as jsx6 } from "react/jsx-runtime";
13150
+ import { jsx as jsx13 } from "react/jsx-runtime";
11916
13151
  function createMppCli(repository) {
11917
- const cli2 = Cli2.create("mpp", {
13152
+ const cli2 = Cli3.create("mpp", {
11918
13153
  description: "Machine payment protocol (MPP) commands"
11919
13154
  });
11920
13155
  cli2.command("pay", {
11921
13156
  description: "Complete a machine payment protocol (MPP) payment using an approved spend request",
11922
- args: z3.object({
11923
- url: z3.string().describe("URL to pay")
13157
+ args: z4.object({
13158
+ url: z4.string().describe("URL to pay")
11924
13159
  }),
11925
13160
  options: payOptions,
11926
13161
  alias: { method: "X", data: "d", header: "H" },
@@ -11944,8 +13179,8 @@ function createMppCli(repository) {
11944
13179
  const headers = opts.header?.length ? opts.header : void 0;
11945
13180
  if (!c.agent && !c.formatExplicit) {
11946
13181
  return new Promise((resolve) => {
11947
- const { waitUntilExit } = render2(
11948
- /* @__PURE__ */ jsx6(
13182
+ const { waitUntilExit } = render3(
13183
+ /* @__PURE__ */ jsx13(
11949
13184
  MppPay,
11950
13185
  {
11951
13186
  url,
@@ -11991,8 +13226,8 @@ function createMppCli(repository) {
11991
13226
  const decoded = decodeStripeChallenge(c.options.challenge);
11992
13227
  if (!c.agent && !c.formatExplicit) {
11993
13228
  return new Promise((resolve) => {
11994
- const { waitUntilExit } = render2(
11995
- /* @__PURE__ */ jsx6(DecodeChallengeView, { decoded })
13229
+ const { waitUntilExit } = render3(
13230
+ /* @__PURE__ */ jsx13(DecodeChallengeView, { decoded })
11996
13231
  );
11997
13232
  waitUntilExit().then(() => resolve(decoded));
11998
13233
  });
@@ -12003,26 +13238,183 @@ function createMppCli(repository) {
12003
13238
  return cli2;
12004
13239
  }
12005
13240
 
13241
+ // src/commands/onboard/index.tsx
13242
+ import { Cli as Cli4 } from "incur";
13243
+ import { render as render4 } from "ink";
13244
+
13245
+ // src/commands/onboard/onboard-runner.tsx
13246
+ import { Box as Box10, Text as Text11, useInput as useInput5 } from "ink";
13247
+ import { useEffect as useEffect6, useRef as useRef3, useState as useState7 } from "react";
13248
+ import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
13249
+ var OnboardRunner = ({
13250
+ authRepo: authRepo2,
13251
+ spendRequestRepo: spendRequestRepo2,
13252
+ paymentMethodsResource,
13253
+ onComplete
13254
+ }) => {
13255
+ const [phase, setPhase] = useState7("welcome");
13256
+ const [authSkipped, setAuthSkipped] = useState7(false);
13257
+ const [pmMissing, setPmMissing] = useState7(false);
13258
+ const [error, setError] = useState7("");
13259
+ const enterResolver = useRef3(null);
13260
+ function waitForEnter() {
13261
+ return new Promise((resolve) => {
13262
+ enterResolver.current = resolve;
13263
+ });
13264
+ }
13265
+ const authResolver = useRef3(null);
13266
+ function waitForAuth() {
13267
+ return new Promise((resolve) => {
13268
+ authResolver.current = resolve;
13269
+ });
13270
+ }
13271
+ useInput5((_input, key) => {
13272
+ if (key.return && enterResolver.current) {
13273
+ const resolve = enterResolver.current;
13274
+ enterResolver.current = null;
13275
+ resolve();
13276
+ }
13277
+ });
13278
+ const started = useRef3(false);
13279
+ useEffect6(() => {
13280
+ if (started.current) return;
13281
+ started.current = true;
13282
+ const run = async () => {
13283
+ try {
13284
+ setPhase("auth");
13285
+ if (storage.isAuthenticated()) {
13286
+ setAuthSkipped(true);
13287
+ } else {
13288
+ setAuthSkipped(false);
13289
+ await waitForAuth();
13290
+ }
13291
+ setPhase("payment-methods");
13292
+ while (true) {
13293
+ const methods = await paymentMethodsResource.listPaymentMethods();
13294
+ if (methods.length > 0) break;
13295
+ setPmMissing(true);
13296
+ await waitForEnter();
13297
+ setPmMissing(false);
13298
+ }
13299
+ setPhase("demo");
13300
+ } catch (err) {
13301
+ setError(err.message);
13302
+ }
13303
+ };
13304
+ run();
13305
+ }, []);
13306
+ const pastPhase = (target) => {
13307
+ const order = ["welcome", "auth", "payment-methods", "demo"];
13308
+ return order.indexOf(phase) > order.indexOf(target);
13309
+ };
13310
+ const prompt = (label = "Press [Enter] to continue") => /* @__PURE__ */ jsxs9(Text11, { dimColor: true, children: [
13311
+ "\n",
13312
+ ">",
13313
+ " ",
13314
+ label
13315
+ ] });
13316
+ return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", gap: 1, children: [
13317
+ /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", children: [
13318
+ /* @__PURE__ */ jsx14(Text11, { bold: true, children: ONBOARD.title }),
13319
+ /* @__PURE__ */ jsx14(Text11, { children: ONBOARD.subtitle })
13320
+ ] }),
13321
+ /* @__PURE__ */ jsx14(Box10, { flexDirection: "column", children: authSkipped || pastPhase("auth") ? /* @__PURE__ */ jsxs9(Text11, { color: "green", children: [
13322
+ "\u2713 ",
13323
+ authSkipped ? ONBOARD.auth.alreadyLoggedIn : ONBOARD.auth.authenticated
13324
+ ] }) : phase === "auth" && !storage.isAuthenticated() ? /* @__PURE__ */ jsx14(
13325
+ Login,
13326
+ {
13327
+ authResource: authRepo2,
13328
+ clientName: ONBOARD.auth.clientName,
13329
+ onComplete: () => authResolver.current?.()
13330
+ }
13331
+ ) : null }),
13332
+ pastPhase("auth") && /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", children: [
13333
+ phase === "payment-methods" && !pmMissing && /* @__PURE__ */ jsx14(Text11, { color: "cyan", children: ONBOARD.paymentMethods.loading }),
13334
+ pmMissing && /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", children: [
13335
+ /* @__PURE__ */ jsx14(Text11, { color: "yellow", children: ONBOARD.paymentMethods.missing }),
13336
+ /* @__PURE__ */ jsx14(Box10, { marginTop: 1, children: /* @__PURE__ */ jsxs9(Text11, { children: [
13337
+ "Visit",
13338
+ " ",
13339
+ /* @__PURE__ */ jsx14(Text11, { bold: true, color: "cyan", children: "app.link.com/wallet" }),
13340
+ " ",
13341
+ "to add a payment method, then press [Enter] to continue."
13342
+ ] }) }),
13343
+ prompt(ONBOARD.paymentMethods.retryPrompt)
13344
+ ] }),
13345
+ pastPhase("payment-methods") && /* @__PURE__ */ jsx14(Text11, { color: "green", children: "\u2713 Payment method found" })
13346
+ ] }),
13347
+ phase === "demo" && /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", children: [
13348
+ /* @__PURE__ */ jsx14(Text11, { dimColor: true, children: "\u2500\u2500\u2500" }),
13349
+ /* @__PURE__ */ jsx14(
13350
+ DemoRunner,
13351
+ {
13352
+ authRepo: authRepo2,
13353
+ spendRequestRepo: spendRequestRepo2,
13354
+ paymentMethodsResource,
13355
+ onComplete
13356
+ }
13357
+ )
13358
+ ] }),
13359
+ error && /* @__PURE__ */ jsxs9(Text11, { color: "red", children: [
13360
+ "Error: ",
13361
+ error
13362
+ ] })
13363
+ ] });
13364
+ };
13365
+
13366
+ // src/commands/onboard/index.tsx
13367
+ import { jsx as jsx15 } from "react/jsx-runtime";
13368
+ function createOnboardCli(authRepo2, spendRequestRepo2, createPaymentMethodsResource) {
13369
+ return Cli4.create("onboard", {
13370
+ description: "Guided setup: authenticate, verify payment methods, and demo both payment flows",
13371
+ outputPolicy: "agent-only",
13372
+ async run(c) {
13373
+ if (c.agent || c.formatExplicit) {
13374
+ return c.error({
13375
+ code: "REQUIRES_TTY",
13376
+ message: "The onboard command requires an interactive terminal."
13377
+ });
13378
+ }
13379
+ const paymentMethodsResource = createPaymentMethodsResource();
13380
+ return new Promise((resolve) => {
13381
+ const { waitUntilExit, unmount } = render4(
13382
+ /* @__PURE__ */ jsx15(
13383
+ OnboardRunner,
13384
+ {
13385
+ authRepo: authRepo2,
13386
+ spendRequestRepo: spendRequestRepo2,
13387
+ paymentMethodsResource,
13388
+ onComplete: () => unmount()
13389
+ }
13390
+ )
13391
+ );
13392
+ waitUntilExit().then(() => resolve({}));
13393
+ });
13394
+ }
13395
+ });
13396
+ }
13397
+
12006
13398
  // src/commands/payment-methods/index.tsx
12007
- import { Cli as Cli3 } from "incur";
12008
- import { render as render3 } from "ink";
13399
+ import { Cli as Cli5 } from "incur";
13400
+ import { render as render5 } from "ink";
12009
13401
 
12010
13402
  // src/commands/payment-methods/add.tsx
12011
- import { Box as Box5, Text as Text5, useApp, useInput as useInput2 } from "ink";
12012
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
13403
+ import { Box as Box11, Text as Text12, useApp, useInput as useInput6 } from "ink";
13404
+ import { jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
12013
13405
  var WALLET_URL = "https://app.link.com/wallet";
12014
13406
  var AddPaymentMethod = () => {
12015
13407
  const { exit } = useApp();
12016
- useInput2((_input, key) => {
13408
+ useInput6((_input, key) => {
12017
13409
  if (key.return) {
12018
13410
  openUrl(WALLET_URL);
12019
13411
  exit();
12020
13412
  }
12021
13413
  });
12022
- return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", paddingY: 1, children: [
12023
- /* @__PURE__ */ jsx7(Box5, { marginBottom: 1, children: /* @__PURE__ */ jsx7(Text5, { bold: true, children: "Add Payment Method" }) }),
12024
- /* @__PURE__ */ jsxs4(
12025
- Box5,
13414
+ return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", paddingY: 1, children: [
13415
+ /* @__PURE__ */ jsx16(Box11, { marginBottom: 1, children: /* @__PURE__ */ jsx16(Text12, { bold: true, children: "Add Payment Method" }) }),
13416
+ /* @__PURE__ */ jsxs10(
13417
+ Box11,
12026
13418
  {
12027
13419
  flexDirection: "column",
12028
13420
  borderStyle: "round",
@@ -12030,12 +13422,12 @@ var AddPaymentMethod = () => {
12030
13422
  paddingX: 2,
12031
13423
  paddingY: 1,
12032
13424
  children: [
12033
- /* @__PURE__ */ jsxs4(Text5, { children: [
13425
+ /* @__PURE__ */ jsxs10(Text12, { children: [
12034
13426
  "Open:",
12035
13427
  " ",
12036
- /* @__PURE__ */ jsx7(Text5, { bold: true, color: "cyan", children: WALLET_URL })
13428
+ /* @__PURE__ */ jsx16(Text12, { bold: true, color: "cyan", children: WALLET_URL })
12037
13429
  ] }),
12038
- /* @__PURE__ */ jsx7(Text5, { dimColor: true, children: "Press Enter to open in browser" })
13430
+ /* @__PURE__ */ jsx16(Text12, { dimColor: true, children: "Press Enter to open in browser" })
12039
13431
  ]
12040
13432
  }
12041
13433
  )
@@ -12043,20 +13435,20 @@ var AddPaymentMethod = () => {
12043
13435
  };
12044
13436
 
12045
13437
  // src/commands/payment-methods/list.tsx
12046
- import { Box as Box6, Text as Text6 } from "ink";
13438
+ import { Box as Box12, Text as Text13 } from "ink";
12047
13439
  import Spinner3 from "ink-spinner";
12048
- import { useEffect as useEffect4, useState as useState4 } from "react";
12049
- import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
13440
+ import { useEffect as useEffect7, useState as useState8 } from "react";
13441
+ import { jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
12050
13442
  var PaymentMethodsList = ({
12051
13443
  resource,
12052
13444
  onComplete
12053
13445
  }) => {
12054
- const [status, setStatus] = useState4(
13446
+ const [status, setStatus] = useState8(
12055
13447
  "loading"
12056
13448
  );
12057
- const [methods, setMethods] = useState4([]);
12058
- const [error, setError] = useState4("");
12059
- useEffect4(() => {
13449
+ const [methods, setMethods] = useState8([]);
13450
+ const [error, setError] = useState8("");
13451
+ useEffect7(() => {
12060
13452
  const fetch2 = async () => {
12061
13453
  try {
12062
13454
  const result = await resource.listPaymentMethods();
@@ -12072,43 +13464,43 @@ var PaymentMethodsList = ({
12072
13464
  fetch2();
12073
13465
  }, [resource, onComplete]);
12074
13466
  if (status === "loading") {
12075
- return /* @__PURE__ */ jsx8(Box6, { children: /* @__PURE__ */ jsxs5(Text6, { color: "cyan", children: [
12076
- /* @__PURE__ */ jsx8(Spinner3, { type: "dots" }),
13467
+ return /* @__PURE__ */ jsx17(Box12, { children: /* @__PURE__ */ jsxs11(Text13, { color: "cyan", children: [
13468
+ /* @__PURE__ */ jsx17(Spinner3, { type: "dots" }),
12077
13469
  " Loading payment methods..."
12078
13470
  ] }) });
12079
13471
  }
12080
13472
  if (status === "error") {
12081
- return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
12082
- /* @__PURE__ */ jsx8(Text6, { color: "red", children: "\u2717 Failed to load payment methods" }),
12083
- /* @__PURE__ */ jsx8(Text6, { color: "red", children: error })
13473
+ return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", children: [
13474
+ /* @__PURE__ */ jsx17(Text13, { color: "red", children: "\u2717 Failed to load payment methods" }),
13475
+ /* @__PURE__ */ jsx17(Text13, { color: "red", children: error })
12084
13476
  ] });
12085
13477
  }
12086
13478
  if (methods.length === 0) {
12087
- return /* @__PURE__ */ jsx8(Box6, { children: /* @__PURE__ */ jsx8(Text6, { dimColor: true, children: "No payment methods found" }) });
13479
+ return /* @__PURE__ */ jsx17(Box12, { children: /* @__PURE__ */ jsx17(Text13, { dimColor: true, children: "No payment methods found" }) });
12088
13480
  }
12089
- return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
12090
- /* @__PURE__ */ jsx8(Text6, { bold: true, children: "Payment Methods" }),
12091
- /* @__PURE__ */ jsx8(Box6, { flexDirection: "column", marginTop: 1, children: methods.map((pm) => {
13481
+ return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", children: [
13482
+ /* @__PURE__ */ jsx17(Text13, { bold: true, children: "Payment Methods" }),
13483
+ /* @__PURE__ */ jsx17(Box12, { flexDirection: "column", marginTop: 1, children: methods.map((pm) => {
12092
13484
  const label = pm.card_details?.brand ?? pm.bank_account_details?.bank_name ?? "Bank account";
12093
13485
  const last4 = pm.card_details?.last4 ?? pm.bank_account_details?.last4;
12094
13486
  const suffix = [pm.nickname ? `(${pm.nickname})` : ""].filter(Boolean).join(" ");
12095
- return /* @__PURE__ */ jsx8(Box6, { paddingX: 2, children: /* @__PURE__ */ jsxs5(Text6, { children: [
12096
- /* @__PURE__ */ jsx8(Text6, { dimColor: true, children: pm.id }),
13487
+ return /* @__PURE__ */ jsx17(Box12, { paddingX: 2, children: /* @__PURE__ */ jsxs11(Text13, { children: [
13488
+ /* @__PURE__ */ jsx17(Text13, { dimColor: true, children: pm.id }),
12097
13489
  " ",
12098
13490
  label,
12099
13491
  " ****",
12100
13492
  last4,
12101
13493
  suffix ? ` ${suffix}` : "",
12102
- pm.is_default ? /* @__PURE__ */ jsx8(Text6, { color: "green", children: " (default)" }) : ""
13494
+ pm.is_default ? /* @__PURE__ */ jsx17(Text13, { color: "green", children: " (default)" }) : ""
12103
13495
  ] }) }, pm.id);
12104
13496
  }) })
12105
13497
  ] });
12106
13498
  };
12107
13499
 
12108
13500
  // src/commands/payment-methods/index.tsx
12109
- import { jsx as jsx9 } from "react/jsx-runtime";
13501
+ import { jsx as jsx18 } from "react/jsx-runtime";
12110
13502
  function createPaymentMethodsCli(createResource) {
12111
- const cli2 = Cli3.create("payment-methods", {
13503
+ const cli2 = Cli5.create("payment-methods", {
12112
13504
  description: "Payment methods management commands"
12113
13505
  });
12114
13506
  cli2.command("list", {
@@ -12129,8 +13521,8 @@ function createPaymentMethodsCli(createResource) {
12129
13521
  const resource = createResource();
12130
13522
  if (!c.agent && !c.formatExplicit) {
12131
13523
  return new Promise((resolve) => {
12132
- const { waitUntilExit } = render3(
12133
- /* @__PURE__ */ jsx9(PaymentMethodsList, { resource, onComplete: () => {
13524
+ const { waitUntilExit } = render5(
13525
+ /* @__PURE__ */ jsx18(PaymentMethodsList, { resource, onComplete: () => {
12134
13526
  } })
12135
13527
  );
12136
13528
  waitUntilExit().then(async () => {
@@ -12158,7 +13550,7 @@ function createPaymentMethodsCli(createResource) {
12158
13550
  }
12159
13551
  if (!c.agent && !c.formatExplicit) {
12160
13552
  return new Promise((resolve) => {
12161
- const { waitUntilExit } = render3(/* @__PURE__ */ jsx9(AddPaymentMethod, {}));
13553
+ const { waitUntilExit } = render5(/* @__PURE__ */ jsx18(AddPaymentMethod, {}));
12162
13554
  waitUntilExit().then(() => resolve({ url: WALLET_URL }));
12163
13555
  });
12164
13556
  }
@@ -12169,25 +13561,25 @@ function createPaymentMethodsCli(createResource) {
12169
13561
  }
12170
13562
 
12171
13563
  // src/commands/spend-request/index.tsx
12172
- import { Cli as Cli4, z as z6 } from "incur";
12173
- import { render as render4 } from "ink";
13564
+ import { Cli as Cli6, z as z7 } from "incur";
13565
+ import { render as render6 } from "ink";
12174
13566
 
12175
13567
  // src/utils/line-item-parser.ts
12176
- import { z as z4 } from "zod";
12177
- var LineItemSchema = z4.object({
12178
- name: z4.string(),
12179
- url: z4.string().optional(),
12180
- image_url: z4.string().optional(),
12181
- description: z4.string().optional(),
12182
- sku: z4.string().optional(),
12183
- quantity: z4.coerce.number().optional(),
12184
- unit_amount: z4.coerce.number().optional(),
12185
- product_url: z4.string().optional()
13568
+ import { z as z5 } from "zod";
13569
+ var LineItemSchema = z5.object({
13570
+ name: z5.string(),
13571
+ url: z5.string().optional(),
13572
+ image_url: z5.string().optional(),
13573
+ description: z5.string().optional(),
13574
+ sku: z5.string().optional(),
13575
+ quantity: z5.coerce.number().optional(),
13576
+ unit_amount: z5.coerce.number().optional(),
13577
+ product_url: z5.string().optional()
12186
13578
  }).strict();
12187
- var TotalSchema = z4.object({
12188
- type: z4.string(),
12189
- display_text: z4.string(),
12190
- amount: z4.coerce.number()
13579
+ var TotalSchema = z5.object({
13580
+ type: z5.string(),
13581
+ display_text: z5.string(),
13582
+ amount: z5.coerce.number()
12191
13583
  }).strict();
12192
13584
  function parseKvString(raw) {
12193
13585
  const result = {};
@@ -12212,7 +13604,7 @@ function parseLineItemFlag(raw) {
12212
13604
  try {
12213
13605
  return LineItemSchema.parse(obj);
12214
13606
  } catch (err) {
12215
- if (err instanceof z4.ZodError) throw formatZodError(err, "Line item");
13607
+ if (err instanceof z5.ZodError) throw formatZodError(err, "Line item");
12216
13608
  throw err;
12217
13609
  }
12218
13610
  }
@@ -12221,80 +13613,26 @@ function parseTotalFlag(raw) {
12221
13613
  try {
12222
13614
  return TotalSchema.parse(obj);
12223
13615
  } catch (err) {
12224
- if (err instanceof z4.ZodError) throw formatZodError(err, "Total");
13616
+ if (err instanceof z5.ZodError) throw formatZodError(err, "Total");
12225
13617
  throw err;
12226
13618
  }
12227
13619
  }
12228
13620
 
12229
13621
  // src/commands/spend-request/create.tsx
12230
- import { Box as Box9, Text as Text9 } from "ink";
13622
+ import { Box as Box14, Text as Text15 } from "ink";
12231
13623
  import Spinner5 from "ink-spinner";
12232
- import { useCallback, useEffect as useEffect6, useState as useState5 } from "react";
12233
-
12234
- // src/commands/spend-request/app-download-qr-codes.tsx
12235
- import { Box as Box7, Text as Text7 } from "ink";
12236
- import { useMemo } from "react";
12237
-
12238
- // src/utils/render-qr-matrix.ts
12239
- import QRCode from "qrcode";
12240
- function renderQrMatrix(url) {
12241
- const qr = QRCode.create(url, { errorCorrectionLevel: "L" });
12242
- const size = qr.modules.size;
12243
- const data = qr.modules.data;
12244
- const quiet = 1;
12245
- const total = size + quiet * 2;
12246
- const matrix = Array.from(
12247
- { length: total },
12248
- (_, r) => Array.from({ length: total }, (_2, c) => {
12249
- if (r < quiet || r >= size + quiet || c < quiet || c >= size + quiet) {
12250
- return false;
12251
- }
12252
- return data[(r - quiet) * size + (c - quiet)] === 1;
12253
- })
12254
- );
12255
- const lines = [];
12256
- for (let r = 0; r < total; r += 2) {
12257
- let line = "";
12258
- for (let c = 0; c < total; c++) {
12259
- const top = matrix[r][c];
12260
- const bottom = r + 1 < total ? matrix[r + 1][c] : false;
12261
- if (top && bottom) line += "\u2588";
12262
- else if (top) line += "\u2580";
12263
- else if (bottom) line += "\u2584";
12264
- else line += " ";
12265
- }
12266
- lines.push(line);
12267
- }
12268
- return lines;
12269
- }
12270
-
12271
- // src/commands/spend-request/app-download-qr-codes.tsx
12272
- import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
12273
- var DOWNLOAD_URL = "https://link.com/download";
12274
- var AppDownloadQrCodes = () => {
12275
- const qrLines = useMemo(() => renderQrMatrix(DOWNLOAD_URL), []);
12276
- return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", marginTop: 1, children: [
12277
- /* @__PURE__ */ jsx10(Text7, { dimColor: true, children: "New! Get the Link app to approve spend requests easily" }),
12278
- /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", alignItems: "flex-start", marginTop: 1, children: [
12279
- qrLines.map((line, i) => (
12280
- // biome-ignore lint/suspicious/noArrayIndexKey: stable static array
12281
- /* @__PURE__ */ jsx10(Text7, { children: line }, i)
12282
- )),
12283
- /* @__PURE__ */ jsx10(Text7, { dimColor: true, children: DOWNLOAD_URL })
12284
- ] })
12285
- ] });
12286
- };
13624
+ import { useCallback as useCallback2, useEffect as useEffect9, useState as useState9 } from "react";
12287
13625
 
12288
13626
  // src/commands/spend-request/approval-waiting-view.tsx
12289
- import { Box as Box8, Text as Text8 } from "ink";
13627
+ import { Box as Box13, Text as Text14 } from "ink";
12290
13628
  import Spinner4 from "ink-spinner";
12291
- import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
13629
+ import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
12292
13630
  var ApprovalWaitingView = ({
12293
13631
  status,
12294
13632
  approvalUrl
12295
- }) => /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", paddingY: 1, children: [
12296
- /* @__PURE__ */ jsxs7(
12297
- Box8,
13633
+ }) => /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", paddingY: 1, children: [
13634
+ /* @__PURE__ */ jsxs12(
13635
+ Box13,
12298
13636
  {
12299
13637
  flexDirection: "column",
12300
13638
  borderStyle: "round",
@@ -12302,51 +13640,25 @@ var ApprovalWaitingView = ({
12302
13640
  paddingX: 2,
12303
13641
  paddingY: 1,
12304
13642
  children: [
12305
- /* @__PURE__ */ jsxs7(Text8, { children: [
13643
+ /* @__PURE__ */ jsxs12(Text14, { children: [
12306
13644
  "Approve at:",
12307
13645
  " ",
12308
- /* @__PURE__ */ jsx11(Text8, { bold: true, color: "cyan", children: approvalUrl })
13646
+ /* @__PURE__ */ jsx19(Text14, { bold: true, color: "cyan", children: approvalUrl })
12309
13647
  ] }),
12310
- /* @__PURE__ */ jsx11(Text8, { dimColor: true, children: "Press Enter to open in browser" })
13648
+ /* @__PURE__ */ jsx19(Text14, { dimColor: true, children: "Press Enter to open in browser" })
12311
13649
  ]
12312
13650
  }
12313
13651
  ),
12314
- /* @__PURE__ */ jsx11(AppDownloadQrCodes, {}),
12315
- /* @__PURE__ */ jsx11(Box8, { marginTop: 1, children: status === "polling" ? /* @__PURE__ */ jsxs7(Text8, { color: "cyan", children: [
12316
- /* @__PURE__ */ jsx11(Spinner4, { type: "dots" }),
13652
+ /* @__PURE__ */ jsx19(AppDownloadQrCodes, {}),
13653
+ /* @__PURE__ */ jsx19(Box13, { marginTop: 1, children: status === "polling" ? /* @__PURE__ */ jsxs12(Text14, { color: "cyan", children: [
13654
+ /* @__PURE__ */ jsx19(Spinner4, { type: "dots" }),
12317
13655
  " Waiting for approval..."
12318
- ] }) : /* @__PURE__ */ jsx11(Text8, { dimColor: true, children: "Waiting..." }) })
13656
+ ] }) : /* @__PURE__ */ jsx19(Text14, { dimColor: true, children: "Waiting..." }) })
12319
13657
  ] });
12320
13658
 
12321
13659
  // src/commands/spend-request/use-approval-polling.ts
12322
- import { useInput as useInput3 } from "ink";
12323
- import { useEffect as useEffect5 } from "react";
12324
-
12325
- // src/utils/poll-until-approved.ts
12326
- function pollUntilApproved(repository, id, options = {}) {
12327
- const pollIntervalMs = options.pollIntervalMs ?? 2e3;
12328
- const timeoutMs = options.timeoutMs ?? 3e5;
12329
- const startTime = Date.now();
12330
- const poll = async () => {
12331
- const elapsed = Date.now() - startTime;
12332
- if (elapsed > timeoutMs) {
12333
- throw new Error("Approval polling timed out");
12334
- }
12335
- const request = await repository.getSpendRequest(id);
12336
- if (!request) {
12337
- throw new Error(`Spend request ${id} not found`);
12338
- }
12339
- if (request.status !== "created" && request.status !== "pending_approval") {
12340
- return request;
12341
- }
12342
- options.onProgress?.(Math.floor(elapsed / 1e3));
12343
- await new Promise((r) => setTimeout(r, pollIntervalMs));
12344
- return poll();
12345
- };
12346
- return poll();
12347
- }
12348
-
12349
- // src/commands/spend-request/use-approval-polling.ts
13660
+ import { useInput as useInput7 } from "ink";
13661
+ import { useEffect as useEffect8 } from "react";
12350
13662
  function useApprovalPolling({
12351
13663
  status,
12352
13664
  setStatus,
@@ -12358,18 +13670,18 @@ function useApprovalPolling({
12358
13670
  onError
12359
13671
  }) {
12360
13672
  const isWaiting = status === "waiting" || status === "polling";
12361
- useInput3(
13673
+ useInput7(
12362
13674
  (_input, key) => {
12363
13675
  if (key.return && approvalUrl) openUrl(approvalUrl);
12364
13676
  },
12365
13677
  { isActive: isWaiting }
12366
13678
  );
12367
- useEffect5(() => {
13679
+ useEffect8(() => {
12368
13680
  if (status !== "waiting") return;
12369
13681
  const timeout = setTimeout(() => setStatus("polling"), 1e3);
12370
13682
  return () => clearTimeout(timeout);
12371
13683
  }, [status, setStatus]);
12372
- useEffect5(() => {
13684
+ useEffect8(() => {
12373
13685
  if (status !== "polling" || !requestId) return;
12374
13686
  let cancelled = false;
12375
13687
  const poll = async () => {
@@ -12403,22 +13715,22 @@ function useApprovalPolling({
12403
13715
  }
12404
13716
 
12405
13717
  // src/commands/spend-request/create.tsx
12406
- import { Fragment, jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
13718
+ import { Fragment as Fragment3, jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
12407
13719
  var CreateSpendRequest = ({
12408
13720
  repository,
12409
13721
  params,
12410
13722
  requestApproval = false,
12411
13723
  onComplete
12412
13724
  }) => {
12413
- const [status, setStatus] = useState5("creating");
12414
- const [request, setRequest] = useState5(null);
12415
- const [error, setError] = useState5("");
13725
+ const [status, setStatus] = useState9("creating");
13726
+ const [request, setRequest] = useState9(null);
13727
+ const [error, setError] = useState9("");
12416
13728
  const approvalUrl = request?.approval_url ?? "";
12417
- const onSuccess = useCallback(
13729
+ const onSuccess = useCallback2(
12418
13730
  (result) => setRequest(result),
12419
13731
  []
12420
13732
  );
12421
- const onError = useCallback((msg) => setError(msg), []);
13733
+ const onError = useCallback2((msg) => setError(msg), []);
12422
13734
  useApprovalPolling({
12423
13735
  status,
12424
13736
  setStatus,
@@ -12429,7 +13741,7 @@ var CreateSpendRequest = ({
12429
13741
  onSuccess,
12430
13742
  onError
12431
13743
  });
12432
- useEffect6(() => {
13744
+ useEffect9(() => {
12433
13745
  const create = async () => {
12434
13746
  try {
12435
13747
  const result = await repository.createSpendRequest(params);
@@ -12449,57 +13761,57 @@ var CreateSpendRequest = ({
12449
13761
  create();
12450
13762
  }, [repository, params, requestApproval, onComplete]);
12451
13763
  if (status === "creating") {
12452
- return /* @__PURE__ */ jsx12(Box9, { children: /* @__PURE__ */ jsxs8(Text9, { color: "cyan", children: [
12453
- /* @__PURE__ */ jsx12(Spinner5, { type: "dots" }),
13764
+ return /* @__PURE__ */ jsx20(Box14, { children: /* @__PURE__ */ jsxs13(Text15, { color: "cyan", children: [
13765
+ /* @__PURE__ */ jsx20(Spinner5, { type: "dots" }),
12454
13766
  " Creating spend request..."
12455
13767
  ] }) });
12456
13768
  }
12457
13769
  if (status === "error") {
12458
- return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "column", children: [
12459
- /* @__PURE__ */ jsx12(Text9, { color: "red", children: "\u2717 Failed to create spend request" }),
12460
- /* @__PURE__ */ jsx12(Text9, { color: "red", children: error })
13770
+ return /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", children: [
13771
+ /* @__PURE__ */ jsx20(Text15, { color: "red", children: "\u2717 Failed to create spend request" }),
13772
+ /* @__PURE__ */ jsx20(Text15, { color: "red", children: error })
12461
13773
  ] });
12462
13774
  }
12463
13775
  if (status === "success") {
12464
- return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "column", children: [
12465
- /* @__PURE__ */ jsx12(Text9, { color: "green", children: "\u2713 Spend request created" }),
12466
- /* @__PURE__ */ jsxs8(Box9, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
12467
- /* @__PURE__ */ jsxs8(Text9, { children: [
13776
+ return /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", children: [
13777
+ /* @__PURE__ */ jsx20(Text15, { color: "green", children: "\u2713 Spend request created" }),
13778
+ /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
13779
+ /* @__PURE__ */ jsxs13(Text15, { children: [
12468
13780
  "ID: ",
12469
- /* @__PURE__ */ jsx12(Text9, { bold: true, children: request?.id })
13781
+ /* @__PURE__ */ jsx20(Text15, { bold: true, children: request?.id })
12470
13782
  ] }),
12471
- /* @__PURE__ */ jsxs8(Text9, { children: [
13783
+ /* @__PURE__ */ jsxs13(Text15, { children: [
12472
13784
  "Status: ",
12473
- /* @__PURE__ */ jsx12(Text9, { bold: true, children: request?.status })
13785
+ /* @__PURE__ */ jsx20(Text15, { bold: true, children: request?.status })
12474
13786
  ] }),
12475
- /* @__PURE__ */ jsxs8(Text9, { children: [
13787
+ /* @__PURE__ */ jsxs13(Text15, { children: [
12476
13788
  "Amount:",
12477
13789
  " ",
12478
- /* @__PURE__ */ jsx12(Text9, { bold: true, children: (() => {
13790
+ /* @__PURE__ */ jsx20(Text15, { bold: true, children: (() => {
12479
13791
  const t = request?.totals.find((t2) => t2.type === "total");
12480
13792
  return t ? String(t.amount) : "N/A";
12481
13793
  })() })
12482
13794
  ] }),
12483
- /* @__PURE__ */ jsxs8(Text9, { children: [
13795
+ /* @__PURE__ */ jsxs13(Text15, { children: [
12484
13796
  "Merchant: ",
12485
- /* @__PURE__ */ jsx12(Text9, { bold: true, children: request?.merchant_name })
13797
+ /* @__PURE__ */ jsx20(Text15, { bold: true, children: request?.merchant_name })
12486
13798
  ] }),
12487
- /* @__PURE__ */ jsxs8(Text9, { children: [
13799
+ /* @__PURE__ */ jsxs13(Text15, { children: [
12488
13800
  "Line Items:",
12489
13801
  " ",
12490
- /* @__PURE__ */ jsx12(Text9, { bold: true, children: request?.line_items.map((li) => li.name).join(", ") || "N/A" })
13802
+ /* @__PURE__ */ jsx20(Text15, { bold: true, children: request?.line_items.map((li) => li.name).join(", ") || "N/A" })
12491
13803
  ] })
12492
13804
  ] }),
12493
- /* @__PURE__ */ jsx12(AppDownloadQrCodes, {})
13805
+ /* @__PURE__ */ jsx20(AppDownloadQrCodes, {})
12494
13806
  ] });
12495
13807
  }
12496
- return /* @__PURE__ */ jsxs8(Fragment, { children: [
12497
- /* @__PURE__ */ jsx12(Box9, { children: /* @__PURE__ */ jsxs8(Text9, { color: "green", children: [
13808
+ return /* @__PURE__ */ jsxs13(Fragment3, { children: [
13809
+ /* @__PURE__ */ jsx20(Box14, { children: /* @__PURE__ */ jsxs13(Text15, { color: "green", children: [
12498
13810
  "\u2713 Spend request created (ID: ",
12499
- /* @__PURE__ */ jsx12(Text9, { bold: true, children: request?.id }),
13811
+ /* @__PURE__ */ jsx20(Text15, { bold: true, children: request?.id }),
12500
13812
  ")"
12501
13813
  ] }) }),
12502
- /* @__PURE__ */ jsx12(
13814
+ /* @__PURE__ */ jsx20(
12503
13815
  ApprovalWaitingView,
12504
13816
  {
12505
13817
  status,
@@ -12510,21 +13822,21 @@ var CreateSpendRequest = ({
12510
13822
  };
12511
13823
 
12512
13824
  // src/commands/spend-request/request-approval.tsx
12513
- import { Box as Box10, Text as Text10 } from "ink";
13825
+ import { Box as Box15, Text as Text16 } from "ink";
12514
13826
  import Spinner6 from "ink-spinner";
12515
- import { useCallback as useCallback2, useEffect as useEffect7, useState as useState6 } from "react";
12516
- import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
13827
+ import { useCallback as useCallback3, useEffect as useEffect10, useState as useState10 } from "react";
13828
+ import { jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
12517
13829
  var RequestApproval = ({
12518
13830
  repository,
12519
13831
  id,
12520
13832
  onComplete
12521
13833
  }) => {
12522
- const [status, setStatus] = useState6("requesting");
12523
- const [approvalUrl, setApprovalUrl] = useState6("");
12524
- const [result, setResult] = useState6(null);
12525
- const [error, setError] = useState6("");
12526
- const onSuccess = useCallback2((r) => setResult(r), []);
12527
- const onError = useCallback2((msg) => setError(msg), []);
13834
+ const [status, setStatus] = useState10("requesting");
13835
+ const [approvalUrl, setApprovalUrl] = useState10("");
13836
+ const [result, setResult] = useState10(null);
13837
+ const [error, setError] = useState10("");
13838
+ const onSuccess = useCallback3((r) => setResult(r), []);
13839
+ const onError = useCallback3((msg) => setError(msg), []);
12528
13840
  useApprovalPolling({
12529
13841
  status,
12530
13842
  setStatus,
@@ -12535,7 +13847,7 @@ var RequestApproval = ({
12535
13847
  onSuccess,
12536
13848
  onError
12537
13849
  });
12538
- useEffect7(() => {
13850
+ useEffect10(() => {
12539
13851
  const request = async () => {
12540
13852
  try {
12541
13853
  const res = await repository.requestApproval(id);
@@ -12549,45 +13861,45 @@ var RequestApproval = ({
12549
13861
  request();
12550
13862
  }, [repository, id]);
12551
13863
  if (status === "requesting") {
12552
- return /* @__PURE__ */ jsx13(Box10, { children: /* @__PURE__ */ jsxs9(Text10, { color: "cyan", children: [
12553
- /* @__PURE__ */ jsx13(Spinner6, { type: "dots" }),
13864
+ return /* @__PURE__ */ jsx21(Box15, { children: /* @__PURE__ */ jsxs14(Text16, { color: "cyan", children: [
13865
+ /* @__PURE__ */ jsx21(Spinner6, { type: "dots" }),
12554
13866
  " Requesting approval..."
12555
13867
  ] }) });
12556
13868
  }
12557
13869
  if (status === "error") {
12558
- return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", children: [
12559
- /* @__PURE__ */ jsx13(Text10, { color: "red", children: "\u2717 Failed to request approval" }),
12560
- /* @__PURE__ */ jsx13(Text10, { color: "red", children: error })
13870
+ return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", children: [
13871
+ /* @__PURE__ */ jsx21(Text16, { color: "red", children: "\u2717 Failed to request approval" }),
13872
+ /* @__PURE__ */ jsx21(Text16, { color: "red", children: error })
12561
13873
  ] });
12562
13874
  }
12563
13875
  if (status === "success") {
12564
- return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", children: [
12565
- /* @__PURE__ */ jsx13(Text10, { color: "green", children: "\u2713 Approval completed" }),
12566
- /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
12567
- /* @__PURE__ */ jsxs9(Text10, { children: [
13876
+ return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", children: [
13877
+ /* @__PURE__ */ jsx21(Text16, { color: "green", children: "\u2713 Approval completed" }),
13878
+ /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
13879
+ /* @__PURE__ */ jsxs14(Text16, { children: [
12568
13880
  "ID: ",
12569
- /* @__PURE__ */ jsx13(Text10, { bold: true, children: result?.id })
13881
+ /* @__PURE__ */ jsx21(Text16, { bold: true, children: result?.id })
12570
13882
  ] }),
12571
- /* @__PURE__ */ jsxs9(Text10, { children: [
13883
+ /* @__PURE__ */ jsxs14(Text16, { children: [
12572
13884
  "Status: ",
12573
- /* @__PURE__ */ jsx13(Text10, { bold: true, children: result?.status })
13885
+ /* @__PURE__ */ jsx21(Text16, { bold: true, children: result?.status })
12574
13886
  ] }),
12575
- /* @__PURE__ */ jsxs9(Text10, { children: [
13887
+ /* @__PURE__ */ jsxs14(Text16, { children: [
12576
13888
  "Amount:",
12577
13889
  " ",
12578
- /* @__PURE__ */ jsx13(Text10, { bold: true, children: (() => {
13890
+ /* @__PURE__ */ jsx21(Text16, { bold: true, children: (() => {
12579
13891
  const t = result?.totals.find((t2) => t2.type === "total");
12580
13892
  return t ? String(t.amount) : "N/A";
12581
13893
  })() })
12582
13894
  ] }),
12583
- /* @__PURE__ */ jsxs9(Text10, { children: [
13895
+ /* @__PURE__ */ jsxs14(Text16, { children: [
12584
13896
  "Merchant: ",
12585
- /* @__PURE__ */ jsx13(Text10, { bold: true, children: result?.merchant_name })
13897
+ /* @__PURE__ */ jsx21(Text16, { bold: true, children: result?.merchant_name })
12586
13898
  ] })
12587
13899
  ] })
12588
13900
  ] });
12589
13901
  }
12590
- return /* @__PURE__ */ jsx13(
13902
+ return /* @__PURE__ */ jsx21(
12591
13903
  ApprovalWaitingView,
12592
13904
  {
12593
13905
  status,
@@ -12597,10 +13909,10 @@ var RequestApproval = ({
12597
13909
  };
12598
13910
 
12599
13911
  // src/commands/spend-request/retrieve.tsx
12600
- import { Box as Box11, Text as Text11 } from "ink";
13912
+ import { Box as Box16, Text as Text17 } from "ink";
12601
13913
  import Spinner7 from "ink-spinner";
12602
- import { useEffect as useEffect8, useRef, useState as useState7 } from "react";
12603
- import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
13914
+ import { useEffect as useEffect11, useRef as useRef4, useState as useState11 } from "react";
13915
+ import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
12604
13916
  var RetrieveSpendRequest = ({
12605
13917
  repository,
12606
13918
  id,
@@ -12608,20 +13920,20 @@ var RetrieveSpendRequest = ({
12608
13920
  include,
12609
13921
  onComplete
12610
13922
  }) => {
12611
- const [phase, setPhase] = useState7("fetching");
12612
- const [request, setRequest] = useState7(null);
12613
- const [error, setError] = useState7("");
12614
- const [elapsed, setElapsed] = useState7(0);
12615
- const startTimeRef = useRef(Date.now());
12616
- const pollRef = useRef(null);
12617
- const timerRef = useRef(null);
12618
- useEffect8(() => {
13923
+ const [phase, setPhase] = useState11("fetching");
13924
+ const [request, setRequest] = useState11(null);
13925
+ const [error, setError] = useState11("");
13926
+ const [elapsed, setElapsed] = useState11(0);
13927
+ const startTimeRef = useRef4(Date.now());
13928
+ const pollRef = useRef4(null);
13929
+ const timerRef = useRef4(null);
13930
+ useEffect11(() => {
12619
13931
  return () => {
12620
13932
  if (pollRef.current) clearInterval(pollRef.current);
12621
13933
  if (timerRef.current) clearInterval(timerRef.current);
12622
13934
  };
12623
13935
  }, []);
12624
- useEffect8(() => {
13936
+ useEffect11(() => {
12625
13937
  const fetch2 = async () => {
12626
13938
  try {
12627
13939
  const result = await repository.getSpendRequest(id, { include });
@@ -12650,7 +13962,7 @@ var RetrieveSpendRequest = ({
12650
13962
  };
12651
13963
  fetch2();
12652
13964
  }, [repository, id, include, onComplete]);
12653
- useEffect8(() => {
13965
+ useEffect11(() => {
12654
13966
  if (phase !== "polling") return;
12655
13967
  timerRef.current = setInterval(() => {
12656
13968
  const secs = Math.floor((Date.now() - startTimeRef.current) / 1e3);
@@ -12689,169 +14001,169 @@ var RetrieveSpendRequest = ({
12689
14001
  };
12690
14002
  }, [phase, repository, id, include, timeout, onComplete]);
12691
14003
  if (phase === "fetching") {
12692
- return /* @__PURE__ */ jsx14(Box11, { children: /* @__PURE__ */ jsxs10(Text11, { color: "cyan", children: [
12693
- /* @__PURE__ */ jsx14(Spinner7, { type: "dots" }),
14004
+ return /* @__PURE__ */ jsx22(Box16, { children: /* @__PURE__ */ jsxs15(Text17, { color: "cyan", children: [
14005
+ /* @__PURE__ */ jsx22(Spinner7, { type: "dots" }),
12694
14006
  " Retrieving spend request ",
12695
14007
  id,
12696
14008
  "..."
12697
14009
  ] }) });
12698
14010
  }
12699
14011
  if (phase === "error") {
12700
- return /* @__PURE__ */ jsx14(Box11, { flexDirection: "column", children: /* @__PURE__ */ jsxs10(Text11, { color: "red", children: [
14012
+ return /* @__PURE__ */ jsx22(Box16, { flexDirection: "column", children: /* @__PURE__ */ jsxs15(Text17, { color: "red", children: [
12701
14013
  "\u2717 ",
12702
14014
  error
12703
14015
  ] }) });
12704
14016
  }
12705
14017
  if (phase === "timeout") {
12706
- return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", children: [
12707
- /* @__PURE__ */ jsxs10(Text11, { color: "yellow", children: [
14018
+ return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", children: [
14019
+ /* @__PURE__ */ jsxs15(Text17, { color: "yellow", children: [
12708
14020
  "\u2717 Timed out waiting for approval after ",
12709
14021
  timeout,
12710
14022
  "s"
12711
14023
  ] }),
12712
- request && /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
12713
- /* @__PURE__ */ jsxs10(Text11, { children: [
14024
+ request && /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
14025
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12714
14026
  "ID: ",
12715
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request.id })
14027
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request.id })
12716
14028
  ] }),
12717
- /* @__PURE__ */ jsxs10(Text11, { children: [
14029
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12718
14030
  "Status: ",
12719
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request.status })
14031
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request.status })
12720
14032
  ] })
12721
14033
  ] })
12722
14034
  ] });
12723
14035
  }
12724
14036
  if (phase === "polling") {
12725
- return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", children: [
12726
- /* @__PURE__ */ jsx14(Box11, { children: /* @__PURE__ */ jsxs10(Text11, { color: "cyan", children: [
12727
- /* @__PURE__ */ jsx14(Spinner7, { type: "dots" }),
14037
+ return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", children: [
14038
+ /* @__PURE__ */ jsx22(Box16, { children: /* @__PURE__ */ jsxs15(Text17, { color: "cyan", children: [
14039
+ /* @__PURE__ */ jsx22(Spinner7, { type: "dots" }),
12728
14040
  " Awaiting approval... (",
12729
14041
  elapsed,
12730
14042
  "s elapsed)"
12731
14043
  ] }) }),
12732
- request?.approval_url && /* @__PURE__ */ jsx14(Box11, { marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsxs10(Text11, { dimColor: true, children: [
14044
+ request?.approval_url && /* @__PURE__ */ jsx22(Box16, { marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsxs15(Text17, { dimColor: true, children: [
12733
14045
  "Approval URL: ",
12734
- /* @__PURE__ */ jsx14(Text11, { color: "cyan", children: request.approval_url })
14046
+ /* @__PURE__ */ jsx22(Text17, { color: "cyan", children: request.approval_url })
12735
14047
  ] }) })
12736
14048
  ] });
12737
14049
  }
12738
14050
  if (phase === "declined") {
12739
- return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", children: [
12740
- /* @__PURE__ */ jsx14(Text11, { color: "red", children: "\u2717 Spend request declined" }),
12741
- /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
12742
- /* @__PURE__ */ jsxs10(Text11, { children: [
14051
+ return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", children: [
14052
+ /* @__PURE__ */ jsx22(Text17, { color: "red", children: "\u2717 Spend request declined" }),
14053
+ /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
14054
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12743
14055
  "ID: ",
12744
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request?.id })
14056
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request?.id })
12745
14057
  ] }),
12746
- /* @__PURE__ */ jsxs10(Text11, { children: [
14058
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12747
14059
  "Status:",
12748
14060
  " ",
12749
- /* @__PURE__ */ jsx14(Text11, { bold: true, color: "red", children: request?.status })
14061
+ /* @__PURE__ */ jsx22(Text17, { bold: true, color: "red", children: request?.status })
12750
14062
  ] }),
12751
- /* @__PURE__ */ jsxs10(Text11, { children: [
14063
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12752
14064
  "Amount:",
12753
14065
  " ",
12754
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: (() => {
14066
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: (() => {
12755
14067
  const t = request?.totals.find((t2) => t2.type === "total");
12756
14068
  return t ? String(t.amount) : "N/A";
12757
14069
  })() })
12758
14070
  ] }),
12759
- /* @__PURE__ */ jsxs10(Text11, { children: [
14071
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12760
14072
  "Merchant: ",
12761
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request?.merchant_name })
14073
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request?.merchant_name })
12762
14074
  ] })
12763
14075
  ] })
12764
14076
  ] });
12765
14077
  }
12766
- return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", children: [
12767
- /* @__PURE__ */ jsx14(Text11, { color: "green", children: "\u2713 Spend request approved" }),
12768
- /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
12769
- /* @__PURE__ */ jsxs10(Text11, { children: [
14078
+ return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", children: [
14079
+ /* @__PURE__ */ jsx22(Text17, { color: "green", children: "\u2713 Spend request approved" }),
14080
+ /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
14081
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12770
14082
  "ID: ",
12771
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request?.id })
14083
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request?.id })
12772
14084
  ] }),
12773
- /* @__PURE__ */ jsxs10(Text11, { children: [
14085
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12774
14086
  "Status:",
12775
14087
  " ",
12776
- /* @__PURE__ */ jsx14(Text11, { bold: true, color: "green", children: request?.status })
14088
+ /* @__PURE__ */ jsx22(Text17, { bold: true, color: "green", children: request?.status })
12777
14089
  ] }),
12778
- /* @__PURE__ */ jsxs10(Text11, { children: [
14090
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12779
14091
  "Amount:",
12780
14092
  " ",
12781
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: (() => {
14093
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: (() => {
12782
14094
  const t = request?.totals.find((t2) => t2.type === "total");
12783
14095
  return t ? String(t.amount) : "N/A";
12784
14096
  })() })
12785
14097
  ] }),
12786
- /* @__PURE__ */ jsxs10(Text11, { children: [
14098
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12787
14099
  "Merchant: ",
12788
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request?.merchant_name })
14100
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request?.merchant_name })
12789
14101
  ] }),
12790
- /* @__PURE__ */ jsxs10(Text11, { children: [
14102
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12791
14103
  "Line Items:",
12792
14104
  " ",
12793
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request?.line_items.map((li) => li.name).join(", ") })
14105
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request?.line_items.map((li) => li.name).join(", ") })
12794
14106
  ] }),
12795
- request?.shared_payment_token && /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", marginTop: 1, children: [
12796
- /* @__PURE__ */ jsxs10(Text11, { bold: true, children: [
14107
+ request?.shared_payment_token && /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", marginTop: 1, children: [
14108
+ /* @__PURE__ */ jsxs15(Text17, { bold: true, children: [
12797
14109
  "\x1B]8;;https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens\x07",
12798
14110
  "Shared Payment Token",
12799
14111
  "\x1B]8;;\x07",
12800
14112
  ":"
12801
14113
  ] }),
12802
- /* @__PURE__ */ jsxs10(Text11, { children: [
14114
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12803
14115
  " ",
12804
14116
  "Token: ",
12805
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request.shared_payment_token.id })
14117
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request.shared_payment_token.id })
12806
14118
  ] })
12807
14119
  ] }),
12808
- request?.card && /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", marginTop: 1, children: [
12809
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: "Card Details:" }),
12810
- /* @__PURE__ */ jsxs10(Text11, { children: [
14120
+ request?.card && /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", marginTop: 1, children: [
14121
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: "Card Details:" }),
14122
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12811
14123
  " ",
12812
14124
  "Number: ",
12813
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request?.card.number })
14125
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request?.card.number })
12814
14126
  ] }),
12815
- /* @__PURE__ */ jsxs10(Text11, { children: [
14127
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12816
14128
  " ",
12817
14129
  "Brand: ",
12818
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request?.card.brand })
14130
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request?.card.brand })
12819
14131
  ] }),
12820
- /* @__PURE__ */ jsxs10(Text11, { children: [
14132
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12821
14133
  " ",
12822
14134
  "Expiry:",
12823
14135
  " ",
12824
- /* @__PURE__ */ jsxs10(Text11, { bold: true, children: [
14136
+ /* @__PURE__ */ jsxs15(Text17, { bold: true, children: [
12825
14137
  String(request?.card.exp_month).padStart(2, "0"),
12826
14138
  "/",
12827
14139
  request?.card.exp_year
12828
14140
  ] })
12829
14141
  ] }),
12830
- request?.card.cvc && /* @__PURE__ */ jsxs10(Text11, { children: [
14142
+ request?.card.cvc && /* @__PURE__ */ jsxs15(Text17, { children: [
12831
14143
  " ",
12832
14144
  "CVC: ",
12833
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request.card.cvc })
14145
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request.card.cvc })
12834
14146
  ] }),
12835
- request?.card.valid_until && /* @__PURE__ */ jsxs10(Text11, { children: [
14147
+ request?.card.valid_until && /* @__PURE__ */ jsxs15(Text17, { children: [
12836
14148
  " ",
12837
14149
  "Valid Until: ",
12838
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request.card.valid_until })
14150
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request.card.valid_until })
12839
14151
  ] }),
12840
- request?.card.billing_address && /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", marginTop: 1, children: [
12841
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: " Billing Address:" }),
12842
- /* @__PURE__ */ jsxs10(Text11, { children: [
14152
+ request?.card.billing_address && /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", marginTop: 1, children: [
14153
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: " Billing Address:" }),
14154
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12843
14155
  " ",
12844
14156
  request.card.billing_address.name
12845
14157
  ] }),
12846
- /* @__PURE__ */ jsxs10(Text11, { children: [
14158
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12847
14159
  " ",
12848
14160
  request.card.billing_address.line1
12849
14161
  ] }),
12850
- request.card.billing_address.line2 && /* @__PURE__ */ jsxs10(Text11, { children: [
14162
+ request.card.billing_address.line2 && /* @__PURE__ */ jsxs15(Text17, { children: [
12851
14163
  " ",
12852
14164
  request.card.billing_address.line2
12853
14165
  ] }),
12854
- /* @__PURE__ */ jsxs10(Text11, { children: [
14166
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12855
14167
  " ",
12856
14168
  [
12857
14169
  request.card.billing_address.city,
@@ -12859,7 +14171,7 @@ var RetrieveSpendRequest = ({
12859
14171
  request.card.billing_address.postal_code
12860
14172
  ].filter(Boolean).join(", ")
12861
14173
  ] }),
12862
- /* @__PURE__ */ jsxs10(Text11, { children: [
14174
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12863
14175
  " ",
12864
14176
  request.card.billing_address.country
12865
14177
  ] })
@@ -12870,69 +14182,69 @@ var RetrieveSpendRequest = ({
12870
14182
  };
12871
14183
 
12872
14184
  // src/commands/spend-request/schema.ts
12873
- import { z as z5 } from "incur";
12874
- var createOptions = z5.object({
12875
- paymentMethodId: z5.string().describe("Payment method ID"),
12876
- credentialType: z5.enum(["shared_payment_token", "card"]).default("card").describe(
14185
+ import { z as z6 } from "incur";
14186
+ var createOptions = z6.object({
14187
+ paymentMethodId: z6.string().describe("Payment method ID"),
14188
+ credentialType: z6.enum(["shared_payment_token", "card"]).default("card").describe(
12877
14189
  '"card" for checkout forms/Stripe Elements; "shared_payment_token" for HTTP 402/machine payment flows'
12878
14190
  ),
12879
- networkId: z5.string().optional().describe(
14191
+ networkId: z6.string().optional().describe(
12880
14192
  "Network ID (required for shared_payment_token) \u2014 use `link-cli mpp decode` to extract"
12881
14193
  ),
12882
- amount: z5.coerce.number().int().positive().max(5e4).describe("Amount in cents, max 50000 ($500.00)"),
12883
- currency: z5.string().length(3).default("usd").describe("Currency code"),
12884
- merchantName: z5.string().optional().describe(
14194
+ amount: z6.coerce.number().int().positive().max(5e4).describe("Amount in cents, max 50000 ($500.00)"),
14195
+ currency: z6.string().length(3).default("usd").describe("Currency code"),
14196
+ merchantName: z6.string().optional().describe(
12885
14197
  "Merchant name (required for card; forbidden for shared_payment_token)"
12886
14198
  ),
12887
- merchantUrl: z5.string().optional().describe(
14199
+ merchantUrl: z6.string().optional().describe(
12888
14200
  "Merchant URL (required for card; forbidden for shared_payment_token)"
12889
14201
  ),
12890
- context: z5.string().min(100).describe(
14202
+ context: z6.string().min(100).describe(
12891
14203
  "Min 100 chars \u2014 describe the purchase and rationale; the user reads this when approving"
12892
14204
  ),
12893
- lineItem: z5.array(z5.union([z5.string(), z5.record(z5.string(), z5.unknown())])).default([]).describe("Line item (repeatable, key:value format)"),
12894
- total: z5.array(z5.union([z5.string(), z5.record(z5.string(), z5.unknown())])).default([]).describe("Total (repeatable, key:value format)"),
12895
- requestApproval: z5.boolean().default(true).describe("Request approval and poll until approved/denied/expired"),
12896
- test: z5.boolean().default(false).describe(
14205
+ lineItem: z6.array(z6.union([z6.string(), z6.record(z6.string(), z6.unknown())])).default([]).describe("Line item (repeatable, key:value format)"),
14206
+ total: z6.array(z6.union([z6.string(), z6.record(z6.string(), z6.unknown())])).default([]).describe("Total (repeatable, key:value format)"),
14207
+ requestApproval: z6.boolean().default(true).describe("Request approval and poll until approved/denied/expired"),
14208
+ test: z6.boolean().default(false).describe(
12897
14209
  "Use test mode (creates testmode credentials from test card data)"
12898
14210
  )
12899
14211
  });
12900
- var retrieveOptions = z5.object({
12901
- timeout: z5.coerce.number().default(300).describe("Polling timeout in seconds"),
12902
- interval: z5.coerce.number().default(0).describe(
14212
+ var retrieveOptions = z6.object({
14213
+ timeout: z6.coerce.number().default(300).describe("Polling timeout in seconds"),
14214
+ interval: z6.coerce.number().default(0).describe(
12903
14215
  "Poll interval in seconds. When > 0, polls until status is terminal or timeout is reached, yielding status on each attempt."
12904
14216
  ),
12905
- maxAttempts: z5.coerce.number().default(0).describe("Max poll attempts. 0 = unlimited (use timeout instead)."),
12906
- include: z5.array(z5.string()).default([]).describe("Include extra data (repeatable, e.g. --include card)")
14217
+ maxAttempts: z6.coerce.number().default(0).describe("Max poll attempts. 0 = unlimited (use timeout instead)."),
14218
+ include: z6.array(z6.string()).default([]).describe("Include extra data (repeatable, e.g. --include card)")
12907
14219
  });
12908
- var updateOptions = z5.object({
12909
- paymentMethodId: z5.string().optional().describe("Payment method ID"),
12910
- amount: z5.coerce.number().optional().describe("Amount in cents"),
12911
- merchantUrl: z5.string().optional().describe("Merchant URL"),
12912
- profileId: z5.string().optional().describe("Profile ID"),
12913
- merchantId: z5.string().optional().describe("Merchant ID"),
12914
- currency: z5.string().optional().describe("Currency code"),
12915
- lineItem: z5.array(z5.union([z5.string(), z5.record(z5.string(), z5.unknown())])).default([]).describe("Line item (repeatable, key:value format)"),
12916
- total: z5.array(z5.union([z5.string(), z5.record(z5.string(), z5.unknown())])).default([]).describe("Total (repeatable, key:value format)")
14220
+ var updateOptions = z6.object({
14221
+ paymentMethodId: z6.string().optional().describe("Payment method ID"),
14222
+ amount: z6.coerce.number().optional().describe("Amount in cents"),
14223
+ merchantUrl: z6.string().optional().describe("Merchant URL"),
14224
+ profileId: z6.string().optional().describe("Profile ID"),
14225
+ merchantId: z6.string().optional().describe("Merchant ID"),
14226
+ currency: z6.string().optional().describe("Currency code"),
14227
+ lineItem: z6.array(z6.union([z6.string(), z6.record(z6.string(), z6.unknown())])).default([]).describe("Line item (repeatable, key:value format)"),
14228
+ total: z6.array(z6.union([z6.string(), z6.record(z6.string(), z6.unknown())])).default([]).describe("Total (repeatable, key:value format)")
12917
14229
  });
12918
14230
 
12919
14231
  // src/commands/spend-request/update.tsx
12920
- import { Box as Box12, Text as Text12 } from "ink";
14232
+ import { Box as Box17, Text as Text18 } from "ink";
12921
14233
  import Spinner8 from "ink-spinner";
12922
- import { useEffect as useEffect9, useState as useState8 } from "react";
12923
- import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
14234
+ import { useEffect as useEffect12, useState as useState12 } from "react";
14235
+ import { jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
12924
14236
  var UpdateSpendRequest = ({
12925
14237
  repository,
12926
14238
  id,
12927
14239
  params,
12928
14240
  onComplete
12929
14241
  }) => {
12930
- const [status, setStatus] = useState8(
14242
+ const [status, setStatus] = useState12(
12931
14243
  "loading"
12932
14244
  );
12933
- const [request, setRequest] = useState8(null);
12934
- const [error, setError] = useState8("");
12935
- useEffect9(() => {
14245
+ const [request, setRequest] = useState12(null);
14246
+ const [error, setError] = useState12("");
14247
+ useEffect12(() => {
12936
14248
  const update = async () => {
12937
14249
  try {
12938
14250
  const result = await repository.updateSpendRequest(id, params);
@@ -12948,55 +14260,55 @@ var UpdateSpendRequest = ({
12948
14260
  update();
12949
14261
  }, [repository, id, params, onComplete]);
12950
14262
  if (status === "loading") {
12951
- return /* @__PURE__ */ jsx15(Box12, { children: /* @__PURE__ */ jsxs11(Text12, { color: "cyan", children: [
12952
- /* @__PURE__ */ jsx15(Spinner8, { type: "dots" }),
14263
+ return /* @__PURE__ */ jsx23(Box17, { children: /* @__PURE__ */ jsxs16(Text18, { color: "cyan", children: [
14264
+ /* @__PURE__ */ jsx23(Spinner8, { type: "dots" }),
12953
14265
  " Updating spend request ",
12954
14266
  id,
12955
14267
  "..."
12956
14268
  ] }) });
12957
14269
  }
12958
14270
  if (status === "error") {
12959
- return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", children: [
12960
- /* @__PURE__ */ jsx15(Text12, { color: "red", children: "\u2717 Failed to update spend request" }),
12961
- /* @__PURE__ */ jsx15(Text12, { color: "red", children: error })
14271
+ return /* @__PURE__ */ jsxs16(Box17, { flexDirection: "column", children: [
14272
+ /* @__PURE__ */ jsx23(Text18, { color: "red", children: "\u2717 Failed to update spend request" }),
14273
+ /* @__PURE__ */ jsx23(Text18, { color: "red", children: error })
12962
14274
  ] });
12963
14275
  }
12964
- return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", children: [
12965
- /* @__PURE__ */ jsx15(Text12, { color: "green", children: "\u2713 Spend request updated" }),
12966
- /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
12967
- /* @__PURE__ */ jsxs11(Text12, { children: [
14276
+ return /* @__PURE__ */ jsxs16(Box17, { flexDirection: "column", children: [
14277
+ /* @__PURE__ */ jsx23(Text18, { color: "green", children: "\u2713 Spend request updated" }),
14278
+ /* @__PURE__ */ jsxs16(Box17, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
14279
+ /* @__PURE__ */ jsxs16(Text18, { children: [
12968
14280
  "ID: ",
12969
- /* @__PURE__ */ jsx15(Text12, { bold: true, children: request?.id })
14281
+ /* @__PURE__ */ jsx23(Text18, { bold: true, children: request?.id })
12970
14282
  ] }),
12971
- /* @__PURE__ */ jsxs11(Text12, { children: [
14283
+ /* @__PURE__ */ jsxs16(Text18, { children: [
12972
14284
  "Status: ",
12973
- /* @__PURE__ */ jsx15(Text12, { bold: true, children: request?.status })
14285
+ /* @__PURE__ */ jsx23(Text18, { bold: true, children: request?.status })
12974
14286
  ] }),
12975
- /* @__PURE__ */ jsxs11(Text12, { children: [
14287
+ /* @__PURE__ */ jsxs16(Text18, { children: [
12976
14288
  "Amount:",
12977
14289
  " ",
12978
- /* @__PURE__ */ jsx15(Text12, { bold: true, children: (() => {
14290
+ /* @__PURE__ */ jsx23(Text18, { bold: true, children: (() => {
12979
14291
  const t = request?.totals.find((t2) => t2.type === "total");
12980
14292
  return t ? String(t.amount) : "N/A";
12981
14293
  })() })
12982
14294
  ] }),
12983
- /* @__PURE__ */ jsxs11(Text12, { children: [
14295
+ /* @__PURE__ */ jsxs16(Text18, { children: [
12984
14296
  "Merchant: ",
12985
- /* @__PURE__ */ jsx15(Text12, { bold: true, children: request?.merchant_name })
14297
+ /* @__PURE__ */ jsx23(Text18, { bold: true, children: request?.merchant_name })
12986
14298
  ] }),
12987
- /* @__PURE__ */ jsxs11(Text12, { children: [
14299
+ /* @__PURE__ */ jsxs16(Text18, { children: [
12988
14300
  "Line Items:",
12989
14301
  " ",
12990
- /* @__PURE__ */ jsx15(Text12, { bold: true, children: request?.line_items.map((li) => li.name).join(", ") })
14302
+ /* @__PURE__ */ jsx23(Text18, { bold: true, children: request?.line_items.map((li) => li.name).join(", ") })
12991
14303
  ] })
12992
14304
  ] })
12993
14305
  ] });
12994
14306
  };
12995
14307
 
12996
14308
  // src/commands/spend-request/index.tsx
12997
- import { jsx as jsx16 } from "react/jsx-runtime";
14309
+ import { jsx as jsx24 } from "react/jsx-runtime";
12998
14310
  function createSpendRequestCli(repository) {
12999
- const cli2 = Cli4.create("spend-request", {
14311
+ const cli2 = Cli6.create("spend-request", {
13000
14312
  description: "Spend request management commands"
13001
14313
  });
13002
14314
  cli2.command("create", {
@@ -13074,8 +14386,8 @@ function createSpendRequestCli(repository) {
13074
14386
  };
13075
14387
  if (!c.agent && !c.formatExplicit) {
13076
14388
  return new Promise((resolve) => {
13077
- const { waitUntilExit } = render4(
13078
- /* @__PURE__ */ jsx16(
14389
+ const { waitUntilExit } = render6(
14390
+ /* @__PURE__ */ jsx24(
13079
14391
  CreateSpendRequest,
13080
14392
  {
13081
14393
  repository,
@@ -13109,8 +14421,8 @@ function createSpendRequestCli(repository) {
13109
14421
  });
13110
14422
  cli2.command("update", {
13111
14423
  description: "Update a spend request",
13112
- args: z6.object({
13113
- id: z6.string().describe("Spend request ID")
14424
+ args: z7.object({
14425
+ id: z7.string().describe("Spend request ID")
13114
14426
  }),
13115
14427
  options: updateOptions,
13116
14428
  outputPolicy: "agent-only",
@@ -13147,8 +14459,8 @@ function createSpendRequestCli(repository) {
13147
14459
  );
13148
14460
  if (!c.agent && !c.formatExplicit) {
13149
14461
  return new Promise((resolve) => {
13150
- const { waitUntilExit } = render4(
13151
- /* @__PURE__ */ jsx16(
14462
+ const { waitUntilExit } = render6(
14463
+ /* @__PURE__ */ jsx24(
13152
14464
  UpdateSpendRequest,
13153
14465
  {
13154
14466
  repository,
@@ -13169,8 +14481,8 @@ function createSpendRequestCli(repository) {
13169
14481
  });
13170
14482
  cli2.command("request-approval", {
13171
14483
  description: "Request approval for a spend request",
13172
- args: z6.object({
13173
- id: z6.string().describe("Spend request ID")
14484
+ args: z7.object({
14485
+ id: z7.string().describe("Spend request ID")
13174
14486
  }),
13175
14487
  outputPolicy: "agent-only",
13176
14488
  async *run(c) {
@@ -13188,8 +14500,8 @@ function createSpendRequestCli(repository) {
13188
14500
  const id = c.args.id;
13189
14501
  if (!c.agent && !c.formatExplicit) {
13190
14502
  return new Promise((resolve) => {
13191
- const { waitUntilExit } = render4(
13192
- /* @__PURE__ */ jsx16(
14503
+ const { waitUntilExit } = render6(
14504
+ /* @__PURE__ */ jsx24(
13193
14505
  RequestApproval,
13194
14506
  {
13195
14507
  repository,
@@ -13218,8 +14530,8 @@ function createSpendRequestCli(repository) {
13218
14530
  });
13219
14531
  cli2.command("retrieve", {
13220
14532
  description: "Retrieve a spend request",
13221
- args: z6.object({
13222
- id: z6.string().describe("Spend request ID")
14533
+ args: z7.object({
14534
+ id: z7.string().describe("Spend request ID")
13223
14535
  }),
13224
14536
  options: retrieveOptions,
13225
14537
  outputPolicy: "agent-only",
@@ -13244,8 +14556,8 @@ function createSpendRequestCli(repository) {
13244
14556
  const include = includeArr?.length ? includeArr : void 0;
13245
14557
  if (!c.agent && !c.formatExplicit) {
13246
14558
  return new Promise((resolve) => {
13247
- const { waitUntilExit } = render4(
13248
- /* @__PURE__ */ jsx16(
14559
+ const { waitUntilExit } = render6(
14560
+ /* @__PURE__ */ jsx24(
13249
14561
  RetrieveSpendRequest,
13250
14562
  {
13251
14563
  repository,
@@ -13603,7 +14915,7 @@ var ResourceFactory = class {
13603
14915
  };
13604
14916
 
13605
14917
  // src/cli.tsx
13606
- var cliVersion = "0.2.3";
14918
+ var cliVersion = "0.3.0";
13607
14919
  var buildNumber = "1";
13608
14920
  var cliName = "@stripe/link-cli";
13609
14921
  var defaultHeaders = {
@@ -13617,7 +14929,7 @@ var spendRequestRepo = factory.createSpendRequestResource();
13617
14929
  var notifier = updateNotifier({
13618
14930
  pkg: { name: cliName, version: cliVersion }
13619
14931
  });
13620
- var cli = Cli5.create("link-cli", {
14932
+ var cli = Cli7.create("link-cli", {
13621
14933
  description: "Create a secure, one-time payment credential from a Link wallet to let agents complete purchases on behalf of users.",
13622
14934
  version: `${cliVersion} (build ${buildNumber})`
13623
14935
  });
@@ -13627,6 +14939,20 @@ cli.command(
13627
14939
  createPaymentMethodsCli(() => factory.createPaymentMethodsResource())
13628
14940
  );
13629
14941
  cli.command(createMppCli(spendRequestRepo));
14942
+ cli.command(
14943
+ createDemoCli(
14944
+ authRepo,
14945
+ spendRequestRepo,
14946
+ () => factory.createPaymentMethodsResource()
14947
+ )
14948
+ );
14949
+ cli.command(
14950
+ createOnboardCli(
14951
+ authRepo,
14952
+ spendRequestRepo,
14953
+ () => factory.createPaymentMethodsResource()
14954
+ )
14955
+ );
13630
14956
  var isAgent = process.argv.includes("--format") || process.argv.includes("--mcp");
13631
14957
  if (!isAgent) {
13632
14958
  notifier.notify({ defer: false });