@stripe/link-cli 0.16.0 → 0.17.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 (2) hide show
  1. package/dist/cli.js +95 -17
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -802,11 +802,13 @@ var SpendRequestResource = class extends BaseResource {
802
802
  );
803
803
  }
804
804
  async update(id, params) {
805
+ const { approve, ...body } = params;
806
+ const url = approve ? `${this.endpoint}/${id}/update_delegated` : `${this.endpoint}/${id}`;
805
807
  const { status, data, rawBody } = await this.apiFetch({
806
808
  method: "POST",
807
- url: `${this.endpoint}/${id}`,
809
+ url,
808
810
  headers: { "Content-Type": "application/json" },
809
- body: JSON.stringify(params)
811
+ body: JSON.stringify(body)
810
812
  });
811
813
  if (status < 200 || status >= 300) {
812
814
  this.throwApiError("update spend request", status, data, rawBody);
@@ -2801,7 +2803,7 @@ function buildHeaders(data, headers) {
2801
2803
  if (key) result[key] = value;
2802
2804
  }
2803
2805
  if (!Object.keys(result).some((key) => key.toLowerCase() === "user-agent")) {
2804
- result["User-Agent"] = `link-cli/${"0.16.0"}`;
2806
+ result["User-Agent"] = `link-cli/${"0.17.0"}`;
2805
2807
  }
2806
2808
  return result;
2807
2809
  }
@@ -4939,6 +4941,7 @@ var CreateSpendRequest = ({
4939
4941
  repository,
4940
4942
  params,
4941
4943
  requestApproval = false,
4944
+ approve = false,
4942
4945
  outputFile,
4943
4946
  force,
4944
4947
  onComplete
@@ -5077,7 +5080,7 @@ var CreateSpendRequest = ({
5077
5080
  result.status_details?.requires_action?.next_action ?? null
5078
5081
  );
5079
5082
  setStatus("requires_action");
5080
- } else if (requestApproval) {
5083
+ } else if (requestApproval && result.status !== "approved") {
5081
5084
  setStatus("waiting");
5082
5085
  } else {
5083
5086
  setStatus("success");
@@ -5352,7 +5355,7 @@ var CreateSpendRequest = ({
5352
5355
  fileError
5353
5356
  ] })
5354
5357
  ] }),
5355
- /* @__PURE__ */ jsx27(AppDownloadQrCodes, {})
5358
+ !approve && /* @__PURE__ */ jsx27(AppDownloadQrCodes, {})
5356
5359
  ] });
5357
5360
  }
