@stripe/link-cli 0.4.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -3
- package/dist/cli.js +1503 -870
- package/package.json +6 -4
package/dist/cli.js
CHANGED
|
@@ -3218,8 +3218,8 @@ var require_utils = __commonJS({
|
|
|
3218
3218
|
}
|
|
3219
3219
|
return ind;
|
|
3220
3220
|
}
|
|
3221
|
-
function removeDotSegments(
|
|
3222
|
-
let input =
|
|
3221
|
+
function removeDotSegments(path7) {
|
|
3222
|
+
let input = path7;
|
|
3223
3223
|
const output = [];
|
|
3224
3224
|
let nextSlash = -1;
|
|
3225
3225
|
let len = 0;
|
|
@@ -3418,8 +3418,8 @@ var require_schemes = __commonJS({
|
|
|
3418
3418
|
wsComponent.secure = void 0;
|
|
3419
3419
|
}
|
|
3420
3420
|
if (wsComponent.resourceName) {
|
|
3421
|
-
const [
|
|
3422
|
-
wsComponent.path =
|
|
3421
|
+
const [path7, query] = wsComponent.resourceName.split("?");
|
|
3422
|
+
wsComponent.path = path7 && path7 !== "/" ? path7 : void 0;
|
|
3423
3423
|
wsComponent.query = query;
|
|
3424
3424
|
wsComponent.resourceName = void 0;
|
|
3425
3425
|
}
|
|
@@ -9548,11 +9548,9 @@ var require_semver2 = __commonJS({
|
|
|
9548
9548
|
}
|
|
9549
9549
|
});
|
|
9550
9550
|
|
|
9551
|
-
// src/cli.tsx
|
|
9552
|
-
import { Cli as Cli7 } from "incur";
|
|
9553
|
-
|
|
9554
9551
|
// ../sdk/dist/index.js
|
|
9555
9552
|
import fs3 from "fs";
|
|
9553
|
+
import path5 from "path";
|
|
9556
9554
|
|
|
9557
9555
|
// ../../node_modules/.pnpm/conf@13.1.0/node_modules/conf/dist/source/index.js
|
|
9558
9556
|
import { isDeepStrictEqual } from "util";
|
|
@@ -9573,12 +9571,12 @@ var disallowedKeys = /* @__PURE__ */ new Set([
|
|
|
9573
9571
|
"constructor"
|
|
9574
9572
|
]);
|
|
9575
9573
|
var digits = new Set("0123456789");
|
|
9576
|
-
function getPathSegments(
|
|
9574
|
+
function getPathSegments(path7) {
|
|
9577
9575
|
const parts = [];
|
|
9578
9576
|
let currentSegment = "";
|
|
9579
9577
|
let currentPart = "start";
|
|
9580
9578
|
let isIgnoring = false;
|
|
9581
|
-
for (const character of
|
|
9579
|
+
for (const character of path7) {
|
|
9582
9580
|
switch (character) {
|
|
9583
9581
|
case "\\": {
|
|
9584
9582
|
if (currentPart === "index") {
|
|
@@ -9700,11 +9698,11 @@ function assertNotStringIndex(object, key) {
|
|
|
9700
9698
|
throw new Error("Cannot use string index");
|
|
9701
9699
|
}
|
|
9702
9700
|
}
|
|
9703
|
-
function getProperty(object,
|
|
9704
|
-
if (!isObject(object) || typeof
|
|
9701
|
+
function getProperty(object, path7, value) {
|
|
9702
|
+
if (!isObject(object) || typeof path7 !== "string") {
|
|
9705
9703
|
return value === void 0 ? object : value;
|
|
9706
9704
|
}
|
|
9707
|
-
const pathArray = getPathSegments(
|
|
9705
|
+
const pathArray = getPathSegments(path7);
|
|
9708
9706
|
if (pathArray.length === 0) {
|
|
9709
9707
|
return value;
|
|
9710
9708
|
}
|
|
@@ -9724,12 +9722,12 @@ function getProperty(object, path6, value) {
|
|
|
9724
9722
|
}
|
|
9725
9723
|
return object === void 0 ? value : object;
|
|
9726
9724
|
}
|
|
9727
|
-
function setProperty(object,
|
|
9728
|
-
if (!isObject(object) || typeof
|
|
9725
|
+
function setProperty(object, path7, value) {
|
|
9726
|
+
if (!isObject(object) || typeof path7 !== "string") {
|
|
9729
9727
|
return object;
|
|
9730
9728
|
}
|
|
9731
9729
|
const root = object;
|
|
9732
|
-
const pathArray = getPathSegments(
|
|
9730
|
+
const pathArray = getPathSegments(path7);
|
|
9733
9731
|
for (let index = 0; index < pathArray.length; index++) {
|
|
9734
9732
|
const key = pathArray[index];
|
|
9735
9733
|
assertNotStringIndex(object, key);
|
|
@@ -9742,11 +9740,11 @@ function setProperty(object, path6, value) {
|
|
|
9742
9740
|
}
|
|
9743
9741
|
return root;
|
|
9744
9742
|
}
|
|
9745
|
-
function deleteProperty(object,
|
|
9746
|
-
if (!isObject(object) || typeof
|
|
9743
|
+
function deleteProperty(object, path7) {
|
|
9744
|
+
if (!isObject(object) || typeof path7 !== "string") {
|
|
9747
9745
|
return false;
|
|
9748
9746
|
}
|
|
9749
|
-
const pathArray = getPathSegments(
|
|
9747
|
+
const pathArray = getPathSegments(path7);
|
|
9750
9748
|
for (let index = 0; index < pathArray.length; index++) {
|
|
9751
9749
|
const key = pathArray[index];
|
|
9752
9750
|
assertNotStringIndex(object, key);
|
|
@@ -9760,11 +9758,11 @@ function deleteProperty(object, path6) {
|
|
|
9760
9758
|
}
|
|
9761
9759
|
}
|
|
9762
9760
|
}
|
|
9763
|
-
function hasProperty(object,
|
|
9764
|
-
if (!isObject(object) || typeof
|
|
9761
|
+
function hasProperty(object, path7) {
|
|
9762
|
+
if (!isObject(object) || typeof path7 !== "string") {
|
|
9765
9763
|
return false;
|
|
9766
9764
|
}
|
|
9767
|
-
const pathArray = getPathSegments(
|
|
9765
|
+
const pathArray = getPathSegments(path7);
|
|
9768
9766
|
if (pathArray.length === 0) {
|
|
9769
9767
|
return false;
|
|
9770
9768
|
}
|
|
@@ -10869,10 +10867,18 @@ var Storage = class {
|
|
|
10869
10867
|
}
|
|
10870
10868
|
getConfig() {
|
|
10871
10869
|
if (!this.config) {
|
|
10870
|
+
let locationOverride;
|
|
10871
|
+
if (this.options.configPath) {
|
|
10872
|
+
const parsed = path5.parse(path5.resolve(this.options.configPath));
|
|
10873
|
+
const configName = parsed.ext === ".json" ? parsed.name : parsed.base;
|
|
10874
|
+
locationOverride = { cwd: parsed.dir, configName };
|
|
10875
|
+
} else if (this.options.cwd) {
|
|
10876
|
+
locationOverride = { cwd: this.options.cwd };
|
|
10877
|
+
}
|
|
10872
10878
|
this.config = new Conf({
|
|
10873
10879
|
projectName: "link-cli",
|
|
10874
10880
|
configFileMode: CONFIG_FILE_MODE,
|
|
10875
|
-
...
|
|
10881
|
+
...locationOverride,
|
|
10876
10882
|
defaults: {
|
|
10877
10883
|
auth: null,
|
|
10878
10884
|
pendingDeviceAuth: null
|
|
@@ -11082,6 +11088,91 @@ var PaymentMethodsResource = class {
|
|
|
11082
11088
|
return body?.payment_details ?? [];
|
|
11083
11089
|
}
|
|
11084
11090
|
};
|
|
11091
|
+
var ShippingAddressResource = class {
|
|
11092
|
+
verbose;
|
|
11093
|
+
getAccessToken;
|
|
11094
|
+
fetchImpl;
|
|
11095
|
+
shippingAddressesEndpoint;
|
|
11096
|
+
logger;
|
|
11097
|
+
constructor(options) {
|
|
11098
|
+
const config = resolveLinkSdkConfig(options);
|
|
11099
|
+
this.verbose = config.verbose;
|
|
11100
|
+
this.getAccessToken = config.getAccessToken;
|
|
11101
|
+
this.fetchImpl = requireFetchImplementation(config);
|
|
11102
|
+
this.shippingAddressesEndpoint = `${config.apiBaseUrl}/shipping_addresses`;
|
|
11103
|
+
this.logger = config.logger;
|
|
11104
|
+
}
|
|
11105
|
+
async rawFetch(opts) {
|
|
11106
|
+
if (this.verbose) {
|
|
11107
|
+
const redactedHeaders = { ...opts.headers };
|
|
11108
|
+
if (redactedHeaders.Authorization)
|
|
11109
|
+
redactedHeaders.Authorization = "Bearer <redacted>";
|
|
11110
|
+
this.logger.debug(`> ${opts.method} ${opts.url}`);
|
|
11111
|
+
this.logger.debug(` Headers: ${JSON.stringify(redactedHeaders)}`);
|
|
11112
|
+
}
|
|
11113
|
+
let response;
|
|
11114
|
+
try {
|
|
11115
|
+
response = await this.fetchImpl(opts.url, {
|
|
11116
|
+
method: opts.method,
|
|
11117
|
+
headers: opts.headers
|
|
11118
|
+
});
|
|
11119
|
+
} catch (error) {
|
|
11120
|
+
throw new LinkTransportError(
|
|
11121
|
+
`Request failed: ${opts.method} ${opts.url}`,
|
|
11122
|
+
{
|
|
11123
|
+
cause: error
|
|
11124
|
+
}
|
|
11125
|
+
);
|
|
11126
|
+
}
|
|
11127
|
+
const rawBody = await response.text();
|
|
11128
|
+
let data = null;
|
|
11129
|
+
try {
|
|
11130
|
+
data = JSON.parse(rawBody);
|
|
11131
|
+
} catch {
|
|
11132
|
+
}
|
|
11133
|
+
if (this.verbose) {
|
|
11134
|
+
this.logger.debug(`< ${response.status} ${response.statusText}`);
|
|
11135
|
+
response.headers.forEach((value, key) => {
|
|
11136
|
+
this.logger.debug(` ${key}: ${value}`);
|
|
11137
|
+
});
|
|
11138
|
+
this.logger.debug(rawBody);
|
|
11139
|
+
}
|
|
11140
|
+
return { status: response.status, data, rawBody };
|
|
11141
|
+
}
|
|
11142
|
+
async apiFetch(opts) {
|
|
11143
|
+
const token = await this.getAccessToken();
|
|
11144
|
+
const authedOpts = {
|
|
11145
|
+
...opts,
|
|
11146
|
+
headers: { ...opts.headers, Authorization: `Bearer ${token}` }
|
|
11147
|
+
};
|
|
11148
|
+
const res = await this.rawFetch(authedOpts);
|
|
11149
|
+
if (res.status === 401) {
|
|
11150
|
+
const refreshedToken = await this.getAccessToken({ forceRefresh: true });
|
|
11151
|
+
authedOpts.headers.Authorization = `Bearer ${refreshedToken}`;
|
|
11152
|
+
return this.rawFetch(authedOpts);
|
|
11153
|
+
}
|
|
11154
|
+
return res;
|
|
11155
|
+
}
|
|
11156
|
+
list() {
|
|
11157
|
+
return this.listShippingAddresses();
|
|
11158
|
+
}
|
|
11159
|
+
async listShippingAddresses() {
|
|
11160
|
+
const { status, data, rawBody } = await this.apiFetch({
|
|
11161
|
+
method: "GET",
|
|
11162
|
+
url: this.shippingAddressesEndpoint
|
|
11163
|
+
});
|
|
11164
|
+
if (status < 200 || status >= 300) {
|
|
11165
|
+
const body2 = data;
|
|
11166
|
+
const msg = body2?.error ?? body2?.message ?? (rawBody || "unknown error");
|
|
11167
|
+
throw new LinkApiError(
|
|
11168
|
+
`Failed to list shipping addresses (${status}): ${msg}`,
|
|
11169
|
+
{ status, rawBody, details: data }
|
|
11170
|
+
);
|
|
11171
|
+
}
|
|
11172
|
+
const body = data;
|
|
11173
|
+
return body?.shipping_addresses ?? [];
|
|
11174
|
+
}
|
|
11175
|
+
};
|
|
11085
11176
|
function normalizeSpendRequest(data) {
|
|
11086
11177
|
const sr = data;
|
|
11087
11178
|
if (typeof sr.shared_payment_token === "string") {
|
|
@@ -11214,6 +11305,22 @@ var SpendRequestResource = class {
|
|
|
11214
11305
|
}
|
|
11215
11306
|
return normalizeSpendRequest(data);
|
|
11216
11307
|
}
|
|
11308
|
+
cancel(id) {
|
|
11309
|
+
return this.cancelSpendRequest(id);
|
|
11310
|
+
}
|
|
11311
|
+
async cancelSpendRequest(id) {
|
|
11312
|
+
const { status, data, rawBody } = await this.apiFetch({
|
|
11313
|
+
method: "POST",
|
|
11314
|
+
url: `${this.spendRequestsEndpoint}/${id}/cancel`
|
|
11315
|
+
});
|
|
11316
|
+
if (status < 200 || status >= 300) {
|
|
11317
|
+
throw new LinkApiError(
|
|
11318
|
+
`Failed to cancel spend request (${status}): ${extractApiError(data, rawBody)}`,
|
|
11319
|
+
{ status, rawBody, details: data }
|
|
11320
|
+
);
|
|
11321
|
+
}
|
|
11322
|
+
return normalizeSpendRequest(data);
|
|
11323
|
+
}
|
|
11217
11324
|
async requestApproval(id) {
|
|
11218
11325
|
const { status, data, rawBody } = await this.apiFetch({
|
|
11219
11326
|
method: "POST",
|
|
@@ -11251,16 +11358,155 @@ var SpendRequestResource = class {
|
|
|
11251
11358
|
return normalizeSpendRequest(data);
|
|
11252
11359
|
}
|
|
11253
11360
|
};
|
|
11361
|
+
var UserInfoResource = class {
|
|
11362
|
+
verbose;
|
|
11363
|
+
getAccessToken;
|
|
11364
|
+
fetchImpl;
|
|
11365
|
+
userInfoEndpoint;
|
|
11366
|
+
logger;
|
|
11367
|
+
constructor(options) {
|
|
11368
|
+
const config = resolveLinkSdkConfig(options);
|
|
11369
|
+
this.verbose = config.verbose;
|
|
11370
|
+
this.getAccessToken = config.getAccessToken;
|
|
11371
|
+
this.fetchImpl = requireFetchImplementation(config);
|
|
11372
|
+
this.userInfoEndpoint = `${config.apiBaseUrl}/userinfo`;
|
|
11373
|
+
this.logger = config.logger;
|
|
11374
|
+
}
|
|
11375
|
+
async rawFetch(opts) {
|
|
11376
|
+
if (this.verbose) {
|
|
11377
|
+
const redactedHeaders = { ...opts.headers };
|
|
11378
|
+
if (redactedHeaders.Authorization)
|
|
11379
|
+
redactedHeaders.Authorization = "Bearer <redacted>";
|
|
11380
|
+
this.logger.debug(`> ${opts.method} ${opts.url}`);
|
|
11381
|
+
this.logger.debug(` Headers: ${JSON.stringify(redactedHeaders)}`);
|
|
11382
|
+
}
|
|
11383
|
+
let response;
|
|
11384
|
+
try {
|
|
11385
|
+
response = await this.fetchImpl(opts.url, {
|
|
11386
|
+
method: opts.method,
|
|
11387
|
+
headers: opts.headers
|
|
11388
|
+
});
|
|
11389
|
+
} catch (error) {
|
|
11390
|
+
throw new LinkTransportError(
|
|
11391
|
+
`Request failed: ${opts.method} ${opts.url}`,
|
|
11392
|
+
{
|
|
11393
|
+
cause: error
|
|
11394
|
+
}
|
|
11395
|
+
);
|
|
11396
|
+
}
|
|
11397
|
+
const rawBody = await response.text();
|
|
11398
|
+
let data = null;
|
|
11399
|
+
try {
|
|
11400
|
+
data = JSON.parse(rawBody);
|
|
11401
|
+
} catch {
|
|
11402
|
+
}
|
|
11403
|
+
if (this.verbose) {
|
|
11404
|
+
this.logger.debug(`< ${response.status} ${response.statusText}`);
|
|
11405
|
+
response.headers.forEach((value, key) => {
|
|
11406
|
+
this.logger.debug(` ${key}: ${value}`);
|
|
11407
|
+
});
|
|
11408
|
+
this.logger.debug(rawBody);
|
|
11409
|
+
}
|
|
11410
|
+
return { status: response.status, data, rawBody };
|
|
11411
|
+
}
|
|
11412
|
+
async apiFetch(opts) {
|
|
11413
|
+
const token = await this.getAccessToken();
|
|
11414
|
+
const authedOpts = {
|
|
11415
|
+
...opts,
|
|
11416
|
+
headers: { ...opts.headers, Authorization: `Bearer ${token}` }
|
|
11417
|
+
};
|
|
11418
|
+
const res = await this.rawFetch(authedOpts);
|
|
11419
|
+
if (res.status === 401) {
|
|
11420
|
+
const refreshedToken = await this.getAccessToken({ forceRefresh: true });
|
|
11421
|
+
authedOpts.headers.Authorization = `Bearer ${refreshedToken}`;
|
|
11422
|
+
return this.rawFetch(authedOpts);
|
|
11423
|
+
}
|
|
11424
|
+
return res;
|
|
11425
|
+
}
|
|
11426
|
+
async retrieve() {
|
|
11427
|
+
const { status, data, rawBody } = await this.apiFetch({
|
|
11428
|
+
method: "GET",
|
|
11429
|
+
url: this.userInfoEndpoint
|
|
11430
|
+
});
|
|
11431
|
+
if (status < 200 || status >= 300) {
|
|
11432
|
+
const body2 = data;
|
|
11433
|
+
const msg = body2?.error ?? body2?.message ?? (rawBody || "unknown error");
|
|
11434
|
+
throw new LinkApiError(
|
|
11435
|
+
`Failed to retrieve user info (${status}): ${msg}`,
|
|
11436
|
+
{
|
|
11437
|
+
status,
|
|
11438
|
+
rawBody,
|
|
11439
|
+
details: data
|
|
11440
|
+
}
|
|
11441
|
+
);
|
|
11442
|
+
}
|
|
11443
|
+
const body = data;
|
|
11444
|
+
return {
|
|
11445
|
+
email: body?.email ?? null,
|
|
11446
|
+
name: body?.name ?? null,
|
|
11447
|
+
first_name: body?.first_name ?? null,
|
|
11448
|
+
last_name: body?.last_name ?? null,
|
|
11449
|
+
phone: body?.phone ?? null
|
|
11450
|
+
};
|
|
11451
|
+
}
|
|
11452
|
+
};
|
|
11453
|
+
|
|
11454
|
+
// src/cli.tsx
|
|
11455
|
+
import { Cli as Cli9 } from "incur";
|
|
11254
11456
|
|
|
11255
11457
|
// src/commands/auth/index.tsx
|
|
11256
11458
|
import { Cli } from "incur";
|
|
11459
|
+
|
|
11460
|
+
// src/utils/poll-until.ts
|
|
11461
|
+
async function* pollUntil(options) {
|
|
11462
|
+
const { fn, isTerminal, interval, timeout, maxAttempts } = options;
|
|
11463
|
+
const deadline = timeout !== void 0 && timeout >= 0 ? Date.now() + timeout * 1e3 : void 0;
|
|
11464
|
+
let attempts = 0;
|
|
11465
|
+
let previousSnapshot;
|
|
11466
|
+
while (true) {
|
|
11467
|
+
const value = await fn();
|
|
11468
|
+
if (isTerminal(value) || interval <= 0) {
|
|
11469
|
+
yield { value, terminal: true };
|
|
11470
|
+
return;
|
|
11471
|
+
}
|
|
11472
|
+
attempts++;
|
|
11473
|
+
const maxAttemptsExhausted = maxAttempts > 0 && attempts >= maxAttempts;
|
|
11474
|
+
const timeoutReached = deadline !== void 0 && Date.now() >= deadline;
|
|
11475
|
+
if (maxAttemptsExhausted) {
|
|
11476
|
+
yield { value, terminal: true, reason: "max_attempts" };
|
|
11477
|
+
return;
|
|
11478
|
+
}
|
|
11479
|
+
if (timeoutReached) {
|
|
11480
|
+
yield { value, terminal: true, reason: "timeout" };
|
|
11481
|
+
return;
|
|
11482
|
+
}
|
|
11483
|
+
const snapshot = JSON.stringify(value);
|
|
11484
|
+
if (snapshot !== previousSnapshot) {
|
|
11485
|
+
previousSnapshot = snapshot;
|
|
11486
|
+
yield { value, terminal: false };
|
|
11487
|
+
}
|
|
11488
|
+
await new Promise((resolve) => setTimeout(resolve, interval * 1e3));
|
|
11489
|
+
}
|
|
11490
|
+
}
|
|
11491
|
+
|
|
11492
|
+
// src/utils/render-interactive.tsx
|
|
11257
11493
|
import { render } from "ink";
|
|
11494
|
+
async function renderInteractive(element, getResult) {
|
|
11495
|
+
const { waitUntilExit } = render(element);
|
|
11496
|
+
await waitUntilExit();
|
|
11497
|
+
if (getResult) {
|
|
11498
|
+
return getResult();
|
|
11499
|
+
}
|
|
11500
|
+
}
|
|
11258
11501
|
|
|
11259
11502
|
// src/commands/auth/login.tsx
|
|
11260
11503
|
import { Box, Text, useInput } from "ink";
|
|
11261
11504
|
import Spinner from "ink-spinner";
|
|
11262
11505
|
import { useEffect, useState } from "react";
|
|
11263
11506
|
|
|
11507
|
+
// src/utils/constants.ts
|
|
11508
|
+
var DISPLAY_DELAY_MS = 1500;
|
|
11509
|
+
|
|
11264
11510
|
// src/utils/open-url.ts
|
|
11265
11511
|
import { spawn } from "child_process";
|
|
11266
11512
|
function openUrl(url) {
|
|
@@ -11292,8 +11538,10 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
11292
11538
|
var Login = ({
|
|
11293
11539
|
authResource,
|
|
11294
11540
|
clientName,
|
|
11541
|
+
authStorage: authStorage2 = storage,
|
|
11295
11542
|
onComplete
|
|
11296
11543
|
}) => {
|
|
11544
|
+
const storage2 = authStorage2;
|
|
11297
11545
|
const [status, setStatus] = useState("initiating");
|
|
11298
11546
|
const [userCode, setUserCode] = useState("");
|
|
11299
11547
|
const [verificationUrl, setVerificationUrl] = useState("");
|
|
@@ -11330,9 +11578,9 @@ var Login = ({
|
|
|
11330
11578
|
const tokens = await authResource.pollDeviceAuth(deviceCode);
|
|
11331
11579
|
if (tokens) {
|
|
11332
11580
|
clearInterval(pollInterval);
|
|
11333
|
-
|
|
11581
|
+
storage2.setAuth(tokens);
|
|
11334
11582
|
setStatus("success");
|
|
11335
|
-
setTimeout(onComplete,
|
|
11583
|
+
setTimeout(onComplete, DISPLAY_DELAY_MS);
|
|
11336
11584
|
}
|
|
11337
11585
|
} catch (err) {
|
|
11338
11586
|
clearInterval(pollInterval);
|
|
@@ -11344,7 +11592,7 @@ var Login = ({
|
|
|
11344
11592
|
};
|
|
11345
11593
|
const timeout = setTimeout(startPolling, 1e3);
|
|
11346
11594
|
return () => clearTimeout(timeout);
|
|
11347
|
-
}, [status, deviceCode, authResource, onComplete]);
|
|
11595
|
+
}, [status, deviceCode, authResource, onComplete, storage2]);
|
|
11348
11596
|
if (status === "initiating") {
|
|
11349
11597
|
return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
|
|
11350
11598
|
/* @__PURE__ */ jsx(Spinner, { type: "dots" }),
|
|
@@ -11397,28 +11645,75 @@ var Login = ({
|
|
|
11397
11645
|
|
|
11398
11646
|
// src/commands/auth/logout.tsx
|
|
11399
11647
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
11400
|
-
import
|
|
11401
|
-
import {
|
|
11402
|
-
|
|
11403
|
-
|
|
11648
|
+
import Spinner2 from "ink-spinner";
|
|
11649
|
+
import { useCallback } from "react";
|
|
11650
|
+
|
|
11651
|
+
// src/hooks/use-async-action.ts
|
|
11652
|
+
import { useEffect as useEffect2, useRef, useState as useState2 } from "react";
|
|
11653
|
+
function useAsyncAction(action, onComplete) {
|
|
11654
|
+
const [status, setStatus] = useState2("loading");
|
|
11655
|
+
const [data, setData] = useState2(null);
|
|
11656
|
+
const [error, setError] = useState2("");
|
|
11657
|
+
const onCompleteRef = useRef(onComplete);
|
|
11658
|
+
onCompleteRef.current = onComplete;
|
|
11404
11659
|
useEffect2(() => {
|
|
11660
|
+
let timeoutId = null;
|
|
11661
|
+
let cancelled = false;
|
|
11405
11662
|
const run = async () => {
|
|
11406
|
-
|
|
11407
|
-
|
|
11408
|
-
|
|
11409
|
-
|
|
11410
|
-
|
|
11411
|
-
|
|
11663
|
+
try {
|
|
11664
|
+
const result = await action();
|
|
11665
|
+
if (cancelled) return;
|
|
11666
|
+
setData(result);
|
|
11667
|
+
setStatus("success");
|
|
11668
|
+
timeoutId = setTimeout(
|
|
11669
|
+
() => onCompleteRef.current(result),
|
|
11670
|
+
DISPLAY_DELAY_MS
|
|
11671
|
+
);
|
|
11672
|
+
} catch (err) {
|
|
11673
|
+
if (cancelled) return;
|
|
11674
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
11675
|
+
setError(message);
|
|
11676
|
+
setStatus("error");
|
|
11677
|
+
timeoutId = setTimeout(
|
|
11678
|
+
() => onCompleteRef.current(null),
|
|
11679
|
+
DISPLAY_DELAY_MS
|
|
11680
|
+
);
|
|
11412
11681
|
}
|
|
11413
|
-
storage.clearAuth();
|
|
11414
|
-
storage.deleteConfig();
|
|
11415
|
-
setDone(true);
|
|
11416
|
-
setTimeout(onComplete, 1e3);
|
|
11417
11682
|
};
|
|
11418
11683
|
run();
|
|
11419
|
-
|
|
11420
|
-
|
|
11421
|
-
|
|
11684
|
+
return () => {
|
|
11685
|
+
cancelled = true;
|
|
11686
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
11687
|
+
};
|
|
11688
|
+
}, [action]);
|
|
11689
|
+
return { status, data, error };
|
|
11690
|
+
}
|
|
11691
|
+
|
|
11692
|
+
// src/commands/auth/logout.tsx
|
|
11693
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
11694
|
+
var Logout = ({
|
|
11695
|
+
authResource,
|
|
11696
|
+
authStorage: authStorage2 = storage,
|
|
11697
|
+
onComplete
|
|
11698
|
+
}) => {
|
|
11699
|
+
const storage2 = authStorage2;
|
|
11700
|
+
const action = useCallback(async () => {
|
|
11701
|
+
const auth = storage2.getAuth();
|
|
11702
|
+
if (auth?.refresh_token) {
|
|
11703
|
+
try {
|
|
11704
|
+
await authResource.revokeToken(auth.refresh_token);
|
|
11705
|
+
} catch {
|
|
11706
|
+
}
|
|
11707
|
+
}
|
|
11708
|
+
storage2.clearAuth();
|
|
11709
|
+
storage2.deleteConfig();
|
|
11710
|
+
}, [authResource, storage2]);
|
|
11711
|
+
const { status } = useAsyncAction(action, onComplete);
|
|
11712
|
+
if (status === "loading") {
|
|
11713
|
+
return /* @__PURE__ */ jsx2(Box2, { children: /* @__PURE__ */ jsxs2(Text2, { color: "cyan", children: [
|
|
11714
|
+
/* @__PURE__ */ jsx2(Spinner2, { type: "dots" }),
|
|
11715
|
+
" Logging out..."
|
|
11716
|
+
] }) });
|
|
11422
11717
|
}
|
|
11423
11718
|
return /* @__PURE__ */ jsx2(Box2, { children: /* @__PURE__ */ jsx2(Text2, { color: "green", children: "\u2713 Logged out successfully" }) });
|
|
11424
11719
|
};
|
|
@@ -11441,16 +11736,20 @@ var statusOptions = z.object({
|
|
|
11441
11736
|
// src/commands/auth/status.tsx
|
|
11442
11737
|
import { Box as Box3, Text as Text3 } from "ink";
|
|
11443
11738
|
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
11444
|
-
import { jsx as jsx3, jsxs as
|
|
11445
|
-
var AuthStatus = ({
|
|
11739
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
11740
|
+
var AuthStatus = ({
|
|
11741
|
+
authStorage: authStorage2 = storage,
|
|
11742
|
+
onComplete
|
|
11743
|
+
}) => {
|
|
11744
|
+
const storage2 = authStorage2;
|
|
11446
11745
|
const [checked, setChecked] = useState3(false);
|
|
11447
11746
|
const [authenticated, setAuthenticated] = useState3(false);
|
|
11448
11747
|
const [tokenPreview, setTokenPreview] = useState3("");
|
|
11449
11748
|
const [tokenType, setTokenType] = useState3("");
|
|
11450
11749
|
const [credentialsPath, setCredentialsPath] = useState3("");
|
|
11451
11750
|
useEffect3(() => {
|
|
11452
|
-
const auth =
|
|
11453
|
-
const credentialsPath2 =
|
|
11751
|
+
const auth = storage2.getAuth();
|
|
11752
|
+
const credentialsPath2 = storage2.getPath();
|
|
11454
11753
|
if (auth) {
|
|
11455
11754
|
setAuthenticated(true);
|
|
11456
11755
|
setTokenPreview(`${auth.access_token.substring(0, 20)}...`);
|
|
@@ -11458,34 +11757,34 @@ var AuthStatus = ({ onComplete }) => {
|
|
|
11458
11757
|
}
|
|
11459
11758
|
setCredentialsPath(credentialsPath2);
|
|
11460
11759
|
setChecked(true);
|
|
11461
|
-
setTimeout(onComplete,
|
|
11462
|
-
}, [onComplete]);
|
|
11760
|
+
setTimeout(onComplete, DISPLAY_DELAY_MS);
|
|
11761
|
+
}, [onComplete, storage2]);
|
|
11463
11762
|
if (!checked) {
|
|
11464
11763
|
return null;
|
|
11465
11764
|
}
|
|
11466
11765
|
if (authenticated) {
|
|
11467
|
-
return /* @__PURE__ */
|
|
11766
|
+
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
|
|
11468
11767
|
/* @__PURE__ */ jsx3(Text3, { color: "green", children: "\u2713 Authenticated" }),
|
|
11469
|
-
/* @__PURE__ */
|
|
11470
|
-
/* @__PURE__ */
|
|
11768
|
+
/* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
11769
|
+
/* @__PURE__ */ jsxs3(Text3, { children: [
|
|
11471
11770
|
"Access token: ",
|
|
11472
11771
|
/* @__PURE__ */ jsx3(Text3, { bold: true, children: tokenPreview })
|
|
11473
11772
|
] }),
|
|
11474
|
-
/* @__PURE__ */
|
|
11773
|
+
/* @__PURE__ */ jsxs3(Text3, { children: [
|
|
11475
11774
|
"Token type: ",
|
|
11476
11775
|
/* @__PURE__ */ jsx3(Text3, { bold: true, children: tokenType })
|
|
11477
11776
|
] }),
|
|
11478
|
-
/* @__PURE__ */
|
|
11777
|
+
/* @__PURE__ */ jsxs3(Text3, { children: [
|
|
11479
11778
|
"Credentials: ",
|
|
11480
11779
|
/* @__PURE__ */ jsx3(Text3, { bold: true, children: credentialsPath })
|
|
11481
11780
|
] })
|
|
11482
11781
|
] })
|
|
11483
11782
|
] });
|
|
11484
11783
|
}
|
|
11485
|
-
return /* @__PURE__ */
|
|
11784
|
+
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
|
|
11486
11785
|
/* @__PURE__ */ jsx3(Text3, { color: "yellow", children: "\u2717 Not authenticated" }),
|
|
11487
11786
|
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: 'Run "link-cli auth login" to authenticate' }),
|
|
11488
|
-
/* @__PURE__ */ jsx3(Box3, { marginTop: 1, paddingX: 2, children: /* @__PURE__ */
|
|
11787
|
+
/* @__PURE__ */ jsx3(Box3, { marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsxs3(Text3, { children: [
|
|
11489
11788
|
"Credentials: ",
|
|
11490
11789
|
/* @__PURE__ */ jsx3(Text3, { bold: true, children: credentialsPath })
|
|
11491
11790
|
] }) })
|
|
@@ -11494,7 +11793,8 @@ var AuthStatus = ({ onComplete }) => {
|
|
|
11494
11793
|
|
|
11495
11794
|
// src/commands/auth/index.tsx
|
|
11496
11795
|
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
11497
|
-
function createAuthCli(authResource, getUpdateInfo2) {
|
|
11796
|
+
function createAuthCli(authResource, getUpdateInfo2, authStorage2) {
|
|
11797
|
+
const storage2 = authStorage2 ?? storage;
|
|
11498
11798
|
const cli2 = Cli.create("auth", {
|
|
11499
11799
|
description: "Authentication commands"
|
|
11500
11800
|
});
|
|
@@ -11511,25 +11811,22 @@ function createAuthCli(authResource, getUpdateInfo2) {
|
|
|
11511
11811
|
});
|
|
11512
11812
|
}
|
|
11513
11813
|
if (!c.agent && !c.formatExplicit) {
|
|
11514
|
-
return
|
|
11515
|
-
|
|
11516
|
-
|
|
11517
|
-
|
|
11518
|
-
|
|
11519
|
-
|
|
11520
|
-
|
|
11521
|
-
|
|
11522
|
-
}
|
|
11814
|
+
return renderInteractive(
|
|
11815
|
+
/* @__PURE__ */ jsx4(
|
|
11816
|
+
Login,
|
|
11817
|
+
{
|
|
11818
|
+
authResource,
|
|
11819
|
+
clientName,
|
|
11820
|
+
authStorage: storage2,
|
|
11821
|
+
onComplete: () => {
|
|
11523
11822
|
}
|
|
11524
|
-
|
|
11525
|
-
)
|
|
11526
|
-
|
|
11527
|
-
|
|
11528
|
-
);
|
|
11529
|
-
});
|
|
11823
|
+
}
|
|
11824
|
+
),
|
|
11825
|
+
() => ({ authenticated: true, token_type: "Bearer" })
|
|
11826
|
+
);
|
|
11530
11827
|
}
|
|
11531
11828
|
const authRequest = await authResource.initiateDeviceAuth(clientName);
|
|
11532
|
-
|
|
11829
|
+
storage2.setPendingDeviceAuth({
|
|
11533
11830
|
device_code: authRequest.device_code,
|
|
11534
11831
|
interval: authRequest.interval,
|
|
11535
11832
|
expires_at: Date.now() + authRequest.expires_in * 1e3,
|
|
@@ -11552,25 +11849,30 @@ function createAuthCli(authResource, getUpdateInfo2) {
|
|
|
11552
11849
|
description: "Log out from Link",
|
|
11553
11850
|
outputPolicy: "agent-only",
|
|
11554
11851
|
async run(c) {
|
|
11555
|
-
const auth =
|
|
11852
|
+
const auth = storage2.getAuth();
|
|
11556
11853
|
if (auth?.refresh_token) {
|
|
11557
11854
|
try {
|
|
11558
11855
|
await authResource.revokeToken(auth.refresh_token);
|
|
11559
11856
|
} catch {
|
|
11560
11857
|
}
|
|
11561
11858
|
}
|
|
11562
|
-
|
|
11563
|
-
|
|
11564
|
-
|
|
11859
|
+
storage2.clearAuth();
|
|
11860
|
+
storage2.clearPendingDeviceAuth();
|
|
11861
|
+
storage2.deleteConfig();
|
|
11565
11862
|
const result = { authenticated: false };
|
|
11566
11863
|
if (!c.agent && !c.formatExplicit) {
|
|
11567
|
-
return
|
|
11568
|
-
|
|
11569
|
-
|
|
11570
|
-
|
|
11571
|
-
|
|
11572
|
-
|
|
11573
|
-
|
|
11864
|
+
return renderInteractive(
|
|
11865
|
+
/* @__PURE__ */ jsx4(
|
|
11866
|
+
Logout,
|
|
11867
|
+
{
|
|
11868
|
+
authResource,
|
|
11869
|
+
authStorage: storage2,
|
|
11870
|
+
onComplete: () => {
|
|
11871
|
+
}
|
|
11872
|
+
}
|
|
11873
|
+
),
|
|
11874
|
+
() => result
|
|
11875
|
+
);
|
|
11574
11876
|
}
|
|
11575
11877
|
return result;
|
|
11576
11878
|
}
|
|
@@ -11583,7 +11885,6 @@ function createAuthCli(authResource, getUpdateInfo2) {
|
|
|
11583
11885
|
const opts = c.options;
|
|
11584
11886
|
const interval = opts.interval;
|
|
11585
11887
|
const maxAttempts = opts.maxAttempts;
|
|
11586
|
-
const deadline = Date.now() + opts.timeout * 1e3;
|
|
11587
11888
|
const updateInfo = await getUpdateInfo2?.({
|
|
11588
11889
|
polling: interval > 0
|
|
11589
11890
|
});
|
|
@@ -11593,70 +11894,63 @@ function createAuthCli(authResource, getUpdateInfo2) {
|
|
|
11593
11894
|
update_command: "npm install -g @stripe/link-cli"
|
|
11594
11895
|
} : void 0;
|
|
11595
11896
|
if (!c.agent && !c.formatExplicit) {
|
|
11596
|
-
return
|
|
11597
|
-
|
|
11598
|
-
|
|
11599
|
-
|
|
11600
|
-
|
|
11601
|
-
|
|
11602
|
-
const auth = storage.getAuth();
|
|
11603
|
-
resolve({
|
|
11897
|
+
return renderInteractive(
|
|
11898
|
+
/* @__PURE__ */ jsx4(AuthStatus, { authStorage: storage2, onComplete: () => {
|
|
11899
|
+
} }),
|
|
11900
|
+
() => {
|
|
11901
|
+
const auth = storage2.getAuth();
|
|
11902
|
+
return {
|
|
11604
11903
|
authenticated: !!auth,
|
|
11605
11904
|
...auth ? {
|
|
11606
11905
|
access_token: `${auth.access_token.substring(0, 20)}...`,
|
|
11607
11906
|
token_type: auth.token_type
|
|
11608
11907
|
} : {},
|
|
11609
|
-
credentials_path:
|
|
11908
|
+
credentials_path: storage2.getPath(),
|
|
11610
11909
|
...update && { update }
|
|
11611
|
-
}
|
|
11612
|
-
}
|
|
11613
|
-
|
|
11910
|
+
};
|
|
11911
|
+
}
|
|
11912
|
+
);
|
|
11614
11913
|
}
|
|
11615
|
-
|
|
11616
|
-
|
|
11617
|
-
|
|
11618
|
-
|
|
11619
|
-
|
|
11620
|
-
|
|
11621
|
-
|
|
11622
|
-
|
|
11623
|
-
|
|
11624
|
-
|
|
11625
|
-
|
|
11626
|
-
|
|
11627
|
-
|
|
11628
|
-
|
|
11629
|
-
|
|
11630
|
-
|
|
11631
|
-
|
|
11632
|
-
|
|
11633
|
-
|
|
11914
|
+
for await (const result of pollUntil({
|
|
11915
|
+
fn: async () => {
|
|
11916
|
+
const pending = storage2.getPendingDeviceAuth();
|
|
11917
|
+
if (pending && !storage2.isAuthenticated()) {
|
|
11918
|
+
const tokens = await authResource.pollDeviceAuth(
|
|
11919
|
+
pending.device_code
|
|
11920
|
+
);
|
|
11921
|
+
if (tokens) {
|
|
11922
|
+
storage2.setAuth(tokens);
|
|
11923
|
+
storage2.clearPendingDeviceAuth();
|
|
11924
|
+
}
|
|
11925
|
+
}
|
|
11926
|
+
const auth = storage2.getAuth();
|
|
11927
|
+
if (auth) {
|
|
11928
|
+
return {
|
|
11929
|
+
authenticated: true,
|
|
11930
|
+
access_token: `${auth.access_token.substring(0, 20)}...`,
|
|
11931
|
+
token_type: auth.token_type,
|
|
11932
|
+
credentials_path: storage2.getPath(),
|
|
11933
|
+
...update && { update }
|
|
11934
|
+
};
|
|
11935
|
+
}
|
|
11936
|
+
const currentPending = storage2.getPendingDeviceAuth();
|
|
11937
|
+
return {
|
|
11938
|
+
authenticated: false,
|
|
11939
|
+
credentials_path: storage2.getPath(),
|
|
11940
|
+
...update && { update },
|
|
11941
|
+
...currentPending ? {
|
|
11942
|
+
pending: true,
|
|
11943
|
+
verification_url: currentPending.verification_url,
|
|
11944
|
+
phrase: currentPending.phrase
|
|
11945
|
+
} : {}
|
|
11634
11946
|
};
|
|
11635
|
-
|
|
11636
|
-
|
|
11637
|
-
|
|
11638
|
-
|
|
11639
|
-
|
|
11640
|
-
|
|
11641
|
-
|
|
11642
|
-
...currentPending ? {
|
|
11643
|
-
pending: true,
|
|
11644
|
-
verification_url: currentPending.verification_url,
|
|
11645
|
-
phrase: currentPending.phrase
|
|
11646
|
-
} : {}
|
|
11647
|
-
};
|
|
11648
|
-
attempts++;
|
|
11649
|
-
const shouldStop = interval <= 0 || maxAttempts > 0 && attempts >= maxAttempts || Date.now() >= deadline;
|
|
11650
|
-
if (shouldStop) {
|
|
11651
|
-
yield status;
|
|
11652
|
-
return;
|
|
11653
|
-
}
|
|
11654
|
-
const snapshot = JSON.stringify(status);
|
|
11655
|
-
if (snapshot !== previousAttemptData) {
|
|
11656
|
-
previousAttemptData = snapshot;
|
|
11657
|
-
yield status;
|
|
11658
|
-
}
|
|
11659
|
-
await new Promise((resolve) => setTimeout(resolve, interval * 1e3));
|
|
11947
|
+
},
|
|
11948
|
+
isTerminal: (status) => status.authenticated,
|
|
11949
|
+
interval,
|
|
11950
|
+
maxAttempts,
|
|
11951
|
+
timeout: opts.timeout
|
|
11952
|
+
})) {
|
|
11953
|
+
yield result.value;
|
|
11660
11954
|
}
|
|
11661
11955
|
}
|
|
11662
11956
|
});
|
|
@@ -11665,11 +11959,10 @@ function createAuthCli(authResource, getUpdateInfo2) {
|
|
|
11665
11959
|
|
|
11666
11960
|
// src/commands/demo/index.tsx
|
|
11667
11961
|
import { Cli as Cli2, z as z2 } from "incur";
|
|
11668
|
-
import { render as render2 } from "ink";
|
|
11669
11962
|
|
|
11670
11963
|
// src/commands/demo/demo-runner.tsx
|
|
11671
|
-
import { Box as Box8, Text as Text9, useInput as useInput4 } from "ink";
|
|
11672
|
-
import { useCallback, useState as useState7 } from "react";
|
|
11964
|
+
import { Box as Box8, Text as Text9, useApp, useInput as useInput4 } from "ink";
|
|
11965
|
+
import { useCallback as useCallback2, useState as useState7 } from "react";
|
|
11673
11966
|
|
|
11674
11967
|
// src/utils/markdown-text.tsx
|
|
11675
11968
|
import { Text as Text4 } from "ink";
|
|
@@ -11758,13 +12051,13 @@ function renderQrMatrix(url) {
|
|
|
11758
12051
|
}
|
|
11759
12052
|
|
|
11760
12053
|
// src/commands/spend-request/app-download-qr-codes.tsx
|
|
11761
|
-
import { jsx as jsx6, jsxs as
|
|
12054
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
11762
12055
|
var DOWNLOAD_URL = "https://link.com/download";
|
|
11763
12056
|
var AppDownloadQrCodes = () => {
|
|
11764
12057
|
const qrLines = useMemo(() => renderQrMatrix(DOWNLOAD_URL), []);
|
|
11765
|
-
return /* @__PURE__ */
|
|
12058
|
+
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: 1, children: [
|
|
11766
12059
|
/* @__PURE__ */ jsx6(Text5, { dimColor: true, children: "Get the Link app to approve spend requests from your phone" }),
|
|
11767
|
-
/* @__PURE__ */
|
|
12060
|
+
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", alignItems: "flex-start", marginTop: 1, children: [
|
|
11768
12061
|
qrLines.map((line, i) => (
|
|
11769
12062
|
// biome-ignore lint/suspicious/noArrayIndexKey: stable static array
|
|
11770
12063
|
/* @__PURE__ */ jsx6(Text5, { children: line }, i)
|
|
@@ -11776,7 +12069,7 @@ var AppDownloadQrCodes = () => {
|
|
|
11776
12069
|
|
|
11777
12070
|
// src/commands/demo/card-flow.tsx
|
|
11778
12071
|
import { Box as Box5, Text as Text6, useInput as useInput2 } from "ink";
|
|
11779
|
-
import { useEffect as useEffect4, useRef, useState as useState4 } from "react";
|
|
12072
|
+
import { useEffect as useEffect4, useRef as useRef2, useState as useState4 } from "react";
|
|
11780
12073
|
|
|
11781
12074
|
// src/utils/poll-until-approved.ts
|
|
11782
12075
|
function pollUntilApproved(repository, id, options = {}) {
|
|
@@ -11940,7 +12233,7 @@ var ONBOARD = {
|
|
|
11940
12233
|
};
|
|
11941
12234
|
|
|
11942
12235
|
// src/commands/demo/card-flow.tsx
|
|
11943
|
-
import { Fragment, jsx as jsx7, jsxs as
|
|
12236
|
+
import { Fragment, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
11944
12237
|
function formatPmLabel(pm) {
|
|
11945
12238
|
return `${pm.card_details?.brand ?? pm.type} ****${pm.card_details?.last4 ?? ""}`;
|
|
11946
12239
|
}
|
|
@@ -11965,11 +12258,11 @@ var CardFlow = ({
|
|
|
11965
12258
|
const [spendRequest, setSpendRequest] = useState4(null);
|
|
11966
12259
|
const [error, setError] = useState4("");
|
|
11967
12260
|
const approvalUrl = spendRequest?.approval_url ?? "";
|
|
11968
|
-
const enterResolver =
|
|
11969
|
-
const pmResolver =
|
|
11970
|
-
const retryChoiceResolver =
|
|
11971
|
-
function waitForEnter() {
|
|
11972
|
-
return new Promise((resolve) => {
|
|
12261
|
+
const enterResolver = useRef2(null);
|
|
12262
|
+
const pmResolver = useRef2(null);
|
|
12263
|
+
const retryChoiceResolver = useRef2(null);
|
|
12264
|
+
function waitForEnter() {
|
|
12265
|
+
return new Promise((resolve) => {
|
|
11973
12266
|
enterResolver.current = resolve;
|
|
11974
12267
|
});
|
|
11975
12268
|
}
|
|
@@ -12015,7 +12308,7 @@ var CardFlow = ({
|
|
|
12015
12308
|
}
|
|
12016
12309
|
}
|
|
12017
12310
|
});
|
|
12018
|
-
const started =
|
|
12311
|
+
const started = useRef2(false);
|
|
12019
12312
|
useEffect4(() => {
|
|
12020
12313
|
if (started.current) return;
|
|
12021
12314
|
started.current = true;
|
|
@@ -12066,7 +12359,12 @@ var CardFlow = ({
|
|
|
12066
12359
|
setStep("await-approval");
|
|
12067
12360
|
for (; ; ) {
|
|
12068
12361
|
try {
|
|
12069
|
-
await pollUntilApproved(spendRequestRepo2, result.id);
|
|
12362
|
+
const final = await pollUntilApproved(spendRequestRepo2, result.id);
|
|
12363
|
+
if (final.status !== "approved") {
|
|
12364
|
+
throw new Error(
|
|
12365
|
+
`Spend request did not reach approved (status: ${final.status})`
|
|
12366
|
+
);
|
|
12367
|
+
}
|
|
12070
12368
|
break;
|
|
12071
12369
|
} catch (err) {
|
|
12072
12370
|
if (err.message === "Approval polling timed out") {
|
|
@@ -12119,21 +12417,21 @@ var CardFlow = ({
|
|
|
12119
12417
|
];
|
|
12120
12418
|
return order.indexOf(step) > order.indexOf(target);
|
|
12121
12419
|
};
|
|
12122
|
-
const prompt = (label = "Press [Enter] to continue") => /* @__PURE__ */
|
|
12420
|
+
const prompt = (label = "Press [Enter] to continue") => /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
|
|
12123
12421
|
"\n",
|
|
12124
12422
|
">",
|
|
12125
12423
|
" ",
|
|
12126
12424
|
label
|
|
12127
12425
|
] });
|
|
12128
|
-
return /* @__PURE__ */
|
|
12426
|
+
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", gap: 1, children: [
|
|
12129
12427
|
/* @__PURE__ */ jsx7(Text6, { bold: true, color: "cyan", children: CARD_FLOW.title }),
|
|
12130
|
-
/* @__PURE__ */
|
|
12131
|
-
/* @__PURE__ */
|
|
12428
|
+
/* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
12429
|
+
/* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", gap: 1, children: [
|
|
12132
12430
|
/* @__PURE__ */ jsx7(Text6, { color: "yellow", children: "[testmode]" }),
|
|
12133
12431
|
/* @__PURE__ */ jsx7(Text6, { dimColor: true, children: DEMO_MERCHANT_URL })
|
|
12134
12432
|
] }),
|
|
12135
12433
|
/* @__PURE__ */ jsx7(MarkdownText, { children: CARD_FLOW.intro.description }),
|
|
12136
|
-
/* @__PURE__ */
|
|
12434
|
+
/* @__PURE__ */ jsxs5(Box5, { marginTop: 1, flexDirection: "column", children: [
|
|
12137
12435
|
/* @__PURE__ */ jsx7(Text6, { children: "What happens:" }),
|
|
12138
12436
|
CARD_FLOW.intro.steps.map((s, i) => {
|
|
12139
12437
|
const doneAfter = [
|
|
@@ -12150,17 +12448,17 @@ var CardFlow = ({
|
|
|
12150
12448
|
];
|
|
12151
12449
|
const done = pastStep(doneAfter[i]);
|
|
12152
12450
|
const active = !done && (step === activeFrom[i] || pastStep(activeFrom[i]));
|
|
12153
|
-
return done ? /* @__PURE__ */
|
|
12451
|
+
return done ? /* @__PURE__ */ jsxs5(Text6, { dimColor: true, strikethrough: true, children: [
|
|
12154
12452
|
" ",
|
|
12155
12453
|
i + 1,
|
|
12156
12454
|
". ",
|
|
12157
12455
|
s
|
|
12158
|
-
] }, s) : active ? /* @__PURE__ */
|
|
12456
|
+
] }, s) : active ? /* @__PURE__ */ jsxs5(Text6, { bold: true, color: "cyan", children: [
|
|
12159
12457
|
" ",
|
|
12160
12458
|
i + 1,
|
|
12161
12459
|
". ",
|
|
12162
12460
|
s
|
|
12163
|
-
] }, s) : /* @__PURE__ */
|
|
12461
|
+
] }, s) : /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
|
|
12164
12462
|
" ",
|
|
12165
12463
|
i + 1,
|
|
12166
12464
|
". ",
|
|
@@ -12171,23 +12469,23 @@ var CardFlow = ({
|
|
|
12171
12469
|
step === "intro" && prompt(CARD_FLOW.intro.prompt)
|
|
12172
12470
|
] }),
|
|
12173
12471
|
step === "fetch-pm" && /* @__PURE__ */ jsx7(Box5, { flexDirection: "column", children: /* @__PURE__ */ jsx7(Text6, { dimColor: true, children: "Fetching payment methods from your Link wallet..." }) }),
|
|
12174
|
-
(step === "pick-pm" || step === "explain-pm") && /* @__PURE__ */
|
|
12175
|
-
step === "pick-pm" && paymentMethods.length > 1 && /* @__PURE__ */
|
|
12472
|
+
(step === "pick-pm" || step === "explain-pm") && /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
12473
|
+
step === "pick-pm" && paymentMethods.length > 1 && /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
12176
12474
|
/* @__PURE__ */ jsx7(Text6, { children: "Which payment method should we use for the demo?" }),
|
|
12177
|
-
/* @__PURE__ */ jsx7(Box5, { flexDirection: "column", marginTop: 1, children: paymentMethods.map((pm, i) => /* @__PURE__ */ jsx7(Text6, { children: i === selectedPmIndex ? /* @__PURE__ */
|
|
12475
|
+
/* @__PURE__ */ jsx7(Box5, { flexDirection: "column", marginTop: 1, children: paymentMethods.map((pm, i) => /* @__PURE__ */ jsx7(Text6, { children: i === selectedPmIndex ? /* @__PURE__ */ jsxs5(Text6, { color: "cyan", bold: true, children: [
|
|
12178
12476
|
">",
|
|
12179
12477
|
" ",
|
|
12180
12478
|
formatPmLabel(pm),
|
|
12181
12479
|
pm.is_default ? " (default)" : ""
|
|
12182
|
-
] }) : /* @__PURE__ */
|
|
12480
|
+
] }) : /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
|
|
12183
12481
|
" ",
|
|
12184
12482
|
formatPmLabel(pm),
|
|
12185
12483
|
pm.is_default ? " (default)" : ""
|
|
12186
12484
|
] }) }, pm.id)) }),
|
|
12187
12485
|
/* @__PURE__ */ jsx7(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text6, { dimColor: true, children: "Use \u2191\u2193 to select, [Enter] to confirm" }) })
|
|
12188
12486
|
] }),
|
|
12189
|
-
paymentMethod && /* @__PURE__ */
|
|
12190
|
-
/* @__PURE__ */
|
|
12487
|
+
paymentMethod && /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
12488
|
+
/* @__PURE__ */ jsxs5(Text6, { color: "green", children: [
|
|
12191
12489
|
"\u2713 Using ",
|
|
12192
12490
|
/* @__PURE__ */ jsx7(Text6, { bold: true, children: pmLabel }),
|
|
12193
12491
|
paymentMethod.is_default ? " (default)" : ""
|
|
@@ -12195,19 +12493,19 @@ var CardFlow = ({
|
|
|
12195
12493
|
step === "explain-pm" && prompt(CARD_FLOW.explainPm.prompt)
|
|
12196
12494
|
] })
|
|
12197
12495
|
] }),
|
|
12198
|
-
step === "create-spend" && /* @__PURE__ */
|
|
12496
|
+
step === "create-spend" && /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
12199
12497
|
/* @__PURE__ */ jsx7(MarkdownText, { children: CARD_FLOW.createSpend.description }),
|
|
12200
12498
|
/* @__PURE__ */ jsx7(Box5, { marginY: 1, children: /* @__PURE__ */ jsx7(Text6, { color: "cyan", children: CARD_FLOW.createSpend.loading }) })
|
|
12201
12499
|
] }),
|
|
12202
|
-
(step === "await-approval" || step === "approval-timeout") && spendRequest && /* @__PURE__ */
|
|
12203
|
-
/* @__PURE__ */
|
|
12500
|
+
(step === "await-approval" || step === "approval-timeout") && spendRequest && /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
12501
|
+
/* @__PURE__ */ jsxs5(Text6, { color: "green", children: [
|
|
12204
12502
|
"\u2713 Spend request created (",
|
|
12205
12503
|
spendRequest.id,
|
|
12206
12504
|
")"
|
|
12207
12505
|
] }),
|
|
12208
|
-
step === "await-approval" && /* @__PURE__ */
|
|
12506
|
+
step === "await-approval" && /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
12209
12507
|
/* @__PURE__ */ jsx7(Text6, { children: CARD_FLOW.approval.description }),
|
|
12210
|
-
/* @__PURE__ */
|
|
12508
|
+
/* @__PURE__ */ jsxs5(
|
|
12211
12509
|
Box5,
|
|
12212
12510
|
{
|
|
12213
12511
|
flexDirection: "column",
|
|
@@ -12217,7 +12515,7 @@ var CardFlow = ({
|
|
|
12217
12515
|
paddingY: 1,
|
|
12218
12516
|
marginTop: 1,
|
|
12219
12517
|
children: [
|
|
12220
|
-
/* @__PURE__ */
|
|
12518
|
+
/* @__PURE__ */ jsxs5(Text6, { children: [
|
|
12221
12519
|
"Approve at:",
|
|
12222
12520
|
" ",
|
|
12223
12521
|
/* @__PURE__ */ jsx7(Text6, { bold: true, color: "cyan", children: approvalUrl })
|
|
@@ -12228,9 +12526,9 @@ var CardFlow = ({
|
|
|
12228
12526
|
),
|
|
12229
12527
|
/* @__PURE__ */ jsx7(Box5, { marginY: 1, children: /* @__PURE__ */ jsx7(Text6, { color: "cyan", children: CARD_FLOW.approval.loading }) })
|
|
12230
12528
|
] }),
|
|
12231
|
-
step === "approval-timeout" && /* @__PURE__ */
|
|
12529
|
+
step === "approval-timeout" && /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
12232
12530
|
/* @__PURE__ */ jsx7(Text6, { color: "yellow", children: "\u26A0 Approval timed out (5 min). Still pending \u2014 you can still approve." }),
|
|
12233
|
-
/* @__PURE__ */
|
|
12531
|
+
/* @__PURE__ */ jsxs5(
|
|
12234
12532
|
Box5,
|
|
12235
12533
|
{
|
|
12236
12534
|
flexDirection: "column",
|
|
@@ -12240,7 +12538,7 @@ var CardFlow = ({
|
|
|
12240
12538
|
paddingY: 1,
|
|
12241
12539
|
marginTop: 1,
|
|
12242
12540
|
children: [
|
|
12243
|
-
/* @__PURE__ */
|
|
12541
|
+
/* @__PURE__ */ jsxs5(Text6, { children: [
|
|
12244
12542
|
"Approve at:",
|
|
12245
12543
|
" ",
|
|
12246
12544
|
/* @__PURE__ */ jsx7(Text6, { bold: true, color: "cyan", children: approvalUrl })
|
|
@@ -12252,10 +12550,10 @@ var CardFlow = ({
|
|
|
12252
12550
|
/* @__PURE__ */ jsx7(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text6, { dimColor: true, children: "r Retry polling q Quit demo" }) })
|
|
12253
12551
|
] })
|
|
12254
12552
|
] }),
|
|
12255
|
-
(step === "show-card" || step === "open-url" || step === "done") && card && /* @__PURE__ */
|
|
12553
|
+
(step === "show-card" || step === "open-url" || step === "done") && card && /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
12256
12554
|
/* @__PURE__ */ jsx7(Text6, { color: "green", children: "\u2713 Approved!" }),
|
|
12257
12555
|
/* @__PURE__ */ jsx7(MarkdownText, { children: CARD_FLOW.showCard.description }),
|
|
12258
|
-
/* @__PURE__ */ jsx7(Box5, { flexDirection: "column", paddingX: 2, marginTop: 1, children: /* @__PURE__ */
|
|
12556
|
+
/* @__PURE__ */ jsx7(Box5, { flexDirection: "column", paddingX: 2, marginTop: 1, children: /* @__PURE__ */ jsxs5(Text6, { children: [
|
|
12259
12557
|
/* @__PURE__ */ jsx7(Text6, { dimColor: true, children: "Number " }),
|
|
12260
12558
|
/* @__PURE__ */ jsx7(Text6, { bold: true, children: formatCardNumber(card.number) }),
|
|
12261
12559
|
" ",
|
|
@@ -12264,14 +12562,14 @@ var CardFlow = ({
|
|
|
12264
12562
|
" ",
|
|
12265
12563
|
/* @__PURE__ */ jsx7(Text6, { dimColor: true, children: "CVC " }),
|
|
12266
12564
|
/* @__PURE__ */ jsx7(Text6, { bold: true, children: card.cvc }),
|
|
12267
|
-
card.billing_address?.postal_code && /* @__PURE__ */
|
|
12565
|
+
card.billing_address?.postal_code && /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
12268
12566
|
" ",
|
|
12269
12567
|
/* @__PURE__ */ jsx7(Text6, { dimColor: true, children: "Zip " }),
|
|
12270
12568
|
/* @__PURE__ */ jsx7(Text6, { bold: true, children: card.billing_address.postal_code })
|
|
12271
12569
|
] }),
|
|
12272
|
-
card.valid_until && /* @__PURE__ */
|
|
12570
|
+
card.valid_until && /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
12273
12571
|
" ",
|
|
12274
|
-
/* @__PURE__ */
|
|
12572
|
+
/* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
|
|
12275
12573
|
"expires",
|
|
12276
12574
|
" ",
|
|
12277
12575
|
new Date(card.valid_until).toLocaleTimeString([], {
|
|
@@ -12283,14 +12581,14 @@ var CardFlow = ({
|
|
|
12283
12581
|
] }) }),
|
|
12284
12582
|
step === "show-card" && prompt(CARD_FLOW.showCard.prompt)
|
|
12285
12583
|
] }),
|
|
12286
|
-
step === "done" && /* @__PURE__ */
|
|
12287
|
-
/* @__PURE__ */
|
|
12584
|
+
step === "done" && /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
12585
|
+
/* @__PURE__ */ jsxs5(Text6, { color: "green", children: [
|
|
12288
12586
|
"\u2713 ",
|
|
12289
12587
|
CARD_FLOW.done.success
|
|
12290
12588
|
] }),
|
|
12291
12589
|
/* @__PURE__ */ jsx7(Text6, { children: CARD_FLOW.done.detail })
|
|
12292
12590
|
] }),
|
|
12293
|
-
step === "error" && /* @__PURE__ */
|
|
12591
|
+
step === "error" && /* @__PURE__ */ jsxs5(Text6, { color: "red", children: [
|
|
12294
12592
|
"Error: ",
|
|
12295
12593
|
error
|
|
12296
12594
|
] })
|
|
@@ -12299,20 +12597,20 @@ var CardFlow = ({
|
|
|
12299
12597
|
|
|
12300
12598
|
// src/commands/demo/spt-flow.tsx
|
|
12301
12599
|
import { Box as Box7, Text as Text8, useInput as useInput3 } from "ink";
|
|
12302
|
-
import { useEffect as useEffect6, useRef as
|
|
12600
|
+
import { useEffect as useEffect6, useRef as useRef3, useState as useState6 } from "react";
|
|
12303
12601
|
|
|
12304
12602
|
// src/commands/mpp/decode.ts
|
|
12305
12603
|
import { Challenge } from "mppx";
|
|
12306
|
-
function getString(value,
|
|
12604
|
+
function getString(value, path7, required = true) {
|
|
12307
12605
|
if (value == null) {
|
|
12308
12606
|
if (required) {
|
|
12309
|
-
throw new Error(`Invalid stripe challenge request: ${
|
|
12607
|
+
throw new Error(`Invalid stripe challenge request: ${path7}: missing`);
|
|
12310
12608
|
}
|
|
12311
12609
|
return void 0;
|
|
12312
12610
|
}
|
|
12313
12611
|
if (typeof value !== "string") {
|
|
12314
12612
|
throw new Error(
|
|
12315
|
-
`Invalid stripe challenge request: ${
|
|
12613
|
+
`Invalid stripe challenge request: ${path7}: expected string, received ${typeof value}`
|
|
12316
12614
|
);
|
|
12317
12615
|
}
|
|
12318
12616
|
return value;
|
|
@@ -12381,12 +12679,12 @@ function decodeStripeChallenge(challengeHeader) {
|
|
|
12381
12679
|
|
|
12382
12680
|
// src/commands/mpp/pay.tsx
|
|
12383
12681
|
import { Box as Box6, Text as Text7 } from "ink";
|
|
12384
|
-
import
|
|
12682
|
+
import Spinner3 from "ink-spinner";
|
|
12385
12683
|
import { Credential, Method } from "mppx";
|
|
12386
12684
|
import { Mppx, Transport } from "mppx/client";
|
|
12387
12685
|
import { Methods as StripeMethods } from "mppx/stripe";
|
|
12388
12686
|
import { useEffect as useEffect5, useState as useState5 } from "react";
|
|
12389
|
-
import { jsx as jsx8, jsxs as
|
|
12687
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
12390
12688
|
function buildHeaders(data, headers) {
|
|
12391
12689
|
const result = {};
|
|
12392
12690
|
if (data !== void 0) {
|
|
@@ -12401,14 +12699,9 @@ function buildHeaders(data, headers) {
|
|
|
12401
12699
|
}
|
|
12402
12700
|
return result;
|
|
12403
12701
|
}
|
|
12404
|
-
async function readPayResult(response
|
|
12702
|
+
async function readPayResult(response) {
|
|
12405
12703
|
const responseHeaders = Object.fromEntries(response.headers.entries());
|
|
12406
12704
|
const body = await response.text();
|
|
12407
|
-
if (options?.failOnError && !response.ok) {
|
|
12408
|
-
throw new Error(
|
|
12409
|
-
`Payment submission failed with status ${response.status}: ${body}`
|
|
12410
|
-
);
|
|
12411
|
-
}
|
|
12412
12705
|
return { status: response.status, headers: responseHeaders, body };
|
|
12413
12706
|
}
|
|
12414
12707
|
function createStripePaymentClient(spt) {
|
|
@@ -12480,7 +12773,7 @@ async function runMppPay(url, spendRequestId, method, data, headers, repository)
|
|
|
12480
12773
|
Authorization: authHeader
|
|
12481
12774
|
}
|
|
12482
12775
|
});
|
|
12483
|
-
return readPayResult(retryResponse
|
|
12776
|
+
return readPayResult(retryResponse);
|
|
12484
12777
|
}
|
|
12485
12778
|
function MppPay({
|
|
12486
12779
|
url,
|
|
@@ -12528,9 +12821,10 @@ function MppPay({
|
|
|
12528
12821
|
headers: requestHeaders
|
|
12529
12822
|
});
|
|
12530
12823
|
if (initialResponse.status !== 402) {
|
|
12531
|
-
|
|
12824
|
+
const payResult2 = await readPayResult(initialResponse);
|
|
12825
|
+
setResult(payResult2);
|
|
12532
12826
|
setStep("done");
|
|
12533
|
-
onComplete();
|
|
12827
|
+
onComplete(payResult2);
|
|
12534
12828
|
return;
|
|
12535
12829
|
}
|
|
12536
12830
|
setStep("signing");
|
|
@@ -12546,12 +12840,13 @@ function MppPay({
|
|
|
12546
12840
|
Authorization: authHeader
|
|
12547
12841
|
}
|
|
12548
12842
|
});
|
|
12549
|
-
|
|
12843
|
+
const payResult = await readPayResult(retryResponse);
|
|
12844
|
+
setResult(payResult);
|
|
12550
12845
|
setStep("done");
|
|
12551
|
-
onComplete();
|
|
12846
|
+
onComplete(payResult);
|
|
12552
12847
|
} catch (err) {
|
|
12553
12848
|
setError(err.message);
|
|
12554
|
-
onComplete();
|
|
12849
|
+
onComplete(null);
|
|
12555
12850
|
}
|
|
12556
12851
|
})();
|
|
12557
12852
|
}, [url, spendRequestId, method, data, headers, repository, onComplete]);
|
|
@@ -12563,30 +12858,36 @@ function MppPay({
|
|
|
12563
12858
|
done: "Done"
|
|
12564
12859
|
};
|
|
12565
12860
|
if (error) {
|
|
12566
|
-
return /* @__PURE__ */
|
|
12861
|
+
return /* @__PURE__ */ jsxs6(Text7, { color: "red", children: [
|
|
12567
12862
|
"Error: ",
|
|
12568
12863
|
error
|
|
12569
12864
|
] });
|
|
12570
12865
|
}
|
|
12571
|
-
return /* @__PURE__ */
|
|
12572
|
-
step !== "done" && /* @__PURE__ */ jsx8(Box6, { children: /* @__PURE__ */
|
|
12573
|
-
/* @__PURE__ */ jsx8(
|
|
12866
|
+
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
12867
|
+
step !== "done" && /* @__PURE__ */ jsx8(Box6, { children: /* @__PURE__ */ jsxs6(Text7, { color: "cyan", children: [
|
|
12868
|
+
/* @__PURE__ */ jsx8(Spinner3, { type: "dots" }),
|
|
12574
12869
|
" ",
|
|
12575
12870
|
stepLabels[step],
|
|
12576
12871
|
"..."
|
|
12577
12872
|
] }) }),
|
|
12578
|
-
result && /* @__PURE__ */
|
|
12579
|
-
/* @__PURE__ */
|
|
12580
|
-
|
|
12581
|
-
|
|
12582
|
-
|
|
12873
|
+
result && /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
12874
|
+
/* @__PURE__ */ jsxs6(
|
|
12875
|
+
Text7,
|
|
12876
|
+
{
|
|
12877
|
+
color: result.status >= 400 ? "red" : result.status >= 300 ? "yellow" : "green",
|
|
12878
|
+
children: [
|
|
12879
|
+
"HTTP ",
|
|
12880
|
+
result.status
|
|
12881
|
+
]
|
|
12882
|
+
}
|
|
12883
|
+
),
|
|
12583
12884
|
/* @__PURE__ */ jsx8(Text7, { children: result.body })
|
|
12584
12885
|
] })
|
|
12585
12886
|
] });
|
|
12586
12887
|
}
|
|
12587
12888
|
|
|
12588
12889
|
// src/commands/demo/spt-flow.tsx
|
|
12589
|
-
import { Fragment as Fragment2, jsx as jsx9, jsxs as
|
|
12890
|
+
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
12590
12891
|
var SptFlow = ({
|
|
12591
12892
|
spendRequestRepo: spendRequestRepo2,
|
|
12592
12893
|
paymentMethodsResource,
|
|
@@ -12601,9 +12902,9 @@ var SptFlow = ({
|
|
|
12601
12902
|
const [payResult, setPayResult] = useState6(null);
|
|
12602
12903
|
const [error, setError] = useState6("");
|
|
12603
12904
|
const approvalUrl = spendRequest?.approval_url ?? "";
|
|
12604
|
-
const enterResolver =
|
|
12605
|
-
const pmResolver =
|
|
12606
|
-
const retryChoiceResolver =
|
|
12905
|
+
const enterResolver = useRef3(null);
|
|
12906
|
+
const pmResolver = useRef3(null);
|
|
12907
|
+
const retryChoiceResolver = useRef3(null);
|
|
12607
12908
|
function waitForEnter() {
|
|
12608
12909
|
return new Promise((resolve) => {
|
|
12609
12910
|
enterResolver.current = resolve;
|
|
@@ -12651,7 +12952,7 @@ var SptFlow = ({
|
|
|
12651
12952
|
}
|
|
12652
12953
|
}
|
|
12653
12954
|
});
|
|
12654
|
-
const started =
|
|
12955
|
+
const started = useRef3(false);
|
|
12655
12956
|
useEffect6(() => {
|
|
12656
12957
|
if (started.current) return;
|
|
12657
12958
|
started.current = true;
|
|
@@ -12711,6 +13012,11 @@ var SptFlow = ({
|
|
|
12711
13012
|
spendRequestRepo2,
|
|
12712
13013
|
result.id
|
|
12713
13014
|
);
|
|
13015
|
+
if (approved.status !== "approved") {
|
|
13016
|
+
throw new Error(
|
|
13017
|
+
`Spend request did not reach approved (status: ${approved.status})`
|
|
13018
|
+
);
|
|
13019
|
+
}
|
|
12714
13020
|
setSpendRequest(approved);
|
|
12715
13021
|
break;
|
|
12716
13022
|
} catch (err) {
|
|
@@ -12764,25 +13070,25 @@ var SptFlow = ({
|
|
|
12764
13070
|
];
|
|
12765
13071
|
return order.indexOf(step) > order.indexOf(target);
|
|
12766
13072
|
};
|
|
12767
|
-
const prompt = (label = "Press [Enter] to continue") => /* @__PURE__ */
|
|
13073
|
+
const prompt = (label = "Press [Enter] to continue") => /* @__PURE__ */ jsxs7(Text8, { dimColor: true, children: [
|
|
12768
13074
|
"\n",
|
|
12769
13075
|
">",
|
|
12770
13076
|
" ",
|
|
12771
13077
|
label
|
|
12772
13078
|
] });
|
|
12773
|
-
return /* @__PURE__ */
|
|
13079
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", gap: 1, children: [
|
|
12774
13080
|
/* @__PURE__ */ jsx9(Text8, { bold: true, color: "cyan", children: SPT_FLOW.title }),
|
|
12775
|
-
/* @__PURE__ */
|
|
12776
|
-
/* @__PURE__ */
|
|
13081
|
+
/* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
13082
|
+
/* @__PURE__ */ jsxs7(Box7, { flexDirection: "row", gap: 1, children: [
|
|
12777
13083
|
/* @__PURE__ */ jsx9(Text8, { color: "yellow", children: "[testmode]" }),
|
|
12778
|
-
/* @__PURE__ */
|
|
13084
|
+
/* @__PURE__ */ jsxs7(Text8, { dimColor: true, children: [
|
|
12779
13085
|
DEMO_CLIMATE_API_URL,
|
|
12780
13086
|
" ",
|
|
12781
13087
|
DEMO_MPP_DEV_URL
|
|
12782
13088
|
] })
|
|
12783
13089
|
] }),
|
|
12784
13090
|
/* @__PURE__ */ jsx9(MarkdownText, { children: SPT_FLOW.intro.description }),
|
|
12785
|
-
/* @__PURE__ */
|
|
13091
|
+
/* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
12786
13092
|
/* @__PURE__ */ jsx9(Text8, { children: SPT_FLOW.intro.preamble }),
|
|
12787
13093
|
SPT_FLOW.intro.steps.map((s, i) => {
|
|
12788
13094
|
const doneAfter = [
|
|
@@ -12802,17 +13108,17 @@ var SptFlow = ({
|
|
|
12802
13108
|
const done = pastStep(doneAfter[i]);
|
|
12803
13109
|
const active = !done && (step === activeFrom[i] || pastStep(activeFrom[i]));
|
|
12804
13110
|
const label = s.replace(/`/g, "");
|
|
12805
|
-
return done ? /* @__PURE__ */
|
|
13111
|
+
return done ? /* @__PURE__ */ jsxs7(Text8, { dimColor: true, strikethrough: true, children: [
|
|
12806
13112
|
" ",
|
|
12807
13113
|
i + 1,
|
|
12808
13114
|
". ",
|
|
12809
13115
|
label
|
|
12810
|
-
] }, s) : active ? /* @__PURE__ */
|
|
13116
|
+
] }, s) : active ? /* @__PURE__ */ jsxs7(Text8, { bold: true, color: "cyan", children: [
|
|
12811
13117
|
" ",
|
|
12812
13118
|
i + 1,
|
|
12813
13119
|
". ",
|
|
12814
13120
|
label
|
|
12815
|
-
] }, s) : /* @__PURE__ */
|
|
13121
|
+
] }, s) : /* @__PURE__ */ jsxs7(Text8, { dimColor: true, children: [
|
|
12816
13122
|
" ",
|
|
12817
13123
|
i + 1,
|
|
12818
13124
|
". ",
|
|
@@ -12823,45 +13129,45 @@ var SptFlow = ({
|
|
|
12823
13129
|
step === "intro" && prompt(SPT_FLOW.intro.prompt)
|
|
12824
13130
|
] }),
|
|
12825
13131
|
step === "fetch-pm" && /* @__PURE__ */ jsx9(Box7, { marginY: 1, children: /* @__PURE__ */ jsx9(Text8, { color: "cyan", children: "Fetching payment methods..." }) }),
|
|
12826
|
-
step === "pick-pm" && paymentMethods.length > 1 && /* @__PURE__ */
|
|
13132
|
+
step === "pick-pm" && paymentMethods.length > 1 && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
12827
13133
|
/* @__PURE__ */ jsx9(Text8, { children: "Which payment method should we use for the demo?" }),
|
|
12828
|
-
/* @__PURE__ */ jsx9(Box7, { flexDirection: "column", marginTop: 1, children: paymentMethods.map((pm, i) => /* @__PURE__ */ jsx9(Text8, { children: i === selectedPmIndex ? /* @__PURE__ */
|
|
13134
|
+
/* @__PURE__ */ jsx9(Box7, { flexDirection: "column", marginTop: 1, children: paymentMethods.map((pm, i) => /* @__PURE__ */ jsx9(Text8, { children: i === selectedPmIndex ? /* @__PURE__ */ jsxs7(Text8, { color: "cyan", bold: true, children: [
|
|
12829
13135
|
">",
|
|
12830
13136
|
" ",
|
|
12831
13137
|
pm.card_details ? `${pm.card_details.brand} ****${pm.card_details.last4}` : pm.type,
|
|
12832
13138
|
pm.is_default ? " (default)" : ""
|
|
12833
|
-
] }) : /* @__PURE__ */
|
|
13139
|
+
] }) : /* @__PURE__ */ jsxs7(Text8, { dimColor: true, children: [
|
|
12834
13140
|
" ",
|
|
12835
13141
|
pm.card_details ? `${pm.card_details.brand} ****${pm.card_details.last4}` : pm.type,
|
|
12836
13142
|
pm.is_default ? " (default)" : ""
|
|
12837
13143
|
] }) }, pm.id)) }),
|
|
12838
13144
|
/* @__PURE__ */ jsx9(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text8, { dimColor: true, children: "Use \u2191\u2193 to select, [Enter] to confirm" }) })
|
|
12839
13145
|
] }),
|
|
12840
|
-
(step === "probe" || step === "explain-402") && /* @__PURE__ */
|
|
13146
|
+
(step === "probe" || step === "explain-402") && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
12841
13147
|
/* @__PURE__ */ jsx9(MarkdownText, { children: SPT_FLOW.probe.description }),
|
|
12842
13148
|
step === "probe" && /* @__PURE__ */ jsx9(Box7, { marginY: 1, children: /* @__PURE__ */ jsx9(Text8, { color: "cyan", children: SPT_FLOW.probe.loading }) }),
|
|
12843
|
-
step === "explain-402" && networkId && /* @__PURE__ */
|
|
13149
|
+
step === "explain-402" && networkId && /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
12844
13150
|
/* @__PURE__ */ jsx9(MarkdownText, { children: SPT_FLOW.probe.detail }),
|
|
12845
|
-
/* @__PURE__ */
|
|
13151
|
+
/* @__PURE__ */ jsxs7(Text8, { color: "green", children: [
|
|
12846
13152
|
"\u2713 Got HTTP 402 \u2014 network_id: ",
|
|
12847
13153
|
/* @__PURE__ */ jsx9(Text8, { bold: true, children: networkId })
|
|
12848
13154
|
] }),
|
|
12849
13155
|
prompt(SPT_FLOW.probe.prompt)
|
|
12850
13156
|
] })
|
|
12851
13157
|
] }),
|
|
12852
|
-
step === "create-spend" && /* @__PURE__ */
|
|
13158
|
+
step === "create-spend" && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
12853
13159
|
/* @__PURE__ */ jsx9(MarkdownText, { children: SPT_FLOW.createSpend.description }),
|
|
12854
13160
|
/* @__PURE__ */ jsx9(Box7, { marginY: 1, children: /* @__PURE__ */ jsx9(Text8, { color: "cyan", children: SPT_FLOW.createSpend.loading }) })
|
|
12855
13161
|
] }),
|
|
12856
|
-
(step === "await-approval" || step === "approval-timeout") && spendRequest && /* @__PURE__ */
|
|
12857
|
-
/* @__PURE__ */
|
|
13162
|
+
(step === "await-approval" || step === "approval-timeout") && spendRequest && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
13163
|
+
/* @__PURE__ */ jsxs7(Text8, { color: "green", children: [
|
|
12858
13164
|
"\u2713 Spend request created (",
|
|
12859
13165
|
spendRequest.id,
|
|
12860
13166
|
")"
|
|
12861
13167
|
] }),
|
|
12862
|
-
step === "await-approval" && /* @__PURE__ */
|
|
13168
|
+
step === "await-approval" && /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
12863
13169
|
/* @__PURE__ */ jsx9(Text8, { children: SPT_FLOW.approval.description }),
|
|
12864
|
-
/* @__PURE__ */
|
|
13170
|
+
/* @__PURE__ */ jsxs7(
|
|
12865
13171
|
Box7,
|
|
12866
13172
|
{
|
|
12867
13173
|
flexDirection: "column",
|
|
@@ -12871,7 +13177,7 @@ var SptFlow = ({
|
|
|
12871
13177
|
paddingY: 1,
|
|
12872
13178
|
marginTop: 1,
|
|
12873
13179
|
children: [
|
|
12874
|
-
/* @__PURE__ */
|
|
13180
|
+
/* @__PURE__ */ jsxs7(Text8, { children: [
|
|
12875
13181
|
"Approve at:",
|
|
12876
13182
|
" ",
|
|
12877
13183
|
/* @__PURE__ */ jsx9(Text8, { bold: true, color: "cyan", children: approvalUrl })
|
|
@@ -12882,9 +13188,9 @@ var SptFlow = ({
|
|
|
12882
13188
|
),
|
|
12883
13189
|
/* @__PURE__ */ jsx9(Box7, { marginY: 1, children: /* @__PURE__ */ jsx9(Text8, { color: "cyan", children: SPT_FLOW.approval.loading }) })
|
|
12884
13190
|
] }),
|
|
12885
|
-
step === "approval-timeout" && /* @__PURE__ */
|
|
13191
|
+
step === "approval-timeout" && /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
12886
13192
|
/* @__PURE__ */ jsx9(Text8, { color: "yellow", children: "\u26A0 Approval timed out (5 min). Still pending \u2014 you can still approve." }),
|
|
12887
|
-
/* @__PURE__ */
|
|
13193
|
+
/* @__PURE__ */ jsxs7(
|
|
12888
13194
|
Box7,
|
|
12889
13195
|
{
|
|
12890
13196
|
flexDirection: "column",
|
|
@@ -12894,7 +13200,7 @@ var SptFlow = ({
|
|
|
12894
13200
|
paddingY: 1,
|
|
12895
13201
|
marginTop: 1,
|
|
12896
13202
|
children: [
|
|
12897
|
-
/* @__PURE__ */
|
|
13203
|
+
/* @__PURE__ */ jsxs7(Text8, { children: [
|
|
12898
13204
|
"Approve at:",
|
|
12899
13205
|
" ",
|
|
12900
13206
|
/* @__PURE__ */ jsx9(Text8, { bold: true, color: "cyan", children: approvalUrl })
|
|
@@ -12906,14 +13212,14 @@ var SptFlow = ({
|
|
|
12906
13212
|
/* @__PURE__ */ jsx9(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text8, { dimColor: true, children: "r Retry polling q Quit demo" }) })
|
|
12907
13213
|
] })
|
|
12908
13214
|
] }),
|
|
12909
|
-
(step === "mpp-pay-gate" || step === "mpp-pay") && /* @__PURE__ */
|
|
13215
|
+
(step === "mpp-pay-gate" || step === "mpp-pay") && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
12910
13216
|
/* @__PURE__ */ jsx9(Text8, { color: "green", children: "\u2713 Approved!" }),
|
|
12911
13217
|
/* @__PURE__ */ jsx9(MarkdownText, { children: SPT_FLOW.mppPay.description }),
|
|
12912
13218
|
step === "mpp-pay-gate" && prompt(SPT_FLOW.mppPay.prompt),
|
|
12913
13219
|
step === "mpp-pay" && /* @__PURE__ */ jsx9(Box7, { marginY: 1, children: /* @__PURE__ */ jsx9(Text8, { color: "cyan", children: SPT_FLOW.mppPay.loading }) })
|
|
12914
13220
|
] }),
|
|
12915
|
-
step === "done" && payResult && /* @__PURE__ */
|
|
12916
|
-
/* @__PURE__ */
|
|
13221
|
+
step === "done" && payResult && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
13222
|
+
/* @__PURE__ */ jsxs7(Text8, { bold: true, color: "green", children: [
|
|
12917
13223
|
"\u2713 ",
|
|
12918
13224
|
SPT_FLOW.done.success,
|
|
12919
13225
|
" (HTTP ",
|
|
@@ -12922,7 +13228,7 @@ var SptFlow = ({
|
|
|
12922
13228
|
] }),
|
|
12923
13229
|
/* @__PURE__ */ jsx9(MarkdownText, { children: SPT_FLOW.done.detail })
|
|
12924
13230
|
] }),
|
|
12925
|
-
step === "error" && /* @__PURE__ */
|
|
13231
|
+
step === "error" && /* @__PURE__ */ jsxs7(Text8, { color: "red", children: [
|
|
12926
13232
|
"Error: ",
|
|
12927
13233
|
error
|
|
12928
13234
|
] })
|
|
@@ -12930,22 +13236,25 @@ var SptFlow = ({
|
|
|
12930
13236
|
};
|
|
12931
13237
|
|
|
12932
13238
|
// src/commands/demo/demo-runner.tsx
|
|
12933
|
-
import { Fragment as Fragment3, jsx as jsx10, jsxs as
|
|
13239
|
+
import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
12934
13240
|
var DemoRunner = ({
|
|
12935
13241
|
authRepo: authRepo2,
|
|
12936
13242
|
spendRequestRepo: spendRequestRepo2,
|
|
12937
13243
|
paymentMethodsResource,
|
|
13244
|
+
authStorage: authStorage2 = storage,
|
|
12938
13245
|
paymentMethodId: preselectedPmId,
|
|
12939
13246
|
onlyCard,
|
|
12940
13247
|
onlySpt,
|
|
12941
13248
|
onComplete
|
|
12942
13249
|
}) => {
|
|
13250
|
+
const { exit } = useApp();
|
|
13251
|
+
const storage2 = authStorage2;
|
|
12943
13252
|
const preselected = onlyCard ? "card" : onlySpt ? "spt" : null;
|
|
12944
13253
|
const [choice, setChoice] = useState7(preselected);
|
|
12945
13254
|
const [menuIndex, setMenuIndex] = useState7(0);
|
|
12946
13255
|
const postAuthPhase = preselected === "spt" ? "spt-flow" : preselected ? "card-flow" : "menu";
|
|
12947
13256
|
const [phase, setPhase] = useState7(
|
|
12948
|
-
|
|
13257
|
+
storage2.isAuthenticated() ? postAuthPhase : "auth"
|
|
12949
13258
|
);
|
|
12950
13259
|
const [paymentMethodId, setPaymentMethodId] = useState7(
|
|
12951
13260
|
preselectedPmId ?? ""
|
|
@@ -12969,29 +13278,35 @@ var DemoRunner = ({
|
|
|
12969
13278
|
setPhase("spt-flow");
|
|
12970
13279
|
}
|
|
12971
13280
|
});
|
|
12972
|
-
const onCardComplete =
|
|
13281
|
+
const onCardComplete = useCallback2(
|
|
12973
13282
|
(result) => {
|
|
12974
13283
|
setPaymentMethodId(result.paymentMethodId);
|
|
12975
13284
|
setCardSuccess(result.success);
|
|
12976
13285
|
if (!runSpt) {
|
|
12977
13286
|
setPhase("summary");
|
|
12978
|
-
setTimeout(
|
|
13287
|
+
setTimeout(() => {
|
|
13288
|
+
onComplete();
|
|
13289
|
+
exit();
|
|
13290
|
+
}, DISPLAY_DELAY_MS);
|
|
12979
13291
|
} else {
|
|
12980
13292
|
setPhase("card-done");
|
|
12981
13293
|
}
|
|
12982
13294
|
},
|
|
12983
|
-
[runSpt, onComplete]
|
|
13295
|
+
[runSpt, onComplete, exit]
|
|
12984
13296
|
);
|
|
12985
|
-
const onSptComplete =
|
|
13297
|
+
const onSptComplete = useCallback2(
|
|
12986
13298
|
(success) => {
|
|
12987
13299
|
setSptSuccess(success);
|
|
12988
13300
|
setPhase("summary");
|
|
12989
|
-
setTimeout(
|
|
13301
|
+
setTimeout(() => {
|
|
13302
|
+
onComplete();
|
|
13303
|
+
exit();
|
|
13304
|
+
}, DISPLAY_DELAY_MS);
|
|
12990
13305
|
},
|
|
12991
|
-
[onComplete]
|
|
13306
|
+
[onComplete, exit]
|
|
12992
13307
|
);
|
|
12993
|
-
return /* @__PURE__ */
|
|
12994
|
-
/* @__PURE__ */
|
|
13308
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", gap: 1, children: [
|
|
13309
|
+
/* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
12995
13310
|
/* @__PURE__ */ jsx10(Text9, { bold: true, children: DEMO_MENU.title }),
|
|
12996
13311
|
/* @__PURE__ */ jsx10(Text9, { children: DEMO_MENU.subtitle })
|
|
12997
13312
|
] }),
|
|
@@ -13000,22 +13315,23 @@ var DemoRunner = ({
|
|
|
13000
13315
|
{
|
|
13001
13316
|
authResource: authRepo2,
|
|
13002
13317
|
clientName: ONBOARD.auth.clientName,
|
|
13318
|
+
authStorage: storage2,
|
|
13003
13319
|
onComplete: () => setPhase(postAuthPhase)
|
|
13004
13320
|
}
|
|
13005
13321
|
),
|
|
13006
|
-
phase === "menu" && /* @__PURE__ */
|
|
13322
|
+
phase === "menu" && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
13007
13323
|
/* @__PURE__ */ jsx10(Text9, { children: DEMO_MENU.question }),
|
|
13008
|
-
/* @__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__ */
|
|
13009
|
-
/* @__PURE__ */
|
|
13324
|
+
/* @__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__ */ jsxs8(Fragment3, { children: [
|
|
13325
|
+
/* @__PURE__ */ jsxs8(Text9, { color: "cyan", bold: true, children: [
|
|
13010
13326
|
">",
|
|
13011
13327
|
" ",
|
|
13012
13328
|
opt.label
|
|
13013
13329
|
] }),
|
|
13014
|
-
/* @__PURE__ */
|
|
13330
|
+
/* @__PURE__ */ jsxs8(Text9, { color: "cyan", children: [
|
|
13015
13331
|
" ",
|
|
13016
13332
|
opt.description
|
|
13017
13333
|
] })
|
|
13018
|
-
] }) : /* @__PURE__ */
|
|
13334
|
+
] }) : /* @__PURE__ */ jsxs8(Text9, { dimColor: true, children: [
|
|
13019
13335
|
" ",
|
|
13020
13336
|
opt.label
|
|
13021
13337
|
] }) }, opt.key)) }),
|
|
@@ -13030,17 +13346,17 @@ var DemoRunner = ({
|
|
|
13030
13346
|
onComplete: onCardComplete
|
|
13031
13347
|
}
|
|
13032
13348
|
),
|
|
13033
|
-
phase === "card-done" && /* @__PURE__ */
|
|
13349
|
+
phase === "card-done" && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
13034
13350
|
/* @__PURE__ */ jsx10(Text9, { dimColor: true, children: "\u2500\u2500\u2500" }),
|
|
13035
13351
|
/* @__PURE__ */ jsx10(MarkdownText, { children: DEMO_MENU.transition }),
|
|
13036
|
-
/* @__PURE__ */
|
|
13352
|
+
/* @__PURE__ */ jsxs8(Text9, { dimColor: true, children: [
|
|
13037
13353
|
"\n",
|
|
13038
13354
|
">",
|
|
13039
13355
|
" ",
|
|
13040
13356
|
DEMO_MENU.transitionPrompt
|
|
13041
13357
|
] })
|
|
13042
13358
|
] }),
|
|
13043
|
-
runSpt && (phase === "spt-flow" || phase === "summary") && /* @__PURE__ */
|
|
13359
|
+
runSpt && (phase === "spt-flow" || phase === "summary") && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
13044
13360
|
runCard && /* @__PURE__ */ jsx10(Text9, { dimColor: true, children: "\u2500\u2500\u2500" }),
|
|
13045
13361
|
/* @__PURE__ */ jsx10(
|
|
13046
13362
|
SptFlow,
|
|
@@ -13052,14 +13368,14 @@ var DemoRunner = ({
|
|
|
13052
13368
|
}
|
|
13053
13369
|
)
|
|
13054
13370
|
] }),
|
|
13055
|
-
phase === "summary" && /* @__PURE__ */
|
|
13371
|
+
phase === "summary" && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
13056
13372
|
/* @__PURE__ */ jsx10(Text9, { dimColor: true, children: "\u2500\u2500\u2500" }),
|
|
13057
13373
|
/* @__PURE__ */ jsx10(Text9, { bold: true, children: "Done!" }),
|
|
13058
|
-
cardSuccess !== null && /* @__PURE__ */
|
|
13374
|
+
cardSuccess !== null && /* @__PURE__ */ jsxs8(Text9, { color: cardSuccess ? "green" : "red", children: [
|
|
13059
13375
|
cardSuccess ? "\u2713" : "\u2717",
|
|
13060
13376
|
" Virtual card flow"
|
|
13061
13377
|
] }),
|
|
13062
|
-
sptSuccess !== null && /* @__PURE__ */
|
|
13378
|
+
sptSuccess !== null && /* @__PURE__ */ jsxs8(Text9, { color: sptSuccess ? "green" : "red", children: [
|
|
13063
13379
|
sptSuccess ? "\u2713" : "\u2717",
|
|
13064
13380
|
" Machine payment flow"
|
|
13065
13381
|
] }),
|
|
@@ -13074,7 +13390,7 @@ var demoOptions = z2.object({
|
|
|
13074
13390
|
onlyCard: z2.boolean().default(false).describe("Run only the virtual card flow"),
|
|
13075
13391
|
onlySpt: z2.boolean().default(false).describe("Run only the machine payment (SPT) flow")
|
|
13076
13392
|
});
|
|
13077
|
-
function createDemoCli(authRepo2, spendRequestRepo2, createPaymentMethodsResource) {
|
|
13393
|
+
function createDemoCli(authRepo2, spendRequestRepo2, createPaymentMethodsResource, authStorage2) {
|
|
13078
13394
|
return Cli2.create("demo", {
|
|
13079
13395
|
description: "Run an interactive demo of both Link payment flows (virtual card + machine payment)",
|
|
13080
13396
|
options: demoOptions,
|
|
@@ -13087,48 +13403,71 @@ function createDemoCli(authRepo2, spendRequestRepo2, createPaymentMethodsResourc
|
|
|
13087
13403
|
});
|
|
13088
13404
|
}
|
|
13089
13405
|
const paymentMethodsResource = createPaymentMethodsResource();
|
|
13090
|
-
return
|
|
13091
|
-
|
|
13092
|
-
|
|
13093
|
-
|
|
13094
|
-
|
|
13095
|
-
|
|
13096
|
-
|
|
13097
|
-
|
|
13098
|
-
|
|
13099
|
-
|
|
13100
|
-
|
|
13406
|
+
return renderInteractive(
|
|
13407
|
+
/* @__PURE__ */ jsx11(
|
|
13408
|
+
DemoRunner,
|
|
13409
|
+
{
|
|
13410
|
+
authRepo: authRepo2,
|
|
13411
|
+
spendRequestRepo: spendRequestRepo2,
|
|
13412
|
+
paymentMethodsResource,
|
|
13413
|
+
authStorage: authStorage2,
|
|
13414
|
+
onlyCard: c.options.onlyCard,
|
|
13415
|
+
onlySpt: c.options.onlySpt,
|
|
13416
|
+
onComplete: () => {
|
|
13101
13417
|
}
|
|
13102
|
-
|
|
13103
|
-
)
|
|
13104
|
-
|
|
13105
|
-
|
|
13418
|
+
}
|
|
13419
|
+
),
|
|
13420
|
+
() => ({})
|
|
13421
|
+
);
|
|
13106
13422
|
}
|
|
13107
13423
|
});
|
|
13108
13424
|
}
|
|
13109
13425
|
|
|
13110
13426
|
// src/commands/mpp/index.tsx
|
|
13111
13427
|
import { Cli as Cli3, z as z4 } from "incur";
|
|
13112
|
-
|
|
13428
|
+
|
|
13429
|
+
// src/utils/require-auth.ts
|
|
13430
|
+
var NOT_AUTHENTICATED_ERROR = {
|
|
13431
|
+
code: "NOT_AUTHENTICATED",
|
|
13432
|
+
message: 'Not authenticated. Run "link-cli auth login" first.',
|
|
13433
|
+
cta: {
|
|
13434
|
+
commands: [{ command: "auth login", description: "Log in to Link" }]
|
|
13435
|
+
}
|
|
13436
|
+
};
|
|
13437
|
+
function requireAuth(authStorage2) {
|
|
13438
|
+
const store = authStorage2 ?? storage;
|
|
13439
|
+
return (c, next) => {
|
|
13440
|
+
if (!store.isAuthenticated()) {
|
|
13441
|
+
return c.error(NOT_AUTHENTICATED_ERROR);
|
|
13442
|
+
}
|
|
13443
|
+
return next();
|
|
13444
|
+
};
|
|
13445
|
+
}
|
|
13446
|
+
function requireAuthGuard(c, authStorage2) {
|
|
13447
|
+
const store = authStorage2 ?? storage;
|
|
13448
|
+
if (!store.isAuthenticated()) {
|
|
13449
|
+
c.error(NOT_AUTHENTICATED_ERROR);
|
|
13450
|
+
}
|
|
13451
|
+
}
|
|
13113
13452
|
|
|
13114
13453
|
// src/commands/mpp/decode-view.tsx
|
|
13115
13454
|
import { Box as Box9, Text as Text10 } from "ink";
|
|
13116
|
-
import { jsx as jsx12, jsxs as
|
|
13455
|
+
import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
13117
13456
|
function DecodeChallengeView({
|
|
13118
13457
|
decoded
|
|
13119
13458
|
}) {
|
|
13120
|
-
return /* @__PURE__ */
|
|
13459
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
13121
13460
|
/* @__PURE__ */ jsx12(Text10, { color: "green", children: "\u2713 Stripe challenge decoded" }),
|
|
13122
|
-
/* @__PURE__ */
|
|
13123
|
-
/* @__PURE__ */
|
|
13461
|
+
/* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
13462
|
+
/* @__PURE__ */ jsxs9(Text10, { children: [
|
|
13124
13463
|
"ID: ",
|
|
13125
13464
|
/* @__PURE__ */ jsx12(Text10, { bold: true, children: decoded.id })
|
|
13126
13465
|
] }),
|
|
13127
|
-
/* @__PURE__ */
|
|
13466
|
+
/* @__PURE__ */ jsxs9(Text10, { children: [
|
|
13128
13467
|
"Realm: ",
|
|
13129
13468
|
/* @__PURE__ */ jsx12(Text10, { bold: true, children: decoded.realm })
|
|
13130
13469
|
] }),
|
|
13131
|
-
/* @__PURE__ */
|
|
13470
|
+
/* @__PURE__ */ jsxs9(Text10, { children: [
|
|
13132
13471
|
"Network ID: ",
|
|
13133
13472
|
/* @__PURE__ */ jsx12(Text10, { bold: true, children: decoded.network_id })
|
|
13134
13473
|
] }),
|
|
@@ -13156,7 +13495,7 @@ var decodeOptions = z3.object({
|
|
|
13156
13495
|
|
|
13157
13496
|
// src/commands/mpp/index.tsx
|
|
13158
13497
|
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
13159
|
-
function createMppCli(repository) {
|
|
13498
|
+
function createMppCli(repository, authStorage2) {
|
|
13160
13499
|
const cli2 = Cli3.create("mpp", {
|
|
13161
13500
|
description: "Machine payment protocol (MPP) commands"
|
|
13162
13501
|
});
|
|
@@ -13168,53 +13507,36 @@ function createMppCli(repository) {
|
|
|
13168
13507
|
options: payOptions,
|
|
13169
13508
|
alias: { method: "X", data: "d", header: "H" },
|
|
13170
13509
|
outputPolicy: "agent-only",
|
|
13510
|
+
middleware: [requireAuth(authStorage2)],
|
|
13171
13511
|
async run(c) {
|
|
13172
|
-
if (!storage.isAuthenticated()) {
|
|
13173
|
-
return c.error({
|
|
13174
|
-
code: "NOT_AUTHENTICATED",
|
|
13175
|
-
message: 'Not authenticated. Run "link-cli auth login" first.',
|
|
13176
|
-
cta: {
|
|
13177
|
-
commands: [
|
|
13178
|
-
{ command: "auth login", description: "Log in to Link" }
|
|
13179
|
-
]
|
|
13180
|
-
}
|
|
13181
|
-
});
|
|
13182
|
-
}
|
|
13183
13512
|
const url = c.args.url;
|
|
13184
13513
|
const opts = c.options;
|
|
13185
13514
|
const method = opts.method;
|
|
13186
13515
|
const data = opts.data;
|
|
13187
13516
|
const headers = opts.header?.length ? opts.header : void 0;
|
|
13188
13517
|
if (!c.agent && !c.formatExplicit) {
|
|
13189
|
-
|
|
13190
|
-
|
|
13191
|
-
|
|
13192
|
-
|
|
13193
|
-
|
|
13194
|
-
|
|
13195
|
-
|
|
13196
|
-
|
|
13197
|
-
|
|
13198
|
-
|
|
13199
|
-
|
|
13200
|
-
|
|
13201
|
-
|
|
13518
|
+
let capturedResult = null;
|
|
13519
|
+
return renderInteractive(
|
|
13520
|
+
/* @__PURE__ */ jsx13(
|
|
13521
|
+
MppPay,
|
|
13522
|
+
{
|
|
13523
|
+
url,
|
|
13524
|
+
spendRequestId: opts.spendRequestId,
|
|
13525
|
+
method,
|
|
13526
|
+
data,
|
|
13527
|
+
headers,
|
|
13528
|
+
repository,
|
|
13529
|
+
onComplete: (result) => {
|
|
13530
|
+
capturedResult = result;
|
|
13202
13531
|
}
|
|
13203
|
-
|
|
13204
|
-
)
|
|
13205
|
-
|
|
13206
|
-
|
|
13207
|
-
|
|
13208
|
-
|
|
13209
|
-
|
|
13210
|
-
|
|
13211
|
-
data,
|
|
13212
|
-
headers,
|
|
13213
|
-
repository
|
|
13214
|
-
)
|
|
13215
|
-
);
|
|
13216
|
-
});
|
|
13217
|
-
});
|
|
13532
|
+
}
|
|
13533
|
+
),
|
|
13534
|
+
() => {
|
|
13535
|
+
if (!capturedResult)
|
|
13536
|
+
throw new Error("Component exited without producing a result");
|
|
13537
|
+
return capturedResult;
|
|
13538
|
+
}
|
|
13539
|
+
);
|
|
13218
13540
|
}
|
|
13219
13541
|
return runMppPay(
|
|
13220
13542
|
url,
|
|
@@ -13233,12 +13555,10 @@ function createMppCli(repository) {
|
|
|
13233
13555
|
async run(c) {
|
|
13234
13556
|
const decoded = decodeStripeChallenge(c.options.challenge);
|
|
13235
13557
|
if (!c.agent && !c.formatExplicit) {
|
|
13236
|
-
return
|
|
13237
|
-
|
|
13238
|
-
|
|
13239
|
-
|
|
13240
|
-
waitUntilExit().then(() => resolve(decoded));
|
|
13241
|
-
});
|
|
13558
|
+
return renderInteractive(
|
|
13559
|
+
/* @__PURE__ */ jsx13(DecodeChallengeView, { decoded }),
|
|
13560
|
+
() => decoded
|
|
13561
|
+
);
|
|
13242
13562
|
}
|
|
13243
13563
|
return decoded;
|
|
13244
13564
|
}
|
|
@@ -13248,29 +13568,31 @@ function createMppCli(repository) {
|
|
|
13248
13568
|
|
|
13249
13569
|
// src/commands/onboard/index.tsx
|
|
13250
13570
|
import { Cli as Cli4 } from "incur";
|
|
13251
|
-
import { render as render4 } from "ink";
|
|
13252
13571
|
|
|
13253
13572
|
// src/commands/onboard/onboard-runner.tsx
|
|
13254
|
-
import { Box as Box10, Text as Text11, useInput as useInput5 } from "ink";
|
|
13255
|
-
import { useEffect as useEffect7, useRef as
|
|
13256
|
-
import { jsx as jsx14, jsxs as
|
|
13573
|
+
import { Box as Box10, Text as Text11, useApp as useApp2, useInput as useInput5 } from "ink";
|
|
13574
|
+
import { useEffect as useEffect7, useRef as useRef4, useState as useState8 } from "react";
|
|
13575
|
+
import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
13257
13576
|
var OnboardRunner = ({
|
|
13258
13577
|
authRepo: authRepo2,
|
|
13259
13578
|
spendRequestRepo: spendRequestRepo2,
|
|
13260
13579
|
paymentMethodsResource,
|
|
13580
|
+
authStorage: authStorage2 = storage,
|
|
13261
13581
|
onComplete
|
|
13262
13582
|
}) => {
|
|
13583
|
+
const { exit } = useApp2();
|
|
13584
|
+
const storage2 = authStorage2;
|
|
13263
13585
|
const [phase, setPhase] = useState8("welcome");
|
|
13264
13586
|
const [authSkipped, setAuthSkipped] = useState8(false);
|
|
13265
13587
|
const [pmMissing, setPmMissing] = useState8(false);
|
|
13266
13588
|
const [error, setError] = useState8("");
|
|
13267
|
-
const enterResolver =
|
|
13589
|
+
const enterResolver = useRef4(null);
|
|
13268
13590
|
function waitForEnter() {
|
|
13269
13591
|
return new Promise((resolve) => {
|
|
13270
13592
|
enterResolver.current = resolve;
|
|
13271
13593
|
});
|
|
13272
13594
|
}
|
|
13273
|
-
const authResolver =
|
|
13595
|
+
const authResolver = useRef4(null);
|
|
13274
13596
|
function waitForAuth() {
|
|
13275
13597
|
return new Promise((resolve) => {
|
|
13276
13598
|
authResolver.current = resolve;
|
|
@@ -13283,14 +13605,14 @@ var OnboardRunner = ({
|
|
|
13283
13605
|
resolve();
|
|
13284
13606
|
}
|
|
13285
13607
|
});
|
|
13286
|
-
const started =
|
|
13608
|
+
const started = useRef4(false);
|
|
13287
13609
|
useEffect7(() => {
|
|
13288
13610
|
if (started.current) return;
|
|
13289
13611
|
started.current = true;
|
|
13290
13612
|
const run = async () => {
|
|
13291
13613
|
try {
|
|
13292
13614
|
setPhase("auth");
|
|
13293
|
-
if (
|
|
13615
|
+
if (storage2.isAuthenticated()) {
|
|
13294
13616
|
setAuthSkipped(true);
|
|
13295
13617
|
} else {
|
|
13296
13618
|
setAuthSkipped(false);
|
|
@@ -13307,6 +13629,7 @@ var OnboardRunner = ({
|
|
|
13307
13629
|
setPhase("demo");
|
|
13308
13630
|
} catch (err) {
|
|
13309
13631
|
setError(err.message);
|
|
13632
|
+
setTimeout(exit, 2e3);
|
|
13310
13633
|
}
|
|
13311
13634
|
};
|
|
13312
13635
|
run();
|
|
@@ -13315,33 +13638,34 @@ var OnboardRunner = ({
|
|
|
13315
13638
|
const order = ["welcome", "auth", "payment-methods", "demo"];
|
|
13316
13639
|
return order.indexOf(phase) > order.indexOf(target);
|
|
13317
13640
|
};
|
|
13318
|
-
const prompt = (label = "Press [Enter] to continue") => /* @__PURE__ */
|
|
13641
|
+
const prompt = (label = "Press [Enter] to continue") => /* @__PURE__ */ jsxs10(Text11, { dimColor: true, children: [
|
|
13319
13642
|
"\n",
|
|
13320
13643
|
">",
|
|
13321
13644
|
" ",
|
|
13322
13645
|
label
|
|
13323
13646
|
] });
|
|
13324
|
-
return /* @__PURE__ */
|
|
13325
|
-
/* @__PURE__ */
|
|
13647
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", gap: 1, children: [
|
|
13648
|
+
/* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
|
|
13326
13649
|
/* @__PURE__ */ jsx14(Text11, { bold: true, children: ONBOARD.title }),
|
|
13327
13650
|
/* @__PURE__ */ jsx14(Text11, { children: ONBOARD.subtitle })
|
|
13328
13651
|
] }),
|
|
13329
|
-
/* @__PURE__ */ jsx14(Box10, { flexDirection: "column", children: authSkipped || pastPhase("auth") ? /* @__PURE__ */
|
|
13652
|
+
/* @__PURE__ */ jsx14(Box10, { flexDirection: "column", children: authSkipped || pastPhase("auth") ? /* @__PURE__ */ jsxs10(Text11, { color: "green", children: [
|
|
13330
13653
|
"\u2713 ",
|
|
13331
13654
|
authSkipped ? ONBOARD.auth.alreadyLoggedIn : ONBOARD.auth.authenticated
|
|
13332
|
-
] }) : phase === "auth" && !
|
|
13655
|
+
] }) : phase === "auth" && !storage2.isAuthenticated() ? /* @__PURE__ */ jsx14(
|
|
13333
13656
|
Login,
|
|
13334
13657
|
{
|
|
13335
13658
|
authResource: authRepo2,
|
|
13336
13659
|
clientName: ONBOARD.auth.clientName,
|
|
13660
|
+
authStorage: storage2,
|
|
13337
13661
|
onComplete: () => authResolver.current?.()
|
|
13338
13662
|
}
|
|
13339
13663
|
) : null }),
|
|
13340
|
-
pastPhase("auth") && /* @__PURE__ */
|
|
13664
|
+
pastPhase("auth") && /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
|
|
13341
13665
|
phase === "payment-methods" && !pmMissing && /* @__PURE__ */ jsx14(Text11, { color: "cyan", children: ONBOARD.paymentMethods.loading }),
|
|
13342
|
-
pmMissing && /* @__PURE__ */
|
|
13666
|
+
pmMissing && /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
|
|
13343
13667
|
/* @__PURE__ */ jsx14(Text11, { color: "yellow", children: ONBOARD.paymentMethods.missing }),
|
|
13344
|
-
/* @__PURE__ */ jsx14(Box10, { marginTop: 1, children: /* @__PURE__ */
|
|
13668
|
+
/* @__PURE__ */ jsx14(Box10, { marginTop: 1, children: /* @__PURE__ */ jsxs10(Text11, { children: [
|
|
13345
13669
|
"Visit",
|
|
13346
13670
|
" ",
|
|
13347
13671
|
/* @__PURE__ */ jsx14(Text11, { bold: true, color: "cyan", children: "app.link.com/wallet" }),
|
|
@@ -13352,7 +13676,7 @@ var OnboardRunner = ({
|
|
|
13352
13676
|
] }),
|
|
13353
13677
|
pastPhase("payment-methods") && /* @__PURE__ */ jsx14(Text11, { color: "green", children: "\u2713 Payment method found" })
|
|
13354
13678
|
] }),
|
|
13355
|
-
phase === "demo" && /* @__PURE__ */
|
|
13679
|
+
phase === "demo" && /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
|
|
13356
13680
|
/* @__PURE__ */ jsx14(Text11, { dimColor: true, children: "\u2500\u2500\u2500" }),
|
|
13357
13681
|
/* @__PURE__ */ jsx14(
|
|
13358
13682
|
DemoRunner,
|
|
@@ -13360,11 +13684,12 @@ var OnboardRunner = ({
|
|
|
13360
13684
|
authRepo: authRepo2,
|
|
13361
13685
|
spendRequestRepo: spendRequestRepo2,
|
|
13362
13686
|
paymentMethodsResource,
|
|
13687
|
+
authStorage: storage2,
|
|
13363
13688
|
onComplete
|
|
13364
13689
|
}
|
|
13365
13690
|
)
|
|
13366
13691
|
] }),
|
|
13367
|
-
error && /* @__PURE__ */
|
|
13692
|
+
error && /* @__PURE__ */ jsxs10(Text11, { color: "red", children: [
|
|
13368
13693
|
"Error: ",
|
|
13369
13694
|
error
|
|
13370
13695
|
] })
|
|
@@ -13373,7 +13698,7 @@ var OnboardRunner = ({
|
|
|
13373
13698
|
|
|
13374
13699
|
// src/commands/onboard/index.tsx
|
|
13375
13700
|
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
13376
|
-
function createOnboardCli(authRepo2, spendRequestRepo2, createPaymentMethodsResource) {
|
|
13701
|
+
function createOnboardCli(authRepo2, spendRequestRepo2, createPaymentMethodsResource, authStorage2) {
|
|
13377
13702
|
return Cli4.create("onboard", {
|
|
13378
13703
|
description: "Guided setup: authenticate, verify payment methods, and demo both payment flows",
|
|
13379
13704
|
outputPolicy: "agent-only",
|
|
@@ -13385,43 +13710,42 @@ function createOnboardCli(authRepo2, spendRequestRepo2, createPaymentMethodsReso
|
|
|
13385
13710
|
});
|
|
13386
13711
|
}
|
|
13387
13712
|
const paymentMethodsResource = createPaymentMethodsResource();
|
|
13388
|
-
return
|
|
13389
|
-
|
|
13390
|
-
|
|
13391
|
-
|
|
13392
|
-
|
|
13393
|
-
|
|
13394
|
-
|
|
13395
|
-
|
|
13396
|
-
|
|
13713
|
+
return renderInteractive(
|
|
13714
|
+
/* @__PURE__ */ jsx15(
|
|
13715
|
+
OnboardRunner,
|
|
13716
|
+
{
|
|
13717
|
+
authRepo: authRepo2,
|
|
13718
|
+
spendRequestRepo: spendRequestRepo2,
|
|
13719
|
+
paymentMethodsResource,
|
|
13720
|
+
authStorage: authStorage2,
|
|
13721
|
+
onComplete: () => {
|
|
13397
13722
|
}
|
|
13398
|
-
|
|
13399
|
-
)
|
|
13400
|
-
|
|
13401
|
-
|
|
13723
|
+
}
|
|
13724
|
+
),
|
|
13725
|
+
() => ({})
|
|
13726
|
+
);
|
|
13402
13727
|
}
|
|
13403
13728
|
});
|
|
13404
13729
|
}
|
|
13405
13730
|
|
|
13406
13731
|
// src/commands/payment-methods/index.tsx
|
|
13407
13732
|
import { Cli as Cli5 } from "incur";
|
|
13408
|
-
import { render as render5 } from "ink";
|
|
13409
13733
|
|
|
13410
13734
|
// src/commands/payment-methods/add.tsx
|
|
13411
|
-
import { Box as Box11, Text as Text12, useApp, useInput as useInput6 } from "ink";
|
|
13412
|
-
import { jsx as jsx16, jsxs as
|
|
13735
|
+
import { Box as Box11, Text as Text12, useApp as useApp3, useInput as useInput6 } from "ink";
|
|
13736
|
+
import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
13413
13737
|
var WALLET_URL = "https://app.link.com/wallet";
|
|
13414
13738
|
var AddPaymentMethod = () => {
|
|
13415
|
-
const { exit } =
|
|
13739
|
+
const { exit } = useApp3();
|
|
13416
13740
|
useInput6((_input, key) => {
|
|
13417
13741
|
if (key.return) {
|
|
13418
13742
|
openUrl(WALLET_URL);
|
|
13419
13743
|
exit();
|
|
13420
13744
|
}
|
|
13421
13745
|
});
|
|
13422
|
-
return /* @__PURE__ */
|
|
13746
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", paddingY: 1, children: [
|
|
13423
13747
|
/* @__PURE__ */ jsx16(Box11, { marginBottom: 1, children: /* @__PURE__ */ jsx16(Text12, { bold: true, children: "Add Payment Method" }) }),
|
|
13424
|
-
/* @__PURE__ */
|
|
13748
|
+
/* @__PURE__ */ jsxs11(
|
|
13425
13749
|
Box11,
|
|
13426
13750
|
{
|
|
13427
13751
|
flexDirection: "column",
|
|
@@ -13430,7 +13754,7 @@ var AddPaymentMethod = () => {
|
|
|
13430
13754
|
paddingX: 2,
|
|
13431
13755
|
paddingY: 1,
|
|
13432
13756
|
children: [
|
|
13433
|
-
/* @__PURE__ */
|
|
13757
|
+
/* @__PURE__ */ jsxs11(Text12, { children: [
|
|
13434
13758
|
"Open:",
|
|
13435
13759
|
" ",
|
|
13436
13760
|
/* @__PURE__ */ jsx16(Text12, { bold: true, color: "cyan", children: WALLET_URL })
|
|
@@ -13444,55 +13768,37 @@ var AddPaymentMethod = () => {
|
|
|
13444
13768
|
|
|
13445
13769
|
// src/commands/payment-methods/list.tsx
|
|
13446
13770
|
import { Box as Box12, Text as Text13 } from "ink";
|
|
13447
|
-
import
|
|
13448
|
-
import {
|
|
13449
|
-
import { jsx as jsx17, jsxs as
|
|
13771
|
+
import Spinner4 from "ink-spinner";
|
|
13772
|
+
import { useCallback as useCallback3 } from "react";
|
|
13773
|
+
import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
13450
13774
|
var PaymentMethodsList = ({
|
|
13451
13775
|
resource,
|
|
13452
13776
|
onComplete
|
|
13453
13777
|
}) => {
|
|
13454
|
-
const
|
|
13455
|
-
|
|
13456
|
-
);
|
|
13457
|
-
const [methods, setMethods] = useState9([]);
|
|
13458
|
-
const [error, setError] = useState9("");
|
|
13459
|
-
useEffect8(() => {
|
|
13460
|
-
const fetch2 = async () => {
|
|
13461
|
-
try {
|
|
13462
|
-
const result = await resource.listPaymentMethods();
|
|
13463
|
-
setMethods(result);
|
|
13464
|
-
setStatus("success");
|
|
13465
|
-
setTimeout(onComplete, 1500);
|
|
13466
|
-
} catch (err) {
|
|
13467
|
-
setError(err.message);
|
|
13468
|
-
setStatus("error");
|
|
13469
|
-
setTimeout(onComplete, 1500);
|
|
13470
|
-
}
|
|
13471
|
-
};
|
|
13472
|
-
fetch2();
|
|
13473
|
-
}, [resource, onComplete]);
|
|
13778
|
+
const action = useCallback3(() => resource.listPaymentMethods(), [resource]);
|
|
13779
|
+
const { status, data: methods, error } = useAsyncAction(action, onComplete);
|
|
13474
13780
|
if (status === "loading") {
|
|
13475
|
-
return /* @__PURE__ */ jsx17(Box12, { children: /* @__PURE__ */
|
|
13476
|
-
/* @__PURE__ */ jsx17(
|
|
13781
|
+
return /* @__PURE__ */ jsx17(Box12, { children: /* @__PURE__ */ jsxs12(Text13, { color: "cyan", children: [
|
|
13782
|
+
/* @__PURE__ */ jsx17(Spinner4, { type: "dots" }),
|
|
13477
13783
|
" Loading payment methods..."
|
|
13478
13784
|
] }) });
|
|
13479
13785
|
}
|
|
13480
13786
|
if (status === "error") {
|
|
13481
|
-
return /* @__PURE__ */
|
|
13787
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
|
|
13482
13788
|
/* @__PURE__ */ jsx17(Text13, { color: "red", children: "\u2717 Failed to load payment methods" }),
|
|
13483
13789
|
/* @__PURE__ */ jsx17(Text13, { color: "red", children: error })
|
|
13484
13790
|
] });
|
|
13485
13791
|
}
|
|
13486
|
-
if (methods.length === 0) {
|
|
13792
|
+
if (!methods || methods.length === 0) {
|
|
13487
13793
|
return /* @__PURE__ */ jsx17(Box12, { children: /* @__PURE__ */ jsx17(Text13, { dimColor: true, children: "No payment methods found" }) });
|
|
13488
13794
|
}
|
|
13489
|
-
return /* @__PURE__ */
|
|
13795
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
|
|
13490
13796
|
/* @__PURE__ */ jsx17(Text13, { bold: true, children: "Payment Methods" }),
|
|
13491
13797
|
/* @__PURE__ */ jsx17(Box12, { flexDirection: "column", marginTop: 1, children: methods.map((pm) => {
|
|
13492
13798
|
const label = pm.card_details?.brand ?? pm.bank_account_details?.bank_name ?? "Bank account";
|
|
13493
13799
|
const last4 = pm.card_details?.last4 ?? pm.bank_account_details?.last4;
|
|
13494
|
-
const suffix =
|
|
13495
|
-
return /* @__PURE__ */ jsx17(Box12, { paddingX: 2, children: /* @__PURE__ */
|
|
13800
|
+
const suffix = pm.nickname ? `(${pm.nickname})` : "";
|
|
13801
|
+
return /* @__PURE__ */ jsx17(Box12, { paddingX: 2, children: /* @__PURE__ */ jsxs12(Text13, { children: [
|
|
13496
13802
|
/* @__PURE__ */ jsx17(Text13, { dimColor: true, children: pm.id }),
|
|
13497
13803
|
" ",
|
|
13498
13804
|
label,
|
|
@@ -13507,36 +13813,22 @@ var PaymentMethodsList = ({
|
|
|
13507
13813
|
|
|
13508
13814
|
// src/commands/payment-methods/index.tsx
|
|
13509
13815
|
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
13510
|
-
function createPaymentMethodsCli(createResource) {
|
|
13816
|
+
function createPaymentMethodsCli(createResource, authStorage2) {
|
|
13511
13817
|
const cli2 = Cli5.create("payment-methods", {
|
|
13512
13818
|
description: "Payment methods management commands"
|
|
13513
13819
|
});
|
|
13514
13820
|
cli2.command("list", {
|
|
13515
13821
|
description: "List all payment methods on your account",
|
|
13516
13822
|
outputPolicy: "agent-only",
|
|
13823
|
+
middleware: [requireAuth(authStorage2)],
|
|
13517
13824
|
async run(c) {
|
|
13518
|
-
if (!storage.isAuthenticated()) {
|
|
13519
|
-
return c.error({
|
|
13520
|
-
code: "NOT_AUTHENTICATED",
|
|
13521
|
-
message: 'Not authenticated. Run "link-cli auth login" first.',
|
|
13522
|
-
cta: {
|
|
13523
|
-
commands: [
|
|
13524
|
-
{ command: "auth login", description: "Log in to Link" }
|
|
13525
|
-
]
|
|
13526
|
-
}
|
|
13527
|
-
});
|
|
13528
|
-
}
|
|
13529
13825
|
const resource = createResource();
|
|
13530
13826
|
if (!c.agent && !c.formatExplicit) {
|
|
13531
|
-
return
|
|
13532
|
-
|
|
13533
|
-
|
|
13534
|
-
|
|
13535
|
-
|
|
13536
|
-
waitUntilExit().then(async () => {
|
|
13537
|
-
resolve(await resource.listPaymentMethods());
|
|
13538
|
-
});
|
|
13539
|
-
});
|
|
13827
|
+
return renderInteractive(
|
|
13828
|
+
/* @__PURE__ */ jsx18(PaymentMethodsList, { resource, onComplete: () => {
|
|
13829
|
+
} }),
|
|
13830
|
+
() => resource.listPaymentMethods()
|
|
13831
|
+
);
|
|
13540
13832
|
}
|
|
13541
13833
|
return resource.listPaymentMethods();
|
|
13542
13834
|
}
|
|
@@ -13544,23 +13836,12 @@ function createPaymentMethodsCli(createResource) {
|
|
|
13544
13836
|
cli2.command("add", {
|
|
13545
13837
|
description: "Open the Link wallet to add a new payment method",
|
|
13546
13838
|
outputPolicy: "agent-only",
|
|
13839
|
+
middleware: [requireAuth(authStorage2)],
|
|
13547
13840
|
async run(c) {
|
|
13548
|
-
if (!storage.isAuthenticated()) {
|
|
13549
|
-
return c.error({
|
|
13550
|
-
code: "NOT_AUTHENTICATED",
|
|
13551
|
-
message: 'Not authenticated. Run "link-cli auth login" first.',
|
|
13552
|
-
cta: {
|
|
13553
|
-
commands: [
|
|
13554
|
-
{ command: "auth login", description: "Log in to Link" }
|
|
13555
|
-
]
|
|
13556
|
-
}
|
|
13557
|
-
});
|
|
13558
|
-
}
|
|
13559
13841
|
if (!c.agent && !c.formatExplicit) {
|
|
13560
|
-
return
|
|
13561
|
-
|
|
13562
|
-
|
|
13563
|
-
});
|
|
13842
|
+
return renderInteractive(/* @__PURE__ */ jsx18(AddPaymentMethod, {}), () => ({
|
|
13843
|
+
url: WALLET_URL
|
|
13844
|
+
}));
|
|
13564
13845
|
}
|
|
13565
13846
|
return { url: WALLET_URL };
|
|
13566
13847
|
}
|
|
@@ -13568,15 +13849,131 @@ function createPaymentMethodsCli(createResource) {
|
|
|
13568
13849
|
return cli2;
|
|
13569
13850
|
}
|
|
13570
13851
|
|
|
13852
|
+
// src/commands/shipping-address/index.tsx
|
|
13853
|
+
import { Cli as Cli6 } from "incur";
|
|
13854
|
+
|
|
13855
|
+
// src/commands/shipping-address/list.tsx
|
|
13856
|
+
import { Box as Box13, Text as Text14 } from "ink";
|
|
13857
|
+
import Spinner5 from "ink-spinner";
|
|
13858
|
+
import { useCallback as useCallback4 } from "react";
|
|
13859
|
+
import { jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
13860
|
+
function formatStreetLine(address) {
|
|
13861
|
+
const parts = [address.line_1, address.line_2].filter(Boolean);
|
|
13862
|
+
return parts.length > 0 ? parts.join(", ") : null;
|
|
13863
|
+
}
|
|
13864
|
+
function formatLocalityLine(address) {
|
|
13865
|
+
const locality = [
|
|
13866
|
+
address.dependent_locality,
|
|
13867
|
+
address.locality,
|
|
13868
|
+
address.administrative_area
|
|
13869
|
+
].filter(Boolean).join(", ");
|
|
13870
|
+
const postal = [address.postal_code, address.sorting_code].filter(Boolean).join(" ");
|
|
13871
|
+
const localityPostal = locality && postal ? `${locality} ${postal}` : locality || postal || null;
|
|
13872
|
+
if (localityPostal && address.country_code) {
|
|
13873
|
+
return `${localityPostal}, ${address.country_code}`;
|
|
13874
|
+
}
|
|
13875
|
+
return localityPostal || address.country_code || null;
|
|
13876
|
+
}
|
|
13877
|
+
function formatAddressLines(addressRecord) {
|
|
13878
|
+
if (!addressRecord.address) {
|
|
13879
|
+
return ["Address details unavailable"];
|
|
13880
|
+
}
|
|
13881
|
+
const address = addressRecord.address;
|
|
13882
|
+
const lines = [formatStreetLine(address), formatLocalityLine(address)].filter(
|
|
13883
|
+
(line) => Boolean(line)
|
|
13884
|
+
);
|
|
13885
|
+
return lines.length > 0 ? lines : ["Address details unavailable"];
|
|
13886
|
+
}
|
|
13887
|
+
var ShippingAddressList = ({
|
|
13888
|
+
resource,
|
|
13889
|
+
onComplete
|
|
13890
|
+
}) => {
|
|
13891
|
+
const action = useCallback4(
|
|
13892
|
+
() => resource.listShippingAddresses(),
|
|
13893
|
+
[resource]
|
|
13894
|
+
);
|
|
13895
|
+
const {
|
|
13896
|
+
status,
|
|
13897
|
+
data: shippingAddresses,
|
|
13898
|
+
error
|
|
13899
|
+
} = useAsyncAction(action, onComplete);
|
|
13900
|
+
if (status === "loading") {
|
|
13901
|
+
return /* @__PURE__ */ jsx19(Box13, { children: /* @__PURE__ */ jsxs13(Text14, { color: "cyan", children: [
|
|
13902
|
+
/* @__PURE__ */ jsx19(Spinner5, { type: "dots" }),
|
|
13903
|
+
" Loading shipping addresses..."
|
|
13904
|
+
] }) });
|
|
13905
|
+
}
|
|
13906
|
+
if (status === "error") {
|
|
13907
|
+
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
|
|
13908
|
+
/* @__PURE__ */ jsx19(Text14, { color: "red", children: "\u2717 Failed to load shipping addresses" }),
|
|
13909
|
+
/* @__PURE__ */ jsx19(Text14, { color: "red", children: error })
|
|
13910
|
+
] });
|
|
13911
|
+
}
|
|
13912
|
+
if (!shippingAddresses || shippingAddresses.length === 0) {
|
|
13913
|
+
return /* @__PURE__ */ jsx19(Box13, { children: /* @__PURE__ */ jsx19(Text14, { dimColor: true, children: "No shipping addresses found" }) });
|
|
13914
|
+
}
|
|
13915
|
+
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
|
|
13916
|
+
/* @__PURE__ */ jsx19(Text14, { bold: true, children: "Shipping Addresses" }),
|
|
13917
|
+
/* @__PURE__ */ jsx19(Box13, { flexDirection: "column", marginTop: 1, children: shippingAddresses.map((shippingAddress) => {
|
|
13918
|
+
const addressName = shippingAddress.address?.name;
|
|
13919
|
+
const nickname = shippingAddress.nickname ? ` (${shippingAddress.nickname})` : "";
|
|
13920
|
+
return /* @__PURE__ */ jsxs13(
|
|
13921
|
+
Box13,
|
|
13922
|
+
{
|
|
13923
|
+
flexDirection: "column",
|
|
13924
|
+
paddingX: 2,
|
|
13925
|
+
marginBottom: 1,
|
|
13926
|
+
children: [
|
|
13927
|
+
/* @__PURE__ */ jsxs13(Text14, { children: [
|
|
13928
|
+
/* @__PURE__ */ jsx19(Text14, { dimColor: true, children: shippingAddress.id }),
|
|
13929
|
+
nickname,
|
|
13930
|
+
shippingAddress.is_default ? /* @__PURE__ */ jsx19(Text14, { color: "green", children: " (default)" }) : null
|
|
13931
|
+
] }),
|
|
13932
|
+
/* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", marginTop: 1, children: [
|
|
13933
|
+
addressName ? /* @__PURE__ */ jsx19(Text14, { bold: true, children: addressName }) : null,
|
|
13934
|
+
formatAddressLines(shippingAddress).map((line) => /* @__PURE__ */ jsx19(Text14, { children: line }, `${shippingAddress.id}:${line}`))
|
|
13935
|
+
] })
|
|
13936
|
+
]
|
|
13937
|
+
},
|
|
13938
|
+
shippingAddress.id
|
|
13939
|
+
);
|
|
13940
|
+
}) })
|
|
13941
|
+
] });
|
|
13942
|
+
};
|
|
13943
|
+
|
|
13944
|
+
// src/commands/shipping-address/index.tsx
|
|
13945
|
+
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
13946
|
+
function createShippingAddressCli(createResource, authStorage2) {
|
|
13947
|
+
const cli2 = Cli6.create("shipping-address", {
|
|
13948
|
+
description: "Shipping address management commands"
|
|
13949
|
+
});
|
|
13950
|
+
cli2.command("list", {
|
|
13951
|
+
description: "List all shipping addresses on your account",
|
|
13952
|
+
outputPolicy: "agent-only",
|
|
13953
|
+
middleware: [requireAuth(authStorage2)],
|
|
13954
|
+
async run(c) {
|
|
13955
|
+
const resource = createResource();
|
|
13956
|
+
if (!c.agent && !c.formatExplicit) {
|
|
13957
|
+
return renderInteractive(
|
|
13958
|
+
/* @__PURE__ */ jsx20(ShippingAddressList, { resource, onComplete: () => {
|
|
13959
|
+
} }),
|
|
13960
|
+
() => resource.listShippingAddresses()
|
|
13961
|
+
);
|
|
13962
|
+
}
|
|
13963
|
+
return resource.listShippingAddresses();
|
|
13964
|
+
}
|
|
13965
|
+
});
|
|
13966
|
+
return cli2;
|
|
13967
|
+
}
|
|
13968
|
+
|
|
13571
13969
|
// src/commands/spend-request/index.tsx
|
|
13572
|
-
import { Cli as
|
|
13573
|
-
import { render as render6 } from "ink";
|
|
13970
|
+
import { Cli as Cli7, z as z7 } from "incur";
|
|
13574
13971
|
|
|
13575
13972
|
// src/utils/credential-output.ts
|
|
13576
13973
|
import fs4 from "fs/promises";
|
|
13577
|
-
import
|
|
13974
|
+
import path6 from "path";
|
|
13578
13975
|
async function writeCredentialFile(filePath, data, force) {
|
|
13579
|
-
const resolved =
|
|
13976
|
+
const resolved = path6.resolve(filePath);
|
|
13580
13977
|
if (!force) {
|
|
13581
13978
|
try {
|
|
13582
13979
|
await fs4.access(resolved);
|
|
@@ -13655,21 +14052,59 @@ function parseTotalFlag(raw) {
|
|
|
13655
14052
|
}
|
|
13656
14053
|
}
|
|
13657
14054
|
|
|
13658
|
-
// src/commands/spend-request/
|
|
14055
|
+
// src/commands/spend-request/cancel.tsx
|
|
13659
14056
|
import { Box as Box14, Text as Text15 } from "ink";
|
|
13660
|
-
import
|
|
13661
|
-
import { useCallback as
|
|
14057
|
+
import Spinner6 from "ink-spinner";
|
|
14058
|
+
import { useCallback as useCallback5 } from "react";
|
|
14059
|
+
import { jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
14060
|
+
var CancelSpendRequest = ({
|
|
14061
|
+
repository,
|
|
14062
|
+
id,
|
|
14063
|
+
onComplete
|
|
14064
|
+
}) => {
|
|
14065
|
+
const action = useCallback5(
|
|
14066
|
+
() => repository.cancelSpendRequest(id),
|
|
14067
|
+
[repository, id]
|
|
14068
|
+
);
|
|
14069
|
+
const { status, data: request, error } = useAsyncAction(action, onComplete);
|
|
14070
|
+
if (status === "loading") {
|
|
14071
|
+
return /* @__PURE__ */ jsx21(Box14, { children: /* @__PURE__ */ jsxs14(Text15, { color: "cyan", children: [
|
|
14072
|
+
/* @__PURE__ */ jsx21(Spinner6, { type: "dots" }),
|
|
14073
|
+
" Canceling spend request ",
|
|
14074
|
+
id,
|
|
14075
|
+
"..."
|
|
14076
|
+
] }) });
|
|
14077
|
+
}
|
|
14078
|
+
if (status === "error") {
|
|
14079
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
14080
|
+
/* @__PURE__ */ jsx21(Text15, { color: "red", children: "\u2717 Failed to cancel spend request" }),
|
|
14081
|
+
/* @__PURE__ */ jsx21(Text15, { color: "red", children: error })
|
|
14082
|
+
] });
|
|
14083
|
+
}
|
|
14084
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
14085
|
+
/* @__PURE__ */ jsx21(Text15, { color: "green", children: "\u2713 Spend request canceled" }),
|
|
14086
|
+
/* @__PURE__ */ jsx21(Box14, { flexDirection: "column", marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsxs14(Text15, { children: [
|
|
14087
|
+
"ID: ",
|
|
14088
|
+
/* @__PURE__ */ jsx21(Text15, { bold: true, children: request?.id })
|
|
14089
|
+
] }) })
|
|
14090
|
+
] });
|
|
14091
|
+
};
|
|
14092
|
+
|
|
14093
|
+
// src/commands/spend-request/create.tsx
|
|
14094
|
+
import { Box as Box16, Text as Text17 } from "ink";
|
|
14095
|
+
import Spinner8 from "ink-spinner";
|
|
14096
|
+
import { useCallback as useCallback6, useEffect as useEffect9, useState as useState9 } from "react";
|
|
13662
14097
|
|
|
13663
14098
|
// src/commands/spend-request/approval-waiting-view.tsx
|
|
13664
|
-
import { Box as
|
|
13665
|
-
import
|
|
13666
|
-
import { jsx as
|
|
14099
|
+
import { Box as Box15, Text as Text16 } from "ink";
|
|
14100
|
+
import Spinner7 from "ink-spinner";
|
|
14101
|
+
import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
13667
14102
|
var ApprovalWaitingView = ({
|
|
13668
14103
|
status,
|
|
13669
14104
|
approvalUrl
|
|
13670
|
-
}) => /* @__PURE__ */
|
|
13671
|
-
/* @__PURE__ */
|
|
13672
|
-
|
|
14105
|
+
}) => /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", paddingY: 1, children: [
|
|
14106
|
+
/* @__PURE__ */ jsxs15(
|
|
14107
|
+
Box15,
|
|
13673
14108
|
{
|
|
13674
14109
|
flexDirection: "column",
|
|
13675
14110
|
borderStyle: "round",
|
|
@@ -13677,25 +14112,25 @@ var ApprovalWaitingView = ({
|
|
|
13677
14112
|
paddingX: 2,
|
|
13678
14113
|
paddingY: 1,
|
|
13679
14114
|
children: [
|
|
13680
|
-
/* @__PURE__ */
|
|
14115
|
+
/* @__PURE__ */ jsxs15(Text16, { children: [
|
|
13681
14116
|
"Approve at:",
|
|
13682
14117
|
" ",
|
|
13683
|
-
/* @__PURE__ */
|
|
14118
|
+
/* @__PURE__ */ jsx22(Text16, { bold: true, color: "cyan", children: approvalUrl })
|
|
13684
14119
|
] }),
|
|
13685
|
-
/* @__PURE__ */
|
|
14120
|
+
/* @__PURE__ */ jsx22(Text16, { dimColor: true, children: "Press Enter to open in browser" })
|
|
13686
14121
|
]
|
|
13687
14122
|
}
|
|
13688
14123
|
),
|
|
13689
|
-
/* @__PURE__ */
|
|
13690
|
-
/* @__PURE__ */
|
|
13691
|
-
/* @__PURE__ */
|
|
14124
|
+
/* @__PURE__ */ jsx22(AppDownloadQrCodes, {}),
|
|
14125
|
+
/* @__PURE__ */ jsx22(Box15, { marginTop: 1, children: status === "polling" ? /* @__PURE__ */ jsxs15(Text16, { color: "cyan", children: [
|
|
14126
|
+
/* @__PURE__ */ jsx22(Spinner7, { type: "dots" }),
|
|
13692
14127
|
" Waiting for approval..."
|
|
13693
|
-
] }) : /* @__PURE__ */
|
|
14128
|
+
] }) : /* @__PURE__ */ jsx22(Text16, { dimColor: true, children: "Waiting..." }) })
|
|
13694
14129
|
] });
|
|
13695
14130
|
|
|
13696
14131
|
// src/commands/spend-request/use-approval-polling.ts
|
|
13697
14132
|
import { useInput as useInput7 } from "ink";
|
|
13698
|
-
import { useEffect as
|
|
14133
|
+
import { useEffect as useEffect8 } from "react";
|
|
13699
14134
|
function useApprovalPolling({
|
|
13700
14135
|
status,
|
|
13701
14136
|
setStatus,
|
|
@@ -13713,22 +14148,29 @@ function useApprovalPolling({
|
|
|
13713
14148
|
},
|
|
13714
14149
|
{ isActive: isWaiting }
|
|
13715
14150
|
);
|
|
13716
|
-
|
|
14151
|
+
useEffect8(() => {
|
|
13717
14152
|
if (status !== "waiting") return;
|
|
13718
14153
|
const timeout = setTimeout(() => setStatus("polling"), 1e3);
|
|
13719
14154
|
return () => clearTimeout(timeout);
|
|
13720
14155
|
}, [status, setStatus]);
|
|
13721
|
-
|
|
14156
|
+
useEffect8(() => {
|
|
13722
14157
|
if (status !== "polling" || !requestId) return;
|
|
13723
14158
|
let cancelled = false;
|
|
13724
14159
|
const poll = async () => {
|
|
13725
14160
|
try {
|
|
13726
14161
|
const final = await pollUntilApproved(repository, requestId);
|
|
13727
|
-
if (
|
|
13728
|
-
|
|
13729
|
-
|
|
13730
|
-
|
|
14162
|
+
if (cancelled) return;
|
|
14163
|
+
if (final.status !== "approved") {
|
|
14164
|
+
onError(
|
|
14165
|
+
`Spend request did not reach approved (status: ${final.status})`
|
|
14166
|
+
);
|
|
14167
|
+
setStatus("error");
|
|
14168
|
+
setTimeout(() => onComplete(final), DISPLAY_DELAY_MS);
|
|
14169
|
+
return;
|
|
13731
14170
|
}
|
|
14171
|
+
onSuccess(final);
|
|
14172
|
+
setStatus("success");
|
|
14173
|
+
setTimeout(() => onComplete(final), DISPLAY_DELAY_MS);
|
|
13732
14174
|
} catch (err) {
|
|
13733
14175
|
if (!cancelled) {
|
|
13734
14176
|
onError(err.message);
|
|
@@ -13752,7 +14194,7 @@ function useApprovalPolling({
|
|
|
13752
14194
|
}
|
|
13753
14195
|
|
|
13754
14196
|
// src/commands/spend-request/create.tsx
|
|
13755
|
-
import { Fragment as Fragment4, jsx as
|
|
14197
|
+
import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
13756
14198
|
var CreateSpendRequest = ({
|
|
13757
14199
|
repository,
|
|
13758
14200
|
params,
|
|
@@ -13761,17 +14203,17 @@ var CreateSpendRequest = ({
|
|
|
13761
14203
|
force,
|
|
13762
14204
|
onComplete
|
|
13763
14205
|
}) => {
|
|
13764
|
-
const [status, setStatus] =
|
|
13765
|
-
const [request, setRequest] =
|
|
13766
|
-
const [error, setError] =
|
|
13767
|
-
const [outputFilePath, setOutputFilePath] =
|
|
13768
|
-
const [fileError, setFileError] =
|
|
14206
|
+
const [status, setStatus] = useState9("creating");
|
|
14207
|
+
const [request, setRequest] = useState9(null);
|
|
14208
|
+
const [error, setError] = useState9("");
|
|
14209
|
+
const [outputFilePath, setOutputFilePath] = useState9(null);
|
|
14210
|
+
const [fileError, setFileError] = useState9("");
|
|
13769
14211
|
const approvalUrl = request?.approval_url ?? "";
|
|
13770
|
-
const onSuccess =
|
|
14212
|
+
const onSuccess = useCallback6(
|
|
13771
14213
|
(result) => setRequest(result),
|
|
13772
14214
|
[]
|
|
13773
14215
|
);
|
|
13774
|
-
const onError =
|
|
14216
|
+
const onError = useCallback6((msg) => setError(msg), []);
|
|
13775
14217
|
useApprovalPolling({
|
|
13776
14218
|
status,
|
|
13777
14219
|
setStatus,
|
|
@@ -13782,7 +14224,7 @@ var CreateSpendRequest = ({
|
|
|
13782
14224
|
onSuccess,
|
|
13783
14225
|
onError
|
|
13784
14226
|
});
|
|
13785
|
-
|
|
14227
|
+
useEffect9(() => {
|
|
13786
14228
|
const create = async () => {
|
|
13787
14229
|
try {
|
|
13788
14230
|
const result = await repository.createSpendRequest(params);
|
|
@@ -13791,17 +14233,17 @@ var CreateSpendRequest = ({
|
|
|
13791
14233
|
setStatus("waiting");
|
|
13792
14234
|
} else {
|
|
13793
14235
|
setStatus("success");
|
|
13794
|
-
setTimeout(() => onComplete(result),
|
|
14236
|
+
setTimeout(() => onComplete(result), DISPLAY_DELAY_MS);
|
|
13795
14237
|
}
|
|
13796
14238
|
} catch (err) {
|
|
13797
14239
|
setError(err.message);
|
|
13798
14240
|
setStatus("error");
|
|
13799
|
-
setTimeout(() => onComplete(null),
|
|
14241
|
+
setTimeout(() => onComplete(null), DISPLAY_DELAY_MS);
|
|
13800
14242
|
}
|
|
13801
14243
|
};
|
|
13802
14244
|
create();
|
|
13803
14245
|
}, [repository, params, requestApproval, onComplete]);
|
|
13804
|
-
|
|
14246
|
+
useEffect9(() => {
|
|
13805
14247
|
if (status !== "success" || !outputFile || !request?.card) return;
|
|
13806
14248
|
const fileData = {
|
|
13807
14249
|
spend_request_id: request.id,
|
|
@@ -13811,104 +14253,104 @@ var CreateSpendRequest = ({
|
|
|
13811
14253
|
created_at: request.created_at,
|
|
13812
14254
|
card: request.card
|
|
13813
14255
|
};
|
|
13814
|
-
writeCredentialFile(outputFile, fileData, force ?? false).then((
|
|
14256
|
+
writeCredentialFile(outputFile, fileData, force ?? false).then((path7) => setOutputFilePath(path7)).catch((err) => setFileError(err.message));
|
|
13815
14257
|
}, [status, outputFile, force, request]);
|
|
13816
14258
|
if (status === "creating") {
|
|
13817
|
-
return /* @__PURE__ */
|
|
13818
|
-
/* @__PURE__ */
|
|
14259
|
+
return /* @__PURE__ */ jsx23(Box16, { children: /* @__PURE__ */ jsxs16(Text17, { color: "cyan", children: [
|
|
14260
|
+
/* @__PURE__ */ jsx23(Spinner8, { type: "dots" }),
|
|
13819
14261
|
" Creating spend request..."
|
|
13820
14262
|
] }) });
|
|
13821
14263
|
}
|
|
13822
14264
|
if (status === "error") {
|
|
13823
|
-
return /* @__PURE__ */
|
|
13824
|
-
/* @__PURE__ */
|
|
13825
|
-
/* @__PURE__ */
|
|
14265
|
+
return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
|
|
14266
|
+
/* @__PURE__ */ jsx23(Text17, { color: "red", children: "\u2717 Failed to create spend request" }),
|
|
14267
|
+
/* @__PURE__ */ jsx23(Text17, { color: "red", children: error })
|
|
13826
14268
|
] });
|
|
13827
14269
|
}
|
|
13828
14270
|
if (status === "success") {
|
|
13829
|
-
return /* @__PURE__ */
|
|
13830
|
-
/* @__PURE__ */
|
|
13831
|
-
/* @__PURE__ */
|
|
13832
|
-
/* @__PURE__ */
|
|
14271
|
+
return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
|
|
14272
|
+
/* @__PURE__ */ jsx23(Text17, { color: "green", children: "\u2713 Spend request created" }),
|
|
14273
|
+
/* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
14274
|
+
/* @__PURE__ */ jsxs16(Text17, { children: [
|
|
13833
14275
|
"ID: ",
|
|
13834
|
-
/* @__PURE__ */
|
|
14276
|
+
/* @__PURE__ */ jsx23(Text17, { bold: true, children: request?.id })
|
|
13835
14277
|
] }),
|
|
13836
|
-
/* @__PURE__ */
|
|
14278
|
+
/* @__PURE__ */ jsxs16(Text17, { children: [
|
|
13837
14279
|
"Status: ",
|
|
13838
|
-
/* @__PURE__ */
|
|
14280
|
+
/* @__PURE__ */ jsx23(Text17, { bold: true, children: request?.status })
|
|
13839
14281
|
] }),
|
|
13840
|
-
/* @__PURE__ */
|
|
14282
|
+
/* @__PURE__ */ jsxs16(Text17, { children: [
|
|
13841
14283
|
"Amount:",
|
|
13842
14284
|
" ",
|
|
13843
|
-
/* @__PURE__ */
|
|
14285
|
+
/* @__PURE__ */ jsx23(Text17, { bold: true, children: request?.amount != null ? `${request.amount} ${request.currency?.toUpperCase() ?? ""}`.trim() : "N/A" })
|
|
13844
14286
|
] }),
|
|
13845
|
-
/* @__PURE__ */
|
|
14287
|
+
/* @__PURE__ */ jsxs16(Text17, { children: [
|
|
13846
14288
|
"Merchant: ",
|
|
13847
|
-
/* @__PURE__ */
|
|
14289
|
+
/* @__PURE__ */ jsx23(Text17, { bold: true, children: request?.merchant_name })
|
|
13848
14290
|
] }),
|
|
13849
|
-
/* @__PURE__ */
|
|
14291
|
+
/* @__PURE__ */ jsxs16(Text17, { children: [
|
|
13850
14292
|
"Line Items:",
|
|
13851
14293
|
" ",
|
|
13852
|
-
/* @__PURE__ */
|
|
14294
|
+
/* @__PURE__ */ jsx23(Text17, { bold: true, children: request?.line_items.map((li) => li.name).join(", ") || "N/A" })
|
|
13853
14295
|
] }),
|
|
13854
|
-
request?.credential_type === "shared_payment_token" && request.shared_payment_token && /* @__PURE__ */
|
|
14296
|
+
request?.credential_type === "shared_payment_token" && request.shared_payment_token && /* @__PURE__ */ jsxs16(Text17, { children: [
|
|
13855
14297
|
"Token: ",
|
|
13856
|
-
/* @__PURE__ */
|
|
14298
|
+
/* @__PURE__ */ jsx23(Text17, { bold: true, children: request.shared_payment_token.id })
|
|
13857
14299
|
] })
|
|
13858
14300
|
] }),
|
|
13859
|
-
request?.card && !outputFile && /* @__PURE__ */
|
|
13860
|
-
/* @__PURE__ */
|
|
13861
|
-
/* @__PURE__ */
|
|
14301
|
+
request?.card && !outputFile && /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", marginTop: 1, children: [
|
|
14302
|
+
/* @__PURE__ */ jsx23(Text17, { bold: true, children: "Card Details:" }),
|
|
14303
|
+
/* @__PURE__ */ jsxs16(Text17, { children: [
|
|
13862
14304
|
" ",
|
|
13863
14305
|
"Number: ",
|
|
13864
|
-
/* @__PURE__ */
|
|
14306
|
+
/* @__PURE__ */ jsx23(Text17, { bold: true, children: request.card.number })
|
|
13865
14307
|
] }),
|
|
13866
|
-
/* @__PURE__ */
|
|
14308
|
+
/* @__PURE__ */ jsxs16(Text17, { children: [
|
|
13867
14309
|
" ",
|
|
13868
14310
|
"Brand: ",
|
|
13869
|
-
/* @__PURE__ */
|
|
14311
|
+
/* @__PURE__ */ jsx23(Text17, { bold: true, children: request.card.brand })
|
|
13870
14312
|
] }),
|
|
13871
|
-
/* @__PURE__ */
|
|
14313
|
+
/* @__PURE__ */ jsxs16(Text17, { children: [
|
|
13872
14314
|
" ",
|
|
13873
14315
|
"Expiry:",
|
|
13874
14316
|
" ",
|
|
13875
|
-
/* @__PURE__ */
|
|
14317
|
+
/* @__PURE__ */ jsxs16(Text17, { bold: true, children: [
|
|
13876
14318
|
String(request.card.exp_month).padStart(2, "0"),
|
|
13877
14319
|
"/",
|
|
13878
14320
|
request.card.exp_year
|
|
13879
14321
|
] })
|
|
13880
14322
|
] }),
|
|
13881
|
-
request.card.cvc && /* @__PURE__ */
|
|
14323
|
+
request.card.cvc && /* @__PURE__ */ jsxs16(Text17, { children: [
|
|
13882
14324
|
" ",
|
|
13883
14325
|
"CVC: ",
|
|
13884
|
-
/* @__PURE__ */
|
|
14326
|
+
/* @__PURE__ */ jsx23(Text17, { bold: true, children: request.card.cvc })
|
|
13885
14327
|
] }),
|
|
13886
|
-
request.card.valid_until && /* @__PURE__ */
|
|
14328
|
+
request.card.valid_until && /* @__PURE__ */ jsxs16(Text17, { children: [
|
|
13887
14329
|
" ",
|
|
13888
14330
|
"Valid Until: ",
|
|
13889
|
-
/* @__PURE__ */
|
|
14331
|
+
/* @__PURE__ */ jsx23(Text17, { bold: true, children: request.card.valid_until })
|
|
13890
14332
|
] })
|
|
13891
14333
|
] }),
|
|
13892
|
-
request?.card && outputFile && /* @__PURE__ */
|
|
13893
|
-
outputFilePath && /* @__PURE__ */
|
|
14334
|
+
request?.card && outputFile && /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", marginTop: 1, children: [
|
|
14335
|
+
outputFilePath && /* @__PURE__ */ jsxs16(Text17, { color: "green", children: [
|
|
13894
14336
|
"Card credentials written to ",
|
|
13895
|
-
/* @__PURE__ */
|
|
14337
|
+
/* @__PURE__ */ jsx23(Text17, { bold: true, children: outputFilePath })
|
|
13896
14338
|
] }),
|
|
13897
|
-
fileError && /* @__PURE__ */
|
|
14339
|
+
fileError && /* @__PURE__ */ jsxs16(Text17, { color: "red", children: [
|
|
13898
14340
|
"Failed to write card file: ",
|
|
13899
14341
|
fileError
|
|
13900
14342
|
] })
|
|
13901
14343
|
] }),
|
|
13902
|
-
/* @__PURE__ */
|
|
14344
|
+
/* @__PURE__ */ jsx23(AppDownloadQrCodes, {})
|
|
13903
14345
|
] });
|
|
13904
14346
|
}
|
|
13905
|
-
return /* @__PURE__ */
|
|
13906
|
-
/* @__PURE__ */
|
|
14347
|
+
return /* @__PURE__ */ jsxs16(Fragment4, { children: [
|
|
14348
|
+
/* @__PURE__ */ jsx23(Box16, { children: /* @__PURE__ */ jsxs16(Text17, { color: "green", children: [
|
|
13907
14349
|
"\u2713 Spend request created (ID: ",
|
|
13908
|
-
/* @__PURE__ */
|
|
14350
|
+
/* @__PURE__ */ jsx23(Text17, { bold: true, children: request?.id }),
|
|
13909
14351
|
")"
|
|
13910
14352
|
] }) }),
|
|
13911
|
-
/* @__PURE__ */
|
|
14353
|
+
/* @__PURE__ */ jsx23(
|
|
13912
14354
|
ApprovalWaitingView,
|
|
13913
14355
|
{
|
|
13914
14356
|
status,
|
|
@@ -13919,21 +14361,21 @@ var CreateSpendRequest = ({
|
|
|
13919
14361
|
};
|
|
13920
14362
|
|
|
13921
14363
|
// src/commands/spend-request/request-approval.tsx
|
|
13922
|
-
import { Box as
|
|
13923
|
-
import
|
|
13924
|
-
import { useCallback as
|
|
13925
|
-
import { jsx as
|
|
14364
|
+
import { Box as Box17, Text as Text18 } from "ink";
|
|
14365
|
+
import Spinner9 from "ink-spinner";
|
|
14366
|
+
import { useCallback as useCallback7, useEffect as useEffect10, useState as useState10 } from "react";
|
|
14367
|
+
import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
13926
14368
|
var RequestApproval = ({
|
|
13927
14369
|
repository,
|
|
13928
14370
|
id,
|
|
13929
14371
|
onComplete
|
|
13930
14372
|
}) => {
|
|
13931
|
-
const [status, setStatus] =
|
|
13932
|
-
const [approvalUrl, setApprovalUrl] =
|
|
13933
|
-
const [result, setResult] =
|
|
13934
|
-
const [error, setError] =
|
|
13935
|
-
const onSuccess =
|
|
13936
|
-
const onError =
|
|
14373
|
+
const [status, setStatus] = useState10("requesting");
|
|
14374
|
+
const [approvalUrl, setApprovalUrl] = useState10("");
|
|
14375
|
+
const [result, setResult] = useState10(null);
|
|
14376
|
+
const [error, setError] = useState10("");
|
|
14377
|
+
const onSuccess = useCallback7((r) => setResult(r), []);
|
|
14378
|
+
const onError = useCallback7((msg) => setError(msg), []);
|
|
13937
14379
|
useApprovalPolling({
|
|
13938
14380
|
status,
|
|
13939
14381
|
setStatus,
|
|
@@ -13944,7 +14386,7 @@ var RequestApproval = ({
|
|
|
13944
14386
|
onSuccess,
|
|
13945
14387
|
onError
|
|
13946
14388
|
});
|
|
13947
|
-
|
|
14389
|
+
useEffect10(() => {
|
|
13948
14390
|
const request = async () => {
|
|
13949
14391
|
try {
|
|
13950
14392
|
const res = await repository.requestApproval(id);
|
|
@@ -13958,46 +14400,46 @@ var RequestApproval = ({
|
|
|
13958
14400
|
request();
|
|
13959
14401
|
}, [repository, id]);
|
|
13960
14402
|
if (status === "requesting") {
|
|
13961
|
-
return /* @__PURE__ */
|
|
13962
|
-
/* @__PURE__ */
|
|
14403
|
+
return /* @__PURE__ */ jsx24(Box17, { children: /* @__PURE__ */ jsxs17(Text18, { color: "cyan", children: [
|
|
14404
|
+
/* @__PURE__ */ jsx24(Spinner9, { type: "dots" }),
|
|
13963
14405
|
" Requesting approval..."
|
|
13964
14406
|
] }) });
|
|
13965
14407
|
}
|
|
13966
14408
|
if (status === "error") {
|
|
13967
|
-
return /* @__PURE__ */
|
|
13968
|
-
/* @__PURE__ */
|
|
13969
|
-
/* @__PURE__ */
|
|
14409
|
+
return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", children: [
|
|
14410
|
+
/* @__PURE__ */ jsx24(Text18, { color: "red", children: "\u2717 Failed to request approval" }),
|
|
14411
|
+
/* @__PURE__ */ jsx24(Text18, { color: "red", children: error })
|
|
13970
14412
|
] });
|
|
13971
14413
|
}
|
|
13972
14414
|
if (status === "success") {
|
|
13973
|
-
return /* @__PURE__ */
|
|
13974
|
-
/* @__PURE__ */
|
|
13975
|
-
/* @__PURE__ */
|
|
13976
|
-
/* @__PURE__ */
|
|
14415
|
+
return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", children: [
|
|
14416
|
+
/* @__PURE__ */ jsx24(Text18, { color: "green", children: "\u2713 Approval completed" }),
|
|
14417
|
+
/* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
14418
|
+
/* @__PURE__ */ jsxs17(Text18, { children: [
|
|
13977
14419
|
"ID: ",
|
|
13978
|
-
/* @__PURE__ */
|
|
14420
|
+
/* @__PURE__ */ jsx24(Text18, { bold: true, children: result?.id })
|
|
13979
14421
|
] }),
|
|
13980
|
-
/* @__PURE__ */
|
|
14422
|
+
/* @__PURE__ */ jsxs17(Text18, { children: [
|
|
13981
14423
|
"Status: ",
|
|
13982
|
-
/* @__PURE__ */
|
|
14424
|
+
/* @__PURE__ */ jsx24(Text18, { bold: true, children: result?.status })
|
|
13983
14425
|
] }),
|
|
13984
|
-
/* @__PURE__ */
|
|
14426
|
+
/* @__PURE__ */ jsxs17(Text18, { children: [
|
|
13985
14427
|
"Amount:",
|
|
13986
14428
|
" ",
|
|
13987
|
-
/* @__PURE__ */
|
|
14429
|
+
/* @__PURE__ */ jsx24(Text18, { bold: true, children: result?.amount != null ? `${result.amount} ${result.currency?.toUpperCase() ?? ""}`.trim() : "N/A" })
|
|
13988
14430
|
] }),
|
|
13989
|
-
/* @__PURE__ */
|
|
14431
|
+
/* @__PURE__ */ jsxs17(Text18, { children: [
|
|
13990
14432
|
"Merchant: ",
|
|
13991
|
-
/* @__PURE__ */
|
|
14433
|
+
/* @__PURE__ */ jsx24(Text18, { bold: true, children: result?.merchant_name })
|
|
13992
14434
|
] }),
|
|
13993
|
-
result?.credential_type === "shared_payment_token" && result.shared_payment_token && /* @__PURE__ */
|
|
14435
|
+
result?.credential_type === "shared_payment_token" && result.shared_payment_token && /* @__PURE__ */ jsxs17(Text18, { children: [
|
|
13994
14436
|
"Token: ",
|
|
13995
|
-
/* @__PURE__ */
|
|
14437
|
+
/* @__PURE__ */ jsx24(Text18, { bold: true, children: result.shared_payment_token.id })
|
|
13996
14438
|
] })
|
|
13997
14439
|
] })
|
|
13998
14440
|
] });
|
|
13999
14441
|
}
|
|
14000
|
-
return /* @__PURE__ */
|
|
14442
|
+
return /* @__PURE__ */ jsx24(
|
|
14001
14443
|
ApprovalWaitingView,
|
|
14002
14444
|
{
|
|
14003
14445
|
status,
|
|
@@ -14007,36 +14449,44 @@ var RequestApproval = ({
|
|
|
14007
14449
|
};
|
|
14008
14450
|
|
|
14009
14451
|
// src/commands/spend-request/retrieve.tsx
|
|
14010
|
-
import { Box as
|
|
14011
|
-
import
|
|
14012
|
-
import { useEffect as
|
|
14013
|
-
import { jsx as
|
|
14452
|
+
import { Box as Box18, Text as Text19 } from "ink";
|
|
14453
|
+
import Spinner10 from "ink-spinner";
|
|
14454
|
+
import { useEffect as useEffect11, useRef as useRef5, useState as useState11 } from "react";
|
|
14455
|
+
import { jsx as jsx25, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
14456
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
14457
|
+
"approved",
|
|
14458
|
+
"denied",
|
|
14459
|
+
"expired",
|
|
14460
|
+
"succeeded",
|
|
14461
|
+
"failed",
|
|
14462
|
+
"canceled"
|
|
14463
|
+
]);
|
|
14014
14464
|
var RetrieveSpendRequest = ({
|
|
14015
14465
|
repository,
|
|
14016
14466
|
id,
|
|
14017
|
-
timeout =
|
|
14467
|
+
timeout = 600,
|
|
14018
14468
|
include,
|
|
14019
14469
|
outputFile,
|
|
14020
14470
|
force,
|
|
14021
14471
|
onComplete
|
|
14022
14472
|
}) => {
|
|
14023
|
-
const [phase, setPhase] =
|
|
14024
|
-
const [request, setRequest] =
|
|
14025
|
-
const [error, setError] =
|
|
14026
|
-
const [elapsed, setElapsed] =
|
|
14027
|
-
const [outputFilePath, setOutputFilePath] =
|
|
14028
|
-
const [fileError, setFileError] =
|
|
14029
|
-
const startTimeRef =
|
|
14030
|
-
const pollRef =
|
|
14031
|
-
const timerRef =
|
|
14032
|
-
const requestRef =
|
|
14033
|
-
|
|
14473
|
+
const [phase, setPhase] = useState11("fetching");
|
|
14474
|
+
const [request, setRequest] = useState11(null);
|
|
14475
|
+
const [error, setError] = useState11("");
|
|
14476
|
+
const [elapsed, setElapsed] = useState11(0);
|
|
14477
|
+
const [outputFilePath, setOutputFilePath] = useState11(null);
|
|
14478
|
+
const [fileError, setFileError] = useState11("");
|
|
14479
|
+
const startTimeRef = useRef5(Date.now());
|
|
14480
|
+
const pollRef = useRef5(null);
|
|
14481
|
+
const timerRef = useRef5(null);
|
|
14482
|
+
const requestRef = useRef5(null);
|
|
14483
|
+
useEffect11(() => {
|
|
14034
14484
|
return () => {
|
|
14035
14485
|
if (pollRef.current) clearInterval(pollRef.current);
|
|
14036
14486
|
if (timerRef.current) clearInterval(timerRef.current);
|
|
14037
14487
|
};
|
|
14038
14488
|
}, []);
|
|
14039
|
-
|
|
14489
|
+
useEffect11(() => {
|
|
14040
14490
|
if (phase !== "success" || !outputFile || !request?.card) return;
|
|
14041
14491
|
const fileData = {
|
|
14042
14492
|
spend_request_id: request.id,
|
|
@@ -14046,26 +14496,29 @@ var RetrieveSpendRequest = ({
|
|
|
14046
14496
|
created_at: request.created_at,
|
|
14047
14497
|
card: request.card
|
|
14048
14498
|
};
|
|
14049
|
-
writeCredentialFile(outputFile, fileData, force ?? false).then((
|
|
14499
|
+
writeCredentialFile(outputFile, fileData, force ?? false).then((path7) => setOutputFilePath(path7)).catch((err) => setFileError(err.message));
|
|
14050
14500
|
}, [phase, outputFile, force, request]);
|
|
14051
|
-
|
|
14501
|
+
useEffect11(() => {
|
|
14052
14502
|
const fetch2 = async () => {
|
|
14053
14503
|
try {
|
|
14054
14504
|
const result = await repository.getSpendRequest(id, { include });
|
|
14055
14505
|
if (!result) {
|
|
14056
14506
|
setError(`Spend request ${id} not found`);
|
|
14057
14507
|
setPhase("error");
|
|
14058
|
-
setTimeout(() => onComplete(null),
|
|
14508
|
+
setTimeout(() => onComplete(null), DISPLAY_DELAY_MS);
|
|
14059
14509
|
return;
|
|
14060
14510
|
}
|
|
14061
14511
|
requestRef.current = result;
|
|
14062
14512
|
setRequest(result);
|
|
14063
14513
|
if (result.status === "approved") {
|
|
14064
14514
|
setPhase("success");
|
|
14065
|
-
setTimeout(() => onComplete(result),
|
|
14515
|
+
setTimeout(() => onComplete(result), DISPLAY_DELAY_MS);
|
|
14066
14516
|
} else if (result.status === "denied") {
|
|
14067
14517
|
setPhase("declined");
|
|
14068
|
-
setTimeout(() => onComplete(result),
|
|
14518
|
+
setTimeout(() => onComplete(result), DISPLAY_DELAY_MS);
|
|
14519
|
+
} else if (TERMINAL_STATUSES.has(result.status)) {
|
|
14520
|
+
setPhase("finalized");
|
|
14521
|
+
setTimeout(() => onComplete(result), DISPLAY_DELAY_MS);
|
|
14069
14522
|
} else {
|
|
14070
14523
|
startTimeRef.current = Date.now();
|
|
14071
14524
|
setPhase("polling");
|
|
@@ -14073,12 +14526,12 @@ var RetrieveSpendRequest = ({
|
|
|
14073
14526
|
} catch (err) {
|
|
14074
14527
|
setError(err.message);
|
|
14075
14528
|
setPhase("error");
|
|
14076
|
-
setTimeout(() => onComplete(null),
|
|
14529
|
+
setTimeout(() => onComplete(null), DISPLAY_DELAY_MS);
|
|
14077
14530
|
}
|
|
14078
14531
|
};
|
|
14079
14532
|
fetch2();
|
|
14080
14533
|
}, [repository, id, include, onComplete]);
|
|
14081
|
-
|
|
14534
|
+
useEffect11(() => {
|
|
14082
14535
|
if (phase !== "polling") return;
|
|
14083
14536
|
timerRef.current = setInterval(() => {
|
|
14084
14537
|
const secs = Math.floor((Date.now() - startTimeRef.current) / 1e3);
|
|
@@ -14090,7 +14543,7 @@ var RetrieveSpendRequest = ({
|
|
|
14090
14543
|
if (pollRef.current) clearInterval(pollRef.current);
|
|
14091
14544
|
if (timerRef.current) clearInterval(timerRef.current);
|
|
14092
14545
|
setPhase("timeout");
|
|
14093
|
-
setTimeout(() => onComplete(requestRef.current),
|
|
14546
|
+
setTimeout(() => onComplete(requestRef.current), DISPLAY_DELAY_MS);
|
|
14094
14547
|
return;
|
|
14095
14548
|
}
|
|
14096
14549
|
try {
|
|
@@ -14102,12 +14555,17 @@ var RetrieveSpendRequest = ({
|
|
|
14102
14555
|
if (pollRef.current) clearInterval(pollRef.current);
|
|
14103
14556
|
if (timerRef.current) clearInterval(timerRef.current);
|
|
14104
14557
|
setPhase("success");
|
|
14105
|
-
setTimeout(() => onComplete(result),
|
|
14558
|
+
setTimeout(() => onComplete(result), DISPLAY_DELAY_MS);
|
|
14106
14559
|
} else if (result.status === "denied") {
|
|
14107
14560
|
if (pollRef.current) clearInterval(pollRef.current);
|
|
14108
14561
|
if (timerRef.current) clearInterval(timerRef.current);
|
|
14109
14562
|
setPhase("declined");
|
|
14110
|
-
setTimeout(() => onComplete(result),
|
|
14563
|
+
setTimeout(() => onComplete(result), DISPLAY_DELAY_MS);
|
|
14564
|
+
} else if (TERMINAL_STATUSES.has(result.status)) {
|
|
14565
|
+
if (pollRef.current) clearInterval(pollRef.current);
|
|
14566
|
+
if (timerRef.current) clearInterval(timerRef.current);
|
|
14567
|
+
setPhase("finalized");
|
|
14568
|
+
setTimeout(() => onComplete(result), DISPLAY_DELAY_MS);
|
|
14111
14569
|
}
|
|
14112
14570
|
} catch {
|
|
14113
14571
|
}
|
|
@@ -14118,163 +14576,181 @@ var RetrieveSpendRequest = ({
|
|
|
14118
14576
|
};
|
|
14119
14577
|
}, [phase, repository, id, include, timeout, onComplete]);
|
|
14120
14578
|
if (phase === "fetching") {
|
|
14121
|
-
return /* @__PURE__ */
|
|
14122
|
-
/* @__PURE__ */
|
|
14579
|
+
return /* @__PURE__ */ jsx25(Box18, { children: /* @__PURE__ */ jsxs18(Text19, { color: "cyan", children: [
|
|
14580
|
+
/* @__PURE__ */ jsx25(Spinner10, { type: "dots" }),
|
|
14123
14581
|
" Retrieving spend request ",
|
|
14124
14582
|
id,
|
|
14125
14583
|
"..."
|
|
14126
14584
|
] }) });
|
|
14127
14585
|
}
|
|
14128
14586
|
if (phase === "error") {
|
|
14129
|
-
return /* @__PURE__ */
|
|
14587
|
+
return /* @__PURE__ */ jsx25(Box18, { flexDirection: "column", children: /* @__PURE__ */ jsxs18(Text19, { color: "red", children: [
|
|
14130
14588
|
"\u2717 ",
|
|
14131
14589
|
error
|
|
14132
14590
|
] }) });
|
|
14133
14591
|
}
|
|
14134
14592
|
if (phase === "timeout") {
|
|
14135
|
-
return /* @__PURE__ */
|
|
14136
|
-
/* @__PURE__ */
|
|
14593
|
+
return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", children: [
|
|
14594
|
+
/* @__PURE__ */ jsxs18(Text19, { color: "yellow", children: [
|
|
14137
14595
|
"\u2717 Timed out waiting for approval after ",
|
|
14138
14596
|
timeout,
|
|
14139
14597
|
"s"
|
|
14140
14598
|
] }),
|
|
14141
|
-
request && /* @__PURE__ */
|
|
14142
|
-
/* @__PURE__ */
|
|
14599
|
+
request && /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
14600
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14143
14601
|
"ID: ",
|
|
14144
|
-
/* @__PURE__ */
|
|
14602
|
+
/* @__PURE__ */ jsx25(Text19, { bold: true, children: request.id })
|
|
14145
14603
|
] }),
|
|
14146
|
-
/* @__PURE__ */
|
|
14604
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14147
14605
|
"Status: ",
|
|
14148
|
-
/* @__PURE__ */
|
|
14606
|
+
/* @__PURE__ */ jsx25(Text19, { bold: true, children: request.status })
|
|
14149
14607
|
] })
|
|
14150
14608
|
] })
|
|
14151
14609
|
] });
|
|
14152
14610
|
}
|
|
14153
14611
|
if (phase === "polling") {
|
|
14154
|
-
return /* @__PURE__ */
|
|
14155
|
-
/* @__PURE__ */
|
|
14156
|
-
/* @__PURE__ */
|
|
14612
|
+
return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", children: [
|
|
14613
|
+
/* @__PURE__ */ jsx25(Box18, { children: /* @__PURE__ */ jsxs18(Text19, { color: "cyan", children: [
|
|
14614
|
+
/* @__PURE__ */ jsx25(Spinner10, { type: "dots" }),
|
|
14157
14615
|
" Awaiting approval... (",
|
|
14158
14616
|
elapsed,
|
|
14159
14617
|
"s elapsed)"
|
|
14160
14618
|
] }) }),
|
|
14161
|
-
request?.approval_url && /* @__PURE__ */
|
|
14619
|
+
request?.approval_url && /* @__PURE__ */ jsx25(Box18, { marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsxs18(Text19, { dimColor: true, children: [
|
|
14162
14620
|
"Approval URL: ",
|
|
14163
|
-
/* @__PURE__ */
|
|
14621
|
+
/* @__PURE__ */ jsx25(Text19, { color: "cyan", children: request.approval_url })
|
|
14164
14622
|
] }) })
|
|
14165
14623
|
] });
|
|
14166
14624
|
}
|
|
14625
|
+
if (phase === "finalized") {
|
|
14626
|
+
return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", children: [
|
|
14627
|
+
/* @__PURE__ */ jsxs18(Text19, { color: "yellow", children: [
|
|
14628
|
+
"Spend request reached terminal status: ",
|
|
14629
|
+
request?.status
|
|
14630
|
+
] }),
|
|
14631
|
+
/* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
14632
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14633
|
+
"ID: ",
|
|
14634
|
+
/* @__PURE__ */ jsx25(Text19, { bold: true, children: request?.id })
|
|
14635
|
+
] }),
|
|
14636
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14637
|
+
"Status: ",
|
|
14638
|
+
/* @__PURE__ */ jsx25(Text19, { bold: true, children: request?.status })
|
|
14639
|
+
] })
|
|
14640
|
+
] })
|
|
14641
|
+
] });
|
|
14642
|
+
}
|
|
14167
14643
|
if (phase === "declined") {
|
|
14168
|
-
return /* @__PURE__ */
|
|
14169
|
-
/* @__PURE__ */
|
|
14170
|
-
/* @__PURE__ */
|
|
14171
|
-
/* @__PURE__ */
|
|
14644
|
+
return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", children: [
|
|
14645
|
+
/* @__PURE__ */ jsx25(Text19, { color: "red", children: "\u2717 Spend request declined" }),
|
|
14646
|
+
/* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
14647
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14172
14648
|
"ID: ",
|
|
14173
|
-
/* @__PURE__ */
|
|
14649
|
+
/* @__PURE__ */ jsx25(Text19, { bold: true, children: request?.id })
|
|
14174
14650
|
] }),
|
|
14175
|
-
/* @__PURE__ */
|
|
14651
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14176
14652
|
"Status:",
|
|
14177
14653
|
" ",
|
|
14178
|
-
/* @__PURE__ */
|
|
14654
|
+
/* @__PURE__ */ jsx25(Text19, { bold: true, color: "red", children: request?.status })
|
|
14179
14655
|
] }),
|
|
14180
|
-
/* @__PURE__ */
|
|
14656
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14181
14657
|
"Amount:",
|
|
14182
14658
|
" ",
|
|
14183
|
-
/* @__PURE__ */
|
|
14659
|
+
/* @__PURE__ */ jsx25(Text19, { bold: true, children: request?.amount != null ? String(request.amount) : "N/A" })
|
|
14184
14660
|
] }),
|
|
14185
|
-
/* @__PURE__ */
|
|
14661
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14186
14662
|
"Merchant: ",
|
|
14187
|
-
/* @__PURE__ */
|
|
14663
|
+
/* @__PURE__ */ jsx25(Text19, { bold: true, children: request?.merchant_name })
|
|
14188
14664
|
] })
|
|
14189
14665
|
] })
|
|
14190
14666
|
] });
|
|
14191
14667
|
}
|
|
14192
|
-
return /* @__PURE__ */
|
|
14193
|
-
/* @__PURE__ */
|
|
14194
|
-
/* @__PURE__ */
|
|
14195
|
-
/* @__PURE__ */
|
|
14668
|
+
return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", children: [
|
|
14669
|
+
/* @__PURE__ */ jsx25(Text19, { color: "green", children: "\u2713 Spend request approved" }),
|
|
14670
|
+
/* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
14671
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14196
14672
|
"ID: ",
|
|
14197
|
-
/* @__PURE__ */
|
|
14673
|
+
/* @__PURE__ */ jsx25(Text19, { bold: true, children: request?.id })
|
|
14198
14674
|
] }),
|
|
14199
|
-
/* @__PURE__ */
|
|
14675
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14200
14676
|
"Status:",
|
|
14201
14677
|
" ",
|
|
14202
|
-
/* @__PURE__ */
|
|
14678
|
+
/* @__PURE__ */ jsx25(Text19, { bold: true, color: "green", children: request?.status })
|
|
14203
14679
|
] }),
|
|
14204
|
-
/* @__PURE__ */
|
|
14680
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14205
14681
|
"Amount:",
|
|
14206
14682
|
" ",
|
|
14207
|
-
/* @__PURE__ */
|
|
14683
|
+
/* @__PURE__ */ jsx25(Text19, { bold: true, children: request?.amount != null ? String(request.amount) : "N/A" })
|
|
14208
14684
|
] }),
|
|
14209
|
-
/* @__PURE__ */
|
|
14685
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14210
14686
|
"Merchant: ",
|
|
14211
|
-
/* @__PURE__ */
|
|
14687
|
+
/* @__PURE__ */ jsx25(Text19, { bold: true, children: request?.merchant_name })
|
|
14212
14688
|
] }),
|
|
14213
|
-
/* @__PURE__ */
|
|
14689
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14214
14690
|
"Line Items:",
|
|
14215
14691
|
" ",
|
|
14216
|
-
/* @__PURE__ */
|
|
14692
|
+
/* @__PURE__ */ jsx25(Text19, { bold: true, children: request?.line_items.map((li) => li.name).join(", ") })
|
|
14217
14693
|
] }),
|
|
14218
|
-
request?.shared_payment_token && /* @__PURE__ */
|
|
14219
|
-
/* @__PURE__ */
|
|
14694
|
+
request?.shared_payment_token && /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", marginTop: 1, children: [
|
|
14695
|
+
/* @__PURE__ */ jsxs18(Text19, { bold: true, children: [
|
|
14220
14696
|
"\x1B]8;;https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens\x07",
|
|
14221
14697
|
"Shared Payment Token",
|
|
14222
14698
|
"\x1B]8;;\x07",
|
|
14223
14699
|
":"
|
|
14224
14700
|
] }),
|
|
14225
|
-
/* @__PURE__ */
|
|
14701
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14226
14702
|
" ",
|
|
14227
14703
|
"Token: ",
|
|
14228
|
-
/* @__PURE__ */
|
|
14704
|
+
/* @__PURE__ */ jsx25(Text19, { bold: true, children: request.shared_payment_token.id })
|
|
14229
14705
|
] })
|
|
14230
14706
|
] }),
|
|
14231
|
-
request?.card && !outputFile && /* @__PURE__ */
|
|
14232
|
-
/* @__PURE__ */
|
|
14233
|
-
/* @__PURE__ */
|
|
14707
|
+
request?.card && !outputFile && /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", marginTop: 1, children: [
|
|
14708
|
+
/* @__PURE__ */ jsx25(Text19, { bold: true, children: "Card Details:" }),
|
|
14709
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14234
14710
|
" ",
|
|
14235
14711
|
"Number: ",
|
|
14236
|
-
/* @__PURE__ */
|
|
14712
|
+
/* @__PURE__ */ jsx25(Text19, { bold: true, children: request?.card.number })
|
|
14237
14713
|
] }),
|
|
14238
|
-
/* @__PURE__ */
|
|
14714
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14239
14715
|
" ",
|
|
14240
14716
|
"Brand: ",
|
|
14241
|
-
/* @__PURE__ */
|
|
14717
|
+
/* @__PURE__ */ jsx25(Text19, { bold: true, children: request?.card.brand })
|
|
14242
14718
|
] }),
|
|
14243
|
-
/* @__PURE__ */
|
|
14719
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14244
14720
|
" ",
|
|
14245
14721
|
"Expiry:",
|
|
14246
14722
|
" ",
|
|
14247
|
-
/* @__PURE__ */
|
|
14723
|
+
/* @__PURE__ */ jsxs18(Text19, { bold: true, children: [
|
|
14248
14724
|
String(request?.card.exp_month).padStart(2, "0"),
|
|
14249
14725
|
"/",
|
|
14250
14726
|
request?.card.exp_year
|
|
14251
14727
|
] })
|
|
14252
14728
|
] }),
|
|
14253
|
-
request?.card.cvc && /* @__PURE__ */
|
|
14729
|
+
request?.card.cvc && /* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14254
14730
|
" ",
|
|
14255
14731
|
"CVC: ",
|
|
14256
|
-
/* @__PURE__ */
|
|
14732
|
+
/* @__PURE__ */ jsx25(Text19, { bold: true, children: request.card.cvc })
|
|
14257
14733
|
] }),
|
|
14258
|
-
request?.card.valid_until && /* @__PURE__ */
|
|
14734
|
+
request?.card.valid_until && /* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14259
14735
|
" ",
|
|
14260
14736
|
"Valid Until: ",
|
|
14261
|
-
/* @__PURE__ */
|
|
14737
|
+
/* @__PURE__ */ jsx25(Text19, { bold: true, children: request.card.valid_until })
|
|
14262
14738
|
] }),
|
|
14263
|
-
request?.card.billing_address && /* @__PURE__ */
|
|
14264
|
-
/* @__PURE__ */
|
|
14265
|
-
/* @__PURE__ */
|
|
14739
|
+
request?.card.billing_address && /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", marginTop: 1, children: [
|
|
14740
|
+
/* @__PURE__ */ jsx25(Text19, { bold: true, children: " Billing Address:" }),
|
|
14741
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14266
14742
|
" ",
|
|
14267
14743
|
request.card.billing_address.name
|
|
14268
14744
|
] }),
|
|
14269
|
-
/* @__PURE__ */
|
|
14745
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14270
14746
|
" ",
|
|
14271
14747
|
request.card.billing_address.line1
|
|
14272
14748
|
] }),
|
|
14273
|
-
request.card.billing_address.line2 && /* @__PURE__ */
|
|
14749
|
+
request.card.billing_address.line2 && /* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14274
14750
|
" ",
|
|
14275
14751
|
request.card.billing_address.line2
|
|
14276
14752
|
] }),
|
|
14277
|
-
/* @__PURE__ */
|
|
14753
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14278
14754
|
" ",
|
|
14279
14755
|
[
|
|
14280
14756
|
request.card.billing_address.city,
|
|
@@ -14282,18 +14758,18 @@ var RetrieveSpendRequest = ({
|
|
|
14282
14758
|
request.card.billing_address.postal_code
|
|
14283
14759
|
].filter(Boolean).join(", ")
|
|
14284
14760
|
] }),
|
|
14285
|
-
/* @__PURE__ */
|
|
14761
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
14286
14762
|
" ",
|
|
14287
14763
|
request.card.billing_address.country
|
|
14288
14764
|
] })
|
|
14289
14765
|
] })
|
|
14290
14766
|
] }),
|
|
14291
|
-
request?.card && outputFile && /* @__PURE__ */
|
|
14292
|
-
outputFilePath && /* @__PURE__ */
|
|
14767
|
+
request?.card && outputFile && /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", marginTop: 1, children: [
|
|
14768
|
+
outputFilePath && /* @__PURE__ */ jsxs18(Text19, { color: "green", children: [
|
|
14293
14769
|
"Card credentials written to ",
|
|
14294
|
-
/* @__PURE__ */
|
|
14770
|
+
/* @__PURE__ */ jsx25(Text19, { bold: true, children: outputFilePath })
|
|
14295
14771
|
] }),
|
|
14296
|
-
fileError && /* @__PURE__ */
|
|
14772
|
+
fileError && /* @__PURE__ */ jsxs18(Text19, { color: "red", children: [
|
|
14297
14773
|
"Failed to write card file: ",
|
|
14298
14774
|
fileError
|
|
14299
14775
|
] })
|
|
@@ -14327,7 +14803,7 @@ var createOptions = z6.object({
|
|
|
14327
14803
|
'Line item (repeatable, key:value format). Keys: name (required), quantity, unit_amount, description, sku, url, image_url, product_url. Example: "name:Shoes,unit_amount:5000,quantity:2"'
|
|
14328
14804
|
),
|
|
14329
14805
|
total: z6.array(z6.union([z6.string(), z6.record(z6.string(), z6.unknown())])).default([]).describe(
|
|
14330
|
-
'Total (repeatable, key:value format). Keys: type (required; one of: subtotal, tax, total), display_text (required), amount (required). Example: "type:total,display_text:Total,amount:5000"'
|
|
14806
|
+
'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"'
|
|
14331
14807
|
),
|
|
14332
14808
|
requestApproval: z6.boolean().default(true).describe("Request approval and poll until approved/denied/expired"),
|
|
14333
14809
|
test: z6.boolean().default(false).describe(
|
|
@@ -14339,8 +14815,8 @@ var createOptions = z6.object({
|
|
|
14339
14815
|
force: z6.boolean().default(false).describe("Overwrite output file if it already exists")
|
|
14340
14816
|
});
|
|
14341
14817
|
var retrieveOptions = z6.object({
|
|
14342
|
-
timeout: z6.coerce.number().default(
|
|
14343
|
-
"Polling timeout in seconds. When reached during active polling, exits non-zero with POLLING_TIMEOUT."
|
|
14818
|
+
timeout: z6.coerce.number().default(600).describe(
|
|
14819
|
+
"Polling timeout in seconds. When reached during active polling, exits non-zero with POLLING_TIMEOUT. Default exceeds the server-side spend-request expiry so polling outlives the request itself."
|
|
14344
14820
|
),
|
|
14345
14821
|
interval: z6.coerce.number().default(0).describe(
|
|
14346
14822
|
"Poll interval in seconds. When > 0, polls until status is terminal, timeout is reached, or max attempts are exhausted."
|
|
@@ -14365,89 +14841,74 @@ var updateOptions = z6.object({
|
|
|
14365
14841
|
'Line item (repeatable, key:value format). Keys: name (required), quantity, unit_amount, description, sku, url, image_url, product_url. Example: "name:Shoes,unit_amount:5000,quantity:2"'
|
|
14366
14842
|
),
|
|
14367
14843
|
total: z6.array(z6.union([z6.string(), z6.record(z6.string(), z6.unknown())])).default([]).describe(
|
|
14368
|
-
'Total (repeatable, key:value format). Keys: type (required; one of: subtotal, tax, total), display_text (required), amount (required). Example: "type:total,display_text:Total,amount:5000"'
|
|
14844
|
+
'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"'
|
|
14369
14845
|
)
|
|
14370
14846
|
});
|
|
14371
14847
|
|
|
14372
14848
|
// src/commands/spend-request/update.tsx
|
|
14373
|
-
import { Box as
|
|
14374
|
-
import
|
|
14375
|
-
import {
|
|
14376
|
-
import { jsx as
|
|
14849
|
+
import { Box as Box19, Text as Text20 } from "ink";
|
|
14850
|
+
import Spinner11 from "ink-spinner";
|
|
14851
|
+
import { useCallback as useCallback8 } from "react";
|
|
14852
|
+
import { jsx as jsx26, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
14377
14853
|
var UpdateSpendRequest = ({
|
|
14378
14854
|
repository,
|
|
14379
14855
|
id,
|
|
14380
14856
|
params,
|
|
14381
14857
|
onComplete
|
|
14382
14858
|
}) => {
|
|
14383
|
-
const
|
|
14384
|
-
|
|
14859
|
+
const action = useCallback8(
|
|
14860
|
+
() => repository.updateSpendRequest(id, params),
|
|
14861
|
+
[repository, id, params]
|
|
14385
14862
|
);
|
|
14386
|
-
const
|
|
14387
|
-
const [error, setError] = useState13("");
|
|
14388
|
-
useEffect13(() => {
|
|
14389
|
-
const update = async () => {
|
|
14390
|
-
try {
|
|
14391
|
-
const result = await repository.updateSpendRequest(id, params);
|
|
14392
|
-
setRequest(result);
|
|
14393
|
-
setStatus("success");
|
|
14394
|
-
setTimeout(() => onComplete(result), 1500);
|
|
14395
|
-
} catch (err) {
|
|
14396
|
-
setError(err.message);
|
|
14397
|
-
setStatus("error");
|
|
14398
|
-
setTimeout(() => onComplete(null), 1500);
|
|
14399
|
-
}
|
|
14400
|
-
};
|
|
14401
|
-
update();
|
|
14402
|
-
}, [repository, id, params, onComplete]);
|
|
14863
|
+
const { status, data: request, error } = useAsyncAction(action, onComplete);
|
|
14403
14864
|
if (status === "loading") {
|
|
14404
|
-
return /* @__PURE__ */
|
|
14405
|
-
/* @__PURE__ */
|
|
14865
|
+
return /* @__PURE__ */ jsx26(Box19, { children: /* @__PURE__ */ jsxs19(Text20, { color: "cyan", children: [
|
|
14866
|
+
/* @__PURE__ */ jsx26(Spinner11, { type: "dots" }),
|
|
14406
14867
|
" Updating spend request ",
|
|
14407
14868
|
id,
|
|
14408
14869
|
"..."
|
|
14409
14870
|
] }) });
|
|
14410
14871
|
}
|
|
14411
14872
|
if (status === "error") {
|
|
14412
|
-
return /* @__PURE__ */
|
|
14413
|
-
/* @__PURE__ */
|
|
14414
|
-
/* @__PURE__ */
|
|
14873
|
+
return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", children: [
|
|
14874
|
+
/* @__PURE__ */ jsx26(Text20, { color: "red", children: "\u2717 Failed to update spend request" }),
|
|
14875
|
+
/* @__PURE__ */ jsx26(Text20, { color: "red", children: error })
|
|
14415
14876
|
] });
|
|
14416
14877
|
}
|
|
14417
|
-
return /* @__PURE__ */
|
|
14418
|
-
/* @__PURE__ */
|
|
14419
|
-
/* @__PURE__ */
|
|
14420
|
-
/* @__PURE__ */
|
|
14878
|
+
return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", children: [
|
|
14879
|
+
/* @__PURE__ */ jsx26(Text20, { color: "green", children: "\u2713 Spend request updated" }),
|
|
14880
|
+
/* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
14881
|
+
/* @__PURE__ */ jsxs19(Text20, { children: [
|
|
14421
14882
|
"ID: ",
|
|
14422
|
-
/* @__PURE__ */
|
|
14883
|
+
/* @__PURE__ */ jsx26(Text20, { bold: true, children: request?.id })
|
|
14423
14884
|
] }),
|
|
14424
|
-
/* @__PURE__ */
|
|
14885
|
+
/* @__PURE__ */ jsxs19(Text20, { children: [
|
|
14425
14886
|
"Status: ",
|
|
14426
|
-
/* @__PURE__ */
|
|
14887
|
+
/* @__PURE__ */ jsx26(Text20, { bold: true, children: request?.status })
|
|
14427
14888
|
] }),
|
|
14428
|
-
/* @__PURE__ */
|
|
14889
|
+
/* @__PURE__ */ jsxs19(Text20, { children: [
|
|
14429
14890
|
"Amount:",
|
|
14430
14891
|
" ",
|
|
14431
|
-
/* @__PURE__ */
|
|
14892
|
+
/* @__PURE__ */ jsx26(Text20, { bold: true, children: (() => {
|
|
14432
14893
|
const t = request?.totals.find((t2) => t2.type === "total");
|
|
14433
14894
|
return t ? String(t.amount) : "N/A";
|
|
14434
14895
|
})() })
|
|
14435
14896
|
] }),
|
|
14436
|
-
/* @__PURE__ */
|
|
14897
|
+
/* @__PURE__ */ jsxs19(Text20, { children: [
|
|
14437
14898
|
"Merchant: ",
|
|
14438
|
-
/* @__PURE__ */
|
|
14899
|
+
/* @__PURE__ */ jsx26(Text20, { bold: true, children: request?.merchant_name })
|
|
14439
14900
|
] }),
|
|
14440
|
-
/* @__PURE__ */
|
|
14901
|
+
/* @__PURE__ */ jsxs19(Text20, { children: [
|
|
14441
14902
|
"Line Items:",
|
|
14442
14903
|
" ",
|
|
14443
|
-
/* @__PURE__ */
|
|
14904
|
+
/* @__PURE__ */ jsx26(Text20, { bold: true, children: request?.line_items.map((li) => li.name).join(", ") })
|
|
14444
14905
|
] })
|
|
14445
14906
|
] })
|
|
14446
14907
|
] });
|
|
14447
14908
|
};
|
|
14448
14909
|
|
|
14449
14910
|
// src/commands/spend-request/index.tsx
|
|
14450
|
-
import { jsx as
|
|
14911
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
14451
14912
|
async function applyOutputFile(request, outputFile, force) {
|
|
14452
14913
|
if (!outputFile || !request.card) return request;
|
|
14453
14914
|
const fileData = {
|
|
@@ -14465,8 +14926,8 @@ async function applyOutputFile(request, outputFile, force) {
|
|
|
14465
14926
|
card_output_file: resolvedPath
|
|
14466
14927
|
};
|
|
14467
14928
|
}
|
|
14468
|
-
function createSpendRequestCli(repository) {
|
|
14469
|
-
const cli2 =
|
|
14929
|
+
function createSpendRequestCli(repository, authStorage2) {
|
|
14930
|
+
const cli2 = Cli7.create("spend-request", {
|
|
14470
14931
|
description: "Spend request management commands"
|
|
14471
14932
|
});
|
|
14472
14933
|
cli2.command("create", {
|
|
@@ -14475,17 +14936,7 @@ function createSpendRequestCli(repository) {
|
|
|
14475
14936
|
alias: { merchantName: "m" },
|
|
14476
14937
|
outputPolicy: "agent-only",
|
|
14477
14938
|
async *run(c) {
|
|
14478
|
-
|
|
14479
|
-
return c.error({
|
|
14480
|
-
code: "NOT_AUTHENTICATED",
|
|
14481
|
-
message: 'Not authenticated. Run "link-cli auth login" first.',
|
|
14482
|
-
cta: {
|
|
14483
|
-
commands: [
|
|
14484
|
-
{ command: "auth login", description: "Log in to Link" }
|
|
14485
|
-
]
|
|
14486
|
-
}
|
|
14487
|
-
});
|
|
14488
|
-
}
|
|
14939
|
+
requireAuthGuard(c, authStorage2);
|
|
14489
14940
|
const opts = c.options;
|
|
14490
14941
|
const requestApproval = !!opts.requestApproval;
|
|
14491
14942
|
const credentialType = opts.credentialType;
|
|
@@ -14545,27 +14996,27 @@ function createSpendRequestCli(repository) {
|
|
|
14545
14996
|
const outputFile = opts.outputFile;
|
|
14546
14997
|
const forceOverwrite = opts.force;
|
|
14547
14998
|
if (!c.agent && !c.formatExplicit) {
|
|
14548
|
-
|
|
14549
|
-
|
|
14550
|
-
|
|
14551
|
-
|
|
14552
|
-
|
|
14553
|
-
|
|
14554
|
-
|
|
14555
|
-
|
|
14556
|
-
|
|
14557
|
-
|
|
14558
|
-
|
|
14559
|
-
|
|
14560
|
-
capturedResult = result;
|
|
14561
|
-
}
|
|
14999
|
+
let capturedResult = null;
|
|
15000
|
+
return renderInteractive(
|
|
15001
|
+
/* @__PURE__ */ jsx27(
|
|
15002
|
+
CreateSpendRequest,
|
|
15003
|
+
{
|
|
15004
|
+
repository,
|
|
15005
|
+
params: createParams,
|
|
15006
|
+
requestApproval,
|
|
15007
|
+
outputFile,
|
|
15008
|
+
force: forceOverwrite,
|
|
15009
|
+
onComplete: (result) => {
|
|
15010
|
+
capturedResult = result;
|
|
14562
15011
|
}
|
|
14563
|
-
|
|
14564
|
-
)
|
|
14565
|
-
|
|
14566
|
-
|
|
14567
|
-
|
|
14568
|
-
|
|
15012
|
+
}
|
|
15013
|
+
),
|
|
15014
|
+
() => {
|
|
15015
|
+
if (!capturedResult)
|
|
15016
|
+
throw new Error("Component exited without producing a result");
|
|
15017
|
+
return capturedResult;
|
|
15018
|
+
}
|
|
15019
|
+
);
|
|
14569
15020
|
}
|
|
14570
15021
|
const created = await repository.createSpendRequest(createParams);
|
|
14571
15022
|
if (!requestApproval) {
|
|
@@ -14582,9 +15033,9 @@ function createSpendRequestCli(repository) {
|
|
|
14582
15033
|
}
|
|
14583
15034
|
yield {
|
|
14584
15035
|
...created,
|
|
14585
|
-
instruction: `Present the approval_url to the user and ask them to approve in the Link app. Then call \`spend-request retrieve ${created.id} --interval 2 --max-attempts
|
|
15036
|
+
instruction: `Present the approval_url to the user and ask them to approve in the Link app. Then call \`spend-request retrieve ${created.id} --interval 2 --max-attempts 300\` to poll until approved. Do not wait for the user to reply \u2014 start polling immediately.`,
|
|
14586
15037
|
_next: {
|
|
14587
|
-
command: `spend-request retrieve ${created.id} --interval 2 --max-attempts
|
|
15038
|
+
command: `spend-request retrieve ${created.id} --interval 2 --max-attempts 300`,
|
|
14588
15039
|
until: "status changes from pending_approval"
|
|
14589
15040
|
}
|
|
14590
15041
|
};
|
|
@@ -14597,18 +15048,8 @@ function createSpendRequestCli(repository) {
|
|
|
14597
15048
|
}),
|
|
14598
15049
|
options: updateOptions,
|
|
14599
15050
|
outputPolicy: "agent-only",
|
|
15051
|
+
middleware: [requireAuth(authStorage2)],
|
|
14600
15052
|
async run(c) {
|
|
14601
|
-
if (!storage.isAuthenticated()) {
|
|
14602
|
-
return c.error({
|
|
14603
|
-
code: "NOT_AUTHENTICATED",
|
|
14604
|
-
message: 'Not authenticated. Run "link-cli auth login" first.',
|
|
14605
|
-
cta: {
|
|
14606
|
-
commands: [
|
|
14607
|
-
{ command: "auth login", description: "Log in to Link" }
|
|
14608
|
-
]
|
|
14609
|
-
}
|
|
14610
|
-
});
|
|
14611
|
-
}
|
|
14612
15053
|
const id = c.args.id;
|
|
14613
15054
|
const opts = c.options;
|
|
14614
15055
|
const params = {};
|
|
@@ -14629,25 +15070,25 @@ function createSpendRequestCli(repository) {
|
|
|
14629
15070
|
(item) => typeof item === "string" ? parseTotalFlag(item) : item
|
|
14630
15071
|
);
|
|
14631
15072
|
if (!c.agent && !c.formatExplicit) {
|
|
14632
|
-
|
|
14633
|
-
|
|
14634
|
-
|
|
14635
|
-
|
|
14636
|
-
|
|
14637
|
-
|
|
14638
|
-
|
|
14639
|
-
|
|
14640
|
-
|
|
14641
|
-
|
|
14642
|
-
capturedResult = result;
|
|
14643
|
-
}
|
|
15073
|
+
let capturedResult = null;
|
|
15074
|
+
return renderInteractive(
|
|
15075
|
+
/* @__PURE__ */ jsx27(
|
|
15076
|
+
UpdateSpendRequest,
|
|
15077
|
+
{
|
|
15078
|
+
repository,
|
|
15079
|
+
id,
|
|
15080
|
+
params,
|
|
15081
|
+
onComplete: (result) => {
|
|
15082
|
+
capturedResult = result;
|
|
14644
15083
|
}
|
|
14645
|
-
|
|
14646
|
-
)
|
|
14647
|
-
|
|
14648
|
-
|
|
14649
|
-
|
|
14650
|
-
|
|
15084
|
+
}
|
|
15085
|
+
),
|
|
15086
|
+
() => {
|
|
15087
|
+
if (!capturedResult)
|
|
15088
|
+
throw new Error("Component exited without producing a result");
|
|
15089
|
+
return capturedResult;
|
|
15090
|
+
}
|
|
15091
|
+
);
|
|
14651
15092
|
}
|
|
14652
15093
|
return repository.updateSpendRequest(id, params);
|
|
14653
15094
|
}
|
|
@@ -14659,44 +15100,34 @@ function createSpendRequestCli(repository) {
|
|
|
14659
15100
|
}),
|
|
14660
15101
|
outputPolicy: "agent-only",
|
|
14661
15102
|
async *run(c) {
|
|
14662
|
-
|
|
14663
|
-
return c.error({
|
|
14664
|
-
code: "NOT_AUTHENTICATED",
|
|
14665
|
-
message: 'Not authenticated. Run "link-cli auth login" first.',
|
|
14666
|
-
cta: {
|
|
14667
|
-
commands: [
|
|
14668
|
-
{ command: "auth login", description: "Log in to Link" }
|
|
14669
|
-
]
|
|
14670
|
-
}
|
|
14671
|
-
});
|
|
14672
|
-
}
|
|
15103
|
+
requireAuthGuard(c, authStorage2);
|
|
14673
15104
|
const id = c.args.id;
|
|
14674
15105
|
if (!c.agent && !c.formatExplicit) {
|
|
14675
|
-
|
|
14676
|
-
|
|
14677
|
-
|
|
14678
|
-
|
|
14679
|
-
|
|
14680
|
-
|
|
14681
|
-
|
|
14682
|
-
|
|
14683
|
-
|
|
14684
|
-
capturedResult = result;
|
|
14685
|
-
}
|
|
15106
|
+
let capturedResult = null;
|
|
15107
|
+
return renderInteractive(
|
|
15108
|
+
/* @__PURE__ */ jsx27(
|
|
15109
|
+
RequestApproval,
|
|
15110
|
+
{
|
|
15111
|
+
repository,
|
|
15112
|
+
id,
|
|
15113
|
+
onComplete: (result) => {
|
|
15114
|
+
capturedResult = result;
|
|
14686
15115
|
}
|
|
14687
|
-
|
|
14688
|
-
)
|
|
14689
|
-
|
|
14690
|
-
|
|
14691
|
-
|
|
14692
|
-
|
|
15116
|
+
}
|
|
15117
|
+
),
|
|
15118
|
+
() => {
|
|
15119
|
+
if (!capturedResult)
|
|
15120
|
+
throw new Error("Component exited without producing a result");
|
|
15121
|
+
return capturedResult;
|
|
15122
|
+
}
|
|
15123
|
+
);
|
|
14693
15124
|
}
|
|
14694
15125
|
const approval = await repository.requestApproval(id);
|
|
14695
15126
|
yield {
|
|
14696
15127
|
...approval,
|
|
14697
|
-
instruction: `Present the approval_url to the user and ask them to approve in the Link app. Then call \`spend-request retrieve ${id} --interval 2 --max-attempts
|
|
15128
|
+
instruction: `Present the approval_url to the user and ask them to approve in the Link app. Then call \`spend-request retrieve ${id} --interval 2 --max-attempts 300\` to poll until approved. Do not wait for the user to reply \u2014 start polling immediately.`,
|
|
14698
15129
|
_next: {
|
|
14699
|
-
command: `spend-request retrieve ${id} --interval 2 --max-attempts
|
|
15130
|
+
command: `spend-request retrieve ${id} --interval 2 --max-attempts 300`,
|
|
14700
15131
|
until: "status changes from pending_approval"
|
|
14701
15132
|
}
|
|
14702
15133
|
};
|
|
@@ -14710,17 +15141,7 @@ function createSpendRequestCli(repository) {
|
|
|
14710
15141
|
options: retrieveOptions,
|
|
14711
15142
|
outputPolicy: "agent-only",
|
|
14712
15143
|
async *run(c) {
|
|
14713
|
-
|
|
14714
|
-
return c.error({
|
|
14715
|
-
code: "NOT_AUTHENTICATED",
|
|
14716
|
-
message: 'Not authenticated. Run "link-cli auth login" first.',
|
|
14717
|
-
cta: {
|
|
14718
|
-
commands: [
|
|
14719
|
-
{ command: "auth login", description: "Log in to Link" }
|
|
14720
|
-
]
|
|
14721
|
-
}
|
|
14722
|
-
});
|
|
14723
|
-
}
|
|
15144
|
+
requireAuthGuard(c, authStorage2);
|
|
14724
15145
|
const id = c.args.id;
|
|
14725
15146
|
const opts = c.options;
|
|
14726
15147
|
const timeout = opts.timeout;
|
|
@@ -14731,78 +15152,178 @@ function createSpendRequestCli(repository) {
|
|
|
14731
15152
|
const outputFile = opts.outputFile;
|
|
14732
15153
|
const forceOverwrite = opts.force;
|
|
14733
15154
|
if (!c.agent && !c.formatExplicit) {
|
|
14734
|
-
|
|
14735
|
-
|
|
14736
|
-
|
|
14737
|
-
|
|
14738
|
-
|
|
14739
|
-
|
|
14740
|
-
|
|
14741
|
-
|
|
14742
|
-
|
|
14743
|
-
|
|
14744
|
-
|
|
14745
|
-
|
|
14746
|
-
|
|
14747
|
-
capturedResult = result;
|
|
14748
|
-
}
|
|
15155
|
+
let capturedResult = null;
|
|
15156
|
+
return renderInteractive(
|
|
15157
|
+
/* @__PURE__ */ jsx27(
|
|
15158
|
+
RetrieveSpendRequest,
|
|
15159
|
+
{
|
|
15160
|
+
repository,
|
|
15161
|
+
id,
|
|
15162
|
+
timeout,
|
|
15163
|
+
include,
|
|
15164
|
+
outputFile,
|
|
15165
|
+
force: forceOverwrite,
|
|
15166
|
+
onComplete: (result) => {
|
|
15167
|
+
capturedResult = result;
|
|
14749
15168
|
}
|
|
14750
|
-
|
|
14751
|
-
)
|
|
14752
|
-
|
|
14753
|
-
|
|
14754
|
-
|
|
14755
|
-
|
|
15169
|
+
}
|
|
15170
|
+
),
|
|
15171
|
+
() => {
|
|
15172
|
+
if (!capturedResult)
|
|
15173
|
+
throw new Error("Component exited without producing a result");
|
|
15174
|
+
return capturedResult;
|
|
15175
|
+
}
|
|
15176
|
+
);
|
|
14756
15177
|
}
|
|
14757
15178
|
const terminalStatuses = /* @__PURE__ */ new Set([
|
|
14758
15179
|
"approved",
|
|
14759
15180
|
"denied",
|
|
14760
15181
|
"expired",
|
|
14761
15182
|
"succeeded",
|
|
14762
|
-
"failed"
|
|
15183
|
+
"failed",
|
|
15184
|
+
"canceled"
|
|
14763
15185
|
]);
|
|
14764
|
-
|
|
14765
|
-
|
|
14766
|
-
|
|
14767
|
-
|
|
14768
|
-
|
|
14769
|
-
|
|
15186
|
+
for await (const result of pollUntil({
|
|
15187
|
+
fn: () => repository.getSpendRequest(id, { include }),
|
|
15188
|
+
isTerminal: (req) => req === null || terminalStatuses.has(req.status),
|
|
15189
|
+
interval,
|
|
15190
|
+
maxAttempts,
|
|
15191
|
+
timeout
|
|
15192
|
+
})) {
|
|
15193
|
+
if (result.value === null) {
|
|
14770
15194
|
return c.error({
|
|
14771
15195
|
code: "NOT_FOUND",
|
|
14772
15196
|
message: `Spend request ${id} not found`
|
|
14773
15197
|
});
|
|
14774
15198
|
}
|
|
14775
|
-
|
|
14776
|
-
|
|
14777
|
-
|
|
14778
|
-
|
|
14779
|
-
|
|
14780
|
-
|
|
14781
|
-
|
|
14782
|
-
|
|
15199
|
+
if (result.terminal) {
|
|
15200
|
+
if (terminalStatuses.has(result.value.status) || !result.reason) {
|
|
15201
|
+
try {
|
|
15202
|
+
yield await applyOutputFile(
|
|
15203
|
+
result.value,
|
|
15204
|
+
outputFile,
|
|
15205
|
+
forceOverwrite
|
|
15206
|
+
);
|
|
15207
|
+
} catch (err) {
|
|
15208
|
+
const message = err.message;
|
|
15209
|
+
if (message.startsWith("OUTPUT_FILE_EXISTS")) {
|
|
15210
|
+
return c.error({ code: "OUTPUT_FILE_EXISTS", message });
|
|
15211
|
+
}
|
|
15212
|
+
return c.error({ code: "OUTPUT_FILE_WRITE_ERROR", message });
|
|
14783
15213
|
}
|
|
14784
|
-
return
|
|
15214
|
+
return;
|
|
14785
15215
|
}
|
|
14786
|
-
|
|
14787
|
-
}
|
|
14788
|
-
attempts++;
|
|
14789
|
-
const maxAttemptsExhausted = maxAttempts > 0 && attempts >= maxAttempts;
|
|
14790
|
-
const timeoutReached = Date.now() >= deadline;
|
|
14791
|
-
if (maxAttemptsExhausted || timeoutReached) {
|
|
14792
|
-
const reason = maxAttemptsExhausted ? `max attempts (${maxAttempts}) exhausted` : `timeout (${timeout}s) reached`;
|
|
15216
|
+
const reason = result.reason === "max_attempts" ? `max attempts (${maxAttempts}) exhausted` : `timeout (${timeout}s) reached`;
|
|
14793
15217
|
return c.error({
|
|
14794
15218
|
code: "POLLING_TIMEOUT",
|
|
14795
|
-
message: `Polling stopped before spend request ${id} reached a terminal status: ${reason}; current status is ${
|
|
15219
|
+
message: `Polling stopped before spend request ${id} reached a terminal status: ${reason}; current status is ${result.value.status}.`,
|
|
14796
15220
|
retryable: true
|
|
14797
15221
|
});
|
|
14798
15222
|
}
|
|
14799
|
-
|
|
14800
|
-
|
|
14801
|
-
|
|
14802
|
-
|
|
14803
|
-
|
|
14804
|
-
|
|
15223
|
+
yield result.value;
|
|
15224
|
+
}
|
|
15225
|
+
}
|
|
15226
|
+
});
|
|
15227
|
+
cli2.command("cancel", {
|
|
15228
|
+
description: "Cancel a spend request",
|
|
15229
|
+
args: z7.object({
|
|
15230
|
+
id: z7.string().describe("Spend request ID")
|
|
15231
|
+
}),
|
|
15232
|
+
outputPolicy: "agent-only",
|
|
15233
|
+
middleware: [requireAuth(authStorage2)],
|
|
15234
|
+
async run(c) {
|
|
15235
|
+
const id = c.args.id;
|
|
15236
|
+
if (!c.agent && !c.formatExplicit) {
|
|
15237
|
+
let capturedResult = null;
|
|
15238
|
+
return renderInteractive(
|
|
15239
|
+
/* @__PURE__ */ jsx27(
|
|
15240
|
+
CancelSpendRequest,
|
|
15241
|
+
{
|
|
15242
|
+
repository,
|
|
15243
|
+
id,
|
|
15244
|
+
onComplete: (result) => {
|
|
15245
|
+
capturedResult = result;
|
|
15246
|
+
}
|
|
15247
|
+
}
|
|
15248
|
+
),
|
|
15249
|
+
() => {
|
|
15250
|
+
if (!capturedResult)
|
|
15251
|
+
throw new Error("Component exited without producing a result");
|
|
15252
|
+
return capturedResult;
|
|
15253
|
+
}
|
|
15254
|
+
);
|
|
15255
|
+
}
|
|
15256
|
+
return repository.cancelSpendRequest(id);
|
|
15257
|
+
}
|
|
15258
|
+
});
|
|
15259
|
+
return cli2;
|
|
15260
|
+
}
|
|
15261
|
+
|
|
15262
|
+
// src/commands/user-info/index.tsx
|
|
15263
|
+
import { Cli as Cli8 } from "incur";
|
|
15264
|
+
|
|
15265
|
+
// src/commands/user-info/retrieve.tsx
|
|
15266
|
+
import { Box as Box20, Text as Text21 } from "ink";
|
|
15267
|
+
import Spinner12 from "ink-spinner";
|
|
15268
|
+
import { useCallback as useCallback9 } from "react";
|
|
15269
|
+
import { jsx as jsx28, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
15270
|
+
var UserInfoRetrieve = ({
|
|
15271
|
+
resource,
|
|
15272
|
+
onComplete
|
|
15273
|
+
}) => {
|
|
15274
|
+
const action = useCallback9(() => resource.retrieve(), [resource]);
|
|
15275
|
+
const { status, data: userInfo, error } = useAsyncAction(action, onComplete);
|
|
15276
|
+
if (status === "loading") {
|
|
15277
|
+
return /* @__PURE__ */ jsx28(Box20, { children: /* @__PURE__ */ jsxs20(Text21, { color: "cyan", children: [
|
|
15278
|
+
/* @__PURE__ */ jsx28(Spinner12, { type: "dots" }),
|
|
15279
|
+
" Loading user info..."
|
|
15280
|
+
] }) });
|
|
15281
|
+
}
|
|
15282
|
+
if (status === "error") {
|
|
15283
|
+
return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", children: [
|
|
15284
|
+
/* @__PURE__ */ jsx28(Text21, { color: "red", children: "\u2717 Failed to load user info" }),
|
|
15285
|
+
/* @__PURE__ */ jsx28(Text21, { color: "red", children: error })
|
|
15286
|
+
] });
|
|
15287
|
+
}
|
|
15288
|
+
return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", children: [
|
|
15289
|
+
/* @__PURE__ */ jsx28(Text21, { bold: true, children: "User Info" }),
|
|
15290
|
+
/* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
15291
|
+
/* @__PURE__ */ jsxs20(Text21, { children: [
|
|
15292
|
+
/* @__PURE__ */ jsx28(Text21, { dimColor: true, children: "Email: " }),
|
|
15293
|
+
userInfo?.email ?? /* @__PURE__ */ jsx28(Text21, { dimColor: true, children: "Not set" })
|
|
15294
|
+
] }),
|
|
15295
|
+
/* @__PURE__ */ jsxs20(Text21, { children: [
|
|
15296
|
+
/* @__PURE__ */ jsx28(Text21, { dimColor: true, children: "Name: " }),
|
|
15297
|
+
userInfo?.name ?? /* @__PURE__ */ jsx28(Text21, { dimColor: true, children: "Not set" })
|
|
15298
|
+
] }),
|
|
15299
|
+
/* @__PURE__ */ jsxs20(Text21, { children: [
|
|
15300
|
+
/* @__PURE__ */ jsx28(Text21, { dimColor: true, children: "Phone: " }),
|
|
15301
|
+
userInfo?.phone ?? /* @__PURE__ */ jsx28(Text21, { dimColor: true, children: "Not set" })
|
|
15302
|
+
] })
|
|
15303
|
+
] })
|
|
15304
|
+
] });
|
|
15305
|
+
};
|
|
15306
|
+
|
|
15307
|
+
// src/commands/user-info/index.tsx
|
|
15308
|
+
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
15309
|
+
function createUserInfoCli(createResource, authStorage2) {
|
|
15310
|
+
const cli2 = Cli8.create("user-info", {
|
|
15311
|
+
description: "User information commands"
|
|
15312
|
+
});
|
|
15313
|
+
cli2.command("retrieve", {
|
|
15314
|
+
description: "Retrieve user info (email, name, phone)",
|
|
15315
|
+
outputPolicy: "agent-only",
|
|
15316
|
+
middleware: [requireAuth(authStorage2)],
|
|
15317
|
+
async run(c) {
|
|
15318
|
+
const resource = createResource();
|
|
15319
|
+
if (!c.agent && !c.formatExplicit) {
|
|
15320
|
+
return renderInteractive(
|
|
15321
|
+
/* @__PURE__ */ jsx29(UserInfoRetrieve, { resource, onComplete: () => {
|
|
15322
|
+
} }),
|
|
15323
|
+
() => resource.retrieve()
|
|
15324
|
+
);
|
|
14805
15325
|
}
|
|
15326
|
+
return resource.retrieve();
|
|
14806
15327
|
}
|
|
14807
15328
|
});
|
|
14808
15329
|
return cli2;
|
|
@@ -15032,9 +15553,9 @@ ${JSON.stringify(redacted, null, 2)}`
|
|
|
15032
15553
|
|
|
15033
15554
|
// src/auth/session.ts
|
|
15034
15555
|
var EXPIRY_BUFFER_MS = 6e4;
|
|
15035
|
-
function createAccessTokenProvider(authResource,
|
|
15556
|
+
function createAccessTokenProvider(authResource, authStorage2 = storage) {
|
|
15036
15557
|
return async ({ forceRefresh } = {}) => {
|
|
15037
|
-
const auth =
|
|
15558
|
+
const auth = authStorage2.getAuth();
|
|
15038
15559
|
if (!auth) {
|
|
15039
15560
|
throw new LinkAuthenticationError(
|
|
15040
15561
|
'Not authenticated. Run "link-cli auth login" first.'
|
|
@@ -15045,22 +15566,78 @@ function createAccessTokenProvider(authResource, authStorage = storage) {
|
|
|
15045
15566
|
return auth.access_token;
|
|
15046
15567
|
}
|
|
15047
15568
|
const refreshed = await authResource.refreshToken(auth.refresh_token);
|
|
15048
|
-
|
|
15569
|
+
authStorage2.setAuth(refreshed);
|
|
15049
15570
|
return refreshed.access_token;
|
|
15050
15571
|
};
|
|
15051
15572
|
}
|
|
15052
15573
|
|
|
15574
|
+
// src/utils/sanitize-text.ts
|
|
15575
|
+
import stripAnsi from "strip-ansi";
|
|
15576
|
+
var CONTROL_CHAR_RE = /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f\r]/g;
|
|
15577
|
+
var NEEDS_SANITIZE_RE = /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f\r\x1b]/;
|
|
15578
|
+
function sanitizeText(input) {
|
|
15579
|
+
if (!input) {
|
|
15580
|
+
return "";
|
|
15581
|
+
}
|
|
15582
|
+
if (!NEEDS_SANITIZE_RE.test(input)) {
|
|
15583
|
+
return input;
|
|
15584
|
+
}
|
|
15585
|
+
return stripAnsi(input).replace(CONTROL_CHAR_RE, "");
|
|
15586
|
+
}
|
|
15587
|
+
function sanitizeDeep(value) {
|
|
15588
|
+
if (value === null || value === void 0) {
|
|
15589
|
+
return value;
|
|
15590
|
+
}
|
|
15591
|
+
if (typeof value === "string") {
|
|
15592
|
+
return sanitizeText(value);
|
|
15593
|
+
}
|
|
15594
|
+
if (Array.isArray(value)) {
|
|
15595
|
+
return value.map(sanitizeDeep);
|
|
15596
|
+
}
|
|
15597
|
+
if (typeof value === "object") {
|
|
15598
|
+
const result = {};
|
|
15599
|
+
const keys = Object.keys(value);
|
|
15600
|
+
for (let i = 0; i < keys.length; i++) {
|
|
15601
|
+
const k = keys[i];
|
|
15602
|
+
result[k] = sanitizeDeep(value[k]);
|
|
15603
|
+
}
|
|
15604
|
+
return result;
|
|
15605
|
+
}
|
|
15606
|
+
return value;
|
|
15607
|
+
}
|
|
15608
|
+
|
|
15053
15609
|
// src/utils/resource-factory.ts
|
|
15610
|
+
function sanitizeResource(resource) {
|
|
15611
|
+
return new Proxy(resource, {
|
|
15612
|
+
get(target, prop, receiver) {
|
|
15613
|
+
const value = Reflect.get(target, prop, receiver);
|
|
15614
|
+
if (typeof value !== "function") {
|
|
15615
|
+
return value;
|
|
15616
|
+
}
|
|
15617
|
+
return (...args) => {
|
|
15618
|
+
const result = value.apply(target, args);
|
|
15619
|
+
if (result && typeof result.then === "function") {
|
|
15620
|
+
return result.then(sanitizeDeep);
|
|
15621
|
+
}
|
|
15622
|
+
return result;
|
|
15623
|
+
};
|
|
15624
|
+
}
|
|
15625
|
+
});
|
|
15626
|
+
}
|
|
15054
15627
|
var ResourceFactory = class {
|
|
15055
15628
|
verbose;
|
|
15056
15629
|
defaultHeaders;
|
|
15630
|
+
authStorage;
|
|
15057
15631
|
authResource;
|
|
15058
15632
|
accessTokenProvider;
|
|
15059
15633
|
spendRequestResource;
|
|
15060
15634
|
paymentMethodsResource;
|
|
15635
|
+
shippingAddressResource;
|
|
15636
|
+
userInfoResource;
|
|
15061
15637
|
constructor(options = {}) {
|
|
15062
15638
|
this.verbose = options.verbose ?? false;
|
|
15063
15639
|
this.defaultHeaders = options.defaultHeaders;
|
|
15640
|
+
this.authStorage = options.authStorage;
|
|
15064
15641
|
}
|
|
15065
15642
|
createAuthResource() {
|
|
15066
15643
|
if (this.authResource) {
|
|
@@ -15072,12 +15649,16 @@ var ResourceFactory = class {
|
|
|
15072
15649
|
});
|
|
15073
15650
|
return this.authResource;
|
|
15074
15651
|
}
|
|
15652
|
+
getAuthStorage() {
|
|
15653
|
+
return this.authStorage;
|
|
15654
|
+
}
|
|
15075
15655
|
createSdkAccessTokenProvider() {
|
|
15076
15656
|
if (this.accessTokenProvider) {
|
|
15077
15657
|
return this.accessTokenProvider;
|
|
15078
15658
|
}
|
|
15079
15659
|
this.accessTokenProvider = createAccessTokenProvider(
|
|
15080
|
-
this.createAuthResource()
|
|
15660
|
+
this.createAuthResource(),
|
|
15661
|
+
this.authStorage
|
|
15081
15662
|
);
|
|
15082
15663
|
return this.accessTokenProvider;
|
|
15083
15664
|
}
|
|
@@ -15086,11 +15667,13 @@ var ResourceFactory = class {
|
|
|
15086
15667
|
return this.spendRequestResource;
|
|
15087
15668
|
}
|
|
15088
15669
|
const getAccessToken = this.createSdkAccessTokenProvider();
|
|
15089
|
-
this.spendRequestResource =
|
|
15090
|
-
|
|
15091
|
-
|
|
15092
|
-
|
|
15093
|
-
|
|
15670
|
+
this.spendRequestResource = sanitizeResource(
|
|
15671
|
+
new SpendRequestResource({
|
|
15672
|
+
verbose: this.verbose,
|
|
15673
|
+
defaultHeaders: this.defaultHeaders,
|
|
15674
|
+
getAccessToken
|
|
15675
|
+
})
|
|
15676
|
+
);
|
|
15094
15677
|
return this.spendRequestResource;
|
|
15095
15678
|
}
|
|
15096
15679
|
createPaymentMethodsResource() {
|
|
@@ -15098,13 +15681,43 @@ var ResourceFactory = class {
|
|
|
15098
15681
|
return this.paymentMethodsResource;
|
|
15099
15682
|
}
|
|
15100
15683
|
const getAccessToken = this.createSdkAccessTokenProvider();
|
|
15101
|
-
this.paymentMethodsResource =
|
|
15102
|
-
|
|
15103
|
-
|
|
15104
|
-
|
|
15105
|
-
|
|
15684
|
+
this.paymentMethodsResource = sanitizeResource(
|
|
15685
|
+
new PaymentMethodsResource({
|
|
15686
|
+
verbose: this.verbose,
|
|
15687
|
+
defaultHeaders: this.defaultHeaders,
|
|
15688
|
+
getAccessToken
|
|
15689
|
+
})
|
|
15690
|
+
);
|
|
15106
15691
|
return this.paymentMethodsResource;
|
|
15107
15692
|
}
|
|
15693
|
+
createShippingAddressResource() {
|
|
15694
|
+
if (this.shippingAddressResource) {
|
|
15695
|
+
return this.shippingAddressResource;
|
|
15696
|
+
}
|
|
15697
|
+
const getAccessToken = this.createSdkAccessTokenProvider();
|
|
15698
|
+
this.shippingAddressResource = sanitizeResource(
|
|
15699
|
+
new ShippingAddressResource({
|
|
15700
|
+
verbose: this.verbose,
|
|
15701
|
+
defaultHeaders: this.defaultHeaders,
|
|
15702
|
+
getAccessToken
|
|
15703
|
+
})
|
|
15704
|
+
);
|
|
15705
|
+
return this.shippingAddressResource;
|
|
15706
|
+
}
|
|
15707
|
+
createUserInfoResource() {
|
|
15708
|
+
if (this.userInfoResource) {
|
|
15709
|
+
return this.userInfoResource;
|
|
15710
|
+
}
|
|
15711
|
+
const getAccessToken = this.createSdkAccessTokenProvider();
|
|
15712
|
+
this.userInfoResource = sanitizeResource(
|
|
15713
|
+
new UserInfoResource({
|
|
15714
|
+
verbose: this.verbose,
|
|
15715
|
+
defaultHeaders: this.defaultHeaders,
|
|
15716
|
+
getAccessToken
|
|
15717
|
+
})
|
|
15718
|
+
);
|
|
15719
|
+
return this.userInfoResource;
|
|
15720
|
+
}
|
|
15108
15721
|
};
|
|
15109
15722
|
|
|
15110
15723
|
// src/utils/update-info.ts
|
|
@@ -15178,7 +15791,7 @@ function cacheUpdateInfo(value, ttlMs = UPDATE_CACHE_TTL_MS) {
|
|
|
15178
15791
|
}
|
|
15179
15792
|
|
|
15180
15793
|
// src/cli.tsx
|
|
15181
|
-
var cliVersion = "0.
|
|
15794
|
+
var cliVersion = "0.5.0";
|
|
15182
15795
|
var buildNumber = "1";
|
|
15183
15796
|
var cliName = "@stripe/link-cli";
|
|
15184
15797
|
var defaultHeaders = {
|
|
@@ -15186,10 +15799,16 @@ var defaultHeaders = {
|
|
|
15186
15799
|
"X-Build-Number": buildNumber
|
|
15187
15800
|
};
|
|
15188
15801
|
var verbose = process.argv.includes("--verbose");
|
|
15189
|
-
var
|
|
15802
|
+
var authFileIndex = process.argv.indexOf("--auth");
|
|
15803
|
+
var credentialFilePath = authFileIndex !== -1 ? process.argv[authFileIndex + 1] : process.env.LINK_AUTH_FILE;
|
|
15804
|
+
if (authFileIndex !== -1) {
|
|
15805
|
+
process.argv.splice(authFileIndex, 2);
|
|
15806
|
+
}
|
|
15807
|
+
var authStorage = credentialFilePath ? new Storage({ configPath: credentialFilePath }) : storage;
|
|
15808
|
+
var factory = new ResourceFactory({ verbose, defaultHeaders, authStorage });
|
|
15190
15809
|
var authRepo = factory.createAuthResource();
|
|
15191
15810
|
var spendRequestRepo = factory.createSpendRequestResource();
|
|
15192
|
-
var cli =
|
|
15811
|
+
var cli = Cli9.create("link-cli", {
|
|
15193
15812
|
description: "Create a secure, one-time payment credential from a Link wallet to let agents complete purchases on behalf of users.",
|
|
15194
15813
|
version: `${cliVersion} (build ${buildNumber})`
|
|
15195
15814
|
});
|
|
@@ -15206,24 +15825,38 @@ if (!isAgent && process.stdout.isTTY) {
|
|
|
15206
15825
|
process.stderr.write(renderInteractiveUpdateNotice(updateInfo));
|
|
15207
15826
|
}
|
|
15208
15827
|
}
|
|
15209
|
-
cli.command(createAuthCli(authRepo, getUpdateInfo));
|
|
15210
|
-
cli.command(createSpendRequestCli(spendRequestRepo));
|
|
15828
|
+
cli.command(createAuthCli(authRepo, getUpdateInfo, authStorage));
|
|
15829
|
+
cli.command(createSpendRequestCli(spendRequestRepo, authStorage));
|
|
15830
|
+
cli.command(
|
|
15831
|
+
createPaymentMethodsCli(
|
|
15832
|
+
() => factory.createPaymentMethodsResource(),
|
|
15833
|
+
authStorage
|
|
15834
|
+
)
|
|
15835
|
+
);
|
|
15836
|
+
cli.command(
|
|
15837
|
+
createShippingAddressCli(
|
|
15838
|
+
() => factory.createShippingAddressResource(),
|
|
15839
|
+
authStorage
|
|
15840
|
+
)
|
|
15841
|
+
);
|
|
15211
15842
|
cli.command(
|
|
15212
|
-
|
|
15843
|
+
createUserInfoCli(() => factory.createUserInfoResource(), authStorage)
|
|
15213
15844
|
);
|
|
15214
|
-
cli.command(createMppCli(spendRequestRepo));
|
|
15845
|
+
cli.command(createMppCli(spendRequestRepo, authStorage));
|
|
15215
15846
|
cli.command(
|
|
15216
15847
|
createDemoCli(
|
|
15217
15848
|
authRepo,
|
|
15218
15849
|
spendRequestRepo,
|
|
15219
|
-
() => factory.createPaymentMethodsResource()
|
|
15850
|
+
() => factory.createPaymentMethodsResource(),
|
|
15851
|
+
authStorage
|
|
15220
15852
|
)
|
|
15221
15853
|
);
|
|
15222
15854
|
cli.command(
|
|
15223
15855
|
createOnboardCli(
|
|
15224
15856
|
authRepo,
|
|
15225
15857
|
spendRequestRepo,
|
|
15226
|
-
() => factory.createPaymentMethodsResource()
|
|
15858
|
+
() => factory.createPaymentMethodsResource(),
|
|
15859
|
+
authStorage
|
|
15227
15860
|
)
|
|
15228
15861
|
);
|
|
15229
15862
|
cli.serve();
|