@stripe/link-cli 0.2.2 → 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 +1760 -424
  3. package/package.json +3 -3
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
@@ -11525,6 +11525,7 @@ function createAuthCli(authResource, updateInfo) {
11525
11525
  const maxAttempts = opts.maxAttempts;
11526
11526
  const deadline = Date.now() + opts.timeout * 1e3;
11527
11527
  let attempts = 0;
11528
+ let previousAttemptData;
11528
11529
  while (true) {
11529
11530
  const pending = storage.getPendingDeviceAuth();
11530
11531
  if (pending && !storage.isAuthenticated()) {
@@ -11567,7 +11568,11 @@ function createAuthCli(authResource, updateInfo) {
11567
11568
  yield status;
11568
11569
  return;
11569
11570
  }
11570
- yield status;
11571
+ const snapshot = JSON.stringify(status);
11572
+ if (snapshot !== previousAttemptData) {
11573
+ previousAttemptData = snapshot;
11574
+ yield status;
11575
+ }
11571
11576
  await new Promise((resolve) => setTimeout(resolve, interval * 1e3));
11572
11577
  }
11573
11578
  }
@@ -11575,10 +11580,686 @@ function createAuthCli(authResource, updateInfo) {
11575
11580
  return cli2;
11576
11581
  }
11577
11582
 
11578
- // src/commands/mpp/index.tsx
11579
- 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";
11580
11585
  import { render as render2 } from "ink";
11581
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
+
11582
12263
  // src/commands/mpp/decode.ts
11583
12264
  import { Challenge } from "mppx";
11584
12265
  function getString(value, path5, required = true) {
@@ -11657,41 +12338,14 @@ function decodeStripeChallenge(challengeHeader) {
11657
12338
  };
11658
12339
  }
11659
12340
 
11660
- // src/commands/mpp/decode-view.tsx
11661
- import { Box as Box3, Text as Text3 } from "ink";
11662
- import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
11663
- function DecodeChallengeView({
11664
- decoded
11665
- }) {
11666
- return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", children: [
11667
- /* @__PURE__ */ jsx4(Text3, { color: "green", children: "\u2713 Stripe challenge decoded" }),
11668
- /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
11669
- /* @__PURE__ */ jsxs2(Text3, { children: [
11670
- "ID: ",
11671
- /* @__PURE__ */ jsx4(Text3, { bold: true, children: decoded.id })
11672
- ] }),
11673
- /* @__PURE__ */ jsxs2(Text3, { children: [
11674
- "Realm: ",
11675
- /* @__PURE__ */ jsx4(Text3, { bold: true, children: decoded.realm })
11676
- ] }),
11677
- /* @__PURE__ */ jsxs2(Text3, { children: [
11678
- "Network ID: ",
11679
- /* @__PURE__ */ jsx4(Text3, { bold: true, children: decoded.network_id })
11680
- ] }),
11681
- /* @__PURE__ */ jsx4(Text3, { children: "Request JSON:" }),
11682
- /* @__PURE__ */ jsx4(Text3, { children: JSON.stringify(decoded.request_json, null, 2) })
11683
- ] })
11684
- ] });
11685
- }
11686
-
11687
12341
  // src/commands/mpp/pay.tsx
11688
- import { Box as Box4, Text as Text4 } from "ink";
12342
+ import { Box as Box6, Text as Text7 } from "ink";
11689
12343
  import Spinner2 from "ink-spinner";
11690
12344
  import { Credential, Method } from "mppx";
11691
12345
  import { Mppx, Transport } from "mppx/client";
11692
12346
  import { Methods as StripeMethods } from "mppx/stripe";