5358
5361
  return /* @__PURE__ */ jsxs18(Fragment4, { children: [
@@ -6190,13 +6193,39 @@ var updateOptions = z19.object({
6190
6193
  ),
6191
6194
  total: z19.array(z19.union([z19.string(), z19.record(z19.string(), z19.unknown())])).default([]).describe(
6192
6195
  'Total (repeatable, key:value format). Keys: type (required; one of: subtotal, tax, total, items_base_amount, items_discount, discount, fulfillment, shipping, fee, gift_wrap, tip, store_credit), display_text (required), amount (required). Example: "type:total,display_text:Total,amount:5000"'
6193
- )
6196
+ ),
6197
+ approve: z19.boolean().default(false).describe("Use the delegated approval flow for this update")
6194
6198
  });
6195
6199
 
6196
6200
  // src/commands/spend-request/update.tsx
6197
- import { Box as Box22, Text as Text24 } from "ink";
6201
+ import { Box as Box22, Text as Text24, useInput as useInput10 } from "ink";
6198
6202
  import Spinner14 from "ink-spinner";
6199
- import { useCallback as useCallback11 } from "react";
6203
+ import { useCallback as useCallback11, useState as useState12 } from "react";
6204
+
6205
+ // src/utils/poll-until-spend-request-update.ts
6206
+ async function pollUntilSpendRequestUpdate(repository, id, pendingAmount, options = {}) {
6207
+ const pollIntervalMs = options.pollIntervalMs ?? 2e3;
6208
+ const timeoutMs = options.timeoutMs ?? 3e5;
6209
+ const startTime = Date.now();
6210
+ while (true) {
6211
+ if (Date.now() - startTime > timeoutMs) {
6212
+ throw new Error("Spend request update polling timed out");
6213
+ }
6214
+ const request = await repository.retrieve(id);
6215
+ if (!request) {
6216
+ throw new Error(`Spend request ${id} not found`);
6217
+ }
6218
+ if (request.amount === pendingAmount) {
6219
+ return { request, outcome: "approved" };
6220
+ }
6221
+ if (!request.approval_url) {
6222
+ return { request, outcome: "denied" };
6223
+ }
6224
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
6225
+ }
6226
+ }
6227
+
6228
+ // src/commands/spend-request/update.tsx
6200
6229
  import { jsx as jsx31, jsxs as jsxs22 } from "react/jsx-runtime";
6201
6230
  var UpdateSpendRequest = ({
6202
6231
  repository,
@@ -6204,12 +6233,45 @@ var UpdateSpendRequest = ({
6204
6233
  params,
6205
6234
  onComplete
6206
6235
  }) => {
6207
- const action = useCallback11(
6208
- () => repository.update(id, params),
6209
- [repository, id, params]
6236
+ const [pendingApproval, setPendingApproval] = useState12(
6237
+ null
6238
+ );
6239
+ const action = useCallback11(async () => {
6240
+ const request2 = await repository.update(id, params);
6241
+ if (params.amount !== void 0 && request2.status === "approved" && request2.approval_url) {
6242
+ setPendingApproval(request2);
6243
+ return pollUntilSpendRequestUpdate(repository, id, params.amount);
6244
+ }
6245
+ return { request: request2, outcome: "updated" };
6246
+ }, [repository, id, params]);
6247
+ const handleComplete = useCallback11(
6248
+ (result2) => onComplete(result2?.request ?? null),
6249
+ [onComplete]
6250
+ );
6251
+ const {
6252
+ status,
6253
+ data: result,
6254
+ error
6255
+ } = useAsyncAction(action, handleComplete);
6256
+ const request = result?.request ?? pendingApproval;
6257
+ useInput10(
6258
+ (_input, key) => {
6259
+ if (key.return && pendingApproval?.approval_url) {
6260
+ openUrl(pendingApproval.approval_url);
6261
+ }
6262
+ },
6263
+ { isActive: status === "loading" && pendingApproval !== null }
6210
6264
  );
6211
- const { status, data: request, error } = useAsyncAction(action, onComplete);
6212
6265
  if (status === "loading") {
6266
+ if (pendingApproval?.approval_url) {
6267
+ return /* @__PURE__ */ jsx31(
6268
+ ApprovalWaitingView,
6269
+ {
6270
+ status: "polling",
6271
+ approvalUrl: pendingApproval.approval_url
6272
+ }
6273
+ );
6274
+ }
6213
6275
  return /* @__PURE__ */ jsx31(Box22, { children: /* @__PURE__ */ jsxs22(Text24, { color: "cyan", children: [
6214
6276
  /* @__PURE__ */ jsx31(Spinner14, { type: "dots" }),
6215
6277
  " Updating spend request ",
@@ -6223,6 +6285,21 @@ var UpdateSpendRequest = ({
6223
6285
  /* @__PURE__ */ jsx31(Text24, { color: "red", children: error })
6224
6286
  ] });
6225
6287
  }
6288
+ if (result?.outcome === "denied") {
6289
+ return /* @__PURE__ */ jsxs22(Box22, { flexDirection: "column", children: [
6290
+ /* @__PURE__ */ jsx31(Text24, { color: "yellow", children: "\u2717 Spend request update denied" }),
6291
+ /* @__PURE__ */ jsxs22(Box22, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
6292
+ /* @__PURE__ */ jsxs22(Text24, { children: [
6293
+ "ID: ",
6294
+ /* @__PURE__ */ jsx31(Text24, { bold: true, children: request?.id })
6295
+ ] }),
6296
+ /* @__PURE__ */ jsxs22(Text24, { children: [
6297
+ "Amount: ",
6298
+ /* @__PURE__ */ jsx31(Text24, { bold: true, children: request?.amount ?? "N/A" })
6299
+ ] })
6300
+ ] })
6301
+ ] });
6302
+ }
6226
6303
  return /* @__PURE__ */ jsxs22(Box22, { flexDirection: "column", children: [
6227
6304
  /* @__PURE__ */ jsx31(Text24, { color: "green", children: "\u2713 Spend request updated" }),
6228
6305
  /* @__PURE__ */ jsxs22(Box22, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
@@ -6237,10 +6314,7 @@ var UpdateSpendRequest = ({
6237
6314
  /* @__PURE__ */ jsxs22(Text24, { children: [
6238
6315
  "Amount:",
6239
6316
  " ",
6240
- /* @__PURE__ */ jsx31(Text24, { bold: true, children: (() => {
6241
- const t = request?.totals?.find((t2) => t2.type === "total");
6242
- return t ? String(t.amount) : "N/A";
6243
- })() })
6317
+ /* @__PURE__ */ jsx31(Text24, { bold: true, children: request?.amount !== void 0 ? String(request.amount) : "N/A" })
6244
6318
  ] }),
6245
6319
  /* @__PURE__ */ jsxs22(Text24, { children: [
6246
6320
  "Merchant: ",
@@ -6452,6 +6526,7 @@ function createSpendRequestCli(repository, authStorage2, envAccessToken2) {
6452
6526
  repository,
6453
6527
  params: createParams,
6454
6528
  requestApproval,
6529
+ approve: opts.approve ? true : void 0,
6455
6530
  outputFile,
6456
6531
  force: forceOverwrite,
6457
6532
  onComplete: (result) => {
@@ -6558,6 +6633,9 @@ function createSpendRequestCli(repository, authStorage2, envAccessToken2) {
6558
6633
  params.totals = opts.total.map(
6559
6634
  (item) => typeof item === "string" ? parseTotalFlag(item) : item
6560
6635
  );
6636
+ if (opts.approve !== void 0) {
6637
+ params.approve = opts.approve;
6638
+ }
6561
6639
  if (!c.agent && !c.formatExplicit) {
6562
6640
  let capturedResult = null;
6563
6641
  return renderInteractive(
@@ -7599,7 +7677,7 @@ function cacheUpdateInfo(value, ttlMs = UPDATE_CACHE_TTL_MS) {
7599
7677
  }
7600
7678
 
7601
7679
  // src/cli.tsx
7602
- var cliVersion = "0.16.0";
7680
+ var cliVersion = "0.17.0";
7603
7681
  var cliName = "@stripe/link-cli";
7604
7682
  var defaultHeaders = {
7605
7683
  "User-Agent": `link-cli/${cliVersion}`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stripe/link-cli",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "link-cli": "./dist/cli.js"
@@ -45,7 +45,7 @@
45
45
  "tsx": "^4.23.5",
46
46
  "typescript": "^5.9.3",
47
47
  "vitest": "^4.1.10",
48
- "@stripe/link-sdk": "0.2.1",
48
+ "@stripe/link-sdk": "0.3.0",
49
49
  "@stripe/link-typescript-config": "0.0.0"
50
50
  },
51
51
  "scripts": {