11693
- import { useEffect as useEffect3, useState as useState3 } from "react";
11694
- 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";
11695
12349
  function buildHeaders(data, headers) {
11696
12350
  const result = {};
11697
12351
  if (data !== void 0) {
@@ -11796,10 +12450,10 @@ function MppPay({
11796
12450
  repository,
11797
12451
  onComplete
11798
12452
  }) {
11799
- const [step, setStep] = useState3("retrieving");
11800
- const [result, setResult] = useState3(null);
11801
- const [error, setError] = useState3(null);
11802
- useEffect3(() => {
12453
+ const [step, setStep] = useState4("retrieving");
12454
+ const [result, setResult] = useState4(null);
12455
+ const [error, setError] = useState4(null);
12456
+ useEffect4(() => {
11803
12457
  (async () => {
11804
12458
  try {
11805
12459
  setStep("retrieving");
@@ -11868,54 +12522,640 @@ function MppPay({
11868
12522
  done: "Done"
11869
12523
  };
11870
12524
  if (error) {
11871
- return /* @__PURE__ */ jsxs3(Text4, { color: "red", children: [
12525
+ return /* @__PURE__ */ jsxs5(Text7, { color: "red", children: [
11872
12526
  "Error: ",
11873
12527
  error
11874
12528
  ] });
11875
12529
  }
11876
- return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", children: [
11877
- step !== "done" && /* @__PURE__ */ jsx5(Box4, { children: /* @__PURE__ */ jsxs3(Text4, { color: "cyan", children: [
11878
- /* @__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" }),
11879
12533
  " ",
11880
12534
  stepLabels[step],
11881
12535
  "..."
11882
12536
  ] }) }),
11883
- result && /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", children: [
11884
- /* @__PURE__ */ jsxs3(Text4, { color: "green", children: [
12537
+ result && /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
12538
+ /* @__PURE__ */ jsxs5(Text7, { color: "green", children: [
11885
12539
  "HTTP ",
11886
12540
  result.status
11887
12541
  ] }),
11888
- /* @__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) })
11889
13129
  ] })
11890
13130
  ] });
11891
13131
  }
11892
13132
 
11893
13133
  // src/commands/mpp/schema.ts
11894
- import { z as z2 } from "incur";
11895
- var payOptions = z2.object({
11896
- spendRequestId: z2.string().describe(
13134
+ import { z as z3 } from "incur";
13135
+ var payOptions = z3.object({
13136
+ spendRequestId: z3.string().describe(
11897
13137
  'Approved spend request ID with credential_type "shared_payment_token"'
11898
13138
  ),
11899
- method: z2.string().optional().describe("HTTP method (default: GET, or POST if --data is provided)"),
11900
- data: z2.string().optional().describe("Request body (implies POST if --method is not set)"),
11901
- 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)')
11902
13142
  });
11903
- var decodeOptions = z2.object({
11904
- challenge: z2.string().describe(
13143
+ var decodeOptions = z3.object({
13144
+ challenge: z3.string().describe(
11905
13145
  "Raw WWW-Authenticate header value; may include multiple payment challenges"
11906
13146
  )
11907
13147
  });
11908
13148
 
11909
13149
  // src/commands/mpp/index.tsx
11910
- import { jsx as jsx6 } from "react/jsx-runtime";
13150
+ import { jsx as jsx13 } from "react/jsx-runtime";
11911
13151
  function createMppCli(repository) {
11912
- const cli2 = Cli2.create("mpp", {
13152
+ const cli2 = Cli3.create("mpp", {
11913
13153
  description: "Machine payment protocol (MPP) commands"
11914
13154
  });
11915
13155
  cli2.command("pay", {
11916
13156
  description: "Complete a machine payment protocol (MPP) payment using an approved spend request",
11917
- args: z3.object({
11918
- url: z3.string().describe("URL to pay")
13157
+ args: z4.object({
13158
+ url: z4.string().describe("URL to pay")
11919
13159
  }),
11920
13160
  options: payOptions,
11921
13161
  alias: { method: "X", data: "d", header: "H" },
@@ -11939,8 +13179,8 @@ function createMppCli(repository) {
11939
13179
  const headers = opts.header?.length ? opts.header : void 0;
11940
13180
  if (!c.agent && !c.formatExplicit) {
11941
13181
  return new Promise((resolve) => {
11942
- const { waitUntilExit } = render2(
11943
- /* @__PURE__ */ jsx6(
13182
+ const { waitUntilExit } = render3(
13183
+ /* @__PURE__ */ jsx13(
11944
13184
  MppPay,
11945
13185
  {
11946
13186
  url,
@@ -11986,8 +13226,8 @@ function createMppCli(repository) {
11986
13226
  const decoded = decodeStripeChallenge(c.options.challenge);
11987
13227
  if (!c.agent && !c.formatExplicit) {
11988
13228
  return new Promise((resolve) => {
11989
- const { waitUntilExit } = render2(
11990
- /* @__PURE__ */ jsx6(DecodeChallengeView, { decoded })
13229
+ const { waitUntilExit } = render3(
13230
+ /* @__PURE__ */ jsx13(DecodeChallengeView, { decoded })
11991
13231
  );
11992
13232
  waitUntilExit().then(() => resolve(decoded));
11993
13233
  });
@@ -11998,26 +13238,183 @@ function createMppCli(repository) {
11998
13238
  return cli2;
11999
13239
  }
12000
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
+
12001
13398
  // src/commands/payment-methods/index.tsx
12002
- import { Cli as Cli3 } from "incur";
12003
- import { render as render3 } from "ink";
13399
+ import { Cli as Cli5 } from "incur";
13400
+ import { render as render5 } from "ink";
12004
13401
 
12005
13402
  // src/commands/payment-methods/add.tsx
12006
- import { Box as Box5, Text as Text5, useApp, useInput as useInput2 } from "ink";
12007
- 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";
12008
13405
  var WALLET_URL = "https://app.link.com/wallet";
12009
13406
  var AddPaymentMethod = () => {
12010
13407
  const { exit } = useApp();
12011
- useInput2((_input, key) => {
13408
+ useInput6((_input, key) => {
12012
13409
  if (key.return) {
12013
13410
  openUrl(WALLET_URL);
12014
13411
  exit();
12015
13412
  }
12016
13413
  });
12017
- return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", paddingY: 1, children: [
12018
- /* @__PURE__ */ jsx7(Box5, { marginBottom: 1, children: /* @__PURE__ */ jsx7(Text5, { bold: true, children: "Add Payment Method" }) }),
12019
- /* @__PURE__ */ jsxs4(
12020
- 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,
12021
13418
  {
12022
13419
  flexDirection: "column",
12023
13420
  borderStyle: "round",
@@ -12025,12 +13422,12 @@ var AddPaymentMethod = () => {
12025
13422
  paddingX: 2,
12026
13423
  paddingY: 1,
12027
13424
  children: [
12028
- /* @__PURE__ */ jsxs4(Text5, { children: [
13425
+ /* @__PURE__ */ jsxs10(Text12, { children: [
12029
13426
  "Open:",
12030
13427
  " ",
12031
- /* @__PURE__ */ jsx7(Text5, { bold: true, color: "cyan", children: WALLET_URL })
13428
+ /* @__PURE__ */ jsx16(Text12, { bold: true, color: "cyan", children: WALLET_URL })
12032
13429
  ] }),
12033
- /* @__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" })
12034
13431
  ]
12035
13432
  }
12036
13433
  )
@@ -12038,20 +13435,20 @@ var AddPaymentMethod = () => {
12038
13435
  };
12039
13436
 
12040
13437
  // src/commands/payment-methods/list.tsx
12041
- import { Box as Box6, Text as Text6 } from "ink";
13438
+ import { Box as Box12, Text as Text13 } from "ink";
12042
13439
  import Spinner3 from "ink-spinner";
12043
- import { useEffect as useEffect4, useState as useState4 } from "react";
12044
- 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";
12045
13442
  var PaymentMethodsList = ({
12046
13443
  resource,
12047
13444
  onComplete
12048
13445
  }) => {
12049
- const [status, setStatus] = useState4(
13446
+ const [status, setStatus] = useState8(
12050
13447
  "loading"
12051
13448
  );
12052
- const [methods, setMethods] = useState4([]);
12053
- const [error, setError] = useState4("");
12054
- useEffect4(() => {
13449
+ const [methods, setMethods] = useState8([]);
13450
+ const [error, setError] = useState8("");
13451
+ useEffect7(() => {
12055
13452
  const fetch2 = async () => {
12056
13453
  try {
12057
13454
  const result = await resource.listPaymentMethods();
@@ -12067,43 +13464,43 @@ var PaymentMethodsList = ({
12067
13464
  fetch2();
12068
13465
  }, [resource, onComplete]);
12069
13466
  if (status === "loading") {
12070
- return /* @__PURE__ */ jsx8(Box6, { children: /* @__PURE__ */ jsxs5(Text6, { color: "cyan", children: [
12071
- /* @__PURE__ */ jsx8(Spinner3, { type: "dots" }),
13467
+ return /* @__PURE__ */ jsx17(Box12, { children: /* @__PURE__ */ jsxs11(Text13, { color: "cyan", children: [
13468
+ /* @__PURE__ */ jsx17(Spinner3, { type: "dots" }),
12072
13469
  " Loading payment methods..."
12073
13470
  ] }) });
12074
13471
  }
12075
13472
  if (status === "error") {
12076
- return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
12077
- /* @__PURE__ */ jsx8(Text6, { color: "red", children: "\u2717 Failed to load payment methods" }),
12078
- /* @__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 })
12079
13476
  ] });
12080
13477
  }
12081
13478
  if (methods.length === 0) {
12082
- 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" }) });
12083
13480
  }
12084
- return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
12085
- /* @__PURE__ */ jsx8(Text6, { bold: true, children: "Payment Methods" }),
12086
- /* @__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) => {
12087
13484
  const label = pm.card_details?.brand ?? pm.bank_account_details?.bank_name ?? "Bank account";
12088
13485
  const last4 = pm.card_details?.last4 ?? pm.bank_account_details?.last4;
12089
13486
  const suffix = [pm.nickname ? `(${pm.nickname})` : ""].filter(Boolean).join(" ");
12090
- return /* @__PURE__ */ jsx8(Box6, { paddingX: 2, children: /* @__PURE__ */ jsxs5(Text6, { children: [
12091
- /* @__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 }),
12092
13489
  " ",
12093
13490
  label,
12094
13491
  " ****",
12095
13492
  last4,
12096
13493
  suffix ? ` ${suffix}` : "",
12097
- pm.is_default ? /* @__PURE__ */ jsx8(Text6, { color: "green", children: " (default)" }) : ""
13494
+ pm.is_default ? /* @__PURE__ */ jsx17(Text13, { color: "green", children: " (default)" }) : ""
12098
13495
  ] }) }, pm.id);
12099
13496
  }) })
12100
13497
  ] });
12101
13498
  };
12102
13499
 
12103
13500
  // src/commands/payment-methods/index.tsx
12104
- import { jsx as jsx9 } from "react/jsx-runtime";
13501
+ import { jsx as jsx18 } from "react/jsx-runtime";
12105
13502
  function createPaymentMethodsCli(createResource) {
12106
- const cli2 = Cli3.create("payment-methods", {
13503
+ const cli2 = Cli5.create("payment-methods", {
12107
13504
  description: "Payment methods management commands"
12108
13505
  });
12109
13506
  cli2.command("list", {
@@ -12124,8 +13521,8 @@ function createPaymentMethodsCli(createResource) {
12124
13521
  const resource = createResource();
12125
13522
  if (!c.agent && !c.formatExplicit) {
12126
13523
  return new Promise((resolve) => {
12127
- const { waitUntilExit } = render3(
12128
- /* @__PURE__ */ jsx9(PaymentMethodsList, { resource, onComplete: () => {
13524
+ const { waitUntilExit } = render5(
13525
+ /* @__PURE__ */ jsx18(PaymentMethodsList, { resource, onComplete: () => {
12129
13526
  } })
12130
13527
  );
12131
13528
  waitUntilExit().then(async () => {
@@ -12153,7 +13550,7 @@ function createPaymentMethodsCli(createResource) {
12153
13550
  }
12154
13551
  if (!c.agent && !c.formatExplicit) {
12155
13552
  return new Promise((resolve) => {
12156
- const { waitUntilExit } = render3(/* @__PURE__ */ jsx9(AddPaymentMethod, {}));
13553
+ const { waitUntilExit } = render5(/* @__PURE__ */ jsx18(AddPaymentMethod, {}));
12157
13554
  waitUntilExit().then(() => resolve({ url: WALLET_URL }));
12158
13555
  });
12159
13556
  }
@@ -12164,25 +13561,25 @@ function createPaymentMethodsCli(createResource) {
12164
13561
  }
12165
13562
 
12166
13563
  // src/commands/spend-request/index.tsx
12167
- import { Cli as Cli4, z as z6 } from "incur";
12168
- import { render as render4 } from "ink";
13564
+ import { Cli as Cli6, z as z7 } from "incur";
13565
+ import { render as render6 } from "ink";
12169
13566
 
12170
13567
  // src/utils/line-item-parser.ts
12171
- import { z as z4 } from "zod";
12172
- var LineItemSchema = z4.object({
12173
- name: z4.string(),
12174
- url: z4.string().optional(),
12175
- image_url: z4.string().optional(),
12176
- description: z4.string().optional(),
12177
- sku: z4.string().optional(),
12178
- quantity: z4.coerce.number().optional(),
12179
- unit_amount: z4.coerce.number().optional(),
12180
- 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()
12181
13578
  }).strict();
12182
- var TotalSchema = z4.object({
12183
- type: z4.string(),
12184
- display_text: z4.string(),
12185
- amount: z4.coerce.number()
13579
+ var TotalSchema = z5.object({
13580
+ type: z5.string(),
13581
+ display_text: z5.string(),
13582
+ amount: z5.coerce.number()
12186
13583
  }).strict();
12187
13584
  function parseKvString(raw) {
12188
13585
  const result = {};
@@ -12207,7 +13604,7 @@ function parseLineItemFlag(raw) {
12207
13604
  try {
12208
13605
  return LineItemSchema.parse(obj);
12209
13606
  } catch (err) {
12210
- if (err instanceof z4.ZodError) throw formatZodError(err, "Line item");
13607
+ if (err instanceof z5.ZodError) throw formatZodError(err, "Line item");
12211
13608
  throw err;
12212
13609
  }
12213
13610
  }
@@ -12216,80 +13613,26 @@ function parseTotalFlag(raw) {
12216
13613
  try {
12217
13614
  return TotalSchema.parse(obj);
12218
13615
  } catch (err) {
12219
- if (err instanceof z4.ZodError) throw formatZodError(err, "Total");
13616
+ if (err instanceof z5.ZodError) throw formatZodError(err, "Total");
12220
13617
  throw err;
12221
13618
  }
12222
13619
  }
12223
13620
 
12224
13621
  // src/commands/spend-request/create.tsx
12225
- import { Box as Box9, Text as Text9 } from "ink";
13622
+ import { Box as Box14, Text as Text15 } from "ink";
12226
13623
  import Spinner5 from "ink-spinner";
12227
- import { useCallback, useEffect as useEffect6, useState as useState5 } from "react";
12228
-
12229
- // src/commands/spend-request/app-download-qr-codes.tsx
12230
- import { Box as Box7, Text as Text7 } from "ink";
12231
- import { useMemo } from "react";
12232
-
12233
- // src/utils/render-qr-matrix.ts
12234
- import QRCode from "qrcode";
12235
- function renderQrMatrix(url) {
12236
- const qr = QRCode.create(url, { errorCorrectionLevel: "L" });
12237
- const size = qr.modules.size;
12238
- const data = qr.modules.data;
12239
- const quiet = 1;
12240
- const total = size + quiet * 2;
12241
- const matrix = Array.from(
12242
- { length: total },
12243
- (_, r) => Array.from({ length: total }, (_2, c) => {
12244
- if (r < quiet || r >= size + quiet || c < quiet || c >= size + quiet) {
12245
- return false;
12246
- }
12247
- return data[(r - quiet) * size + (c - quiet)] === 1;
12248
- })
12249
- );
12250
- const lines = [];
12251
- for (let r = 0; r < total; r += 2) {
12252
- let line = "";
12253
- for (let c = 0; c < total; c++) {
12254
- const top = matrix[r][c];
12255
- const bottom = r + 1 < total ? matrix[r + 1][c] : false;
12256
- if (top && bottom) line += "\u2588";
12257
- else if (top) line += "\u2580";
12258
- else if (bottom) line += "\u2584";
12259
- else line += " ";
12260
- }
12261
- lines.push(line);
12262
- }
12263
- return lines;
12264
- }
12265
-
12266
- // src/commands/spend-request/app-download-qr-codes.tsx
12267
- import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
12268
- var DOWNLOAD_URL = "https://link.com/download";
12269
- var AppDownloadQrCodes = () => {
12270
- const qrLines = useMemo(() => renderQrMatrix(DOWNLOAD_URL), []);
12271
- return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", marginTop: 1, children: [
12272
- /* @__PURE__ */ jsx10(Text7, { dimColor: true, children: "New! Get the Link app to approve spend requests easily" }),
12273
- /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", alignItems: "flex-start", marginTop: 1, children: [
12274
- qrLines.map((line, i) => (
12275
- // biome-ignore lint/suspicious/noArrayIndexKey: stable static array
12276
- /* @__PURE__ */ jsx10(Text7, { children: line }, i)
12277
- )),
12278
- /* @__PURE__ */ jsx10(Text7, { dimColor: true, children: DOWNLOAD_URL })
12279
- ] })
12280
- ] });
12281
- };
13624
+ import { useCallback as useCallback2, useEffect as useEffect9, useState as useState9 } from "react";
12282
13625
 
12283
13626
  // src/commands/spend-request/approval-waiting-view.tsx
12284
- import { Box as Box8, Text as Text8 } from "ink";
13627
+ import { Box as Box13, Text as Text14 } from "ink";
12285
13628
  import Spinner4 from "ink-spinner";
12286
- import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
13629
+ import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
12287
13630
  var ApprovalWaitingView = ({
12288
13631
  status,
12289
13632
  approvalUrl
12290
- }) => /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", paddingY: 1, children: [
12291
- /* @__PURE__ */ jsxs7(
12292
- Box8,
13633
+ }) => /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", paddingY: 1, children: [
13634
+ /* @__PURE__ */ jsxs12(
13635
+ Box13,
12293
13636
  {
12294
13637
  flexDirection: "column",
12295
13638
  borderStyle: "round",
@@ -12297,51 +13640,25 @@ var ApprovalWaitingView = ({
12297
13640
  paddingX: 2,
12298
13641
  paddingY: 1,
12299
13642
  children: [
12300
- /* @__PURE__ */ jsxs7(Text8, { children: [
13643
+ /* @__PURE__ */ jsxs12(Text14, { children: [
12301
13644
  "Approve at:",
12302
13645
  " ",
12303
- /* @__PURE__ */ jsx11(Text8, { bold: true, color: "cyan", children: approvalUrl })
13646
+ /* @__PURE__ */ jsx19(Text14, { bold: true, color: "cyan", children: approvalUrl })
12304
13647
  ] }),
12305
- /* @__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" })
12306
13649
  ]
12307
13650
  }
12308
13651
  ),
12309
- /* @__PURE__ */ jsx11(AppDownloadQrCodes, {}),
12310
- /* @__PURE__ */ jsx11(Box8, { marginTop: 1, children: status === "polling" ? /* @__PURE__ */ jsxs7(Text8, { color: "cyan", children: [
12311
- /* @__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" }),
12312
13655
  " Waiting for approval..."
12313
- ] }) : /* @__PURE__ */ jsx11(Text8, { dimColor: true, children: "Waiting..." }) })
13656
+ ] }) : /* @__PURE__ */ jsx19(Text14, { dimColor: true, children: "Waiting..." }) })
12314
13657
  ] });
12315
13658
 
12316
13659
  // src/commands/spend-request/use-approval-polling.ts
12317
- import { useInput as useInput3 } from "ink";
12318
- import { useEffect as useEffect5 } from "react";
12319
-
12320
- // src/utils/poll-until-approved.ts
12321
- function pollUntilApproved(repository, id, options = {}) {
12322
- const pollIntervalMs = options.pollIntervalMs ?? 2e3;
12323
- const timeoutMs = options.timeoutMs ?? 3e5;
12324
- const startTime = Date.now();
12325
- const poll = async () => {
12326
- const elapsed = Date.now() - startTime;
12327
- if (elapsed > timeoutMs) {
12328
- throw new Error("Approval polling timed out");
12329
- }
12330
- const request = await repository.getSpendRequest(id);
12331
- if (!request) {
12332
- throw new Error(`Spend request ${id} not found`);
12333
- }
12334
- if (request.status !== "created" && request.status !== "pending_approval") {
12335
- return request;
12336
- }
12337
- options.onProgress?.(Math.floor(elapsed / 1e3));
12338
- await new Promise((r) => setTimeout(r, pollIntervalMs));
12339
- return poll();
12340
- };
12341
- return poll();
12342
- }
12343
-
12344
- // src/commands/spend-request/use-approval-polling.ts
13660
+ import { useInput as useInput7 } from "ink";
13661
+ import { useEffect as useEffect8 } from "react";
12345
13662
  function useApprovalPolling({
12346
13663
  status,
12347
13664
  setStatus,
@@ -12353,18 +13670,18 @@ function useApprovalPolling({
12353
13670
  onError
12354
13671
  }) {
12355
13672
  const isWaiting = status === "waiting" || status === "polling";
12356
- useInput3(
13673
+ useInput7(
12357
13674
  (_input, key) => {
12358
13675
  if (key.return && approvalUrl) openUrl(approvalUrl);
12359
13676
  },
12360
13677
  { isActive: isWaiting }
12361
13678
  );
12362
- useEffect5(() => {
13679
+ useEffect8(() => {
12363
13680
  if (status !== "waiting") return;
12364
13681
  const timeout = setTimeout(() => setStatus("polling"), 1e3);
12365
13682
  return () => clearTimeout(timeout);
12366
13683
  }, [status, setStatus]);
12367
- useEffect5(() => {
13684
+ useEffect8(() => {
12368
13685
  if (status !== "polling" || !requestId) return;
12369
13686
  let cancelled = false;
12370
13687
  const poll = async () => {
@@ -12398,22 +13715,22 @@ function useApprovalPolling({
12398
13715
  }
12399
13716
 
12400
13717
  // src/commands/spend-request/create.tsx
12401
- 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";
12402
13719
  var CreateSpendRequest = ({
12403
13720
  repository,
12404
13721
  params,
12405
13722
  requestApproval = false,
12406
13723
  onComplete
12407
13724
  }) => {
12408
- const [status, setStatus] = useState5("creating");
12409
- const [request, setRequest] = useState5(null);
12410
- const [error, setError] = useState5("");
13725
+ const [status, setStatus] = useState9("creating");
13726
+ const [request, setRequest] = useState9(null);
13727
+ const [error, setError] = useState9("");
12411
13728
  const approvalUrl = request?.approval_url ?? "";
12412
- const onSuccess = useCallback(
13729
+ const onSuccess = useCallback2(
12413
13730
  (result) => setRequest(result),
12414
13731
  []
12415
13732
  );
12416
- const onError = useCallback((msg) => setError(msg), []);
13733
+ const onError = useCallback2((msg) => setError(msg), []);
12417
13734
  useApprovalPolling({
12418
13735
  status,
12419
13736
  setStatus,
@@ -12424,7 +13741,7 @@ var CreateSpendRequest = ({
12424
13741
  onSuccess,
12425
13742
  onError
12426
13743
  });
12427
- useEffect6(() => {
13744
+ useEffect9(() => {
12428
13745
  const create = async () => {
12429
13746
  try {
12430
13747
  const result = await repository.createSpendRequest(params);
@@ -12444,57 +13761,57 @@ var CreateSpendRequest = ({
12444
13761
  create();
12445
13762
  }, [repository, params, requestApproval, onComplete]);
12446
13763
  if (status === "creating") {
12447
- return /* @__PURE__ */ jsx12(Box9, { children: /* @__PURE__ */ jsxs8(Text9, { color: "cyan", children: [
12448
- /* @__PURE__ */ jsx12(Spinner5, { type: "dots" }),
13764
+ return /* @__PURE__ */ jsx20(Box14, { children: /* @__PURE__ */ jsxs13(Text15, { color: "cyan", children: [
13765
+ /* @__PURE__ */ jsx20(Spinner5, { type: "dots" }),
12449
13766
  " Creating spend request..."
12450
13767
  ] }) });
12451
13768
  }
12452
13769
  if (status === "error") {
12453
- return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "column", children: [
12454
- /* @__PURE__ */ jsx12(Text9, { color: "red", children: "\u2717 Failed to create spend request" }),
12455
- /* @__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 })
12456
13773
  ] });
12457
13774
  }
12458
13775
  if (status === "success") {
12459
- return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "column", children: [
12460
- /* @__PURE__ */ jsx12(Text9, { color: "green", children: "\u2713 Spend request created" }),
12461
- /* @__PURE__ */ jsxs8(Box9, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
12462
- /* @__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: [
12463
13780
  "ID: ",
12464
- /* @__PURE__ */ jsx12(Text9, { bold: true, children: request?.id })
13781
+ /* @__PURE__ */ jsx20(Text15, { bold: true, children: request?.id })
12465
13782
  ] }),
12466
- /* @__PURE__ */ jsxs8(Text9, { children: [
13783
+ /* @__PURE__ */ jsxs13(Text15, { children: [
12467
13784
  "Status: ",
12468
- /* @__PURE__ */ jsx12(Text9, { bold: true, children: request?.status })
13785
+ /* @__PURE__ */ jsx20(Text15, { bold: true, children: request?.status })
12469
13786
  ] }),
12470
- /* @__PURE__ */ jsxs8(Text9, { children: [
13787
+ /* @__PURE__ */ jsxs13(Text15, { children: [
12471
13788
  "Amount:",
12472
13789
  " ",
12473
- /* @__PURE__ */ jsx12(Text9, { bold: true, children: (() => {
13790
+ /* @__PURE__ */ jsx20(Text15, { bold: true, children: (() => {
12474
13791
  const t = request?.totals.find((t2) => t2.type === "total");
12475
13792
  return t ? String(t.amount) : "N/A";
12476
13793
  })() })
12477
13794
  ] }),
12478
- /* @__PURE__ */ jsxs8(Text9, { children: [
13795
+ /* @__PURE__ */ jsxs13(Text15, { children: [
12479
13796
  "Merchant: ",
12480
- /* @__PURE__ */ jsx12(Text9, { bold: true, children: request?.merchant_name })
13797
+ /* @__PURE__ */ jsx20(Text15, { bold: true, children: request?.merchant_name })
12481
13798
  ] }),
12482
- /* @__PURE__ */ jsxs8(Text9, { children: [
13799
+ /* @__PURE__ */ jsxs13(Text15, { children: [
12483
13800
  "Line Items:",
12484
13801
  " ",
12485
- /* @__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" })
12486
13803
  ] })
12487
13804
  ] }),
12488
- /* @__PURE__ */ jsx12(AppDownloadQrCodes, {})
13805
+ /* @__PURE__ */ jsx20(AppDownloadQrCodes, {})
12489
13806
  ] });
12490
13807
  }
12491
- return /* @__PURE__ */ jsxs8(Fragment, { children: [
12492
- /* @__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: [
12493
13810
  "\u2713 Spend request created (ID: ",
12494
- /* @__PURE__ */ jsx12(Text9, { bold: true, children: request?.id }),
13811
+ /* @__PURE__ */ jsx20(Text15, { bold: true, children: request?.id }),
12495
13812
  ")"
12496
13813
  ] }) }),
12497
- /* @__PURE__ */ jsx12(
13814
+ /* @__PURE__ */ jsx20(
12498
13815
  ApprovalWaitingView,
12499
13816
  {
12500
13817
  status,
@@ -12505,21 +13822,21 @@ var CreateSpendRequest = ({
12505
13822
  };
12506
13823
 
12507
13824
  // src/commands/spend-request/request-approval.tsx
12508
- import { Box as Box10, Text as Text10 } from "ink";
13825
+ import { Box as Box15, Text as Text16 } from "ink";
12509
13826
  import Spinner6 from "ink-spinner";
12510
- import { useCallback as useCallback2, useEffect as useEffect7, useState as useState6 } from "react";
12511
- 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";
12512
13829
  var RequestApproval = ({
12513
13830
  repository,
12514
13831
  id,
12515
13832
  onComplete
12516
13833
  }) => {
12517
- const [status, setStatus] = useState6("requesting");
12518
- const [approvalUrl, setApprovalUrl] = useState6("");
12519
- const [result, setResult] = useState6(null);
12520
- const [error, setError] = useState6("");
12521
- const onSuccess = useCallback2((r) => setResult(r), []);
12522
- 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), []);
12523
13840
  useApprovalPolling({
12524
13841
  status,
12525
13842
  setStatus,
@@ -12530,7 +13847,7 @@ var RequestApproval = ({
12530
13847
  onSuccess,
12531
13848
  onError
12532
13849
  });
12533
- useEffect7(() => {
13850
+ useEffect10(() => {
12534
13851
  const request = async () => {
12535
13852
  try {
12536
13853
  const res = await repository.requestApproval(id);
@@ -12544,45 +13861,45 @@ var RequestApproval = ({
12544
13861
  request();
12545
13862
  }, [repository, id]);
12546
13863
  if (status === "requesting") {
12547
- return /* @__PURE__ */ jsx13(Box10, { children: /* @__PURE__ */ jsxs9(Text10, { color: "cyan", children: [
12548
- /* @__PURE__ */ jsx13(Spinner6, { type: "dots" }),
13864
+ return /* @__PURE__ */ jsx21(Box15, { children: /* @__PURE__ */ jsxs14(Text16, { color: "cyan", children: [
13865
+ /* @__PURE__ */ jsx21(Spinner6, { type: "dots" }),
12549
13866
  " Requesting approval..."
12550
13867
  ] }) });
12551
13868
  }
12552
13869
  if (status === "error") {
12553
- return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", children: [
12554
- /* @__PURE__ */ jsx13(Text10, { color: "red", children: "\u2717 Failed to request approval" }),
12555
- /* @__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 })
12556
13873
  ] });
12557
13874
  }
12558
13875
  if (status === "success") {
12559
- return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", children: [
12560
- /* @__PURE__ */ jsx13(Text10, { color: "green", children: "\u2713 Approval completed" }),
12561
- /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
12562
- /* @__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: [
12563
13880
  "ID: ",
12564
- /* @__PURE__ */ jsx13(Text10, { bold: true, children: result?.id })
13881
+ /* @__PURE__ */ jsx21(Text16, { bold: true, children: result?.id })
12565
13882
  ] }),
12566
- /* @__PURE__ */ jsxs9(Text10, { children: [
13883
+ /* @__PURE__ */ jsxs14(Text16, { children: [
12567
13884
  "Status: ",
12568
- /* @__PURE__ */ jsx13(Text10, { bold: true, children: result?.status })
13885
+ /* @__PURE__ */ jsx21(Text16, { bold: true, children: result?.status })
12569
13886
  ] }),
12570
- /* @__PURE__ */ jsxs9(Text10, { children: [
13887
+ /* @__PURE__ */ jsxs14(Text16, { children: [
12571
13888
  "Amount:",
12572
13889
  " ",
12573
- /* @__PURE__ */ jsx13(Text10, { bold: true, children: (() => {
13890
+ /* @__PURE__ */ jsx21(Text16, { bold: true, children: (() => {
12574
13891
  const t = result?.totals.find((t2) => t2.type === "total");
12575
13892
  return t ? String(t.amount) : "N/A";
12576
13893
  })() })
12577
13894
  ] }),
12578
- /* @__PURE__ */ jsxs9(Text10, { children: [
13895
+ /* @__PURE__ */ jsxs14(Text16, { children: [
12579
13896
  "Merchant: ",
12580
- /* @__PURE__ */ jsx13(Text10, { bold: true, children: result?.merchant_name })
13897
+ /* @__PURE__ */ jsx21(Text16, { bold: true, children: result?.merchant_name })
12581
13898
  ] })
12582
13899
  ] })
12583
13900
  ] });
12584
13901
  }
12585
- return /* @__PURE__ */ jsx13(
13902
+ return /* @__PURE__ */ jsx21(
12586
13903
  ApprovalWaitingView,
12587
13904
  {
12588
13905
  status,
@@ -12592,10 +13909,10 @@ var RequestApproval = ({
12592
13909
  };
12593
13910
 
12594
13911
  // src/commands/spend-request/retrieve.tsx
12595
- import { Box as Box11, Text as Text11 } from "ink";
13912
+ import { Box as Box16, Text as Text17 } from "ink";
12596
13913
  import Spinner7 from "ink-spinner";
12597
- import { useEffect as useEffect8, useRef, useState as useState7 } from "react";
12598
- 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";
12599
13916
  var RetrieveSpendRequest = ({
12600
13917
  repository,
12601
13918
  id,
@@ -12603,20 +13920,20 @@ var RetrieveSpendRequest = ({
12603
13920
  include,
12604
13921
  onComplete
12605
13922
  }) => {
12606
- const [phase, setPhase] = useState7("fetching");
12607
- const [request, setRequest] = useState7(null);
12608
- const [error, setError] = useState7("");
12609
- const [elapsed, setElapsed] = useState7(0);
12610
- const startTimeRef = useRef(Date.now());
12611
- const pollRef = useRef(null);
12612
- const timerRef = useRef(null);
12613
- 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(() => {
12614
13931
  return () => {
12615
13932
  if (pollRef.current) clearInterval(pollRef.current);
12616
13933
  if (timerRef.current) clearInterval(timerRef.current);
12617
13934
  };
12618
13935
  }, []);
12619
- useEffect8(() => {
13936
+ useEffect11(() => {
12620
13937
  const fetch2 = async () => {
12621
13938
  try {
12622
13939
  const result = await repository.getSpendRequest(id, { include });
@@ -12645,7 +13962,7 @@ var RetrieveSpendRequest = ({
12645
13962
  };
12646
13963
  fetch2();
12647
13964
  }, [repository, id, include, onComplete]);
12648
- useEffect8(() => {
13965
+ useEffect11(() => {
12649
13966
  if (phase !== "polling") return;
12650
13967
  timerRef.current = setInterval(() => {
12651
13968
  const secs = Math.floor((Date.now() - startTimeRef.current) / 1e3);
@@ -12684,169 +14001,169 @@ var RetrieveSpendRequest = ({
12684
14001
  };
12685
14002
  }, [phase, repository, id, include, timeout, onComplete]);
12686
14003
  if (phase === "fetching") {
12687
- return /* @__PURE__ */ jsx14(Box11, { children: /* @__PURE__ */ jsxs10(Text11, { color: "cyan", children: [
12688
- /* @__PURE__ */ jsx14(Spinner7, { type: "dots" }),
14004
+ return /* @__PURE__ */ jsx22(Box16, { children: /* @__PURE__ */ jsxs15(Text17, { color: "cyan", children: [
14005
+ /* @__PURE__ */ jsx22(Spinner7, { type: "dots" }),
12689
14006
  " Retrieving spend request ",
12690
14007
  id,
12691
14008
  "..."
12692
14009
  ] }) });
12693
14010
  }
12694
14011
  if (phase === "error") {
12695
- 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: [
12696
14013
  "\u2717 ",
12697
14014
  error
12698
14015
  ] }) });
12699
14016
  }
12700
14017
  if (phase === "timeout") {
12701
- return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", children: [
12702
- /* @__PURE__ */ jsxs10(Text11, { color: "yellow", children: [
14018
+ return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", children: [
14019
+ /* @__PURE__ */ jsxs15(Text17, { color: "yellow", children: [
12703
14020
  "\u2717 Timed out waiting for approval after ",
12704
14021
  timeout,
12705
14022
  "s"
12706
14023
  ] }),
12707
- request && /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
12708
- /* @__PURE__ */ jsxs10(Text11, { children: [
14024
+ request && /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
14025
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12709
14026
  "ID: ",
12710
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request.id })
14027
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request.id })
12711
14028
  ] }),
12712
- /* @__PURE__ */ jsxs10(Text11, { children: [
14029
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12713
14030
  "Status: ",
12714
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request.status })
14031
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request.status })
12715
14032
  ] })
12716
14033
  ] })
12717
14034
  ] });
12718
14035
  }
12719
14036
  if (phase === "polling") {
12720
- return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", children: [
12721
- /* @__PURE__ */ jsx14(Box11, { children: /* @__PURE__ */ jsxs10(Text11, { color: "cyan", children: [
12722
- /* @__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" }),
12723
14040
  " Awaiting approval... (",
12724
14041
  elapsed,
12725
14042
  "s elapsed)"
12726
14043
  ] }) }),
12727
- 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: [
12728
14045
  "Approval URL: ",
12729
- /* @__PURE__ */ jsx14(Text11, { color: "cyan", children: request.approval_url })
14046
+ /* @__PURE__ */ jsx22(Text17, { color: "cyan", children: request.approval_url })
12730
14047
  ] }) })
12731
14048
  ] });
12732
14049
  }
12733
14050
  if (phase === "declined") {
12734
- return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", children: [
12735
- /* @__PURE__ */ jsx14(Text11, { color: "red", children: "\u2717 Spend request declined" }),
12736
- /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
12737
- /* @__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: [
12738
14055
  "ID: ",
12739
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request?.id })
14056
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request?.id })
12740
14057
  ] }),
12741
- /* @__PURE__ */ jsxs10(Text11, { children: [
14058
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12742
14059
  "Status:",
12743
14060
  " ",
12744
- /* @__PURE__ */ jsx14(Text11, { bold: true, color: "red", children: request?.status })
14061
+ /* @__PURE__ */ jsx22(Text17, { bold: true, color: "red", children: request?.status })
12745
14062
  ] }),
12746
- /* @__PURE__ */ jsxs10(Text11, { children: [
14063
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12747
14064
  "Amount:",
12748
14065
  " ",
12749
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: (() => {
14066
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: (() => {
12750
14067
  const t = request?.totals.find((t2) => t2.type === "total");
12751
14068
  return t ? String(t.amount) : "N/A";
12752
14069
  })() })
12753
14070
  ] }),
12754
- /* @__PURE__ */ jsxs10(Text11, { children: [
14071
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12755
14072
  "Merchant: ",
12756
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request?.merchant_name })
14073
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request?.merchant_name })
12757
14074
  ] })
12758
14075
  ] })
12759
14076
  ] });
12760
14077
  }
12761
- return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", children: [
12762
- /* @__PURE__ */ jsx14(Text11, { color: "green", children: "\u2713 Spend request approved" }),
12763
- /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
12764
- /* @__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: [
12765
14082
  "ID: ",
12766
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request?.id })
14083
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request?.id })
12767
14084
  ] }),
12768
- /* @__PURE__ */ jsxs10(Text11, { children: [
14085
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12769
14086
  "Status:",
12770
14087
  " ",
12771
- /* @__PURE__ */ jsx14(Text11, { bold: true, color: "green", children: request?.status })
14088
+ /* @__PURE__ */ jsx22(Text17, { bold: true, color: "green", children: request?.status })
12772
14089
  ] }),
12773
- /* @__PURE__ */ jsxs10(Text11, { children: [
14090
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12774
14091
  "Amount:",
12775
14092
  " ",
12776
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: (() => {
14093
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: (() => {
12777
14094
  const t = request?.totals.find((t2) => t2.type === "total");
12778
14095
  return t ? String(t.amount) : "N/A";
12779
14096
  })() })
12780
14097
  ] }),
12781
- /* @__PURE__ */ jsxs10(Text11, { children: [
14098
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12782
14099
  "Merchant: ",
12783
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request?.merchant_name })
14100
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request?.merchant_name })
12784
14101
  ] }),
12785
- /* @__PURE__ */ jsxs10(Text11, { children: [
14102
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12786
14103
  "Line Items:",
12787
14104
  " ",
12788
- /* @__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(", ") })
12789
14106
  ] }),
12790
- request?.shared_payment_token && /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", marginTop: 1, children: [
12791
- /* @__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: [
12792
14109
  "\x1B]8;;https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens\x07",
12793
14110
  "Shared Payment Token",
12794
14111
  "\x1B]8;;\x07",
12795
14112
  ":"
12796
14113
  ] }),
12797
- /* @__PURE__ */ jsxs10(Text11, { children: [
14114
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12798
14115
  " ",
12799
14116
  "Token: ",
12800
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request.shared_payment_token.id })
14117
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request.shared_payment_token.id })
12801
14118
  ] })
12802
14119
  ] }),
12803
- request?.card && /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", marginTop: 1, children: [
12804
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: "Card Details:" }),
12805
- /* @__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: [
12806
14123
  " ",
12807
14124
  "Number: ",
12808
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request?.card.number })
14125
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request?.card.number })
12809
14126
  ] }),
12810
- /* @__PURE__ */ jsxs10(Text11, { children: [
14127
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12811
14128
  " ",
12812
14129
  "Brand: ",
12813
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request?.card.brand })
14130
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request?.card.brand })
12814
14131
  ] }),
12815
- /* @__PURE__ */ jsxs10(Text11, { children: [
14132
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12816
14133
  " ",
12817
14134
  "Expiry:",
12818
14135
  " ",
12819
- /* @__PURE__ */ jsxs10(Text11, { bold: true, children: [
14136
+ /* @__PURE__ */ jsxs15(Text17, { bold: true, children: [
12820
14137
  String(request?.card.exp_month).padStart(2, "0"),
12821
14138
  "/",
12822
14139
  request?.card.exp_year
12823
14140
  ] })
12824
14141
  ] }),
12825
- request?.card.cvc && /* @__PURE__ */ jsxs10(Text11, { children: [
14142
+ request?.card.cvc && /* @__PURE__ */ jsxs15(Text17, { children: [
12826
14143
  " ",
12827
14144
  "CVC: ",
12828
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request.card.cvc })
14145
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request.card.cvc })
12829
14146
  ] }),
12830
- request?.card.valid_until && /* @__PURE__ */ jsxs10(Text11, { children: [
14147
+ request?.card.valid_until && /* @__PURE__ */ jsxs15(Text17, { children: [
12831
14148
  " ",
12832
14149
  "Valid Until: ",
12833
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: request.card.valid_until })
14150
+ /* @__PURE__ */ jsx22(Text17, { bold: true, children: request.card.valid_until })
12834
14151
  ] }),
12835
- request?.card.billing_address && /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", marginTop: 1, children: [
12836
- /* @__PURE__ */ jsx14(Text11, { bold: true, children: " Billing Address:" }),
12837
- /* @__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: [
12838
14155
  " ",
12839
14156
  request.card.billing_address.name
12840
14157
  ] }),
12841
- /* @__PURE__ */ jsxs10(Text11, { children: [
14158
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12842
14159
  " ",
12843
14160
  request.card.billing_address.line1
12844
14161
  ] }),
12845
- request.card.billing_address.line2 && /* @__PURE__ */ jsxs10(Text11, { children: [
14162
+ request.card.billing_address.line2 && /* @__PURE__ */ jsxs15(Text17, { children: [
12846
14163
  " ",
12847
14164
  request.card.billing_address.line2
12848
14165
  ] }),
12849
- /* @__PURE__ */ jsxs10(Text11, { children: [
14166
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12850
14167
  " ",
12851
14168
  [
12852
14169
  request.card.billing_address.city,
@@ -12854,7 +14171,7 @@ var RetrieveSpendRequest = ({
12854
14171
  request.card.billing_address.postal_code
12855
14172
  ].filter(Boolean).join(", ")
12856
14173
  ] }),
12857
- /* @__PURE__ */ jsxs10(Text11, { children: [
14174
+ /* @__PURE__ */ jsxs15(Text17, { children: [
12858
14175
  " ",
12859
14176
  request.card.billing_address.country
12860
14177
  ] })
@@ -12865,69 +14182,69 @@ var RetrieveSpendRequest = ({
12865
14182
  };
12866
14183
 
12867
14184
  // src/commands/spend-request/schema.ts
12868
- import { z as z5 } from "incur";
12869
- var createOptions = z5.object({
12870
- paymentMethodId: z5.string().describe("Payment method ID"),
12871
- 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(
12872
14189
  '"card" for checkout forms/Stripe Elements; "shared_payment_token" for HTTP 402/machine payment flows'
12873
14190
  ),
12874
- networkId: z5.string().optional().describe(
14191
+ networkId: z6.string().optional().describe(
12875
14192
  "Network ID (required for shared_payment_token) \u2014 use `link-cli mpp decode` to extract"
12876
14193
  ),
12877
- amount: z5.coerce.number().int().positive().max(5e4).describe("Amount in cents, max 50000 ($500.00)"),
12878
- currency: z5.string().length(3).default("usd").describe("Currency code"),
12879
- 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(
12880
14197
  "Merchant name (required for card; forbidden for shared_payment_token)"
12881
14198
  ),
12882
- merchantUrl: z5.string().optional().describe(
14199
+ merchantUrl: z6.string().optional().describe(
12883
14200
  "Merchant URL (required for card; forbidden for shared_payment_token)"
12884
14201
  ),
12885
- context: z5.string().min(100).describe(
14202
+ context: z6.string().min(100).describe(
12886
14203
  "Min 100 chars \u2014 describe the purchase and rationale; the user reads this when approving"
12887
14204
  ),
12888
- lineItem: z5.array(z5.union([z5.string(), z5.record(z5.string(), z5.unknown())])).default([]).describe("Line item (repeatable, key:value format)"),
12889
- total: z5.array(z5.union([z5.string(), z5.record(z5.string(), z5.unknown())])).default([]).describe("Total (repeatable, key:value format)"),
12890
- requestApproval: z5.boolean().default(true).describe("Request approval and poll until approved/denied/expired"),
12891
- 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(
12892
14209
  "Use test mode (creates testmode credentials from test card data)"
12893
14210
  )
12894
14211
  });
12895
- var retrieveOptions = z5.object({
12896
- timeout: z5.coerce.number().default(300).describe("Polling timeout in seconds"),
12897
- 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(
12898
14215
  "Poll interval in seconds. When > 0, polls until status is terminal or timeout is reached, yielding status on each attempt."
12899
14216
  ),
12900
- maxAttempts: z5.coerce.number().default(0).describe("Max poll attempts. 0 = unlimited (use timeout instead)."),
12901
- 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)")
12902
14219
  });
12903
- var updateOptions = z5.object({
12904
- paymentMethodId: z5.string().optional().describe("Payment method ID"),
12905
- amount: z5.coerce.number().optional().describe("Amount in cents"),
12906
- merchantUrl: z5.string().optional().describe("Merchant URL"),
12907
- profileId: z5.string().optional().describe("Profile ID"),
12908
- merchantId: z5.string().optional().describe("Merchant ID"),
12909
- currency: z5.string().optional().describe("Currency code"),
12910
- lineItem: z5.array(z5.union([z5.string(), z5.record(z5.string(), z5.unknown())])).default([]).describe("Line item (repeatable, key:value format)"),
12911
- 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)")
12912
14229
  });
12913
14230
 
12914
14231
  // src/commands/spend-request/update.tsx
12915
- import { Box as Box12, Text as Text12 } from "ink";
14232
+ import { Box as Box17, Text as Text18 } from "ink";
12916
14233
  import Spinner8 from "ink-spinner";
12917
- import { useEffect as useEffect9, useState as useState8 } from "react";
12918
- 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";
12919
14236
  var UpdateSpendRequest = ({
12920
14237
  repository,
12921
14238
  id,
12922
14239
  params,
12923
14240
  onComplete
12924
14241
  }) => {
12925
- const [status, setStatus] = useState8(
14242
+ const [status, setStatus] = useState12(
12926
14243
  "loading"
12927
14244
  );
12928
- const [request, setRequest] = useState8(null);
12929
- const [error, setError] = useState8("");
12930
- useEffect9(() => {
14245
+ const [request, setRequest] = useState12(null);
14246
+ const [error, setError] = useState12("");
14247
+ useEffect12(() => {
12931
14248
  const update = async () => {
12932
14249
  try {
12933
14250
  const result = await repository.updateSpendRequest(id, params);
@@ -12943,55 +14260,55 @@ var UpdateSpendRequest = ({
12943
14260
  update();
12944
14261
  }, [repository, id, params, onComplete]);
12945
14262
  if (status === "loading") {
12946
- return /* @__PURE__ */ jsx15(Box12, { children: /* @__PURE__ */ jsxs11(Text12, { color: "cyan", children: [
12947
- /* @__PURE__ */ jsx15(Spinner8, { type: "dots" }),
14263
+ return /* @__PURE__ */ jsx23(Box17, { children: /* @__PURE__ */ jsxs16(Text18, { color: "cyan", children: [
14264
+ /* @__PURE__ */ jsx23(Spinner8, { type: "dots" }),
12948
14265
  " Updating spend request ",
12949
14266
  id,
12950
14267
  "..."
12951
14268
  ] }) });
12952
14269
  }
12953
14270
  if (status === "error") {
12954
- return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", children: [
12955
- /* @__PURE__ */ jsx15(Text12, { color: "red", children: "\u2717 Failed to update spend request" }),
12956
- /* @__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 })
12957
14274
  ] });
12958
14275
  }
12959
- return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", children: [
12960
- /* @__PURE__ */ jsx15(Text12, { color: "green", children: "\u2713 Spend request updated" }),
12961
- /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
12962
- /* @__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: [
12963
14280
  "ID: ",
12964
- /* @__PURE__ */ jsx15(Text12, { bold: true, children: request?.id })
14281
+ /* @__PURE__ */ jsx23(Text18, { bold: true, children: request?.id })
12965
14282
  ] }),
12966
- /* @__PURE__ */ jsxs11(Text12, { children: [
14283
+ /* @__PURE__ */ jsxs16(Text18, { children: [
12967
14284
  "Status: ",
12968
- /* @__PURE__ */ jsx15(Text12, { bold: true, children: request?.status })
14285
+ /* @__PURE__ */ jsx23(Text18, { bold: true, children: request?.status })
12969
14286
  ] }),
12970
- /* @__PURE__ */ jsxs11(Text12, { children: [
14287
+ /* @__PURE__ */ jsxs16(Text18, { children: [
12971
14288
  "Amount:",
12972
14289
  " ",
12973
- /* @__PURE__ */ jsx15(Text12, { bold: true, children: (() => {
14290
+ /* @__PURE__ */ jsx23(Text18, { bold: true, children: (() => {
12974
14291
  const t = request?.totals.find((t2) => t2.type === "total");
12975
14292
  return t ? String(t.amount) : "N/A";
12976
14293
  })() })
12977
14294
  ] }),
12978
- /* @__PURE__ */ jsxs11(Text12, { children: [
14295
+ /* @__PURE__ */ jsxs16(Text18, { children: [
12979
14296
  "Merchant: ",
12980
- /* @__PURE__ */ jsx15(Text12, { bold: true, children: request?.merchant_name })
14297
+ /* @__PURE__ */ jsx23(Text18, { bold: true, children: request?.merchant_name })
12981
14298
  ] }),
12982
- /* @__PURE__ */ jsxs11(Text12, { children: [
14299
+ /* @__PURE__ */ jsxs16(Text18, { children: [
12983
14300
  "Line Items:",
12984
14301
  " ",
12985
- /* @__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(", ") })
12986
14303
  ] })
12987
14304
  ] })
12988
14305
  ] });
12989
14306
  };
12990
14307
 
12991
14308
  // src/commands/spend-request/index.tsx
12992
- import { jsx as jsx16 } from "react/jsx-runtime";
14309
+ import { jsx as jsx24 } from "react/jsx-runtime";
12993
14310
  function createSpendRequestCli(repository) {
12994
- const cli2 = Cli4.create("spend-request", {
14311
+ const cli2 = Cli6.create("spend-request", {
12995
14312
  description: "Spend request management commands"
12996
14313
  });
12997
14314
  cli2.command("create", {
@@ -13069,8 +14386,8 @@ function createSpendRequestCli(repository) {
13069
14386
  };
13070
14387
  if (!c.agent && !c.formatExplicit) {
13071
14388
  return new Promise((resolve) => {
13072
- const { waitUntilExit } = render4(
13073
- /* @__PURE__ */ jsx16(
14389
+ const { waitUntilExit } = render6(
14390
+ /* @__PURE__ */ jsx24(
13074
14391
  CreateSpendRequest,
13075
14392
  {
13076
14393
  repository,
@@ -13104,8 +14421,8 @@ function createSpendRequestCli(repository) {
13104
14421
  });
13105
14422
  cli2.command("update", {
13106
14423
  description: "Update a spend request",
13107
- args: z6.object({
13108
- id: z6.string().describe("Spend request ID")
14424
+ args: z7.object({
14425
+ id: z7.string().describe("Spend request ID")
13109
14426
  }),
13110
14427
  options: updateOptions,
13111
14428
  outputPolicy: "agent-only",
@@ -13142,8 +14459,8 @@ function createSpendRequestCli(repository) {
13142
14459
  );
13143
14460
  if (!c.agent && !c.formatExplicit) {
13144
14461
  return new Promise((resolve) => {
13145
- const { waitUntilExit } = render4(
13146
- /* @__PURE__ */ jsx16(
14462
+ const { waitUntilExit } = render6(
14463
+ /* @__PURE__ */ jsx24(
13147
14464
  UpdateSpendRequest,
13148
14465
  {
13149
14466
  repository,
@@ -13164,8 +14481,8 @@ function createSpendRequestCli(repository) {
13164
14481
  });
13165
14482
  cli2.command("request-approval", {
13166
14483
  description: "Request approval for a spend request",
13167
- args: z6.object({
13168
- id: z6.string().describe("Spend request ID")
14484
+ args: z7.object({
14485
+ id: z7.string().describe("Spend request ID")
13169
14486
  }),
13170
14487
  outputPolicy: "agent-only",
13171
14488
  async *run(c) {
@@ -13183,8 +14500,8 @@ function createSpendRequestCli(repository) {
13183
14500
  const id = c.args.id;
13184
14501
  if (!c.agent && !c.formatExplicit) {
13185
14502
  return new Promise((resolve) => {
13186
- const { waitUntilExit } = render4(
13187
- /* @__PURE__ */ jsx16(
14503
+ const { waitUntilExit } = render6(
14504
+ /* @__PURE__ */ jsx24(
13188
14505
  RequestApproval,
13189
14506
  {
13190
14507
  repository,
@@ -13213,8 +14530,8 @@ function createSpendRequestCli(repository) {
13213
14530
  });
13214
14531
  cli2.command("retrieve", {
13215
14532
  description: "Retrieve a spend request",
13216
- args: z6.object({
13217
- id: z6.string().describe("Spend request ID")
14533
+ args: z7.object({
14534
+ id: z7.string().describe("Spend request ID")
13218
14535
  }),
13219
14536
  options: retrieveOptions,
13220
14537
  outputPolicy: "agent-only",
@@ -13239,8 +14556,8 @@ function createSpendRequestCli(repository) {
13239
14556
  const include = includeArr?.length ? includeArr : void 0;
13240
14557
  if (!c.agent && !c.formatExplicit) {
13241
14558
  return new Promise((resolve) => {
13242
- const { waitUntilExit } = render4(
13243
- /* @__PURE__ */ jsx16(
14559
+ const { waitUntilExit } = render6(
14560
+ /* @__PURE__ */ jsx24(
13244
14561
  RetrieveSpendRequest,
13245
14562
  {
13246
14563
  repository,
@@ -13267,6 +14584,7 @@ function createSpendRequestCli(repository) {
13267
14584
  ]);
13268
14585
  const deadline = Date.now() + timeout * 1e3;
13269
14586
  let attempts = 0;
14587
+ let previousAttemptData;
13270
14588
  while (true) {
13271
14589
  const request = await repository.getSpendRequest(id, { include });
13272
14590
  if (!request) {
@@ -13285,7 +14603,11 @@ function createSpendRequestCli(repository) {
13285
14603
  yield request;
13286
14604
  return;
13287
14605
  }
13288
- yield request;
14606
+ const snapshot = JSON.stringify(request);
14607
+ if (snapshot !== previousAttemptData) {
14608
+ previousAttemptData = snapshot;
14609
+ yield request;
14610
+ }
13289
14611
  await new Promise((resolve) => setTimeout(resolve, interval * 1e3));
13290
14612
  }
13291
14613
  }
@@ -13593,7 +14915,7 @@ var ResourceFactory = class {
13593
14915
  };
13594
14916
 
13595
14917
  // src/cli.tsx
13596
- var cliVersion = "0.2.2";
14918
+ var cliVersion = "0.3.0";
13597
14919
  var buildNumber = "1";
13598
14920
  var cliName = "@stripe/link-cli";
13599
14921
  var defaultHeaders = {
@@ -13607,7 +14929,7 @@ var spendRequestRepo = factory.createSpendRequestResource();
13607
14929
  var notifier = updateNotifier({
13608
14930
  pkg: { name: cliName, version: cliVersion }
13609
14931
  });
13610
- var cli = Cli5.create("link-cli", {
14932
+ var cli = Cli7.create("link-cli", {
13611
14933
  description: "Create a secure, one-time payment credential from a Link wallet to let agents complete purchases on behalf of users.",
13612
14934
  version: `${cliVersion} (build ${buildNumber})`
13613
14935
  });
@@ -13617,6 +14939,20 @@ cli.command(
13617
14939
  createPaymentMethodsCli(() => factory.createPaymentMethodsResource())
13618
14940
  );
13619
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
+ );
13620
14956
  var isAgent = process.argv.includes("--format") || process.argv.includes("--mcp");
13621
14957
  if (!isAgent) {
13622
14958
  notifier.notify({ defer: false });