@stripe/link-cli 0.8.3 → 0.10.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 +16 -2
- package/dist/cli.js +1934 -966
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -8835,19 +8835,19 @@ var require_range = __commonJS({
|
|
|
8835
8835
|
var replaceCaret = (comp, options) => {
|
|
8836
8836
|
debug("caret", comp, options);
|
|
8837
8837
|
const r = options.loose ? re[t.CARETLOOSE] : re[t.CARET];
|
|
8838
|
-
const
|
|
8838
|
+
const z13 = options.includePrerelease ? "-0" : "";
|
|
8839
8839
|
return comp.replace(r, (_, M, m, p, pr) => {
|
|
8840
8840
|
debug("caret", comp, _, M, m, p, pr);
|
|
8841
8841
|
let ret;
|
|
8842
8842
|
if (isX(M)) {
|
|
8843
8843
|
ret = "";
|
|
8844
8844
|
} else if (isX(m)) {
|
|
8845
|
-
ret = `>=${M}.0.0${
|
|
8845
|
+
ret = `>=${M}.0.0${z13} <${+M + 1}.0.0-0`;
|
|
8846
8846
|
} else if (isX(p)) {
|
|
8847
8847
|
if (M === "0") {
|
|
8848
|
-
ret = `>=${M}.${m}.0${
|
|
8848
|
+
ret = `>=${M}.${m}.0${z13} <${M}.${+m + 1}.0-0`;
|
|
8849
8849
|
} else {
|
|
8850
|
-
ret = `>=${M}.${m}.0${
|
|
8850
|
+
ret = `>=${M}.${m}.0${z13} <${+M + 1}.0.0-0`;
|
|
8851
8851
|
}
|
|
8852
8852
|
} else if (pr) {
|
|
8853
8853
|
debug("replaceCaret pr", pr);
|
|
@@ -8864,9 +8864,9 @@ var require_range = __commonJS({
|
|
|
8864
8864
|
debug("no pr");
|
|
8865
8865
|
if (M === "0") {
|
|
8866
8866
|
if (m === "0") {
|
|
8867
|
-
ret = `>=${M}.${m}.${p}${
|
|
8867
|
+
ret = `>=${M}.${m}.${p}${z13} <${M}.${m}.${+p + 1}-0`;
|
|
8868
8868
|
} else {
|
|
8869
|
-
ret = `>=${M}.${m}.${p}${
|
|
8869
|
+
ret = `>=${M}.${m}.${p}${z13} <${M}.${+m + 1}.0-0`;
|
|
8870
8870
|
}
|
|
8871
8871
|
} else {
|
|
8872
8872
|
ret = `>=${M}.${m}.${p} <${+M + 1}.0.0-0`;
|
|
@@ -11148,6 +11148,178 @@ function requireFetchImplementation(config) {
|
|
|
11148
11148
|
}
|
|
11149
11149
|
return config.fetch;
|
|
11150
11150
|
}
|
|
11151
|
+
function isRecord(value) {
|
|
11152
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
11153
|
+
}
|
|
11154
|
+
function requireBoolean(value, field) {
|
|
11155
|
+
if (typeof value !== "boolean") {
|
|
11156
|
+
throw new TypeError(`Expected ${field} to be a boolean`);
|
|
11157
|
+
}
|
|
11158
|
+
return value;
|
|
11159
|
+
}
|
|
11160
|
+
function extractErrorMessage(data, rawBody) {
|
|
11161
|
+
if (isRecord(data)) {
|
|
11162
|
+
if (typeof data.error === "string") {
|
|
11163
|
+
return data.error;
|
|
11164
|
+
}
|
|
11165
|
+
if (isRecord(data.error)) {
|
|
11166
|
+
const nested = data.error;
|
|
11167
|
+
if (typeof nested.message === "string") {
|
|
11168
|
+
return nested.message;
|
|
11169
|
+
}
|
|
11170
|
+
if (typeof nested.code === "string") {
|
|
11171
|
+
return nested.code;
|
|
11172
|
+
}
|
|
11173
|
+
}
|
|
11174
|
+
if (typeof data.message === "string") {
|
|
11175
|
+
return data.message;
|
|
11176
|
+
}
|
|
11177
|
+
}
|
|
11178
|
+
return rawBody || "unknown error";
|
|
11179
|
+
}
|
|
11180
|
+
var BaseResource = class {
|
|
11181
|
+
verbose;
|
|
11182
|
+
getAccessToken;
|
|
11183
|
+
fetchImpl;
|
|
11184
|
+
endpoint;
|
|
11185
|
+
logger;
|
|
11186
|
+
constructor(options, endpointPath) {
|
|
11187
|
+
const config = resolveLinkSdkConfig(options);
|
|
11188
|
+
this.verbose = config.verbose;
|
|
11189
|
+
this.getAccessToken = config.getAccessToken;
|
|
11190
|
+
this.fetchImpl = requireFetchImplementation(config);
|
|
11191
|
+
this.endpoint = `${config.apiBaseUrl}${endpointPath}`;
|
|
11192
|
+
this.logger = config.logger;
|
|
11193
|
+
}
|
|
11194
|
+
async rawFetch(opts) {
|
|
11195
|
+
if (this.verbose) {
|
|
11196
|
+
const redactedHeaders = { ...opts.headers };
|
|
11197
|
+
if (redactedHeaders.Authorization)
|
|
11198
|
+
redactedHeaders.Authorization = "Bearer <redacted>";
|
|
11199
|
+
this.logger.debug(`> ${opts.method} ${opts.url}`);
|
|
11200
|
+
this.logger.debug(` Headers: ${JSON.stringify(redactedHeaders)}`);
|
|
11201
|
+
}
|
|
11202
|
+
let response;
|
|
11203
|
+
try {
|
|
11204
|
+
response = await this.fetchImpl(opts.url, {
|
|
11205
|
+
method: opts.method,
|
|
11206
|
+
headers: opts.headers
|
|
11207
|
+
});
|
|
11208
|
+
} catch (error) {
|
|
11209
|
+
throw new LinkTransportError(
|
|
11210
|
+
`Request failed: ${opts.method} ${opts.url}`,
|
|
11211
|
+
{ cause: error }
|
|
11212
|
+
);
|
|
11213
|
+
}
|
|
11214
|
+
const rawBody = await response.text();
|
|
11215
|
+
let data = null;
|
|
11216
|
+
try {
|
|
11217
|
+
data = JSON.parse(rawBody);
|
|
11218
|
+
} catch {
|
|
11219
|
+
}
|
|
11220
|
+
if (this.verbose) {
|
|
11221
|
+
this.logger.debug(`< ${response.status} ${response.statusText}`);
|
|
11222
|
+
response.headers.forEach((value, key) => {
|
|
11223
|
+
this.logger.debug(` ${key}: ${value}`);
|
|
11224
|
+
});
|
|
11225
|
+
this.logger.debug(rawBody);
|
|
11226
|
+
}
|
|
11227
|
+
return { status: response.status, data, rawBody };
|
|
11228
|
+
}
|
|
11229
|
+
async apiFetch(opts) {
|
|
11230
|
+
const token = await this.getAccessToken();
|
|
11231
|
+
const authedOpts = {
|
|
11232
|
+
...opts,
|
|
11233
|
+
headers: {
|
|
11234
|
+
...opts.headers,
|
|
11235
|
+
Authorization: `Bearer ${token}`
|
|
11236
|
+
}
|
|
11237
|
+
};
|
|
11238
|
+
const res = await this.rawFetch(authedOpts);
|
|
11239
|
+
if (res.status === 401) {
|
|
11240
|
+
const refreshedToken = await this.getAccessToken({ forceRefresh: true });
|
|
11241
|
+
authedOpts.headers.Authorization = `Bearer ${refreshedToken}`;
|
|
11242
|
+
return this.rawFetch(authedOpts);
|
|
11243
|
+
}
|
|
11244
|
+
return res;
|
|
11245
|
+
}
|
|
11246
|
+
throwApiError(operation, status, data, rawBody, cause) {
|
|
11247
|
+
const msg = extractErrorMessage(data, rawBody);
|
|
11248
|
+
throw new LinkApiError(`Failed to ${operation} (${status}): ${msg}`, {
|
|
11249
|
+
status,
|
|
11250
|
+
rawBody,
|
|
11251
|
+
details: data,
|
|
11252
|
+
cause
|
|
11253
|
+
});
|
|
11254
|
+
}
|
|
11255
|
+
};
|
|
11256
|
+
function normalizeBalances(value) {
|
|
11257
|
+
if (!Array.isArray(value)) {
|
|
11258
|
+
throw new TypeError("Expected balances to be an array");
|
|
11259
|
+
}
|
|
11260
|
+
return value.map((item, index) => {
|
|
11261
|
+
if (!isRecord(item)) {
|
|
11262
|
+
throw new TypeError(`Expected balances[${index}] to be an object`);
|
|
11263
|
+
}
|
|
11264
|
+
return item;
|
|
11265
|
+
});
|
|
11266
|
+
}
|
|
11267
|
+
function normalizeBalancesPage(value) {
|
|
11268
|
+
if (!isRecord(value)) {
|
|
11269
|
+
throw new TypeError("Expected response body to be an object");
|
|
11270
|
+
}
|
|
11271
|
+
const { data, has_more, ...rest } = value;
|
|
11272
|
+
const normalized = normalizeBalances(data);
|
|
11273
|
+
return {
|
|
11274
|
+
...rest,
|
|
11275
|
+
data: normalized,
|
|
11276
|
+
...has_more !== void 0 ? { has_more: requireBoolean(has_more, "has_more") } : {}
|
|
11277
|
+
};
|
|
11278
|
+
}
|
|
11279
|
+
var BalancesResource = class extends BaseResource {
|
|
11280
|
+
constructor(options = {}) {
|
|
11281
|
+
super(options, "/balances");
|
|
11282
|
+
}
|
|
11283
|
+
buildUrl(params) {
|
|
11284
|
+
const url = new URL(this.endpoint);
|
|
11285
|
+
if (params.sources !== void 0) {
|
|
11286
|
+
for (const source of params.sources) {
|
|
11287
|
+
url.searchParams.append("sources[]", source);
|
|
11288
|
+
}
|
|
11289
|
+
}
|
|
11290
|
+
if (params.limit !== void 0) {
|
|
11291
|
+
url.searchParams.set("limit", String(params.limit));
|
|
11292
|
+
}
|
|
11293
|
+
if (params.starting_after !== void 0) {
|
|
11294
|
+
url.searchParams.set("starting_after", params.starting_after);
|
|
11295
|
+
}
|
|
11296
|
+
if (params.ending_before !== void 0) {
|
|
11297
|
+
url.searchParams.set("ending_before", params.ending_before);
|
|
11298
|
+
}
|
|
11299
|
+
return url.toString();
|
|
11300
|
+
}
|
|
11301
|
+
list(params = {}) {
|
|
11302
|
+
return this.listBalances(params);
|
|
11303
|
+
}
|
|
11304
|
+
async listBalances(params = {}) {
|
|
11305
|
+
const { status, data, rawBody } = await this.apiFetch({
|
|
11306
|
+
method: "GET",
|
|
11307
|
+
url: this.buildUrl(params)
|
|
11308
|
+
});
|
|
11309
|
+
if (status < 200 || status >= 300) {
|
|
11310
|
+
this.throwApiError("list balances", status, data, rawBody);
|
|
11311
|
+
}
|
|
11312
|
+
try {
|
|
11313
|
+
return normalizeBalancesPage(data);
|
|
11314
|
+
} catch (error) {
|
|
11315
|
+
const reason = error instanceof Error ? `: ${error.message}` : "";
|
|
11316
|
+
throw new LinkApiError(
|
|
11317
|
+
`Failed to list balances (${status}): invalid response shape${reason}`,
|
|
11318
|
+
{ status, rawBody, details: data, cause: error }
|
|
11319
|
+
);
|
|
11320
|
+
}
|
|
11321
|
+
}
|
|
11322
|
+
};
|
|
11151
11323
|
var PaymentMethodsResource = class {
|
|
11152
11324
|
verbose;
|
|
11153
11325
|
getAccessToken;
|
|
@@ -11318,6 +11490,68 @@ var ShippingAddressResource = class {
|
|
|
11318
11490
|
return body?.shipping_addresses ?? [];
|
|
11319
11491
|
}
|
|
11320
11492
|
};
|
|
11493
|
+
function normalizeSources(value) {
|
|
11494
|
+
if (!Array.isArray(value)) {
|
|
11495
|
+
throw new TypeError("Expected sources to be an array");
|
|
11496
|
+
}
|
|
11497
|
+
return value.map((item, index) => {
|
|
11498
|
+
if (!isRecord(item)) {
|
|
11499
|
+
throw new TypeError(`Expected sources[${index}] to be an object`);
|
|
11500
|
+
}
|
|
11501
|
+
return item;
|
|
11502
|
+
});
|
|
11503
|
+
}
|
|
11504
|
+
function normalizeSourcesPage(value) {
|
|
11505
|
+
if (!isRecord(value)) {
|
|
11506
|
+
throw new TypeError("Expected response body to be an object");
|
|
11507
|
+
}
|
|
11508
|
+
const { data, has_more, ...rest } = value;
|
|
11509
|
+
const normalized = normalizeSources(data);
|
|
11510
|
+
return {
|
|
11511
|
+
...rest,
|
|
11512
|
+
data: normalized,
|
|
11513
|
+
...has_more !== void 0 ? { has_more: requireBoolean(has_more, "has_more") } : {}
|
|
11514
|
+
};
|
|
11515
|
+
}
|
|
11516
|
+
var SourcesResource = class extends BaseResource {
|
|
11517
|
+
constructor(options = {}) {
|
|
11518
|
+
super(options, "/sources");
|
|
11519
|
+
}
|
|
11520
|
+
buildUrl(params) {
|
|
11521
|
+
const url = new URL(this.endpoint);
|
|
11522
|
+
if (params.limit !== void 0) {
|
|
11523
|
+
url.searchParams.set("limit", String(params.limit));
|
|
11524
|
+
}
|
|
11525
|
+
if (params.starting_after !== void 0) {
|
|
11526
|
+
url.searchParams.set("starting_after", params.starting_after);
|
|
11527
|
+
}
|
|
11528
|
+
if (params.ending_before !== void 0) {
|
|
11529
|
+
url.searchParams.set("ending_before", params.ending_before);
|
|
11530
|
+
}
|
|
11531
|
+
return url.toString();
|
|
11532
|
+
}
|
|
11533
|
+
list(params = {}) {
|
|
11534
|
+
return this.listSources(params);
|
|
11535
|
+
}
|
|
11536
|
+
async listSources(params = {}) {
|
|
11537
|
+
const { status, data, rawBody } = await this.apiFetch({
|
|
11538
|
+
method: "GET",
|
|
11539
|
+
url: this.buildUrl(params)
|
|
11540
|
+
});
|
|
11541
|
+
if (status < 200 || status >= 300) {
|
|
11542
|
+
this.throwApiError("list sources", status, data, rawBody);
|
|
11543
|
+
}
|
|
11544
|
+
try {
|
|
11545
|
+
return normalizeSourcesPage(data);
|
|
11546
|
+
} catch (error) {
|
|
11547
|
+
const reason = error instanceof Error ? `: ${error.message}` : "";
|
|
11548
|
+
throw new LinkApiError(
|
|
11549
|
+
`Failed to list sources (${status}): invalid response shape${reason}`,
|
|
11550
|
+
{ status, rawBody, details: data, cause: error }
|
|
11551
|
+
);
|
|
11552
|
+
}
|
|
11553
|
+
}
|
|
11554
|
+
};
|
|
11321
11555
|
function normalizeSpendRequest(data) {
|
|
11322
11556
|
const sr = data;
|
|
11323
11557
|
if (typeof sr.shared_payment_token === "string") {
|
|
@@ -11524,9 +11758,6 @@ var SpendRequestResource = class {
|
|
|
11524
11758
|
return normalizeSpendRequest(data);
|
|
11525
11759
|
}
|
|
11526
11760
|
};
|
|
11527
|
-
function isRecord(value) {
|
|
11528
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
11529
|
-
}
|
|
11530
11761
|
function requireString(value, field) {
|
|
11531
11762
|
if (typeof value !== "string") {
|
|
11532
11763
|
throw new TypeError(`Expected ${field} to be a string`);
|
|
@@ -11548,12 +11779,6 @@ function requireNumber(value, field) {
|
|
|
11548
11779
|
}
|
|
11549
11780
|
return value;
|
|
11550
11781
|
}
|
|
11551
|
-
function requireBoolean(value, field) {
|
|
11552
|
-
if (typeof value !== "boolean") {
|
|
11553
|
-
throw new TypeError(`Expected ${field} to be a boolean`);
|
|
11554
|
-
}
|
|
11555
|
-
return value;
|
|
11556
|
-
}
|
|
11557
11782
|
function requireTransactionOrigin(value, field) {
|
|
11558
11783
|
if (value === "link" || value === "external_connection") {
|
|
11559
11784
|
return value;
|
|
@@ -11611,71 +11836,9 @@ function normalizeTransactionsPage(value) {
|
|
|
11611
11836
|
...has_more !== void 0 ? { has_more: requireBoolean(has_more, "has_more") } : {}
|
|
11612
11837
|
};
|
|
11613
11838
|
}
|
|
11614
|
-
var TransactionsResource = class {
|
|
11615
|
-
verbose;
|
|
11616
|
-
getAccessToken;
|
|
11617
|
-
fetchImpl;
|
|
11618
|
-
endpoint;
|
|
11619
|
-
logger;
|
|
11839
|
+
var TransactionsResource = class extends BaseResource {
|
|
11620
11840
|
constructor(options = {}) {
|
|
11621
|
-
|
|
11622
|
-
this.verbose = config.verbose;
|
|
11623
|
-
this.getAccessToken = config.getAccessToken;
|
|
11624
|
-
this.fetchImpl = requireFetchImplementation(config);
|
|
11625
|
-
this.endpoint = `${config.apiBaseUrl}/transactions`;
|
|
11626
|
-
this.logger = config.logger;
|
|
11627
|
-
}
|
|
11628
|
-
async rawFetch(opts) {
|
|
11629
|
-
if (this.verbose) {
|
|
11630
|
-
const redactedHeaders = { ...opts.headers };
|
|
11631
|
-
if (redactedHeaders.Authorization)
|
|
11632
|
-
redactedHeaders.Authorization = "Bearer <redacted>";
|
|
11633
|
-
this.logger.debug(`> ${opts.method} ${opts.url}`);
|
|
11634
|
-
this.logger.debug(` Headers: ${JSON.stringify(redactedHeaders)}`);
|
|
11635
|
-
}
|
|
11636
|
-
let response;
|
|
11637
|
-
try {
|
|
11638
|
-
response = await this.fetchImpl(opts.url, {
|
|
11639
|
-
method: opts.method,
|
|
11640
|
-
headers: opts.headers
|
|
11641
|
-
});
|
|
11642
|
-
} catch (error) {
|
|
11643
|
-
throw new LinkTransportError(
|
|
11644
|
-
`Request failed: ${opts.method} ${opts.url}`,
|
|
11645
|
-
{ cause: error }
|
|
11646
|
-
);
|
|
11647
|
-
}
|
|
11648
|
-
const rawBody = await response.text();
|
|
11649
|
-
let data = null;
|
|
11650
|
-
try {
|
|
11651
|
-
data = JSON.parse(rawBody);
|
|
11652
|
-
} catch {
|
|
11653
|
-
}
|
|
11654
|
-
if (this.verbose) {
|
|
11655
|
-
this.logger.debug(`< ${response.status} ${response.statusText}`);
|
|
11656
|
-
response.headers.forEach((value, key) => {
|
|
11657
|
-
this.logger.debug(` ${key}: ${value}`);
|
|
11658
|
-
});
|
|
11659
|
-
this.logger.debug(rawBody);
|
|
11660
|
-
}
|
|
11661
|
-
return { status: response.status, data, rawBody };
|
|
11662
|
-
}
|
|
11663
|
-
async apiFetch(opts) {
|
|
11664
|
-
const token = await this.getAccessToken();
|
|
11665
|
-
const authedOpts = {
|
|
11666
|
-
...opts,
|
|
11667
|
-
headers: {
|
|
11668
|
-
...opts.headers,
|
|
11669
|
-
Authorization: `Bearer ${token}`
|
|
11670
|
-
}
|
|
11671
|
-
};
|
|
11672
|
-
const res = await this.rawFetch(authedOpts);
|
|
11673
|
-
if (res.status === 401) {
|
|
11674
|
-
const refreshedToken = await this.getAccessToken({ forceRefresh: true });
|
|
11675
|
-
authedOpts.headers.Authorization = `Bearer ${refreshedToken}`;
|
|
11676
|
-
return this.rawFetch(authedOpts);
|
|
11677
|
-
}
|
|
11678
|
-
return res;
|
|
11841
|
+
super(options, "/transactions");
|
|
11679
11842
|
}
|
|
11680
11843
|
buildUrl(params) {
|
|
11681
11844
|
const url = new URL(this.endpoint);
|
|
@@ -11716,19 +11879,14 @@ var TransactionsResource = class {
|
|
|
11716
11879
|
url: this.buildUrl(params)
|
|
11717
11880
|
});
|
|
11718
11881
|
if (status < 200 || status >= 300) {
|
|
11719
|
-
|
|
11720
|
-
const msg = body?.error ?? body?.message ?? (rawBody || "unknown error");
|
|
11721
|
-
throw new LinkApiError(
|
|
11722
|
-
`Failed to list transactions (${status}): ${msg}`,
|
|
11723
|
-
{ status, rawBody, details: data }
|
|
11724
|
-
);
|
|
11882
|
+
this.throwApiError("list transactions", status, data, rawBody);
|
|
11725
11883
|
}
|
|
11726
11884
|
try {
|
|
11727
11885
|
return normalizeTransactionsPage(data);
|
|
11728
11886
|
} catch (error) {
|
|
11729
11887
|
const reason = error instanceof Error ? `: ${error.message}` : "";
|
|
11730
11888
|
throw new LinkApiError(
|
|
11731
|
-
`Failed to list transactions (
|
|
11889
|
+
`Failed to list transactions (${status}): invalid response shape${reason}`,
|
|
11732
11890
|
{ status, rawBody, details: data, cause: error }
|
|
11733
11891
|
);
|
|
11734
11892
|
}
|
|
@@ -11826,6 +11984,12 @@ var UserInfoResource = class {
|
|
|
11826
11984
|
};
|
|
11827
11985
|
}
|
|
11828
11986
|
};
|
|
11987
|
+
var SOURCE_ACTIONS = [
|
|
11988
|
+
"read_balances",
|
|
11989
|
+
"read_external_transactions",
|
|
11990
|
+
"read_link_transactions",
|
|
11991
|
+
"read_source_details"
|
|
11992
|
+
];
|
|
11829
11993
|
var REPORT_OUTCOMES = ["success", "blocked", "abandoned"];
|
|
11830
11994
|
var REPORT_TAGS = [
|
|
11831
11995
|
"stripe_checkout",
|
|
@@ -12053,12 +12217,69 @@ var ReportResource = class {
|
|
|
12053
12217
|
};
|
|
12054
12218
|
|
|
12055
12219
|
// src/cli.tsx
|
|
12056
|
-
import { Cli as
|
|
12220
|
+
import { Cli as Cli14 } from "incur";
|
|
12057
12221
|
|
|
12058
12222
|
// src/commands/auth/index.tsx
|
|
12059
12223
|
import { Cli } from "incur";
|
|
12060
12224
|
import { Text as Text4 } from "ink";
|
|
12061
12225
|
|
|
12226
|
+
// src/auth/authorization-details.ts
|
|
12227
|
+
var INVALID_AUTHORIZATION_DETAIL_MESSAGE = "authorization-detail must be valid JSON";
|
|
12228
|
+
function dedupe(values) {
|
|
12229
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12230
|
+
const result = [];
|
|
12231
|
+
for (const value of values) {
|
|
12232
|
+
if (seen.has(value)) {
|
|
12233
|
+
continue;
|
|
12234
|
+
}
|
|
12235
|
+
seen.add(value);
|
|
12236
|
+
result.push(value);
|
|
12237
|
+
}
|
|
12238
|
+
return result;
|
|
12239
|
+
}
|
|
12240
|
+
function parseAuthorizationDetails(entries) {
|
|
12241
|
+
const parsed = [];
|
|
12242
|
+
for (const entry of entries ?? []) {
|
|
12243
|
+
try {
|
|
12244
|
+
parsed.push(JSON.parse(entry));
|
|
12245
|
+
} catch {
|
|
12246
|
+
throw new Error(INVALID_AUTHORIZATION_DETAIL_MESSAGE);
|
|
12247
|
+
}
|
|
12248
|
+
}
|
|
12249
|
+
return parsed;
|
|
12250
|
+
}
|
|
12251
|
+
function buildAuthorizationDetails(sourceActions, authorizationDetails) {
|
|
12252
|
+
const details = [];
|
|
12253
|
+
const uniqueSourceActions = dedupe(sourceActions ?? []);
|
|
12254
|
+
if (uniqueSourceActions.length > 0) {
|
|
12255
|
+
details.push({
|
|
12256
|
+
type: "source",
|
|
12257
|
+
actions: uniqueSourceActions
|
|
12258
|
+
});
|
|
12259
|
+
}
|
|
12260
|
+
if (authorizationDetails) {
|
|
12261
|
+
details.push(...authorizationDetails);
|
|
12262
|
+
}
|
|
12263
|
+
return details;
|
|
12264
|
+
}
|
|
12265
|
+
|
|
12266
|
+
// src/auth/scopes.ts
|
|
12267
|
+
var DEFAULT_SCOPES = [
|
|
12268
|
+
"userinfo:read",
|
|
12269
|
+
"payment_methods.agentic"
|
|
12270
|
+
];
|
|
12271
|
+
var DEFAULT_SCOPE = DEFAULT_SCOPES.join(" ");
|
|
12272
|
+
function parseScopeTokens(scope) {
|
|
12273
|
+
return scope.trim().split(/\s+/).filter(Boolean);
|
|
12274
|
+
}
|
|
12275
|
+
function normalizeScopeInput(scope) {
|
|
12276
|
+
if (scope === void 0) {
|
|
12277
|
+
return void 0;
|
|
12278
|
+
}
|
|
12279
|
+
const normalized = parseScopeTokens(scope);
|
|
12280
|
+
return normalized.length > 0 ? normalized.join(" ") : void 0;
|
|
12281
|
+
}
|
|
12282
|
+
|
|
12062
12283
|
// src/utils/poll-until.ts
|
|
12063
12284
|
async function* pollUntil(options) {
|
|
12064
12285
|
const { fn, isTerminal, interval, timeout, maxAttempts } = options;
|
|
@@ -12175,6 +12396,9 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
12175
12396
|
var Login = ({
|
|
12176
12397
|
authResource,
|
|
12177
12398
|
clientName,
|
|
12399
|
+
scope,
|
|
12400
|
+
sourceActions,
|
|
12401
|
+
authorizationDetails,
|
|
12178
12402
|
authStorage: authStorage2 = storage,
|
|
12179
12403
|
onComplete
|
|
12180
12404
|
}) => {
|
|
@@ -12195,7 +12419,12 @@ var Login = ({
|
|
|
12195
12419
|
useEffect(() => {
|
|
12196
12420
|
const initAuth = async () => {
|
|
12197
12421
|
try {
|
|
12198
|
-
const authRequest = await authResource.initiateDeviceAuth(
|
|
12422
|
+
const authRequest = await authResource.initiateDeviceAuth({
|
|
12423
|
+
clientName,
|
|
12424
|
+
scope,
|
|
12425
|
+
sourceActions,
|
|
12426
|
+
authorizationDetails
|
|
12427
|
+
});
|
|
12199
12428
|
setUserCode(authRequest.user_code);
|
|
12200
12429
|
setVerificationUrl(authRequest.verification_url_complete);
|
|
12201
12430
|
setDeviceCode(authRequest.device_code);
|
|
@@ -12206,7 +12435,7 @@ var Login = ({
|
|
|
12206
12435
|
}
|
|
12207
12436
|
};
|
|
12208
12437
|
initAuth();
|
|
12209
|
-
}, [authResource, clientName]);
|
|
12438
|
+
}, [authResource, authorizationDetails, clientName, scope, sourceActions]);
|
|
12210
12439
|
useEffect(() => {
|
|
12211
12440
|
if (status !== "waiting" || !deviceCode) return;
|
|
12212
12441
|
const startPolling = async () => {
|
|
@@ -12245,17 +12474,17 @@ var Login = ({
|
|
|
12245
12474
|
if (status === "declined") {
|
|
12246
12475
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
12247
12476
|
/* @__PURE__ */ jsx(Text, { color: "red", children: "\u2717 Authorization failed" }),
|
|
12248
|
-
Object.entries(scopeEligibility).map(([
|
|
12477
|
+
Object.entries(scopeEligibility).map(([scope2, info]) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [
|
|
12249
12478
|
/* @__PURE__ */ jsxs(Text, { children: [
|
|
12250
12479
|
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
12251
|
-
|
|
12480
|
+
scope2,
|
|
12252
12481
|
":"
|
|
12253
12482
|
] }),
|
|
12254
12483
|
" ineligible",
|
|
12255
12484
|
info.ineligibility_reasons.length > 0 ? ` (${info.ineligibility_reasons.join(", ")})` : ""
|
|
12256
12485
|
] }),
|
|
12257
12486
|
info.description ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: info.description }) : null
|
|
12258
|
-
] },
|
|
12487
|
+
] }, scope2))
|
|
12259
12488
|
] });
|
|
12260
12489
|
}
|
|
12261
12490
|
if (status === "error") {
|
|
@@ -12379,10 +12608,18 @@ var Logout = ({
|
|
|
12379
12608
|
|
|
12380
12609
|
// src/commands/auth/schema.ts
|
|
12381
12610
|
import { z } from "incur";
|
|
12611
|
+
var SOURCE_ACTIONS_DESCRIPTION = SOURCE_ACTIONS.join(", ");
|
|
12382
12612
|
var loginOptions = z.object({
|
|
12383
12613
|
clientName: z.string().default("Link CLI").describe(
|
|
12384
12614
|
"Agent or app name shown in the Link app when approving the device connection"
|
|
12385
12615
|
),
|
|
12616
|
+
scope: z.string().optional().describe(
|
|
12617
|
+
"Optional space-separated Link scopes to request. Quote the value when passing multiple scopes."
|
|
12618
|
+
),
|
|
12619
|
+
sourceActions: z.array(z.enum(SOURCE_ACTIONS)).default([]).describe(
|
|
12620
|
+
`Source action to request via authorization_details (repeatable). Accepted values: ${SOURCE_ACTIONS_DESCRIPTION}.`
|
|
12621
|
+
),
|
|
12622
|
+
authorizationDetail: z.array(z.string()).default([]).describe("Freeform authorization_details entry as raw JSON (repeatable)."),
|
|
12386
12623
|
interval: z.coerce.number().default(0).describe(
|
|
12387
12624
|
"Poll interval in seconds. When > 0, polls until authenticated or timeout is reached, yielding status on each attempt."
|
|
12388
12625
|
),
|
|
@@ -12538,12 +12775,30 @@ function createAuthCli(authResource, getUpdateInfo2, authStorage2, envAccessToke
|
|
|
12538
12775
|
outputPolicy: "agent-only",
|
|
12539
12776
|
async *run(c) {
|
|
12540
12777
|
const clientName = c.options.clientName?.trim();
|
|
12778
|
+
const scope = normalizeScopeInput(c.options.scope);
|
|
12779
|
+
let authorizationDetails;
|
|
12541
12780
|
if (!clientName || clientName.length === 0) {
|
|
12542
12781
|
return c.error({
|
|
12543
12782
|
code: "INVALID_INPUT",
|
|
12544
12783
|
message: "client-name must be a non-empty string"
|
|
12545
12784
|
});
|
|
12546
12785
|
}
|
|
12786
|
+
if (c.options.scope !== void 0 && !scope) {
|
|
12787
|
+
return c.error({
|
|
12788
|
+
code: "INVALID_INPUT",
|
|
12789
|
+
message: "scope must be a non-empty string when provided"
|
|
12790
|
+
});
|
|
12791
|
+
}
|
|
12792
|
+
try {
|
|
12793
|
+
authorizationDetails = parseAuthorizationDetails(
|
|
12794
|
+
c.options.authorizationDetail
|
|
12795
|
+
);
|
|
12796
|
+
} catch (error) {
|
|
12797
|
+
return c.error({
|
|
12798
|
+
code: "INVALID_INPUT",
|
|
12799
|
+
message: error.message
|
|
12800
|
+
});
|
|
12801
|
+
}
|
|
12547
12802
|
const existingAuth = storage2.getAuth();
|
|
12548
12803
|
if (existingAuth?.refresh_token) {
|
|
12549
12804
|
try {
|
|
@@ -12575,6 +12830,9 @@ function createAuthCli(authResource, getUpdateInfo2, authStorage2, envAccessToke
|
|
|
12575
12830
|
{
|
|
12576
12831
|
authResource,
|
|
12577
12832
|
clientName,
|
|
12833
|
+
scope,
|
|
12834
|
+
sourceActions: c.options.sourceActions,
|
|
12835
|
+
authorizationDetails,
|
|
12578
12836
|
authStorage: storage2,
|
|
12579
12837
|
onComplete: () => {
|
|
12580
12838
|
}
|
|
@@ -12583,7 +12841,12 @@ function createAuthCli(authResource, getUpdateInfo2, authStorage2, envAccessToke
|
|
|
12583
12841
|
() => ({ authenticated: true, token_type: "Bearer" })
|
|
12584
12842
|
);
|
|
12585
12843
|
}
|
|
12586
|
-
const authRequest = await authResource.initiateDeviceAuth(
|
|
12844
|
+
const authRequest = await authResource.initiateDeviceAuth({
|
|
12845
|
+
clientName,
|
|
12846
|
+
scope,
|
|
12847
|
+
sourceActions: c.options.sourceActions,
|
|
12848
|
+
authorizationDetails
|
|
12849
|
+
});
|
|
12587
12850
|
storage2.setPendingDeviceAuth({
|
|
12588
12851
|
device_code: authRequest.device_code,
|
|
12589
12852
|
interval: authRequest.interval,
|
|
@@ -12713,29 +12976,202 @@ function createAuthCli(authResource, getUpdateInfo2, authStorage2, envAccessToke
|
|
|
12713
12976
|
return cli2;
|
|
12714
12977
|
}
|
|
12715
12978
|
|
|
12979
|
+
// src/commands/balances/index.tsx
|
|
12980
|
+
import { Cli as Cli2 } from "incur";
|
|
12981
|
+
|
|
12982
|
+
// src/utils/require-auth.ts
|
|
12983
|
+
var NOT_AUTHENTICATED_ERROR = {
|
|
12984
|
+
code: "NOT_AUTHENTICATED",
|
|
12985
|
+
message: 'Not authenticated. Run "link-cli auth login" first.',
|
|
12986
|
+
cta: {
|
|
12987
|
+
commands: [{ command: "auth login", description: "Log in to Link" }]
|
|
12988
|
+
}
|
|
12989
|
+
};
|
|
12990
|
+
function requireAuth(authStorage2, envAccessToken2) {
|
|
12991
|
+
const store = authStorage2 ?? storage;
|
|
12992
|
+
return (c, next) => {
|
|
12993
|
+
if (!envAccessToken2 && !store.isAuthenticated()) {
|
|
12994
|
+
return c.error(NOT_AUTHENTICATED_ERROR);
|
|
12995
|
+
}
|
|
12996
|
+
return next();
|
|
12997
|
+
};
|
|
12998
|
+
}
|
|
12999
|
+
function requireAuthGuard(c, authStorage2, envAccessToken2) {
|
|
13000
|
+
const store = authStorage2 ?? storage;
|
|
13001
|
+
if (!envAccessToken2 && !store.isAuthenticated()) {
|
|
13002
|
+
c.error(NOT_AUTHENTICATED_ERROR);
|
|
13003
|
+
}
|
|
13004
|
+
}
|
|
13005
|
+
|
|
13006
|
+
// src/commands/balances/list.tsx
|
|
13007
|
+
import { Box as Box4, Text as Text5 } from "ink";
|
|
13008
|
+
import Spinner3 from "ink-spinner";
|
|
13009
|
+
import { useCallback as useCallback2 } from "react";
|
|
13010
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
13011
|
+
var COLUMN_GAP = " ";
|
|
13012
|
+
var SOURCE_ID_MIN = 16;
|
|
13013
|
+
var SOURCE_ID_MAX = 48;
|
|
13014
|
+
var TYPE_WIDTH = 12;
|
|
13015
|
+
var CURRENT_WIDTH = 15;
|
|
13016
|
+
var CURRENCY_WIDTH = 8;
|
|
13017
|
+
function truncateCell(value, width) {
|
|
13018
|
+
if (value.length <= width) {
|
|
13019
|
+
return value;
|
|
13020
|
+
}
|
|
13021
|
+
if (width <= 3) {
|
|
13022
|
+
return value.slice(0, width);
|
|
13023
|
+
}
|
|
13024
|
+
return `${value.slice(0, width - 3)}...`;
|
|
13025
|
+
}
|
|
13026
|
+
function formatCell(value, width) {
|
|
13027
|
+
return truncateCell(value, width).padEnd(width);
|
|
13028
|
+
}
|
|
13029
|
+
function formatCents(cents) {
|
|
13030
|
+
const dollars = Math.abs(cents) / 100;
|
|
13031
|
+
const formatted = `$${dollars.toFixed(2)}`;
|
|
13032
|
+
return cents < 0 ? `-${formatted}` : formatted;
|
|
13033
|
+
}
|
|
13034
|
+
function sourceIdWidth(balances) {
|
|
13035
|
+
if (balances.length === 0) return SOURCE_ID_MIN;
|
|
13036
|
+
const maxLen = Math.max(...balances.map((b) => (b.source_id ?? "").length));
|
|
13037
|
+
return Math.min(SOURCE_ID_MAX, Math.max(SOURCE_ID_MIN, maxLen));
|
|
13038
|
+
}
|
|
13039
|
+
var BalancesList = ({
|
|
13040
|
+
resource,
|
|
13041
|
+
params,
|
|
13042
|
+
onComplete
|
|
13043
|
+
}) => {
|
|
13044
|
+
const action = useCallback2(
|
|
13045
|
+
() => resource.listBalances(params),
|
|
13046
|
+
[resource, params]
|
|
13047
|
+
);
|
|
13048
|
+
const { status, data: page, error } = useAsyncAction(action, onComplete);
|
|
13049
|
+
const balances = page?.data ?? [];
|
|
13050
|
+
const nextCursor = page?.has_more && balances.length > 0 ? balances[balances.length - 1].source_id : null;
|
|
13051
|
+
const idWidth = sourceIdWidth(balances);
|
|
13052
|
+
const headerRow = [
|
|
13053
|
+
formatCell("Source ID", idWidth),
|
|
13054
|
+
formatCell("Balance type", TYPE_WIDTH),
|
|
13055
|
+
formatCell("Current balance", CURRENT_WIDTH),
|
|
13056
|
+
formatCell("Currency", CURRENCY_WIDTH)
|
|
13057
|
+
].join(COLUMN_GAP);
|
|
13058
|
+
const separatorRow = "-".repeat(headerRow.length);
|
|
13059
|
+
const rows = balances.map(
|
|
13060
|
+
(balance) => [
|
|
13061
|
+
formatCell(balance.source_id ?? "-", idWidth),
|
|
13062
|
+
formatCell(balance.type ?? "-", TYPE_WIDTH),
|
|
13063
|
+
formatCell(
|
|
13064
|
+
balance.current != null ? formatCents(balance.current) : "-",
|
|
13065
|
+
CURRENT_WIDTH
|
|
13066
|
+
),
|
|
13067
|
+
formatCell(balance.currency ?? "-", CURRENCY_WIDTH)
|
|
13068
|
+
].join(COLUMN_GAP)
|
|
13069
|
+
);
|
|
13070
|
+
if (status === "loading") {
|
|
13071
|
+
return /* @__PURE__ */ jsx5(Box4, { children: /* @__PURE__ */ jsxs4(Text5, { color: "cyan", children: [
|
|
13072
|
+
/* @__PURE__ */ jsx5(Spinner3, { type: "dots" }),
|
|
13073
|
+
" Loading balances..."
|
|
13074
|
+
] }) });
|
|
13075
|
+
}
|
|
13076
|
+
if (status === "error") {
|
|
13077
|
+
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
13078
|
+
/* @__PURE__ */ jsx5(Text5, { color: "red", children: "Failed to load balances" }),
|
|
13079
|
+
/* @__PURE__ */ jsx5(Text5, { color: "red", children: error })
|
|
13080
|
+
] });
|
|
13081
|
+
}
|
|
13082
|
+
if (balances.length === 0) {
|
|
13083
|
+
return /* @__PURE__ */ jsx5(Box4, { children: /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "No balances found" }) });
|
|
13084
|
+
}
|
|
13085
|
+
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
13086
|
+
/* @__PURE__ */ jsx5(Text5, { bold: true, children: "Balances" }),
|
|
13087
|
+
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
13088
|
+
/* @__PURE__ */ jsx5(Text5, { bold: true, children: headerRow }),
|
|
13089
|
+
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: separatorRow }),
|
|
13090
|
+
rows.map((row, index) => /* @__PURE__ */ jsx5(Text5, { children: row }, balances[index].source_id ?? `balance-${index}`))
|
|
13091
|
+
] }),
|
|
13092
|
+
page?.has_more !== void 0 ? /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: 1, children: [
|
|
13093
|
+
/* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
|
|
13094
|
+
"has_more: ",
|
|
13095
|
+
String(page.has_more)
|
|
13096
|
+
] }),
|
|
13097
|
+
typeof nextCursor === "string" && nextCursor.length > 0 ? /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: `next page: --starting-after ${nextCursor}` }) : null
|
|
13098
|
+
] }) : null
|
|
13099
|
+
] });
|
|
13100
|
+
};
|
|
13101
|
+
|
|
13102
|
+
// src/commands/balances/schema.ts
|
|
13103
|
+
import { z as z2 } from "incur";
|
|
13104
|
+
var listOptions = z2.object({
|
|
13105
|
+
source: z2.array(z2.string()).default([]).describe("Filter by source ID. Repeat to include multiple sources."),
|
|
13106
|
+
limit: z2.coerce.number().int().positive().max(100).optional().describe("Maximum number of balances to return (1-100)."),
|
|
13107
|
+
startingAfter: z2.string().optional().describe("Cursor: return balances after this balance ID."),
|
|
13108
|
+
endingBefore: z2.string().optional().describe("Cursor: return balances before this balance ID.")
|
|
13109
|
+
});
|
|
13110
|
+
|
|
13111
|
+
// src/commands/balances/index.tsx
|
|
13112
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
13113
|
+
function createBalancesCli(createResource, authStorage2, envAccessToken2) {
|
|
13114
|
+
const cli2 = Cli2.create("balances", {
|
|
13115
|
+
description: "List balances from your Link wallet"
|
|
13116
|
+
});
|
|
13117
|
+
cli2.command("list", {
|
|
13118
|
+
description: "List balances from your Link wallet",
|
|
13119
|
+
options: listOptions,
|
|
13120
|
+
outputPolicy: "agent-only",
|
|
13121
|
+
middleware: [requireAuth(authStorage2, envAccessToken2)],
|
|
13122
|
+
async run(c) {
|
|
13123
|
+
const opts = c.options;
|
|
13124
|
+
const resource = createResource();
|
|
13125
|
+
const params = {};
|
|
13126
|
+
if (opts.source.length > 0) params.sources = opts.source;
|
|
13127
|
+
if (opts.limit !== void 0) params.limit = opts.limit;
|
|
13128
|
+
if (opts.startingAfter !== void 0)
|
|
13129
|
+
params.starting_after = opts.startingAfter;
|
|
13130
|
+
if (opts.endingBefore !== void 0)
|
|
13131
|
+
params.ending_before = opts.endingBefore;
|
|
13132
|
+
if (!c.agent && !c.formatExplicit) {
|
|
13133
|
+
return renderInteractive(
|
|
13134
|
+
/* @__PURE__ */ jsx6(
|
|
13135
|
+
BalancesList,
|
|
13136
|
+
{
|
|
13137
|
+
resource,
|
|
13138
|
+
params,
|
|
13139
|
+
onComplete: () => {
|
|
13140
|
+
}
|
|
13141
|
+
}
|
|
13142
|
+
),
|
|
13143
|
+
() => resource.listBalances(params)
|
|
13144
|
+
);
|
|
13145
|
+
}
|
|
13146
|
+
return resource.listBalances(params);
|
|
13147
|
+
}
|
|
13148
|
+
});
|
|
13149
|
+
return cli2;
|
|
13150
|
+
}
|
|
13151
|
+
|
|
12716
13152
|
// src/commands/demo/index.tsx
|
|
12717
|
-
import { Cli as
|
|
13153
|
+
import { Cli as Cli3, z as z3 } from "incur";
|
|
12718
13154
|
|
|
12719
13155
|
// src/commands/demo/demo-runner.tsx
|
|
12720
|
-
import { Box as
|
|
12721
|
-
import { useCallback as
|
|
13156
|
+
import { Box as Box9, Text as Text11, useApp, useInput as useInput4 } from "ink";
|
|
13157
|
+
import { useCallback as useCallback3, useState as useState7 } from "react";
|
|
12722
13158
|
|
|
12723
13159
|
// src/utils/markdown-text.tsx
|
|
12724
|
-
import { Text as
|
|
12725
|
-
import { jsx as
|
|
13160
|
+
import { Text as Text6 } from "ink";
|
|
13161
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
12726
13162
|
var MarkdownText = ({
|
|
12727
13163
|
children,
|
|
12728
13164
|
dimColor
|
|
12729
13165
|
}) => {
|
|
12730
13166
|
const parts = tokenize(children);
|
|
12731
|
-
return /* @__PURE__ */
|
|
13167
|
+
return /* @__PURE__ */ jsx7(Text6, { dimColor, children: parts.map((part) => {
|
|
12732
13168
|
if (part.type === "bold") {
|
|
12733
|
-
return /* @__PURE__ */
|
|
13169
|
+
return /* @__PURE__ */ jsx7(Text6, { bold: true, children: part.text }, part.key);
|
|
12734
13170
|
}
|
|
12735
13171
|
if (part.type === "code") {
|
|
12736
|
-
return /* @__PURE__ */
|
|
13172
|
+
return /* @__PURE__ */ jsx7(Text6, { color: "yellow", children: part.text }, part.key);
|
|
12737
13173
|
}
|
|
12738
|
-
return /* @__PURE__ */
|
|
13174
|
+
return /* @__PURE__ */ jsx7(Text6, { children: part.text }, part.key);
|
|
12739
13175
|
}) });
|
|
12740
13176
|
};
|
|
12741
13177
|
function tokenize(input) {
|
|
@@ -12770,7 +13206,7 @@ function tokenize(input) {
|
|
|
12770
13206
|
}
|
|
12771
13207
|
|
|
12772
13208
|
// src/commands/spend-request/app-download-qr-codes.tsx
|
|
12773
|
-
import { Box as
|
|
13209
|
+
import { Box as Box5, Text as Text7 } from "ink";
|
|
12774
13210
|
import { useMemo } from "react";
|
|
12775
13211
|
|
|
12776
13212
|
// src/utils/render-qr-matrix.ts
|
|
@@ -12807,24 +13243,24 @@ function renderQrMatrix(url) {
|
|
|
12807
13243
|
}
|
|
12808
13244
|
|
|
12809
13245
|
// src/commands/spend-request/app-download-qr-codes.tsx
|
|
12810
|
-
import { jsx as
|
|
13246
|
+
import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
12811
13247
|
var DOWNLOAD_URL = "https://link.com/download";
|
|
12812
13248
|
var AppDownloadQrCodes = () => {
|
|
12813
13249
|
const qrLines = useMemo(() => renderQrMatrix(DOWNLOAD_URL), []);
|
|
12814
|
-
return /* @__PURE__ */
|
|
12815
|
-
/* @__PURE__ */
|
|
12816
|
-
/* @__PURE__ */
|
|
13250
|
+
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
|
|
13251
|
+
/* @__PURE__ */ jsx8(Text7, { dimColor: true, children: "Get the Link app to approve spend requests from your phone" }),
|
|
13252
|
+
/* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", alignItems: "flex-start", marginTop: 1, children: [
|
|
12817
13253
|
qrLines.map((line, i) => (
|
|
12818
13254
|
// biome-ignore lint/suspicious/noArrayIndexKey: stable static array
|
|
12819
|
-
/* @__PURE__ */
|
|
13255
|
+
/* @__PURE__ */ jsx8(Text7, { children: line }, i)
|
|
12820
13256
|
)),
|
|
12821
|
-
/* @__PURE__ */
|
|
13257
|
+
/* @__PURE__ */ jsx8(Text7, { dimColor: true, children: DOWNLOAD_URL })
|
|
12822
13258
|
] })
|
|
12823
13259
|
] });
|
|
12824
13260
|
};
|
|
12825
13261
|
|
|
12826
13262
|
// src/commands/demo/card-flow.tsx
|
|
12827
|
-
import { Box as
|
|
13263
|
+
import { Box as Box6, Text as Text8, useInput as useInput2 } from "ink";
|
|
12828
13264
|
import { useEffect as useEffect4, useRef as useRef2, useState as useState4 } from "react";
|
|
12829
13265
|
|
|
12830
13266
|
// src/utils/poll-until-approved.ts
|
|
@@ -12989,7 +13425,7 @@ var ONBOARD = {
|
|
|
12989
13425
|
};
|
|
12990
13426
|
|
|
12991
13427
|
// src/commands/demo/card-flow.tsx
|
|
12992
|
-
import { Fragment, jsx as
|
|
13428
|
+
import { Fragment, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
12993
13429
|
function formatPmLabel(pm) {
|
|
12994
13430
|
return `${pm.card_details?.brand ?? pm.type} ****${pm.card_details?.last4 ?? ""}`;
|
|
12995
13431
|
}
|
|
@@ -13173,22 +13609,22 @@ var CardFlow = ({
|
|
|
13173
13609
|
];
|
|
13174
13610
|
return order.indexOf(step) > order.indexOf(target);
|
|
13175
13611
|
};
|
|
13176
|
-
const prompt = (label = "Press [Enter] to continue") => /* @__PURE__ */
|
|
13612
|
+
const prompt = (label = "Press [Enter] to continue") => /* @__PURE__ */ jsxs6(Text8, { dimColor: true, children: [
|
|
13177
13613
|
"\n",
|
|
13178
13614
|
">",
|
|
13179
13615
|
" ",
|
|
13180
13616
|
label
|
|
13181
13617
|
] });
|
|
13182
|
-
return /* @__PURE__ */
|
|
13183
|
-
/* @__PURE__ */
|
|
13184
|
-
/* @__PURE__ */
|
|
13185
|
-
/* @__PURE__ */
|
|
13186
|
-
/* @__PURE__ */
|
|
13187
|
-
/* @__PURE__ */
|
|
13618
|
+
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", gap: 1, children: [
|
|
13619
|
+
/* @__PURE__ */ jsx9(Text8, { bold: true, color: "cyan", children: CARD_FLOW.title }),
|
|
13620
|
+
/* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
13621
|
+
/* @__PURE__ */ jsxs6(Box6, { flexDirection: "row", gap: 1, children: [
|
|
13622
|
+
/* @__PURE__ */ jsx9(Text8, { color: "yellow", children: "[testmode]" }),
|
|
13623
|
+
/* @__PURE__ */ jsx9(Text8, { dimColor: true, children: DEMO_MERCHANT_URL })
|
|
13188
13624
|
] }),
|
|
13189
|
-
/* @__PURE__ */
|
|
13190
|
-
/* @__PURE__ */
|
|
13191
|
-
/* @__PURE__ */
|
|
13625
|
+
/* @__PURE__ */ jsx9(MarkdownText, { children: CARD_FLOW.intro.description }),
|
|
13626
|
+
/* @__PURE__ */ jsxs6(Box6, { marginTop: 1, flexDirection: "column", children: [
|
|
13627
|
+
/* @__PURE__ */ jsx9(Text8, { children: "What happens:" }),
|
|
13192
13628
|
CARD_FLOW.intro.steps.map((s, i) => {
|
|
13193
13629
|
const doneAfter = [
|
|
13194
13630
|
"pick-pm",
|
|
@@ -13204,17 +13640,17 @@ var CardFlow = ({
|
|
|
13204
13640
|
];
|
|
13205
13641
|
const done = pastStep(doneAfter[i]);
|
|
13206
13642
|
const active = !done && (step === activeFrom[i] || pastStep(activeFrom[i]));
|
|
13207
|
-
return done ? /* @__PURE__ */
|
|
13643
|
+
return done ? /* @__PURE__ */ jsxs6(Text8, { dimColor: true, strikethrough: true, children: [
|
|
13208
13644
|
" ",
|
|
13209
13645
|
i + 1,
|
|
13210
13646
|
". ",
|
|
13211
13647
|
s
|
|
13212
|
-
] }, s) : active ? /* @__PURE__ */
|
|
13648
|
+
] }, s) : active ? /* @__PURE__ */ jsxs6(Text8, { bold: true, color: "cyan", children: [
|
|
13213
13649
|
" ",
|
|
13214
13650
|
i + 1,
|
|
13215
13651
|
". ",
|
|
13216
13652
|
s
|
|
13217
|
-
] }, s) : /* @__PURE__ */
|
|
13653
|
+
] }, s) : /* @__PURE__ */ jsxs6(Text8, { dimColor: true, children: [
|
|
13218
13654
|
" ",
|
|
13219
13655
|
i + 1,
|
|
13220
13656
|
". ",
|
|
@@ -13224,45 +13660,45 @@ var CardFlow = ({
|
|
|
13224
13660
|
] }),
|
|
13225
13661
|
step === "intro" && prompt(CARD_FLOW.intro.prompt)
|
|
13226
13662
|
] }),
|
|
13227
|
-
step === "fetch-pm" && /* @__PURE__ */
|
|
13228
|
-
(step === "pick-pm" || step === "explain-pm") && /* @__PURE__ */
|
|
13229
|
-
step === "pick-pm" && paymentMethods.length > 1 && /* @__PURE__ */
|
|
13230
|
-
/* @__PURE__ */
|
|
13231
|
-
/* @__PURE__ */
|
|
13663
|
+
step === "fetch-pm" && /* @__PURE__ */ jsx9(Box6, { flexDirection: "column", children: /* @__PURE__ */ jsx9(Text8, { dimColor: true, children: "Fetching payment methods from your Link wallet..." }) }),
|
|
13664
|
+
(step === "pick-pm" || step === "explain-pm") && /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
13665
|
+
step === "pick-pm" && paymentMethods.length > 1 && /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
13666
|
+
/* @__PURE__ */ jsx9(Text8, { children: "Which payment method should we use for the demo?" }),
|
|
13667
|
+
/* @__PURE__ */ jsx9(Box6, { flexDirection: "column", marginTop: 1, children: paymentMethods.map((pm, i) => /* @__PURE__ */ jsx9(Text8, { children: i === selectedPmIndex ? /* @__PURE__ */ jsxs6(Text8, { color: "cyan", bold: true, children: [
|
|
13232
13668
|
">",
|
|
13233
13669
|
" ",
|
|
13234
13670
|
formatPmLabel(pm),
|
|
13235
13671
|
pm.is_default ? " (default)" : ""
|
|
13236
|
-
] }) : /* @__PURE__ */
|
|
13672
|
+
] }) : /* @__PURE__ */ jsxs6(Text8, { dimColor: true, children: [
|
|
13237
13673
|
" ",
|
|
13238
13674
|
formatPmLabel(pm),
|
|
13239
13675
|
pm.is_default ? " (default)" : ""
|
|
13240
13676
|
] }) }, pm.id)) }),
|
|
13241
|
-
/* @__PURE__ */
|
|
13677
|
+
/* @__PURE__ */ jsx9(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text8, { dimColor: true, children: "Use \u2191\u2193 to select, [Enter] to confirm" }) })
|
|
13242
13678
|
] }),
|
|
13243
|
-
paymentMethod && /* @__PURE__ */
|
|
13244
|
-
/* @__PURE__ */
|
|
13679
|
+
paymentMethod && /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
13680
|
+
/* @__PURE__ */ jsxs6(Text8, { color: "green", children: [
|
|
13245
13681
|
"\u2713 Using ",
|
|
13246
|
-
/* @__PURE__ */
|
|
13682
|
+
/* @__PURE__ */ jsx9(Text8, { bold: true, children: pmLabel }),
|
|
13247
13683
|
paymentMethod.is_default ? " (default)" : ""
|
|
13248
13684
|
] }),
|
|
13249
13685
|
step === "explain-pm" && prompt(CARD_FLOW.explainPm.prompt)
|
|
13250
13686
|
] })
|
|
13251
13687
|
] }),
|
|
13252
|
-
step === "create-spend" && /* @__PURE__ */
|
|
13253
|
-
/* @__PURE__ */
|
|
13254
|
-
/* @__PURE__ */
|
|
13688
|
+
step === "create-spend" && /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
13689
|
+
/* @__PURE__ */ jsx9(MarkdownText, { children: CARD_FLOW.createSpend.description }),
|
|
13690
|
+
/* @__PURE__ */ jsx9(Box6, { marginY: 1, children: /* @__PURE__ */ jsx9(Text8, { color: "cyan", children: CARD_FLOW.createSpend.loading }) })
|
|
13255
13691
|
] }),
|
|
13256
|
-
(step === "await-approval" || step === "approval-timeout") && spendRequest && /* @__PURE__ */
|
|
13257
|
-
/* @__PURE__ */
|
|
13692
|
+
(step === "await-approval" || step === "approval-timeout") && spendRequest && /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
13693
|
+
/* @__PURE__ */ jsxs6(Text8, { color: "green", children: [
|
|
13258
13694
|
"\u2713 Spend request created (",
|
|
13259
13695
|
spendRequest.id,
|
|
13260
13696
|
")"
|
|
13261
13697
|
] }),
|
|
13262
|
-
step === "await-approval" && /* @__PURE__ */
|
|
13263
|
-
/* @__PURE__ */
|
|
13264
|
-
/* @__PURE__ */
|
|
13265
|
-
|
|
13698
|
+
step === "await-approval" && /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
13699
|
+
/* @__PURE__ */ jsx9(Text8, { children: CARD_FLOW.approval.description }),
|
|
13700
|
+
/* @__PURE__ */ jsxs6(
|
|
13701
|
+
Box6,
|
|
13266
13702
|
{
|
|
13267
13703
|
flexDirection: "column",
|
|
13268
13704
|
borderStyle: "round",
|
|
@@ -13271,21 +13707,21 @@ var CardFlow = ({
|
|
|
13271
13707
|
paddingY: 1,
|
|
13272
13708
|
marginTop: 1,
|
|
13273
13709
|
children: [
|
|
13274
|
-
/* @__PURE__ */
|
|
13710
|
+
/* @__PURE__ */ jsxs6(Text8, { children: [
|
|
13275
13711
|
"Approve at:",
|
|
13276
13712
|
" ",
|
|
13277
|
-
/* @__PURE__ */
|
|
13713
|
+
/* @__PURE__ */ jsx9(Text8, { bold: true, color: "cyan", children: approvalUrl })
|
|
13278
13714
|
] }),
|
|
13279
|
-
/* @__PURE__ */
|
|
13715
|
+
/* @__PURE__ */ jsx9(Text8, { dimColor: true, children: CARD_FLOW.approval.browserHint })
|
|
13280
13716
|
]
|
|
13281
13717
|
}
|
|
13282
13718
|
),
|
|
13283
|
-
/* @__PURE__ */
|
|
13719
|
+
/* @__PURE__ */ jsx9(Box6, { marginY: 1, children: /* @__PURE__ */ jsx9(Text8, { color: "cyan", children: CARD_FLOW.approval.loading }) })
|
|
13284
13720
|
] }),
|
|
13285
|
-
step === "approval-timeout" && /* @__PURE__ */
|
|
13286
|
-
/* @__PURE__ */
|
|
13287
|
-
/* @__PURE__ */
|
|
13288
|
-
|
|
13721
|
+
step === "approval-timeout" && /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
13722
|
+
/* @__PURE__ */ jsx9(Text8, { color: "yellow", children: "\u26A0 Approval timed out (5 min). Still pending \u2014 you can still approve." }),
|
|
13723
|
+
/* @__PURE__ */ jsxs6(
|
|
13724
|
+
Box6,
|
|
13289
13725
|
{
|
|
13290
13726
|
flexDirection: "column",
|
|
13291
13727
|
borderStyle: "round",
|
|
@@ -13294,38 +13730,38 @@ var CardFlow = ({
|
|
|
13294
13730
|
paddingY: 1,
|
|
13295
13731
|
marginTop: 1,
|
|
13296
13732
|
children: [
|
|
13297
|
-
/* @__PURE__ */
|
|
13733
|
+
/* @__PURE__ */ jsxs6(Text8, { children: [
|
|
13298
13734
|
"Approve at:",
|
|
13299
13735
|
" ",
|
|
13300
|
-
/* @__PURE__ */
|
|
13736
|
+
/* @__PURE__ */ jsx9(Text8, { bold: true, color: "cyan", children: approvalUrl })
|
|
13301
13737
|
] }),
|
|
13302
|
-
/* @__PURE__ */
|
|
13738
|
+
/* @__PURE__ */ jsx9(Text8, { dimColor: true, children: "Press [Enter] to open in browser" })
|
|
13303
13739
|
]
|
|
13304
13740
|
}
|
|
13305
13741
|
),
|
|
13306
|
-
/* @__PURE__ */
|
|
13742
|
+
/* @__PURE__ */ jsx9(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text8, { dimColor: true, children: "r Retry polling q Quit demo" }) })
|
|
13307
13743
|
] })
|
|
13308
13744
|
] }),
|
|
13309
|
-
(step === "show-card" || step === "open-url" || step === "done") && card && /* @__PURE__ */
|
|
13310
|
-
/* @__PURE__ */
|
|
13311
|
-
/* @__PURE__ */
|
|
13312
|
-
/* @__PURE__ */
|
|
13313
|
-
/* @__PURE__ */
|
|
13314
|
-
/* @__PURE__ */
|
|
13745
|
+
(step === "show-card" || step === "open-url" || step === "done") && card && /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
13746
|
+
/* @__PURE__ */ jsx9(Text8, { color: "green", children: "\u2713 Approved!" }),
|
|
13747
|
+
/* @__PURE__ */ jsx9(MarkdownText, { children: CARD_FLOW.showCard.description }),
|
|
13748
|
+
/* @__PURE__ */ jsx9(Box6, { flexDirection: "column", paddingX: 2, marginTop: 1, children: /* @__PURE__ */ jsxs6(Text8, { children: [
|
|
13749
|
+
/* @__PURE__ */ jsx9(Text8, { dimColor: true, children: "Number " }),
|
|
13750
|
+
/* @__PURE__ */ jsx9(Text8, { bold: true, children: formatCardNumber(card.number) }),
|
|
13315
13751
|
" ",
|
|
13316
|
-
/* @__PURE__ */
|
|
13317
|
-
/* @__PURE__ */
|
|
13752
|
+
/* @__PURE__ */ jsx9(Text8, { dimColor: true, children: "Exp " }),
|
|
13753
|
+
/* @__PURE__ */ jsx9(Text8, { bold: true, children: formatExpiry(card.exp_month, card.exp_year) }),
|
|
13318
13754
|
" ",
|
|
13319
|
-
/* @__PURE__ */
|
|
13320
|
-
/* @__PURE__ */
|
|
13321
|
-
card.billing_address?.postal_code && /* @__PURE__ */
|
|
13755
|
+
/* @__PURE__ */ jsx9(Text8, { dimColor: true, children: "CVC " }),
|
|
13756
|
+
/* @__PURE__ */ jsx9(Text8, { bold: true, children: card.cvc }),
|
|
13757
|
+
card.billing_address?.postal_code && /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
13322
13758
|
" ",
|
|
13323
|
-
/* @__PURE__ */
|
|
13324
|
-
/* @__PURE__ */
|
|
13759
|
+
/* @__PURE__ */ jsx9(Text8, { dimColor: true, children: "Zip " }),
|
|
13760
|
+
/* @__PURE__ */ jsx9(Text8, { bold: true, children: card.billing_address.postal_code })
|
|
13325
13761
|
] }),
|
|
13326
|
-
card.valid_until && /* @__PURE__ */
|
|
13762
|
+
card.valid_until && /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
13327
13763
|
" ",
|
|
13328
|
-
/* @__PURE__ */
|
|
13764
|
+
/* @__PURE__ */ jsxs6(Text8, { dimColor: true, children: [
|
|
13329
13765
|
"expires",
|
|
13330
13766
|
" ",
|
|
13331
13767
|
new Date(card.valid_until).toLocaleTimeString([], {
|
|
@@ -13337,14 +13773,14 @@ var CardFlow = ({
|
|
|
13337
13773
|
] }) }),
|
|
13338
13774
|
step === "show-card" && prompt(CARD_FLOW.showCard.prompt)
|
|
13339
13775
|
] }),
|
|
13340
|
-
step === "done" && /* @__PURE__ */
|
|
13341
|
-
/* @__PURE__ */
|
|
13776
|
+
step === "done" && /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
13777
|
+
/* @__PURE__ */ jsxs6(Text8, { color: "green", children: [
|
|
13342
13778
|
"\u2713 ",
|
|
13343
13779
|
CARD_FLOW.done.success
|
|
13344
13780
|
] }),
|
|
13345
|
-
/* @__PURE__ */
|
|
13781
|
+
/* @__PURE__ */ jsx9(Text8, { children: CARD_FLOW.done.detail })
|
|
13346
13782
|
] }),
|
|
13347
|
-
step === "error" && /* @__PURE__ */
|
|
13783
|
+
step === "error" && /* @__PURE__ */ jsxs6(Text8, { color: "red", children: [
|
|
13348
13784
|
"Error: ",
|
|
13349
13785
|
error
|
|
13350
13786
|
] })
|
|
@@ -13352,7 +13788,7 @@ var CardFlow = ({
|
|
|
13352
13788
|
};
|
|
13353
13789
|
|
|
13354
13790
|
// src/commands/demo/spt-flow.tsx
|
|
13355
|
-
import { Box as
|
|
13791
|
+
import { Box as Box8, Text as Text10, useInput as useInput3 } from "ink";
|
|
13356
13792
|
import { useEffect as useEffect6, useRef as useRef3, useState as useState6 } from "react";
|
|
13357
13793
|
|
|
13358
13794
|
// src/commands/mpp/decode.ts
|
|
@@ -13385,11 +13821,11 @@ function getMethodDetails(request) {
|
|
|
13385
13821
|
}
|
|
13386
13822
|
function resolveStripeChallenge(challenges) {
|
|
13387
13823
|
const stripeChallenge = challenges.find(
|
|
13388
|
-
(challenge) => challenge.method === "stripe" && challenge.intent === "charge"
|
|
13824
|
+
(challenge) => challenge.method === "stripe" && (challenge.intent === "charge" || challenge.intent === "session")
|
|
13389
13825
|
);
|
|
13390
13826
|
if (!stripeChallenge) {
|
|
13391
13827
|
throw new Error(
|
|
13392
|
-
"WWW-Authenticate header does not include a stripe charge challenge"
|
|
13828
|
+
"WWW-Authenticate header does not include a stripe charge or session challenge"
|
|
13393
13829
|
);
|
|
13394
13830
|
}
|
|
13395
13831
|
if (typeof stripeChallenge.request !== "object" || stripeChallenge.request == null || Array.isArray(stripeChallenge.request)) {
|
|
@@ -13424,7 +13860,7 @@ function decodeStripeChallenge(challengeHeader) {
|
|
|
13424
13860
|
id: challenge.id,
|
|
13425
13861
|
realm: challenge.realm,
|
|
13426
13862
|
method: "stripe",
|
|
13427
|
-
intent:
|
|
13863
|
+
intent: challenge.intent,
|
|
13428
13864
|
description: challenge.description,
|
|
13429
13865
|
digest: challenge.digest,
|
|
13430
13866
|
expires: challenge.expires,
|
|
@@ -13434,13 +13870,13 @@ function decodeStripeChallenge(challengeHeader) {
|
|
|
13434
13870
|
}
|
|
13435
13871
|
|
|
13436
13872
|
// src/commands/mpp/pay.tsx
|
|
13437
|
-
import { Box as
|
|
13438
|
-
import
|
|
13873
|
+
import { Box as Box7, Text as Text9 } from "ink";
|
|
13874
|
+
import Spinner4 from "ink-spinner";
|
|
13439
13875
|
import { Credential, Method } from "mppx";
|
|
13440
13876
|
import { Mppx, Transport } from "mppx/client";
|
|
13441
13877
|
import { Methods as StripeMethods } from "mppx/stripe";
|
|
13442
13878
|
import { useEffect as useEffect5, useState as useState5 } from "react";
|
|
13443
|
-
import { jsx as
|
|
13879
|
+
import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
13444
13880
|
function buildHeaders(data, headers) {
|
|
13445
13881
|
const result = {};
|
|
13446
13882
|
if (data !== void 0) {
|
|
@@ -13469,8 +13905,19 @@ function createStripePaymentClient(spt) {
|
|
|
13469
13905
|
});
|
|
13470
13906
|
}
|
|
13471
13907
|
});
|
|
13908
|
+
const stripeSession = Method.toClient(
|
|
13909
|
+
{ ...StripeMethods.charge, intent: "session" },
|
|
13910
|
+
{
|
|
13911
|
+
async createCredential({ challenge }) {
|
|
13912
|
+
return Credential.serialize({
|
|
13913
|
+
challenge,
|
|
13914
|
+
payload: { action: "open", grantedToken: spt }
|
|
13915
|
+
});
|
|
13916
|
+
}
|
|
13917
|
+
}
|
|
13918
|
+
);
|
|
13472
13919
|
return Mppx.create({
|
|
13473
|
-
methods: [stripeCharge],
|
|
13920
|
+
methods: [stripeCharge, stripeSession],
|
|
13474
13921
|
polyfill: false,
|
|
13475
13922
|
transport: Transport.from({
|
|
13476
13923
|
name: "stripe-http",
|
|
@@ -13488,7 +13935,7 @@ function createStripePaymentClient(spt) {
|
|
|
13488
13935
|
})
|
|
13489
13936
|
});
|
|
13490
13937
|
}
|
|
13491
|
-
async function
|
|
13938
|
+
async function runMppPayWithSpendRequest(url, spendRequestId, method, data, headers, repository) {
|
|
13492
13939
|
const spendRequest = await repository.getSpendRequest(spendRequestId, {
|
|
13493
13940
|
include: ["shared_payment_token"]
|
|
13494
13941
|
});
|
|
@@ -13509,7 +13956,15 @@ async function runMppPay(url, spendRequestId, method, data, headers, repository)
|
|
|
13509
13956
|
if (!spendRequest.shared_payment_token) {
|
|
13510
13957
|
throw new Error("Spend request does not have a shared payment token");
|
|
13511
13958
|
}
|
|
13512
|
-
|
|
13959
|
+
return payWithSpt(
|
|
13960
|
+
url,
|
|
13961
|
+
spendRequest.shared_payment_token.id,
|
|
13962
|
+
method,
|
|
13963
|
+
data,
|
|
13964
|
+
headers
|
|
13965
|
+
);
|
|
13966
|
+
}
|
|
13967
|
+
async function payWithSpt(url, spt, method, data, headers) {
|
|
13513
13968
|
const httpMethod = method ?? (data !== void 0 ? "POST" : "GET");
|
|
13514
13969
|
const requestHeaders = buildHeaders(data, headers);
|
|
13515
13970
|
const initialResponse = await fetch(url, {
|
|
@@ -13529,7 +13984,102 @@ async function runMppPay(url, spendRequestId, method, data, headers, repository)
|
|
|
13529
13984
|
Authorization: authHeader
|
|
13530
13985
|
}
|
|
13531
13986
|
});
|
|
13532
|
-
return readPayResult(retryResponse);
|
|
13987
|
+
return readPayResult(retryResponse);
|
|
13988
|
+
}
|
|
13989
|
+
async function runMppPayFullFlow(opts) {
|
|
13990
|
+
const {
|
|
13991
|
+
url,
|
|
13992
|
+
method,
|
|
13993
|
+
data,
|
|
13994
|
+
headers,
|
|
13995
|
+
context,
|
|
13996
|
+
amountOverride,
|
|
13997
|
+
paymentMethodId,
|
|
13998
|
+
test,
|
|
13999
|
+
repository,
|
|
14000
|
+
paymentMethodsFactory,
|
|
14001
|
+
onStep,
|
|
14002
|
+
onApprovalUrl
|
|
14003
|
+
} = opts;
|
|
14004
|
+
const httpMethod = method ?? (data !== void 0 ? "POST" : "GET");
|
|
14005
|
+
const requestHeaders = buildHeaders(data, headers);
|
|
14006
|
+
onStep?.("probing");
|
|
14007
|
+
const probeResponse = await fetch(url, {
|
|
14008
|
+
method: httpMethod,
|
|
14009
|
+
body: data,
|
|
14010
|
+
headers: requestHeaders
|
|
14011
|
+
});
|
|
14012
|
+
if (probeResponse.status !== 402) {
|
|
14013
|
+
return readPayResult(probeResponse);
|
|
14014
|
+
}
|
|
14015
|
+
const wwwAuth = probeResponse.headers.get("www-authenticate");
|
|
14016
|
+
if (!wwwAuth) {
|
|
14017
|
+
throw new Error("URL returned 402 but no WWW-Authenticate header");
|
|
14018
|
+
}
|
|
14019
|
+
const decoded = decodeStripeChallenge(wwwAuth);
|
|
14020
|
+
const networkId = decoded.network_id;
|
|
14021
|
+
const challengeAmount = decoded.request_json.amount ? Number(decoded.request_json.amount) : void 0;
|
|
14022
|
+
const challengeCurrency = decoded.request_json.currency ?? "usd";
|
|
14023
|
+
const amount = amountOverride ?? challengeAmount;
|
|
14024
|
+
if (!amount) {
|
|
14025
|
+
throw new Error(
|
|
14026
|
+
"Could not determine amount from 402 challenge. Pass --amount explicitly."
|
|
14027
|
+
);
|
|
14028
|
+
}
|
|
14029
|
+
let pmId = paymentMethodId;
|
|
14030
|
+
if (!pmId) {
|
|
14031
|
+
onStep?.("creating");
|
|
14032
|
+
const pmResource = paymentMethodsFactory();
|
|
14033
|
+
const methods = await pmResource.list();
|
|
14034
|
+
if (!methods.length) {
|
|
14035
|
+
throw new Error(
|
|
14036
|
+
"No payment methods found. Add one with `link-cli payment-methods add`."
|
|
14037
|
+
);
|
|
14038
|
+
}
|
|
14039
|
+
pmId = methods[0].id;
|
|
14040
|
+
}
|
|
14041
|
+
onStep?.("creating");
|
|
14042
|
+
const spendRequest = await repository.createSpendRequest({
|
|
14043
|
+
payment_details: pmId,
|
|
14044
|
+
credential_type: "shared_payment_token",
|
|
14045
|
+
network_id: networkId,
|
|
14046
|
+
amount,
|
|
14047
|
+
currency: challengeCurrency,
|
|
14048
|
+
context,
|
|
14049
|
+
request_approval: true,
|
|
14050
|
+
test: test || void 0
|
|
14051
|
+
});
|
|
14052
|
+
onStep?.("approving");
|
|
14053
|
+
if (spendRequest.approval_url) {
|
|
14054
|
+
onApprovalUrl?.(spendRequest.approval_url);
|
|
14055
|
+
}
|
|
14056
|
+
const approved = await pollUntilApproved(repository, spendRequest.id);
|
|
14057
|
+
if (approved.status !== "approved") {
|
|
14058
|
+
throw new Error(
|
|
14059
|
+
`Spend request was not approved (status: ${approved.status})`
|
|
14060
|
+
);
|
|
14061
|
+
}
|
|
14062
|
+
onStep?.("signing");
|
|
14063
|
+
let withSpt = await repository.getSpendRequest(spendRequest.id, {
|
|
14064
|
+
include: ["shared_payment_token"]
|
|
14065
|
+
});
|
|
14066
|
+
for (let i = 0; i < 3 && withSpt && !withSpt.shared_payment_token; i++) {
|
|
14067
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
14068
|
+
withSpt = await repository.getSpendRequest(spendRequest.id, {
|
|
14069
|
+
include: ["shared_payment_token"]
|
|
14070
|
+
});
|
|
14071
|
+
}
|
|
14072
|
+
if (!withSpt?.shared_payment_token) {
|
|
14073
|
+
throw new Error("Failed to retrieve shared payment token");
|
|
14074
|
+
}
|
|
14075
|
+
onStep?.("submitting");
|
|
14076
|
+
return payWithSpt(
|
|
14077
|
+
url,
|
|
14078
|
+
withSpt.shared_payment_token.id,
|
|
14079
|
+
method,
|
|
14080
|
+
data,
|
|
14081
|
+
headers
|
|
14082
|
+
);
|
|
13533
14083
|
}
|
|
13534
14084
|
function MppPay({
|
|
13535
14085
|
url,
|
|
@@ -13537,66 +14087,55 @@ function MppPay({
|
|
|
13537
14087
|
method,
|
|
13538
14088
|
data,
|
|
13539
14089
|
headers,
|
|
14090
|
+
context,
|
|
14091
|
+
amountOverride,
|
|
14092
|
+
paymentMethodId,
|
|
14093
|
+
test,
|
|
13540
14094
|
repository,
|
|
14095
|
+
paymentMethodsFactory,
|
|
13541
14096
|
onComplete
|
|
13542
14097
|
}) {
|
|
13543
|
-
const [step, setStep] = useState5(
|
|
14098
|
+
const [step, setStep] = useState5(
|
|
14099
|
+
spendRequestId ? "signing" : "probing"
|
|
14100
|
+
);
|
|
13544
14101
|
const [result, setResult] = useState5(null);
|
|
13545
14102
|
const [error, setError] = useState5(null);
|
|
14103
|
+
const [approvalUrl, setApprovalUrl] = useState5(null);
|
|
13546
14104
|
useEffect5(() => {
|
|
13547
14105
|
(async () => {
|
|
13548
14106
|
try {
|
|
13549
|
-
|
|
13550
|
-
|
|
13551
|
-
|
|
13552
|
-
|
|
13553
|
-
|
|
13554
|
-
|
|
13555
|
-
|
|
13556
|
-
|
|
13557
|
-
|
|
13558
|
-
|
|
13559
|
-
`Spend request ${spendRequestId} must have credential_type 'shared_payment_token' (current: '${type}')`
|
|
14107
|
+
let payResult;
|
|
14108
|
+
if (spendRequestId) {
|
|
14109
|
+
setStep("signing");
|
|
14110
|
+
payResult = await runMppPayWithSpendRequest(
|
|
14111
|
+
url,
|
|
14112
|
+
spendRequestId,
|
|
14113
|
+
method,
|
|
14114
|
+
data,
|
|
14115
|
+
headers,
|
|
14116
|
+
repository
|
|
13560
14117
|
);
|
|
13561
|
-
}
|
|
13562
|
-
|
|
13563
|
-
|
|
13564
|
-
|
|
13565
|
-
|
|
13566
|
-
}
|
|
13567
|
-
if (!spendRequest.shared_payment_token) {
|
|
13568
|
-
throw new Error("Spend request does not have a shared payment token");
|
|
13569
|
-
}
|
|
13570
|
-
const spt = spendRequest.shared_payment_token.id;
|
|
13571
|
-
const httpMethod = method ?? (data !== void 0 ? "POST" : "GET");
|
|
13572
|
-
const requestHeaders = buildHeaders(data, headers);
|
|
13573
|
-
setStep("probing");
|
|
13574
|
-
const initialResponse = await fetch(url, {
|
|
13575
|
-
method: httpMethod,
|
|
13576
|
-
body: data,
|
|
13577
|
-
headers: requestHeaders
|
|
13578
|
-
});
|
|
13579
|
-
if (initialResponse.status !== 402) {
|
|
13580
|
-
const payResult2 = await readPayResult(initialResponse);
|
|
13581
|
-
setResult(payResult2);
|
|
13582
|
-
setStep("done");
|
|
13583
|
-
onComplete(payResult2);
|
|
13584
|
-
return;
|
|
13585
|
-
}
|
|
13586
|
-
setStep("signing");
|
|
13587
|
-
const authHeader = await createStripePaymentClient(spt).createCredential(
|
|
13588
|
-
initialResponse
|
|
13589
|
-
);
|
|
13590
|
-
setStep("submitting");
|
|
13591
|
-
const retryResponse = await fetch(url, {
|
|
13592
|
-
method: httpMethod,
|
|
13593
|
-
body: data,
|
|
13594
|
-
headers: {
|
|
13595
|
-
...requestHeaders,
|
|
13596
|
-
Authorization: authHeader
|
|
14118
|
+
} else {
|
|
14119
|
+
if (!context) {
|
|
14120
|
+
throw new Error(
|
|
14121
|
+
"--context is required for the full MPP flow (min 100 chars)"
|
|
14122
|
+
);
|
|
13597
14123
|
}
|
|
13598
|
-
|
|
13599
|
-
|
|
14124
|
+
payResult = await runMppPayFullFlow({
|
|
14125
|
+
url,
|
|
14126
|
+
method,
|
|
14127
|
+
data,
|
|
14128
|
+
headers,
|
|
14129
|
+
context,
|
|
14130
|
+
amountOverride,
|
|
14131
|
+
paymentMethodId,
|
|
14132
|
+
test: test ?? false,
|
|
14133
|
+
repository,
|
|
14134
|
+
paymentMethodsFactory,
|
|
14135
|
+
onStep: setStep,
|
|
14136
|
+
onApprovalUrl: (u) => setApprovalUrl(u)
|
|
14137
|
+
});
|
|
14138
|
+
}
|
|
13600
14139
|
setResult(payResult);
|
|
13601
14140
|
setStep("done");
|
|
13602
14141
|
onComplete(payResult);
|
|
@@ -13605,30 +14144,51 @@ function MppPay({
|
|
|
13605
14144
|
onComplete(null);
|
|
13606
14145
|
}
|
|
13607
14146
|
})();
|
|
13608
|
-
}, [
|
|
14147
|
+
}, [
|
|
14148
|
+
url,
|
|
14149
|
+
spendRequestId,
|
|
14150
|
+
method,
|
|
14151
|
+
data,
|
|
14152
|
+
headers,
|
|
14153
|
+
context,
|
|
14154
|
+
amountOverride,
|
|
14155
|
+
paymentMethodId,
|
|
14156
|
+
test,
|
|
14157
|
+
repository,
|
|
14158
|
+
paymentMethodsFactory,
|
|
14159
|
+
onComplete
|
|
14160
|
+
]);
|
|
13609
14161
|
const stepLabels = {
|
|
13610
|
-
|
|
13611
|
-
|
|
14162
|
+
probing: "Probing URL for 402 challenge",
|
|
14163
|
+
creating: "Creating spend request",
|
|
14164
|
+
approving: "Waiting for approval",
|
|
13612
14165
|
signing: "Signing credential",
|
|
13613
14166
|
submitting: "Submitting payment",
|
|
13614
14167
|
done: "Done"
|
|
13615
14168
|
};
|
|
13616
14169
|
if (error) {
|
|
13617
|
-
return /* @__PURE__ */
|
|
14170
|
+
return /* @__PURE__ */ jsxs7(Text9, { color: "red", children: [
|
|
13618
14171
|
"Error: ",
|
|
13619
14172
|
error
|
|
13620
14173
|
] });
|
|
13621
14174
|
}
|
|
13622
|
-
return /* @__PURE__ */
|
|
13623
|
-
step !== "done" && /* @__PURE__ */
|
|
13624
|
-
/* @__PURE__ */
|
|
13625
|
-
|
|
13626
|
-
|
|
13627
|
-
|
|
13628
|
-
|
|
13629
|
-
|
|
13630
|
-
/* @__PURE__ */
|
|
13631
|
-
|
|
14175
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
14176
|
+
step !== "done" && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
14177
|
+
/* @__PURE__ */ jsx10(Box7, { children: /* @__PURE__ */ jsxs7(Text9, { color: "cyan", children: [
|
|
14178
|
+
/* @__PURE__ */ jsx10(Spinner4, { type: "dots" }),
|
|
14179
|
+
" ",
|
|
14180
|
+
stepLabels[step],
|
|
14181
|
+
"..."
|
|
14182
|
+
] }) }),
|
|
14183
|
+
step === "approving" && approvalUrl && /* @__PURE__ */ jsx10(Box7, { marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsxs7(Text9, { children: [
|
|
14184
|
+
"Approve in Link app:",
|
|
14185
|
+
" ",
|
|
14186
|
+
/* @__PURE__ */ jsx10(Text9, { bold: true, color: "blue", children: approvalUrl })
|
|
14187
|
+
] }) })
|
|
14188
|
+
] }),
|
|
14189
|
+
result && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
14190
|
+
/* @__PURE__ */ jsxs7(
|
|
14191
|
+
Text9,
|
|
13632
14192
|
{
|
|
13633
14193
|
color: result.status >= 400 ? "red" : result.status >= 300 ? "yellow" : "green",
|
|
13634
14194
|
children: [
|
|
@@ -13637,13 +14197,13 @@ function MppPay({
|
|
|
13637
14197
|
]
|
|
13638
14198
|
}
|
|
13639
14199
|
),
|
|
13640
|
-
/* @__PURE__ */
|
|
14200
|
+
/* @__PURE__ */ jsx10(Text9, { children: result.body })
|
|
13641
14201
|
] })
|
|
13642
14202
|
] });
|
|
13643
14203
|
}
|
|
13644
14204
|
|
|
13645
14205
|
// src/commands/demo/spt-flow.tsx
|
|
13646
|
-
import { Fragment as Fragment2, jsx as
|
|
14206
|
+
import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
13647
14207
|
var SptFlow = ({
|
|
13648
14208
|
spendRequestRepo: spendRequestRepo2,
|
|
13649
14209
|
paymentMethodsResource,
|
|
@@ -13792,7 +14352,7 @@ var SptFlow = ({
|
|
|
13792
14352
|
setStep("mpp-pay-gate");
|
|
13793
14353
|
await waitForEnter();
|
|
13794
14354
|
setStep("mpp-pay");
|
|
13795
|
-
const payResponse = await
|
|
14355
|
+
const payResponse = await runMppPayWithSpendRequest(
|
|
13796
14356
|
DEMO_CLIMATE_API_URL,
|
|
13797
14357
|
result.id,
|
|
13798
14358
|
"POST",
|
|
@@ -13826,26 +14386,26 @@ var SptFlow = ({
|
|
|
13826
14386
|
];
|
|
13827
14387
|
return order.indexOf(step) > order.indexOf(target);
|
|
13828
14388
|
};
|
|
13829
|
-
const prompt = (label = "Press [Enter] to continue") => /* @__PURE__ */
|
|
14389
|
+
const prompt = (label = "Press [Enter] to continue") => /* @__PURE__ */ jsxs8(Text10, { dimColor: true, children: [
|
|
13830
14390
|
"\n",
|
|
13831
14391
|
">",
|
|
13832
14392
|
" ",
|
|
13833
14393
|
label
|
|
13834
14394
|
] });
|
|
13835
|
-
return /* @__PURE__ */
|
|
13836
|
-
/* @__PURE__ */
|
|
13837
|
-
/* @__PURE__ */
|
|
13838
|
-
/* @__PURE__ */
|
|
13839
|
-
/* @__PURE__ */
|
|
13840
|
-
/* @__PURE__ */
|
|
14395
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", gap: 1, children: [
|
|
14396
|
+
/* @__PURE__ */ jsx11(Text10, { bold: true, color: "cyan", children: SPT_FLOW.title }),
|
|
14397
|
+
/* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
14398
|
+
/* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", gap: 1, children: [
|
|
14399
|
+
/* @__PURE__ */ jsx11(Text10, { color: "yellow", children: "[testmode]" }),
|
|
14400
|
+
/* @__PURE__ */ jsxs8(Text10, { dimColor: true, children: [
|
|
13841
14401
|
DEMO_CLIMATE_API_URL,
|
|
13842
14402
|
" ",
|
|
13843
14403
|
DEMO_MPP_DEV_URL
|
|
13844
14404
|
] })
|
|
13845
14405
|
] }),
|
|
13846
|
-
/* @__PURE__ */
|
|
13847
|
-
/* @__PURE__ */
|
|
13848
|
-
/* @__PURE__ */
|
|
14406
|
+
/* @__PURE__ */ jsx11(MarkdownText, { children: SPT_FLOW.intro.description }),
|
|
14407
|
+
/* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
|
|
14408
|
+
/* @__PURE__ */ jsx11(Text10, { children: SPT_FLOW.intro.preamble }),
|
|
13849
14409
|
SPT_FLOW.intro.steps.map((s, i) => {
|
|
13850
14410
|
const doneAfter = [
|
|
13851
14411
|
"pick-pm",
|
|
@@ -13864,17 +14424,17 @@ var SptFlow = ({
|
|
|
13864
14424
|
const done = pastStep(doneAfter[i]);
|
|
13865
14425
|
const active = !done && (step === activeFrom[i] || pastStep(activeFrom[i]));
|
|
13866
14426
|
const label = s.replace(/`/g, "");
|
|
13867
|
-
return done ? /* @__PURE__ */
|
|
14427
|
+
return done ? /* @__PURE__ */ jsxs8(Text10, { dimColor: true, strikethrough: true, children: [
|
|
13868
14428
|
" ",
|
|
13869
14429
|
i + 1,
|
|
13870
14430
|
". ",
|
|
13871
14431
|
label
|
|
13872
|
-
] }, s) : active ? /* @__PURE__ */
|
|
14432
|
+
] }, s) : active ? /* @__PURE__ */ jsxs8(Text10, { bold: true, color: "cyan", children: [
|
|
13873
14433
|
" ",
|
|
13874
14434
|
i + 1,
|
|
13875
14435
|
". ",
|
|
13876
14436
|
label
|
|
13877
|
-
] }, s) : /* @__PURE__ */
|
|
14437
|
+
] }, s) : /* @__PURE__ */ jsxs8(Text10, { dimColor: true, children: [
|
|
13878
14438
|
" ",
|
|
13879
14439
|
i + 1,
|
|
13880
14440
|
". ",
|
|
@@ -13884,47 +14444,47 @@ var SptFlow = ({
|
|
|
13884
14444
|
] }),
|
|
13885
14445
|
step === "intro" && prompt(SPT_FLOW.intro.prompt)
|
|
13886
14446
|
] }),
|
|
13887
|
-
step === "fetch-pm" && /* @__PURE__ */
|
|
13888
|
-
step === "pick-pm" && paymentMethods.length > 1 && /* @__PURE__ */
|
|
13889
|
-
/* @__PURE__ */
|
|
13890
|
-
/* @__PURE__ */
|
|
14447
|
+
step === "fetch-pm" && /* @__PURE__ */ jsx11(Box8, { marginY: 1, children: /* @__PURE__ */ jsx11(Text10, { color: "cyan", children: "Fetching payment methods..." }) }),
|
|
14448
|
+
step === "pick-pm" && paymentMethods.length > 1 && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
14449
|
+
/* @__PURE__ */ jsx11(Text10, { children: "Which payment method should we use for the demo?" }),
|
|
14450
|
+
/* @__PURE__ */ jsx11(Box8, { flexDirection: "column", marginTop: 1, children: paymentMethods.map((pm, i) => /* @__PURE__ */ jsx11(Text10, { children: i === selectedPmIndex ? /* @__PURE__ */ jsxs8(Text10, { color: "cyan", bold: true, children: [
|
|
13891
14451
|
">",
|
|
13892
14452
|
" ",
|
|
13893
14453
|
pm.card_details ? `${pm.card_details.brand} ****${pm.card_details.last4}` : pm.type,
|
|
13894
14454
|
pm.is_default ? " (default)" : ""
|
|
13895
|
-
] }) : /* @__PURE__ */
|
|
14455
|
+
] }) : /* @__PURE__ */ jsxs8(Text10, { dimColor: true, children: [
|
|
13896
14456
|
" ",
|
|
13897
14457
|
pm.card_details ? `${pm.card_details.brand} ****${pm.card_details.last4}` : pm.type,
|
|
13898
14458
|
pm.is_default ? " (default)" : ""
|
|
13899
14459
|
] }) }, pm.id)) }),
|
|
13900
|
-
/* @__PURE__ */
|
|
14460
|
+
/* @__PURE__ */ jsx11(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text10, { dimColor: true, children: "Use \u2191\u2193 to select, [Enter] to confirm" }) })
|
|
13901
14461
|
] }),
|
|
13902
|
-
(step === "probe" || step === "explain-402") && /* @__PURE__ */
|
|
13903
|
-
/* @__PURE__ */
|
|
13904
|
-
step === "probe" && /* @__PURE__ */
|
|
13905
|
-
step === "explain-402" && networkId && /* @__PURE__ */
|
|
13906
|
-
/* @__PURE__ */
|
|
13907
|
-
/* @__PURE__ */
|
|
14462
|
+
(step === "probe" || step === "explain-402") && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
14463
|
+
/* @__PURE__ */ jsx11(MarkdownText, { children: SPT_FLOW.probe.description }),
|
|
14464
|
+
step === "probe" && /* @__PURE__ */ jsx11(Box8, { marginY: 1, children: /* @__PURE__ */ jsx11(Text10, { color: "cyan", children: SPT_FLOW.probe.loading }) }),
|
|
14465
|
+
step === "explain-402" && networkId && /* @__PURE__ */ jsxs8(Fragment2, { children: [
|
|
14466
|
+
/* @__PURE__ */ jsx11(MarkdownText, { children: SPT_FLOW.probe.detail }),
|
|
14467
|
+
/* @__PURE__ */ jsxs8(Text10, { color: "green", children: [
|
|
13908
14468
|
"\u2713 Got HTTP 402 \u2014 network_id: ",
|
|
13909
|
-
/* @__PURE__ */
|
|
14469
|
+
/* @__PURE__ */ jsx11(Text10, { bold: true, children: networkId })
|
|
13910
14470
|
] }),
|
|
13911
14471
|
prompt(SPT_FLOW.probe.prompt)
|
|
13912
14472
|
] })
|
|
13913
14473
|
] }),
|
|
13914
|
-
step === "create-spend" && /* @__PURE__ */
|
|
13915
|
-
/* @__PURE__ */
|
|
13916
|
-
/* @__PURE__ */
|
|
14474
|
+
step === "create-spend" && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
14475
|
+
/* @__PURE__ */ jsx11(MarkdownText, { children: SPT_FLOW.createSpend.description }),
|
|
14476
|
+
/* @__PURE__ */ jsx11(Box8, { marginY: 1, children: /* @__PURE__ */ jsx11(Text10, { color: "cyan", children: SPT_FLOW.createSpend.loading }) })
|
|
13917
14477
|
] }),
|
|
13918
|
-
(step === "await-approval" || step === "approval-timeout") && spendRequest && /* @__PURE__ */
|
|
13919
|
-
/* @__PURE__ */
|
|
14478
|
+
(step === "await-approval" || step === "approval-timeout") && spendRequest && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
14479
|
+
/* @__PURE__ */ jsxs8(Text10, { color: "green", children: [
|
|
13920
14480
|
"\u2713 Spend request created (",
|
|
13921
14481
|
spendRequest.id,
|
|
13922
14482
|
")"
|
|
13923
14483
|
] }),
|
|
13924
|
-
step === "await-approval" && /* @__PURE__ */
|
|
13925
|
-
/* @__PURE__ */
|
|
13926
|
-
/* @__PURE__ */
|
|
13927
|
-
|
|
14484
|
+
step === "await-approval" && /* @__PURE__ */ jsxs8(Fragment2, { children: [
|
|
14485
|
+
/* @__PURE__ */ jsx11(Text10, { children: SPT_FLOW.approval.description }),
|
|
14486
|
+
/* @__PURE__ */ jsxs8(
|
|
14487
|
+
Box8,
|
|
13928
14488
|
{
|
|
13929
14489
|
flexDirection: "column",
|
|
13930
14490
|
borderStyle: "round",
|
|
@@ -13933,21 +14493,21 @@ var SptFlow = ({
|
|
|
13933
14493
|
paddingY: 1,
|
|
13934
14494
|
marginTop: 1,
|
|
13935
14495
|
children: [
|
|
13936
|
-
/* @__PURE__ */
|
|
14496
|
+
/* @__PURE__ */ jsxs8(Text10, { children: [
|
|
13937
14497
|
"Approve at:",
|
|
13938
14498
|
" ",
|
|
13939
|
-
/* @__PURE__ */
|
|
14499
|
+
/* @__PURE__ */ jsx11(Text10, { bold: true, color: "cyan", children: approvalUrl })
|
|
13940
14500
|
] }),
|
|
13941
|
-
/* @__PURE__ */
|
|
14501
|
+
/* @__PURE__ */ jsx11(Text10, { dimColor: true, children: SPT_FLOW.approval.browserHint })
|
|
13942
14502
|
]
|
|
13943
14503
|
}
|
|
13944
14504
|
),
|
|
13945
|
-
/* @__PURE__ */
|
|
14505
|
+
/* @__PURE__ */ jsx11(Box8, { marginY: 1, children: /* @__PURE__ */ jsx11(Text10, { color: "cyan", children: SPT_FLOW.approval.loading }) })
|
|
13946
14506
|
] }),
|
|
13947
|
-
step === "approval-timeout" && /* @__PURE__ */
|
|
13948
|
-
/* @__PURE__ */
|
|
13949
|
-
/* @__PURE__ */
|
|
13950
|
-
|
|
14507
|
+
step === "approval-timeout" && /* @__PURE__ */ jsxs8(Fragment2, { children: [
|
|
14508
|
+
/* @__PURE__ */ jsx11(Text10, { color: "yellow", children: "\u26A0 Approval timed out (5 min). Still pending \u2014 you can still approve." }),
|
|
14509
|
+
/* @__PURE__ */ jsxs8(
|
|
14510
|
+
Box8,
|
|
13951
14511
|
{
|
|
13952
14512
|
flexDirection: "column",
|
|
13953
14513
|
borderStyle: "round",
|
|
@@ -13956,35 +14516,35 @@ var SptFlow = ({
|
|
|
13956
14516
|
paddingY: 1,
|
|
13957
14517
|
marginTop: 1,
|
|
13958
14518
|
children: [
|
|
13959
|
-
/* @__PURE__ */
|
|
14519
|
+
/* @__PURE__ */ jsxs8(Text10, { children: [
|
|
13960
14520
|
"Approve at:",
|
|
13961
14521
|
" ",
|
|
13962
|
-
/* @__PURE__ */
|
|
14522
|
+
/* @__PURE__ */ jsx11(Text10, { bold: true, color: "cyan", children: approvalUrl })
|
|
13963
14523
|
] }),
|
|
13964
|
-
/* @__PURE__ */
|
|
14524
|
+
/* @__PURE__ */ jsx11(Text10, { dimColor: true, children: "Press [Enter] to open in browser" })
|
|
13965
14525
|
]
|
|
13966
14526
|
}
|
|
13967
14527
|
),
|
|
13968
|
-
/* @__PURE__ */
|
|
14528
|
+
/* @__PURE__ */ jsx11(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text10, { dimColor: true, children: "r Retry polling q Quit demo" }) })
|
|
13969
14529
|
] })
|
|
13970
14530
|
] }),
|
|
13971
|
-
(step === "mpp-pay-gate" || step === "mpp-pay") && /* @__PURE__ */
|
|
13972
|
-
/* @__PURE__ */
|
|
13973
|
-
/* @__PURE__ */
|
|
14531
|
+
(step === "mpp-pay-gate" || step === "mpp-pay") && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
14532
|
+
/* @__PURE__ */ jsx11(Text10, { color: "green", children: "\u2713 Approved!" }),
|
|
14533
|
+
/* @__PURE__ */ jsx11(MarkdownText, { children: SPT_FLOW.mppPay.description }),
|
|
13974
14534
|
step === "mpp-pay-gate" && prompt(SPT_FLOW.mppPay.prompt),
|
|
13975
|
-
step === "mpp-pay" && /* @__PURE__ */
|
|
14535
|
+
step === "mpp-pay" && /* @__PURE__ */ jsx11(Box8, { marginY: 1, children: /* @__PURE__ */ jsx11(Text10, { color: "cyan", children: SPT_FLOW.mppPay.loading }) })
|
|
13976
14536
|
] }),
|
|
13977
|
-
step === "done" && payResult && /* @__PURE__ */
|
|
13978
|
-
/* @__PURE__ */
|
|
14537
|
+
step === "done" && payResult && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
14538
|
+
/* @__PURE__ */ jsxs8(Text10, { bold: true, color: "green", children: [
|
|
13979
14539
|
"\u2713 ",
|
|
13980
14540
|
SPT_FLOW.done.success,
|
|
13981
14541
|
" (HTTP ",
|
|
13982
14542
|
payResult.status,
|
|
13983
14543
|
")"
|
|
13984
14544
|
] }),
|
|
13985
|
-
/* @__PURE__ */
|
|
14545
|
+
/* @__PURE__ */ jsx11(MarkdownText, { children: SPT_FLOW.done.detail })
|
|
13986
14546
|
] }),
|
|
13987
|
-
step === "error" && /* @__PURE__ */
|
|
14547
|
+
step === "error" && /* @__PURE__ */ jsxs8(Text10, { color: "red", children: [
|
|
13988
14548
|
"Error: ",
|
|
13989
14549
|
error
|
|
13990
14550
|
] })
|
|
@@ -13992,7 +14552,7 @@ var SptFlow = ({
|
|
|
13992
14552
|
};
|
|
13993
14553
|
|
|
13994
14554
|
// src/commands/demo/demo-runner.tsx
|
|
13995
|
-
import { Fragment as Fragment3, jsx as
|
|
14555
|
+
import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
13996
14556
|
var DemoRunner = ({
|
|
13997
14557
|
authRepo: authRepo2,
|
|
13998
14558
|
spendRequestRepo: spendRequestRepo2,
|
|
@@ -14034,7 +14594,7 @@ var DemoRunner = ({
|
|
|
14034
14594
|
setPhase("spt-flow");
|
|
14035
14595
|
}
|
|
14036
14596
|
});
|
|
14037
|
-
const onCardComplete =
|
|
14597
|
+
const onCardComplete = useCallback3(
|
|
14038
14598
|
(result) => {
|
|
14039
14599
|
setPaymentMethodId(result.paymentMethodId);
|
|
14040
14600
|
setCardSuccess(result.success);
|
|
@@ -14050,7 +14610,7 @@ var DemoRunner = ({
|
|
|
14050
14610
|
},
|
|
14051
14611
|
[runSpt, onComplete, exit]
|
|
14052
14612
|
);
|
|
14053
|
-
const onSptComplete =
|
|
14613
|
+
const onSptComplete = useCallback3(
|
|
14054
14614
|
(success) => {
|
|
14055
14615
|
setSptSuccess(success);
|
|
14056
14616
|
setPhase("summary");
|
|
@@ -14061,12 +14621,12 @@ var DemoRunner = ({
|
|
|
14061
14621
|
},
|
|
14062
14622
|
[onComplete, exit]
|
|
14063
14623
|
);
|
|
14064
|
-
return /* @__PURE__ */
|
|
14065
|
-
/* @__PURE__ */
|
|
14066
|
-
/* @__PURE__ */
|
|
14067
|
-
/* @__PURE__ */
|
|
14624
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", gap: 1, children: [
|
|
14625
|
+
/* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
14626
|
+
/* @__PURE__ */ jsx12(Text11, { bold: true, children: DEMO_MENU.title }),
|
|
14627
|
+
/* @__PURE__ */ jsx12(Text11, { children: DEMO_MENU.subtitle })
|
|
14068
14628
|
] }),
|
|
14069
|
-
phase === "auth" && /* @__PURE__ */
|
|
14629
|
+
phase === "auth" && /* @__PURE__ */ jsx12(
|
|
14070
14630
|
Login,
|
|
14071
14631
|
{
|
|
14072
14632
|
authResource: authRepo2,
|
|
@@ -14075,25 +14635,25 @@ var DemoRunner = ({
|
|
|
14075
14635
|
onComplete: () => setPhase(postAuthPhase)
|
|
14076
14636
|
}
|
|
14077
14637
|
),
|
|
14078
|
-
phase === "menu" && /* @__PURE__ */
|
|
14079
|
-
/* @__PURE__ */
|
|
14080
|
-
/* @__PURE__ */
|
|
14081
|
-
/* @__PURE__ */
|
|
14638
|
+
phase === "menu" && /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
14639
|
+
/* @__PURE__ */ jsx12(Text11, { children: DEMO_MENU.question }),
|
|
14640
|
+
/* @__PURE__ */ jsx12(Box9, { flexDirection: "column", marginTop: 1, gap: 1, children: DEMO_MENU.options.map((opt, i) => /* @__PURE__ */ jsx12(Box9, { flexDirection: "column", children: i === menuIndex ? /* @__PURE__ */ jsxs9(Fragment3, { children: [
|
|
14641
|
+
/* @__PURE__ */ jsxs9(Text11, { color: "cyan", bold: true, children: [
|
|
14082
14642
|
">",
|
|
14083
14643
|
" ",
|
|
14084
14644
|
opt.label
|
|
14085
14645
|
] }),
|
|
14086
|
-
/* @__PURE__ */
|
|
14646
|
+
/* @__PURE__ */ jsxs9(Text11, { color: "cyan", children: [
|
|
14087
14647
|
" ",
|
|
14088
14648
|
opt.description
|
|
14089
14649
|
] })
|
|
14090
|
-
] }) : /* @__PURE__ */
|
|
14650
|
+
] }) : /* @__PURE__ */ jsxs9(Text11, { dimColor: true, children: [
|
|
14091
14651
|
" ",
|
|
14092
14652
|
opt.label
|
|
14093
14653
|
] }) }, opt.key)) }),
|
|
14094
|
-
/* @__PURE__ */
|
|
14654
|
+
/* @__PURE__ */ jsx12(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: DEMO_MENU.hint }) })
|
|
14095
14655
|
] }),
|
|
14096
|
-
runCard && phase !== "menu" && /* @__PURE__ */
|
|
14656
|
+
runCard && phase !== "menu" && /* @__PURE__ */ jsx12(
|
|
14097
14657
|
CardFlow,
|
|
14098
14658
|
{
|
|
14099
14659
|
spendRequestRepo: spendRequestRepo2,
|
|
@@ -14102,19 +14662,19 @@ var DemoRunner = ({
|
|
|
14102
14662
|
onComplete: onCardComplete
|
|
14103
14663
|
}
|
|
14104
14664
|
),
|
|
14105
|
-
phase === "card-done" && /* @__PURE__ */
|
|
14106
|
-
/* @__PURE__ */
|
|
14107
|
-
/* @__PURE__ */
|
|
14108
|
-
/* @__PURE__ */
|
|
14665
|
+
phase === "card-done" && /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
14666
|
+
/* @__PURE__ */ jsx12(Text11, { dimColor: true, children: "\u2500\u2500\u2500" }),
|
|
14667
|
+
/* @__PURE__ */ jsx12(MarkdownText, { children: DEMO_MENU.transition }),
|
|
14668
|
+
/* @__PURE__ */ jsxs9(Text11, { dimColor: true, children: [
|
|
14109
14669
|
"\n",
|
|
14110
14670
|
">",
|
|
14111
14671
|
" ",
|
|
14112
14672
|
DEMO_MENU.transitionPrompt
|
|
14113
14673
|
] })
|
|
14114
14674
|
] }),
|
|
14115
|
-
runSpt && (phase === "spt-flow" || phase === "summary") && /* @__PURE__ */
|
|
14116
|
-
runCard && /* @__PURE__ */
|
|
14117
|
-
/* @__PURE__ */
|
|
14675
|
+
runSpt && (phase === "spt-flow" || phase === "summary") && /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
14676
|
+
runCard && /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: "\u2500\u2500\u2500" }),
|
|
14677
|
+
/* @__PURE__ */ jsx12(
|
|
14118
14678
|
SptFlow,
|
|
14119
14679
|
{
|
|
14120
14680
|
spendRequestRepo: spendRequestRepo2,
|
|
@@ -14124,30 +14684,30 @@ var DemoRunner = ({
|
|
|
14124
14684
|
}
|
|
14125
14685
|
)
|
|
14126
14686
|
] }),
|
|
14127
|
-
phase === "summary" && /* @__PURE__ */
|
|
14128
|
-
/* @__PURE__ */
|
|
14129
|
-
/* @__PURE__ */
|
|
14130
|
-
cardSuccess !== null && /* @__PURE__ */
|
|
14687
|
+
phase === "summary" && /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
14688
|
+
/* @__PURE__ */ jsx12(Text11, { dimColor: true, children: "\u2500\u2500\u2500" }),
|
|
14689
|
+
/* @__PURE__ */ jsx12(Text11, { bold: true, children: "Done!" }),
|
|
14690
|
+
cardSuccess !== null && /* @__PURE__ */ jsxs9(Text11, { color: cardSuccess ? "green" : "red", children: [
|
|
14131
14691
|
cardSuccess ? "\u2713" : "\u2717",
|
|
14132
14692
|
" Virtual card flow"
|
|
14133
14693
|
] }),
|
|
14134
|
-
sptSuccess !== null && /* @__PURE__ */
|
|
14694
|
+
sptSuccess !== null && /* @__PURE__ */ jsxs9(Text11, { color: sptSuccess ? "green" : "red", children: [
|
|
14135
14695
|
sptSuccess ? "\u2713" : "\u2717",
|
|
14136
14696
|
" Machine payment flow"
|
|
14137
14697
|
] }),
|
|
14138
|
-
/* @__PURE__ */
|
|
14698
|
+
/* @__PURE__ */ jsx12(AppDownloadQrCodes, {})
|
|
14139
14699
|
] })
|
|
14140
14700
|
] });
|
|
14141
14701
|
};
|
|
14142
14702
|
|
|
14143
14703
|
// src/commands/demo/index.tsx
|
|
14144
|
-
import { jsx as
|
|
14145
|
-
var demoOptions =
|
|
14146
|
-
onlyCard:
|
|
14147
|
-
onlySpt:
|
|
14704
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
14705
|
+
var demoOptions = z3.object({
|
|
14706
|
+
onlyCard: z3.boolean().default(false).describe("Run only the virtual card flow"),
|
|
14707
|
+
onlySpt: z3.boolean().default(false).describe("Run only the machine payment (SPT) flow")
|
|
14148
14708
|
});
|
|
14149
14709
|
function createDemoCli(authRepo2, spendRequestRepo2, createPaymentMethodsResource, authStorage2) {
|
|
14150
|
-
return
|
|
14710
|
+
return Cli3.create("demo", {
|
|
14151
14711
|
description: "Run an interactive demo of both Link payment flows (virtual card + machine payment)",
|
|
14152
14712
|
options: demoOptions,
|
|
14153
14713
|
outputPolicy: "agent-only",
|
|
@@ -14160,7 +14720,7 @@ function createDemoCli(authRepo2, spendRequestRepo2, createPaymentMethodsResourc
|
|
|
14160
14720
|
}
|
|
14161
14721
|
const paymentMethodsResource = createPaymentMethodsResource();
|
|
14162
14722
|
return renderInteractive(
|
|
14163
|
-
/* @__PURE__ */
|
|
14723
|
+
/* @__PURE__ */ jsx13(
|
|
14164
14724
|
DemoRunner,
|
|
14165
14725
|
{
|
|
14166
14726
|
authRepo: authRepo2,
|
|
@@ -14180,91 +14740,77 @@ function createDemoCli(authRepo2, spendRequestRepo2, createPaymentMethodsResourc
|
|
|
14180
14740
|
}
|
|
14181
14741
|
|
|
14182
14742
|
// src/commands/mpp/index.tsx
|
|
14183
|
-
import { Cli as
|
|
14184
|
-
|
|
14185
|
-
// src/utils/require-auth.ts
|
|
14186
|
-
var NOT_AUTHENTICATED_ERROR = {
|
|
14187
|
-
code: "NOT_AUTHENTICATED",
|
|
14188
|
-
message: 'Not authenticated. Run "link-cli auth login" first.',
|
|
14189
|
-
cta: {
|
|
14190
|
-
commands: [{ command: "auth login", description: "Log in to Link" }]
|
|
14191
|
-
}
|
|
14192
|
-
};
|
|
14193
|
-
function requireAuth(authStorage2, envAccessToken2) {
|
|
14194
|
-
const store = authStorage2 ?? storage;
|
|
14195
|
-
return (c, next) => {
|
|
14196
|
-
if (!envAccessToken2 && !store.isAuthenticated()) {
|
|
14197
|
-
return c.error(NOT_AUTHENTICATED_ERROR);
|
|
14198
|
-
}
|
|
14199
|
-
return next();
|
|
14200
|
-
};
|
|
14201
|
-
}
|
|
14202
|
-
function requireAuthGuard(c, authStorage2, envAccessToken2) {
|
|
14203
|
-
const store = authStorage2 ?? storage;
|
|
14204
|
-
if (!envAccessToken2 && !store.isAuthenticated()) {
|
|
14205
|
-
c.error(NOT_AUTHENTICATED_ERROR);
|
|
14206
|
-
}
|
|
14207
|
-
}
|
|
14743
|
+
import { Cli as Cli4, z as z5 } from "incur";
|
|
14208
14744
|
|
|
14209
14745
|
// src/commands/mpp/decode-view.tsx
|
|
14210
|
-
import { Box as
|
|
14211
|
-
import { jsx as
|
|
14746
|
+
import { Box as Box10, Text as Text12 } from "ink";
|
|
14747
|
+
import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
14212
14748
|
function DecodeChallengeView({
|
|
14213
14749
|
decoded
|
|
14214
14750
|
}) {
|
|
14215
|
-
return /* @__PURE__ */
|
|
14216
|
-
/* @__PURE__ */
|
|
14217
|
-
/* @__PURE__ */
|
|
14218
|
-
/* @__PURE__ */
|
|
14751
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
|
|
14752
|
+
/* @__PURE__ */ jsx14(Text12, { color: "green", children: "\u2713 Stripe challenge decoded" }),
|
|
14753
|
+
/* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
14754
|
+
/* @__PURE__ */ jsxs10(Text12, { children: [
|
|
14219
14755
|
"ID: ",
|
|
14220
|
-
/* @__PURE__ */
|
|
14756
|
+
/* @__PURE__ */ jsx14(Text12, { bold: true, children: decoded.id })
|
|
14221
14757
|
] }),
|
|
14222
|
-
/* @__PURE__ */
|
|
14758
|
+
/* @__PURE__ */ jsxs10(Text12, { children: [
|
|
14223
14759
|
"Realm: ",
|
|
14224
|
-
/* @__PURE__ */
|
|
14760
|
+
/* @__PURE__ */ jsx14(Text12, { bold: true, children: decoded.realm })
|
|
14225
14761
|
] }),
|
|
14226
|
-
/* @__PURE__ */
|
|
14762
|
+
/* @__PURE__ */ jsxs10(Text12, { children: [
|
|
14227
14763
|
"Network ID: ",
|
|
14228
|
-
/* @__PURE__ */
|
|
14764
|
+
/* @__PURE__ */ jsx14(Text12, { bold: true, children: decoded.network_id })
|
|
14229
14765
|
] }),
|
|
14230
|
-
/* @__PURE__ */
|
|
14231
|
-
/* @__PURE__ */
|
|
14766
|
+
/* @__PURE__ */ jsx14(Text12, { children: "Request JSON:" }),
|
|
14767
|
+
/* @__PURE__ */ jsx14(Text12, { children: JSON.stringify(decoded.request_json, null, 2) })
|
|
14232
14768
|
] })
|
|
14233
14769
|
] });
|
|
14234
14770
|
}
|
|
14235
14771
|
|
|
14236
14772
|
// src/commands/mpp/schema.ts
|
|
14237
|
-
import { z as
|
|
14238
|
-
var payOptions =
|
|
14239
|
-
spendRequestId:
|
|
14240
|
-
'Approved spend request ID with credential_type "shared_payment_token"'
|
|
14773
|
+
import { z as z4 } from "incur";
|
|
14774
|
+
var payOptions = z4.object({
|
|
14775
|
+
spendRequestId: z4.string().optional().describe(
|
|
14776
|
+
'Approved spend request ID with credential_type "shared_payment_token". If omitted, the command handles the full flow: probe URL, parse challenge, create spend request, get approval, and pay.'
|
|
14777
|
+
),
|
|
14778
|
+
method: z4.string().optional().describe("HTTP method (default: GET, or POST if --data is provided)"),
|
|
14779
|
+
data: z4.string().optional().describe("Request body (implies POST if --method is not set)"),
|
|
14780
|
+
header: z4.array(z4.string()).default([]).describe('Request header in "Name: Value" format (repeatable)'),
|
|
14781
|
+
context: z4.string().min(100).optional().describe(
|
|
14782
|
+
"Min 100 chars \u2014 describe the purchase and rationale; the user reads this when approving. Required when --spend-request-id is not provided."
|
|
14783
|
+
),
|
|
14784
|
+
amount: z4.coerce.number().int().positive().optional().describe(
|
|
14785
|
+
"Amount in cents (derived from 402 challenge if omitted; required if challenge has no amount)"
|
|
14241
14786
|
),
|
|
14242
|
-
|
|
14243
|
-
|
|
14244
|
-
|
|
14787
|
+
paymentMethodId: z4.string().optional().describe("Payment method ID (uses default if omitted)"),
|
|
14788
|
+
test: z4.boolean().default(false).describe(
|
|
14789
|
+
"Use test mode (creates testmode credentials from test card data)"
|
|
14790
|
+
)
|
|
14245
14791
|
});
|
|
14246
|
-
var decodeOptions =
|
|
14247
|
-
challenge:
|
|
14792
|
+
var decodeOptions = z4.object({
|
|
14793
|
+
challenge: z4.string().describe(
|
|
14248
14794
|
"Raw WWW-Authenticate header value; may include multiple payment challenges"
|
|
14249
14795
|
)
|
|
14250
14796
|
});
|
|
14251
14797
|
|
|
14252
14798
|
// src/commands/mpp/index.tsx
|
|
14253
|
-
import { jsx as
|
|
14254
|
-
function createMppCli(repository, authStorage2, envAccessToken2) {
|
|
14255
|
-
const cli2 =
|
|
14799
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
14800
|
+
function createMppCli(repository, paymentMethodsFactory, authStorage2, envAccessToken2) {
|
|
14801
|
+
const cli2 = Cli4.create("mpp", {
|
|
14256
14802
|
description: "Machine payment protocol (MPP) commands"
|
|
14257
14803
|
});
|
|
14258
14804
|
cli2.command("pay", {
|
|
14259
|
-
description: "
|
|
14260
|
-
args:
|
|
14261
|
-
url:
|
|
14805
|
+
description: "Pay a URL via the Machine Payment Protocol. Handles the full 402 flow: probes the URL, parses the challenge, creates a spend request, gets approval, and pays with the SPT. Pass --spend-request-id to skip creation and use a pre-approved spend request.",
|
|
14806
|
+
args: z5.object({
|
|
14807
|
+
url: z5.string().describe("URL to pay")
|
|
14262
14808
|
}),
|
|
14263
14809
|
options: payOptions,
|
|
14264
14810
|
alias: { method: "X", data: "d", header: "H" },
|
|
14265
14811
|
outputPolicy: "agent-only",
|
|
14266
14812
|
middleware: [requireAuth(authStorage2, envAccessToken2)],
|
|
14267
|
-
async run(c) {
|
|
14813
|
+
async *run(c) {
|
|
14268
14814
|
const url = c.args.url;
|
|
14269
14815
|
const opts = c.options;
|
|
14270
14816
|
const method = opts.method;
|
|
@@ -14273,7 +14819,7 @@ function createMppCli(repository, authStorage2, envAccessToken2) {
|
|
|
14273
14819
|
if (!c.agent && !c.formatExplicit) {
|
|
14274
14820
|
let capturedResult = null;
|
|
14275
14821
|
return renderInteractive(
|
|
14276
|
-
/* @__PURE__ */
|
|
14822
|
+
/* @__PURE__ */ jsx15(
|
|
14277
14823
|
MppPay,
|
|
14278
14824
|
{
|
|
14279
14825
|
url,
|
|
@@ -14281,7 +14827,12 @@ function createMppCli(repository, authStorage2, envAccessToken2) {
|
|
|
14281
14827
|
method,
|
|
14282
14828
|
data,
|
|
14283
14829
|
headers,
|
|
14830
|
+
context: opts.context,
|
|
14831
|
+
amountOverride: opts.amount,
|
|
14832
|
+
paymentMethodId: opts.paymentMethodId,
|
|
14833
|
+
test: opts.test,
|
|
14284
14834
|
repository,
|
|
14835
|
+
paymentMethodsFactory,
|
|
14285
14836
|
onComplete: (result) => {
|
|
14286
14837
|
capturedResult = result;
|
|
14287
14838
|
}
|
|
@@ -14294,14 +14845,90 @@ function createMppCli(repository, authStorage2, envAccessToken2) {
|
|
|
14294
14845
|
}
|
|
14295
14846
|
);
|
|
14296
14847
|
}
|
|
14297
|
-
|
|
14298
|
-
|
|
14299
|
-
|
|
14300
|
-
|
|
14301
|
-
|
|
14302
|
-
|
|
14303
|
-
|
|
14304
|
-
|
|
14848
|
+
if (opts.spendRequestId) {
|
|
14849
|
+
yield await runMppPayWithSpendRequest(
|
|
14850
|
+
url,
|
|
14851
|
+
opts.spendRequestId,
|
|
14852
|
+
method,
|
|
14853
|
+
data,
|
|
14854
|
+
headers,
|
|
14855
|
+
repository
|
|
14856
|
+
);
|
|
14857
|
+
return;
|
|
14858
|
+
}
|
|
14859
|
+
const httpMethod = method ?? (data !== void 0 ? "POST" : "GET");
|
|
14860
|
+
const requestHeaders = buildHeaders(data, headers);
|
|
14861
|
+
const probeResponse = await fetch(url, {
|
|
14862
|
+
method: httpMethod,
|
|
14863
|
+
body: data,
|
|
14864
|
+
headers: requestHeaders
|
|
14865
|
+
});
|
|
14866
|
+
if (probeResponse.status !== 402) {
|
|
14867
|
+
yield await readPayResult(probeResponse);
|
|
14868
|
+
return;
|
|
14869
|
+
}
|
|
14870
|
+
const wwwAuth = probeResponse.headers.get("www-authenticate");
|
|
14871
|
+
if (!wwwAuth) {
|
|
14872
|
+
return c.error({
|
|
14873
|
+
code: "INVALID_RESPONSE",
|
|
14874
|
+
message: "URL returned 402 but no WWW-Authenticate header"
|
|
14875
|
+
});
|
|
14876
|
+
}
|
|
14877
|
+
const decoded = decodeStripeChallenge(wwwAuth);
|
|
14878
|
+
const networkId = decoded.network_id;
|
|
14879
|
+
const challengeAmount = decoded.request_json.amount ? Number(decoded.request_json.amount) : void 0;
|
|
14880
|
+
const challengeCurrency = decoded.request_json.currency ?? "usd";
|
|
14881
|
+
const amount = opts.amount ?? challengeAmount;
|
|
14882
|
+
if (!amount) {
|
|
14883
|
+
return c.error({
|
|
14884
|
+
code: "INVALID_INPUT",
|
|
14885
|
+
message: "Could not determine amount from 402 challenge. Pass --amount explicitly."
|
|
14886
|
+
});
|
|
14887
|
+
}
|
|
14888
|
+
if (!opts.context) {
|
|
14889
|
+
return c.error({
|
|
14890
|
+
code: "INVALID_INPUT",
|
|
14891
|
+
message: "--context is required for the full MPP flow (min 100 chars). Describe the purchase and rationale."
|
|
14892
|
+
});
|
|
14893
|
+
}
|
|
14894
|
+
let pmId = opts.paymentMethodId;
|
|
14895
|
+
if (!pmId) {
|
|
14896
|
+
const pmResource = paymentMethodsFactory();
|
|
14897
|
+
const methods = await pmResource.list();
|
|
14898
|
+
if (!methods.length) {
|
|
14899
|
+
return c.error({
|
|
14900
|
+
code: "NO_PAYMENT_METHOD",
|
|
14901
|
+
message: "No payment methods found. Add one with `link-cli payment-methods add`."
|
|
14902
|
+
});
|
|
14903
|
+
}
|
|
14904
|
+
pmId = methods[0].id;
|
|
14905
|
+
}
|
|
14906
|
+
const spendRequest = await repository.createSpendRequest({
|
|
14907
|
+
payment_details: pmId,
|
|
14908
|
+
credential_type: "shared_payment_token",
|
|
14909
|
+
network_id: networkId,
|
|
14910
|
+
amount,
|
|
14911
|
+
currency: challengeCurrency,
|
|
14912
|
+
context: opts.context,
|
|
14913
|
+
request_approval: true,
|
|
14914
|
+
test: opts.test || void 0
|
|
14915
|
+
});
|
|
14916
|
+
const nextFlags = [`--spend-request-id ${spendRequest.id}`];
|
|
14917
|
+
if (method) nextFlags.push(`-X ${method}`);
|
|
14918
|
+
if (data) nextFlags.push(`-d '${data}'`);
|
|
14919
|
+
if (headers) {
|
|
14920
|
+
for (const h of headers) nextFlags.push(`-H '${h}'`);
|
|
14921
|
+
}
|
|
14922
|
+
const nextCommand = `mpp pay ${url} ${nextFlags.join(" ")}`;
|
|
14923
|
+
yield {
|
|
14924
|
+
...spendRequest,
|
|
14925
|
+
instruction: `Present the approval_url to the user and ask them to approve in the Link app. Then call \`spend-request retrieve ${spendRequest.id} --interval 2 --max-attempts 300\` to poll until approved. Once approved, run the _next.command to complete payment. Do not wait for the user to reply \u2014 start polling immediately.`,
|
|
14926
|
+
_next: {
|
|
14927
|
+
poll_command: `spend-request retrieve ${spendRequest.id} --interval 2 --max-attempts 300`,
|
|
14928
|
+
pay_command: nextCommand,
|
|
14929
|
+
until: "status changes from pending_approval, then run pay_command"
|
|
14930
|
+
}
|
|
14931
|
+
};
|
|
14305
14932
|
}
|
|
14306
14933
|
});
|
|
14307
14934
|
cli2.command("decode", {
|
|
@@ -14312,7 +14939,7 @@ function createMppCli(repository, authStorage2, envAccessToken2) {
|
|
|
14312
14939
|
const decoded = decodeStripeChallenge(c.options.challenge);
|
|
14313
14940
|
if (!c.agent && !c.formatExplicit) {
|
|
14314
14941
|
return renderInteractive(
|
|
14315
|
-
/* @__PURE__ */
|
|
14942
|
+
/* @__PURE__ */ jsx15(DecodeChallengeView, { decoded }),
|
|
14316
14943
|
() => decoded
|
|
14317
14944
|
);
|
|
14318
14945
|
}
|
|
@@ -14323,12 +14950,12 @@ function createMppCli(repository, authStorage2, envAccessToken2) {
|
|
|
14323
14950
|
}
|
|
14324
14951
|
|
|
14325
14952
|
// src/commands/onboard/index.tsx
|
|
14326
|
-
import { Cli as
|
|
14953
|
+
import { Cli as Cli5 } from "incur";
|
|
14327
14954
|
|
|
14328
14955
|
// src/commands/onboard/onboard-runner.tsx
|
|
14329
|
-
import { Box as
|
|
14956
|
+
import { Box as Box11, Text as Text13, useApp as useApp2, useInput as useInput5 } from "ink";
|
|
14330
14957
|
import { useEffect as useEffect7, useRef as useRef4, useState as useState8 } from "react";
|
|
14331
|
-
import { jsx as
|
|
14958
|
+
import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
14332
14959
|
var OnboardRunner = ({
|
|
14333
14960
|
authRepo: authRepo2,
|
|
14334
14961
|
spendRequestRepo: spendRequestRepo2,
|
|
@@ -14394,21 +15021,21 @@ var OnboardRunner = ({
|
|
|
14394
15021
|
const order = ["welcome", "auth", "payment-methods", "demo"];
|
|
14395
15022
|
return order.indexOf(phase) > order.indexOf(target);
|
|
14396
15023
|
};
|
|
14397
|
-
const prompt = (label = "Press [Enter] to continue") => /* @__PURE__ */
|
|
15024
|
+
const prompt = (label = "Press [Enter] to continue") => /* @__PURE__ */ jsxs11(Text13, { dimColor: true, children: [
|
|
14398
15025
|
"\n",
|
|
14399
15026
|
">",
|
|
14400
15027
|
" ",
|
|
14401
15028
|
label
|
|
14402
15029
|
] });
|
|
14403
|
-
return /* @__PURE__ */
|
|
14404
|
-
/* @__PURE__ */
|
|
14405
|
-
/* @__PURE__ */
|
|
14406
|
-
/* @__PURE__ */
|
|
15030
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", gap: 1, children: [
|
|
15031
|
+
/* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
|
|
15032
|
+
/* @__PURE__ */ jsx16(Text13, { bold: true, children: ONBOARD.title }),
|
|
15033
|
+
/* @__PURE__ */ jsx16(Text13, { children: ONBOARD.subtitle })
|
|
14407
15034
|
] }),
|
|
14408
|
-
/* @__PURE__ */
|
|
15035
|
+
/* @__PURE__ */ jsx16(Box11, { flexDirection: "column", children: authSkipped || pastPhase("auth") ? /* @__PURE__ */ jsxs11(Text13, { color: "green", children: [
|
|
14409
15036
|
"\u2713 ",
|
|
14410
15037
|
authSkipped ? ONBOARD.auth.alreadyLoggedIn : ONBOARD.auth.authenticated
|
|
14411
|
-
] }) : phase === "auth" && !storage2.isAuthenticated() ? /* @__PURE__ */
|
|
15038
|
+
] }) : phase === "auth" && !storage2.isAuthenticated() ? /* @__PURE__ */ jsx16(
|
|
14412
15039
|
Login,
|
|
14413
15040
|
{
|
|
14414
15041
|
authResource: authRepo2,
|
|
@@ -14417,24 +15044,24 @@ var OnboardRunner = ({
|
|
|
14417
15044
|
onComplete: () => authResolver.current?.()
|
|
14418
15045
|
}
|
|
14419
15046
|
) : null }),
|
|
14420
|
-
pastPhase("auth") && /* @__PURE__ */
|
|
14421
|
-
phase === "payment-methods" && !pmMissing && /* @__PURE__ */
|
|
14422
|
-
pmMissing && /* @__PURE__ */
|
|
14423
|
-
/* @__PURE__ */
|
|
14424
|
-
/* @__PURE__ */
|
|
15047
|
+
pastPhase("auth") && /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
|
|
15048
|
+
phase === "payment-methods" && !pmMissing && /* @__PURE__ */ jsx16(Text13, { color: "cyan", children: ONBOARD.paymentMethods.loading }),
|
|
15049
|
+
pmMissing && /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
|
|
15050
|
+
/* @__PURE__ */ jsx16(Text13, { color: "yellow", children: ONBOARD.paymentMethods.missing }),
|
|
15051
|
+
/* @__PURE__ */ jsx16(Box11, { marginTop: 1, children: /* @__PURE__ */ jsxs11(Text13, { children: [
|
|
14425
15052
|
"Visit",
|
|
14426
15053
|
" ",
|
|
14427
|
-
/* @__PURE__ */
|
|
15054
|
+
/* @__PURE__ */ jsx16(Text13, { bold: true, color: "cyan", children: "app.link.com/wallet" }),
|
|
14428
15055
|
" ",
|
|
14429
15056
|
"to add a payment method, then press [Enter] to continue."
|
|
14430
15057
|
] }) }),
|
|
14431
15058
|
prompt(ONBOARD.paymentMethods.retryPrompt)
|
|
14432
15059
|
] }),
|
|
14433
|
-
pastPhase("payment-methods") && /* @__PURE__ */
|
|
15060
|
+
pastPhase("payment-methods") && /* @__PURE__ */ jsx16(Text13, { color: "green", children: "\u2713 Payment method found" })
|
|
14434
15061
|
] }),
|
|
14435
|
-
phase === "demo" && /* @__PURE__ */
|
|
14436
|
-
/* @__PURE__ */
|
|
14437
|
-
/* @__PURE__ */
|
|
15062
|
+
phase === "demo" && /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
|
|
15063
|
+
/* @__PURE__ */ jsx16(Text13, { dimColor: true, children: "\u2500\u2500\u2500" }),
|
|
15064
|
+
/* @__PURE__ */ jsx16(
|
|
14438
15065
|
DemoRunner,
|
|
14439
15066
|
{
|
|
14440
15067
|
authRepo: authRepo2,
|
|
@@ -14445,7 +15072,7 @@ var OnboardRunner = ({
|
|
|
14445
15072
|
}
|
|
14446
15073
|
)
|
|
14447
15074
|
] }),
|
|
14448
|
-
error && /* @__PURE__ */
|
|
15075
|
+
error && /* @__PURE__ */ jsxs11(Text13, { color: "red", children: [
|
|
14449
15076
|
"Error: ",
|
|
14450
15077
|
error
|
|
14451
15078
|
] })
|
|
@@ -14453,9 +15080,9 @@ var OnboardRunner = ({
|
|
|
14453
15080
|
};
|
|
14454
15081
|
|
|
14455
15082
|
// src/commands/onboard/index.tsx
|
|
14456
|
-
import { jsx as
|
|
15083
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
14457
15084
|
function createOnboardCli(authRepo2, spendRequestRepo2, createPaymentMethodsResource, authStorage2) {
|
|
14458
|
-
return
|
|
15085
|
+
return Cli5.create("onboard", {
|
|
14459
15086
|
description: "Guided setup: authenticate, verify payment methods, and demo both payment flows",
|
|
14460
15087
|
outputPolicy: "agent-only",
|
|
14461
15088
|
async run(c) {
|
|
@@ -14467,7 +15094,7 @@ function createOnboardCli(authRepo2, spendRequestRepo2, createPaymentMethodsReso
|
|
|
14467
15094
|
}
|
|
14468
15095
|
const paymentMethodsResource = createPaymentMethodsResource();
|
|
14469
15096
|
return renderInteractive(
|
|
14470
|
-
/* @__PURE__ */
|
|
15097
|
+
/* @__PURE__ */ jsx17(
|
|
14471
15098
|
OnboardRunner,
|
|
14472
15099
|
{
|
|
14473
15100
|
authRepo: authRepo2,
|
|
@@ -14485,11 +15112,11 @@ function createOnboardCli(authRepo2, spendRequestRepo2, createPaymentMethodsReso
|
|
|
14485
15112
|
}
|
|
14486
15113
|
|
|
14487
15114
|
// src/commands/payment-methods/index.tsx
|
|
14488
|
-
import { Cli as
|
|
15115
|
+
import { Cli as Cli6 } from "incur";
|
|
14489
15116
|
|
|
14490
15117
|
// src/commands/payment-methods/add.tsx
|
|
14491
|
-
import { Box as
|
|
14492
|
-
import { jsx as
|
|
15118
|
+
import { Box as Box12, Text as Text14, useApp as useApp3, useInput as useInput6 } from "ink";
|
|
15119
|
+
import { jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
14493
15120
|
var WALLET_URL = "https://app.link.com/wallet";
|
|
14494
15121
|
var AddPaymentMethod = () => {
|
|
14495
15122
|
const { exit } = useApp3();
|
|
@@ -14499,10 +15126,10 @@ var AddPaymentMethod = () => {
|
|
|
14499
15126
|
exit();
|
|
14500
15127
|
}
|
|
14501
15128
|
});
|
|
14502
|
-
return /* @__PURE__ */
|
|
14503
|
-
/* @__PURE__ */
|
|
14504
|
-
/* @__PURE__ */
|
|
14505
|
-
|
|
15129
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingY: 1, children: [
|
|
15130
|
+
/* @__PURE__ */ jsx18(Box12, { marginBottom: 1, children: /* @__PURE__ */ jsx18(Text14, { bold: true, children: "Add Payment Method" }) }),
|
|
15131
|
+
/* @__PURE__ */ jsxs12(
|
|
15132
|
+
Box12,
|
|
14506
15133
|
{
|
|
14507
15134
|
flexDirection: "column",
|
|
14508
15135
|
borderStyle: "round",
|
|
@@ -14510,12 +15137,12 @@ var AddPaymentMethod = () => {
|
|
|
14510
15137
|
paddingX: 2,
|
|
14511
15138
|
paddingY: 1,
|
|
14512
15139
|
children: [
|
|
14513
|
-
/* @__PURE__ */
|
|
15140
|
+
/* @__PURE__ */ jsxs12(Text14, { children: [
|
|
14514
15141
|
"Open:",
|
|
14515
15142
|
" ",
|
|
14516
|
-
/* @__PURE__ */
|
|
15143
|
+
/* @__PURE__ */ jsx18(Text14, { bold: true, color: "cyan", children: WALLET_URL })
|
|
14517
15144
|
] }),
|
|
14518
|
-
/* @__PURE__ */
|
|
15145
|
+
/* @__PURE__ */ jsx18(Text14, { dimColor: true, children: "Press Enter to open in browser" })
|
|
14519
15146
|
]
|
|
14520
15147
|
}
|
|
14521
15148
|
)
|
|
@@ -14523,48 +15150,48 @@ var AddPaymentMethod = () => {
|
|
|
14523
15150
|
};
|
|
14524
15151
|
|
|
14525
15152
|
// src/commands/payment-methods/list.tsx
|
|
14526
|
-
import { Box as
|
|
14527
|
-
import
|
|
14528
|
-
import { useCallback as
|
|
14529
|
-
import { jsx as
|
|
15153
|
+
import { Box as Box13, Text as Text15 } from "ink";
|
|
15154
|
+
import Spinner5 from "ink-spinner";
|
|
15155
|
+
import { useCallback as useCallback4 } from "react";
|
|
15156
|
+
import { jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
14530
15157
|
var PaymentMethodsList = ({
|
|
14531
15158
|
resource,
|
|
14532
15159
|
onComplete
|
|
14533
15160
|
}) => {
|
|
14534
|
-
const action =
|
|
15161
|
+
const action = useCallback4(() => resource.listPaymentMethods(), [resource]);
|
|
14535
15162
|
const { status, data: methods, error } = useAsyncAction(action, onComplete);
|
|
14536
15163
|
if (status === "loading") {
|
|
14537
|
-
return /* @__PURE__ */
|
|
14538
|
-
/* @__PURE__ */
|
|
15164
|
+
return /* @__PURE__ */ jsx19(Box13, { children: /* @__PURE__ */ jsxs13(Text15, { color: "cyan", children: [
|
|
15165
|
+
/* @__PURE__ */ jsx19(Spinner5, { type: "dots" }),
|
|
14539
15166
|
" Loading payment methods..."
|
|
14540
15167
|
] }) });
|
|
14541
15168
|
}
|
|
14542
15169
|
if (status === "error") {
|
|
14543
|
-
return /* @__PURE__ */
|
|
14544
|
-
/* @__PURE__ */
|
|
14545
|
-
/* @__PURE__ */
|
|
15170
|
+
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
|
|
15171
|
+
/* @__PURE__ */ jsx19(Text15, { color: "red", children: "\u2717 Failed to load payment methods" }),
|
|
15172
|
+
/* @__PURE__ */ jsx19(Text15, { color: "red", children: error })
|
|
14546
15173
|
] });
|
|
14547
15174
|
}
|
|
14548
15175
|
if (!methods || methods.length === 0) {
|
|
14549
|
-
return /* @__PURE__ */
|
|
15176
|
+
return /* @__PURE__ */ jsx19(Box13, { children: /* @__PURE__ */ jsx19(Text15, { dimColor: true, children: "No payment methods found" }) });
|
|
14550
15177
|
}
|
|
14551
|
-
return /* @__PURE__ */
|
|
14552
|
-
/* @__PURE__ */
|
|
14553
|
-
/* @__PURE__ */
|
|
15178
|
+
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
|
|
15179
|
+
/* @__PURE__ */ jsx19(Text15, { bold: true, children: "Payment Methods" }),
|
|
15180
|
+
/* @__PURE__ */ jsx19(Box13, { flexDirection: "column", marginTop: 1, children: methods.map((pm) => {
|
|
14554
15181
|
const label = pm.card_details?.brand ?? pm.bank_account_details?.bank_name ?? "Bank account";
|
|
14555
15182
|
const last4 = pm.card_details?.last4 ?? pm.bank_account_details?.last4;
|
|
14556
15183
|
const suffix = pm.nickname ? `(${pm.nickname})` : "";
|
|
14557
15184
|
const agenticCap = pm.capabilities?.agentic_payments;
|
|
14558
15185
|
const ineligible = agenticCap && !agenticCap.eligible;
|
|
14559
|
-
return /* @__PURE__ */
|
|
14560
|
-
/* @__PURE__ */
|
|
15186
|
+
return /* @__PURE__ */ jsx19(Box13, { paddingX: 2, children: /* @__PURE__ */ jsxs13(Text15, { children: [
|
|
15187
|
+
/* @__PURE__ */ jsx19(Text15, { dimColor: true, children: pm.id }),
|
|
14561
15188
|
" ",
|
|
14562
15189
|
label,
|
|
14563
15190
|
" ****",
|
|
14564
15191
|
last4,
|
|
14565
15192
|
suffix ? ` ${suffix}` : "",
|
|
14566
|
-
pm.is_default ? /* @__PURE__ */
|
|
14567
|
-
ineligible ? /* @__PURE__ */
|
|
15193
|
+
pm.is_default ? /* @__PURE__ */ jsx19(Text15, { color: "green", children: " (default)" }) : "",
|
|
15194
|
+
ineligible ? /* @__PURE__ */ jsxs13(Text15, { dimColor: true, children: [
|
|
14568
15195
|
" ",
|
|
14569
15196
|
"agentic_payments: ineligible",
|
|
14570
15197
|
agenticCap.ineligibility_reasons?.length > 0 ? ` (${agenticCap.ineligibility_reasons.join(", ")})` : ""
|
|
@@ -14575,9 +15202,9 @@ var PaymentMethodsList = ({
|
|
|
14575
15202
|
};
|
|
14576
15203
|
|
|
14577
15204
|
// src/commands/payment-methods/index.tsx
|
|
14578
|
-
import { jsx as
|
|
15205
|
+
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
14579
15206
|
function createPaymentMethodsCli(createResource, authStorage2, envAccessToken2) {
|
|
14580
|
-
const cli2 =
|
|
15207
|
+
const cli2 = Cli6.create("payment-methods", {
|
|
14581
15208
|
description: "Payment methods management commands"
|
|
14582
15209
|
});
|
|
14583
15210
|
cli2.command("list", {
|
|
@@ -14588,7 +15215,7 @@ function createPaymentMethodsCli(createResource, authStorage2, envAccessToken2)
|
|
|
14588
15215
|
const resource = createResource();
|
|
14589
15216
|
if (!c.agent && !c.formatExplicit) {
|
|
14590
15217
|
return renderInteractive(
|
|
14591
|
-
/* @__PURE__ */
|
|
15218
|
+
/* @__PURE__ */ jsx20(PaymentMethodsList, { resource, onComplete: () => {
|
|
14592
15219
|
} }),
|
|
14593
15220
|
() => resource.listPaymentMethods()
|
|
14594
15221
|
);
|
|
@@ -14602,7 +15229,7 @@ function createPaymentMethodsCli(createResource, authStorage2, envAccessToken2)
|
|
|
14602
15229
|
middleware: [requireAuth(authStorage2, envAccessToken2)],
|
|
14603
15230
|
async run(c) {
|
|
14604
15231
|
if (!c.agent && !c.formatExplicit) {
|
|
14605
|
-
return renderInteractive(/* @__PURE__ */
|
|
15232
|
+
return renderInteractive(/* @__PURE__ */ jsx20(AddPaymentMethod, {}), () => ({
|
|
14606
15233
|
url: WALLET_URL
|
|
14607
15234
|
}));
|
|
14608
15235
|
}
|
|
@@ -14613,22 +15240,22 @@ function createPaymentMethodsCli(createResource, authStorage2, envAccessToken2)
|
|
|
14613
15240
|
}
|
|
14614
15241
|
|
|
14615
15242
|
// src/commands/report/index.tsx
|
|
14616
|
-
import { Cli as
|
|
15243
|
+
import { Cli as Cli7 } from "incur";
|
|
14617
15244
|
|
|
14618
15245
|
// src/commands/report/schema.ts
|
|
14619
|
-
import { z as
|
|
14620
|
-
var reportOptions =
|
|
14621
|
-
domain:
|
|
14622
|
-
outcome:
|
|
14623
|
-
spendRequestId:
|
|
14624
|
-
tag:
|
|
14625
|
-
step:
|
|
14626
|
-
freeformContext:
|
|
15246
|
+
import { z as z6 } from "incur";
|
|
15247
|
+
var reportOptions = z6.object({
|
|
15248
|
+
domain: z6.string().describe("Domain where the outcome occurred"),
|
|
15249
|
+
outcome: z6.enum(REPORT_OUTCOMES).describe("What happened: success, blocked, or abandoned"),
|
|
15250
|
+
spendRequestId: z6.string().describe("Spend request ID (lsrq_...)"),
|
|
15251
|
+
tag: z6.array(z6.enum(REPORT_TAGS)).optional().describe("Outcome tags (repeatable)"),
|
|
15252
|
+
step: z6.string().max(500).optional().describe("Where in the flow the agent was"),
|
|
15253
|
+
freeformContext: z6.string().max(500).optional().describe("Additional context (max 500 chars)")
|
|
14627
15254
|
});
|
|
14628
15255
|
|
|
14629
15256
|
// src/commands/report/index.tsx
|
|
14630
15257
|
function createReportCli(createResource, authStorage2, envAccessToken2) {
|
|
14631
|
-
const cli2 =
|
|
15258
|
+
const cli2 = Cli7.create("report", {
|
|
14632
15259
|
description: "Report the outcome of an agent action on a domain. Call after every purchase attempt.",
|
|
14633
15260
|
options: reportOptions,
|
|
14634
15261
|
outputPolicy: "agent-only",
|
|
@@ -14653,7 +15280,7 @@ function createReportCli(createResource, authStorage2, envAccessToken2) {
|
|
|
14653
15280
|
import {
|
|
14654
15281
|
createServer
|
|
14655
15282
|
} from "http";
|
|
14656
|
-
import { Cli as
|
|
15283
|
+
import { Cli as Cli8, z as z7 } from "incur";
|
|
14657
15284
|
async function nodeRequestToWebRequest(req, port) {
|
|
14658
15285
|
const body = await new Promise((resolve) => {
|
|
14659
15286
|
const chunks = [];
|
|
@@ -14678,17 +15305,47 @@ async function sendWebResponse(webRes, res) {
|
|
|
14678
15305
|
res.writeHead(webRes.status);
|
|
14679
15306
|
res.end(Buffer.from(buffer));
|
|
14680
15307
|
}
|
|
15308
|
+
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["127.0.0.1", "::1", "localhost"]);
|
|
15309
|
+
function isLoopbackHost(host) {
|
|
15310
|
+
return LOOPBACK_HOSTS.has(host.toLowerCase());
|
|
15311
|
+
}
|
|
15312
|
+
function isAllowedOrigin(origin) {
|
|
15313
|
+
if (!origin) return true;
|
|
15314
|
+
try {
|
|
15315
|
+
return isLoopbackHost(new URL(origin).hostname);
|
|
15316
|
+
} catch {
|
|
15317
|
+
return false;
|
|
15318
|
+
}
|
|
15319
|
+
}
|
|
15320
|
+
function isAllowedRoute(method, pathname) {
|
|
15321
|
+
if (pathname === "/mcp") return true;
|
|
15322
|
+
if (pathname.startsWith("/.well-known/skills/") && method === "GET")
|
|
15323
|
+
return true;
|
|
15324
|
+
return false;
|
|
15325
|
+
}
|
|
14681
15326
|
function createServeCli(rootCli) {
|
|
14682
|
-
return
|
|
15327
|
+
return Cli8.create("serve", {
|
|
14683
15328
|
description: "Start an HTTP server exposing link-cli as an MCP endpoint at /mcp",
|
|
14684
|
-
options:
|
|
14685
|
-
port:
|
|
15329
|
+
options: z7.object({
|
|
15330
|
+
port: z7.coerce.number().default(54321).describe("Port to listen on"),
|
|
15331
|
+
host: z7.string().default("127.0.0.1").describe(
|
|
15332
|
+
"Host/interface to bind. Defaults to loopback; set explicitly (e.g. 0.0.0.0) to expose beyond localhost."
|
|
15333
|
+
)
|
|
14686
15334
|
}),
|
|
14687
15335
|
async run(c) {
|
|
14688
|
-
const { port } = c.options;
|
|
15336
|
+
const { port, host } = c.options;
|
|
14689
15337
|
const server = createServer(
|
|
14690
15338
|
async (req, res) => {
|
|
14691
|
-
|
|
15339
|
+
const origin = req.headers.origin;
|
|
15340
|
+
if (!isAllowedOrigin(origin)) {
|
|
15341
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
15342
|
+
res.end(JSON.stringify({ error: "forbidden origin" }));
|
|
15343
|
+
return;
|
|
15344
|
+
}
|
|
15345
|
+
if (origin) {
|
|
15346
|
+
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
15347
|
+
res.setHeader("Vary", "Origin");
|
|
15348
|
+
}
|
|
14692
15349
|
res.setHeader(
|
|
14693
15350
|
"Access-Control-Allow-Methods",
|
|
14694
15351
|
"GET, POST, DELETE, OPTIONS"
|
|
@@ -14702,6 +15359,12 @@ function createServeCli(rootCli) {
|
|
|
14702
15359
|
res.end();
|
|
14703
15360
|
return;
|
|
14704
15361
|
}
|
|
15362
|
+
const pathname = new URL(req.url ?? "/", `http://localhost:${port}`).pathname;
|
|
15363
|
+
if (!isAllowedRoute(req.method ?? "GET", pathname)) {
|
|
15364
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
15365
|
+
res.end(JSON.stringify({ error: "not found" }));
|
|
15366
|
+
return;
|
|
15367
|
+
}
|
|
14705
15368
|
try {
|
|
14706
15369
|
const webReq = await nodeRequestToWebRequest(req, port);
|
|
14707
15370
|
const webRes = await rootCli.fetch(webReq);
|
|
@@ -14715,9 +15378,16 @@ function createServeCli(rootCli) {
|
|
|
14715
15378
|
);
|
|
14716
15379
|
await new Promise((resolve, reject) => {
|
|
14717
15380
|
server.on("error", reject);
|
|
14718
|
-
server.listen(port, () => {
|
|
15381
|
+
server.listen(port, host, () => {
|
|
15382
|
+
if (!isLoopbackHost(host)) {
|
|
15383
|
+
process.stderr.write(
|
|
15384
|
+
`WARNING: link-cli serve is bound to ${host}, which may be reachable beyond localhost.
|
|
15385
|
+
Any caller that can reach this port can use the authenticated Link session of this CLI. Only do this on a trusted, isolated network.
|
|
15386
|
+
`
|
|
15387
|
+
);
|
|
15388
|
+
}
|
|
14719
15389
|
process.stderr.write(
|
|
14720
|
-
`link-cli MCP server listening on http
|
|
15390
|
+
`link-cli MCP server listening on http://${host}:${port}/mcp
|
|
14721
15391
|
`
|
|
14722
15392
|
);
|
|
14723
15393
|
});
|
|
@@ -14727,13 +15397,13 @@ function createServeCli(rootCli) {
|
|
|
14727
15397
|
}
|
|
14728
15398
|
|
|
14729
15399
|
// src/commands/shipping-address/index.tsx
|
|
14730
|
-
import { Cli as
|
|
15400
|
+
import { Cli as Cli9 } from "incur";
|
|
14731
15401
|
|
|
14732
15402
|
// src/commands/shipping-address/list.tsx
|
|
14733
|
-
import { Box as
|
|
14734
|
-
import
|
|
14735
|
-
import { useCallback as
|
|
14736
|
-
import { jsx as
|
|
15403
|
+
import { Box as Box14, Text as Text16 } from "ink";
|
|
15404
|
+
import Spinner6 from "ink-spinner";
|
|
15405
|
+
import { useCallback as useCallback5 } from "react";
|
|
15406
|
+
import { jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
14737
15407
|
function formatStreetLine(address) {
|
|
14738
15408
|
const parts = [address.line_1, address.line_2].filter(Boolean);
|
|
14739
15409
|
return parts.length > 0 ? parts.join(", ") : null;
|
|
@@ -14751,100 +15421,311 @@ function formatLocalityLine(address) {
|
|
|
14751
15421
|
}
|
|
14752
15422
|
return localityPostal || address.country_code || null;
|
|
14753
15423
|
}
|
|
14754
|
-
function formatAddressLines(addressRecord) {
|
|
14755
|
-
if (!addressRecord.address) {
|
|
14756
|
-
return ["Address details unavailable"];
|
|
15424
|
+
function formatAddressLines(addressRecord) {
|
|
15425
|
+
if (!addressRecord.address) {
|
|
15426
|
+
return ["Address details unavailable"];
|
|
15427
|
+
}
|
|
15428
|
+
const address = addressRecord.address;
|
|
15429
|
+
const lines = [formatStreetLine(address), formatLocalityLine(address)].filter(
|
|
15430
|
+
(line) => Boolean(line)
|
|
15431
|
+
);
|
|
15432
|
+
return lines.length > 0 ? lines : ["Address details unavailable"];
|
|
15433
|
+
}
|
|
15434
|
+
var ShippingAddressList = ({
|
|
15435
|
+
resource,
|
|
15436
|
+
onComplete
|
|
15437
|
+
}) => {
|
|
15438
|
+
const action = useCallback5(
|
|
15439
|
+
() => resource.listShippingAddresses(),
|
|
15440
|
+
[resource]
|
|
15441
|
+
);
|
|
15442
|
+
const {
|
|
15443
|
+
status,
|
|
15444
|
+
data: shippingAddresses,
|
|
15445
|
+
error
|
|
15446
|
+
} = useAsyncAction(action, onComplete);
|
|
15447
|
+
if (status === "loading") {
|
|
15448
|
+
return /* @__PURE__ */ jsx21(Box14, { children: /* @__PURE__ */ jsxs14(Text16, { color: "cyan", children: [
|
|
15449
|
+
/* @__PURE__ */ jsx21(Spinner6, { type: "dots" }),
|
|
15450
|
+
" Loading shipping addresses..."
|
|
15451
|
+
] }) });
|
|
15452
|
+
}
|
|
15453
|
+
if (status === "error") {
|
|
15454
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
15455
|
+
/* @__PURE__ */ jsx21(Text16, { color: "red", children: "\u2717 Failed to load shipping addresses" }),
|
|
15456
|
+
/* @__PURE__ */ jsx21(Text16, { color: "red", children: error })
|
|
15457
|
+
] });
|
|
15458
|
+
}
|
|
15459
|
+
if (!shippingAddresses || shippingAddresses.length === 0) {
|
|
15460
|
+
return /* @__PURE__ */ jsx21(Box14, { children: /* @__PURE__ */ jsx21(Text16, { dimColor: true, children: "No shipping addresses found" }) });
|
|
15461
|
+
}
|
|
15462
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
15463
|
+
/* @__PURE__ */ jsx21(Text16, { bold: true, children: "Shipping Addresses" }),
|
|
15464
|
+
/* @__PURE__ */ jsx21(Box14, { flexDirection: "column", marginTop: 1, children: shippingAddresses.map((shippingAddress) => {
|
|
15465
|
+
const addressName = shippingAddress.address?.name;
|
|
15466
|
+
const nickname = shippingAddress.nickname ? ` (${shippingAddress.nickname})` : "";
|
|
15467
|
+
return /* @__PURE__ */ jsxs14(
|
|
15468
|
+
Box14,
|
|
15469
|
+
{
|
|
15470
|
+
flexDirection: "column",
|
|
15471
|
+
paddingX: 2,
|
|
15472
|
+
marginBottom: 1,
|
|
15473
|
+
children: [
|
|
15474
|
+
/* @__PURE__ */ jsxs14(Text16, { children: [
|
|
15475
|
+
/* @__PURE__ */ jsx21(Text16, { dimColor: true, children: shippingAddress.id }),
|
|
15476
|
+
nickname,
|
|
15477
|
+
shippingAddress.is_default ? /* @__PURE__ */ jsx21(Text16, { color: "green", children: " (default)" }) : null
|
|
15478
|
+
] }),
|
|
15479
|
+
/* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", marginTop: 1, children: [
|
|
15480
|
+
addressName ? /* @__PURE__ */ jsx21(Text16, { bold: true, children: addressName }) : null,
|
|
15481
|
+
formatAddressLines(shippingAddress).map((line) => /* @__PURE__ */ jsx21(Text16, { children: line }, `${shippingAddress.id}:${line}`))
|
|
15482
|
+
] })
|
|
15483
|
+
]
|
|
15484
|
+
},
|
|
15485
|
+
shippingAddress.id
|
|
15486
|
+
);
|
|
15487
|
+
}) })
|
|
15488
|
+
] });
|
|
15489
|
+
};
|
|
15490
|
+
|
|
15491
|
+
// src/commands/shipping-address/index.tsx
|
|
15492
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
15493
|
+
function createShippingAddressCli(createResource, authStorage2, envAccessToken2) {
|
|
15494
|
+
const cli2 = Cli9.create("shipping-address", {
|
|
15495
|
+
description: "Shipping address management commands"
|
|
15496
|
+
});
|
|
15497
|
+
cli2.command("list", {
|
|
15498
|
+
description: "List all shipping addresses on your account",
|
|
15499
|
+
outputPolicy: "agent-only",
|
|
15500
|
+
middleware: [requireAuth(authStorage2, envAccessToken2)],
|
|
15501
|
+
async run(c) {
|
|
15502
|
+
const resource = createResource();
|
|
15503
|
+
if (!c.agent && !c.formatExplicit) {
|
|
15504
|
+
return renderInteractive(
|
|
15505
|
+
/* @__PURE__ */ jsx22(ShippingAddressList, { resource, onComplete: () => {
|
|
15506
|
+
} }),
|
|
15507
|
+
() => resource.listShippingAddresses()
|
|
15508
|
+
);
|
|
15509
|
+
}
|
|
15510
|
+
return resource.listShippingAddresses();
|
|
15511
|
+
}
|
|
15512
|
+
});
|
|
15513
|
+
return cli2;
|
|
15514
|
+
}
|
|
15515
|
+
|
|
15516
|
+
// src/commands/sources/index.tsx
|
|
15517
|
+
import { Cli as Cli10 } from "incur";
|
|
15518
|
+
|
|
15519
|
+
// src/commands/sources/list.tsx
|
|
15520
|
+
import { Box as Box15, Text as Text17 } from "ink";
|
|
15521
|
+
import Spinner7 from "ink-spinner";
|
|
15522
|
+
import { useCallback as useCallback6 } from "react";
|
|
15523
|
+
import { jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
15524
|
+
var COLUMN_GAP2 = " ";
|
|
15525
|
+
var HORIZONTAL_PADDING = 4;
|
|
15526
|
+
function truncateCell2(value, width) {
|
|
15527
|
+
if (value.length <= width) {
|
|
15528
|
+
return value;
|
|
15529
|
+
}
|
|
15530
|
+
if (width <= 3) {
|
|
15531
|
+
return value.slice(0, width);
|
|
15532
|
+
}
|
|
15533
|
+
return `${value.slice(0, width - 3)}...`;
|
|
15534
|
+
}
|
|
15535
|
+
function formatCell2(value, width) {
|
|
15536
|
+
return truncateCell2(value, width).padEnd(width);
|
|
15537
|
+
}
|
|
15538
|
+
function sourceId(source, index) {
|
|
15539
|
+
return typeof source.id === "string" && source.id.length > 0 ? source.id : `source-${index + 1}`;
|
|
15540
|
+
}
|
|
15541
|
+
function statusFromValue(value) {
|
|
15542
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
15543
|
+
const status = value.status;
|
|
15544
|
+
return typeof status === "string" ? status : null;
|
|
15545
|
+
}
|
|
15546
|
+
return null;
|
|
15547
|
+
}
|
|
15548
|
+
function formatCapabilities(source) {
|
|
15549
|
+
const capabilities = source.capabilities;
|
|
15550
|
+
if (!capabilities || typeof capabilities !== "object") {
|
|
15551
|
+
return "-";
|
|
15552
|
+
}
|
|
15553
|
+
const entries = Object.entries(capabilities).map(([capability, value]) => {
|
|
15554
|
+
const status = statusFromValue(value);
|
|
15555
|
+
return status ? `${capability}:${status}` : capability;
|
|
15556
|
+
}).sort();
|
|
15557
|
+
return entries.length > 0 ? entries.join(", ") : "-";
|
|
15558
|
+
}
|
|
15559
|
+
function formatExternalConnection(source) {
|
|
15560
|
+
const status = statusFromValue(source.external_connection);
|
|
15561
|
+
return status ?? "-";
|
|
15562
|
+
}
|
|
15563
|
+
function sourceRow(source, index) {
|
|
15564
|
+
const capabilities = formatCapabilities(source);
|
|
15565
|
+
const external = formatExternalConnection(source);
|
|
15566
|
+
return {
|
|
15567
|
+
key: sourceId(source, index),
|
|
15568
|
+
name: source.name ?? "Source",
|
|
15569
|
+
type: source.type ?? "-",
|
|
15570
|
+
id: sourceId(source, index),
|
|
15571
|
+
capabilities,
|
|
15572
|
+
external
|
|
15573
|
+
};
|
|
15574
|
+
}
|
|
15575
|
+
function tableColumns() {
|
|
15576
|
+
return [
|
|
15577
|
+
{ label: "Name", value: (row) => row.name, minWidth: 14, maxWidth: 24 },
|
|
15578
|
+
{ label: "Type", value: (row) => row.type, minWidth: 10, maxWidth: 14 },
|
|
15579
|
+
{ label: "ID", value: (row) => row.id, minWidth: 16, maxWidth: 48 },
|
|
15580
|
+
{
|
|
15581
|
+
label: "Capabilities",
|
|
15582
|
+
value: (row) => row.capabilities,
|
|
15583
|
+
minWidth: 8,
|
|
15584
|
+
maxWidth: 48
|
|
15585
|
+
},
|
|
15586
|
+
{
|
|
15587
|
+
label: "External connection status",
|
|
15588
|
+
value: (row) => row.external,
|
|
15589
|
+
minWidth: 8,
|
|
15590
|
+
maxWidth: 36
|
|
15591
|
+
}
|
|
15592
|
+
];
|
|
15593
|
+
}
|
|
15594
|
+
function distributeWidths(columns, availableWidth) {
|
|
15595
|
+
const gapWidth = COLUMN_GAP2.length * Math.max(0, columns.length - 1);
|
|
15596
|
+
const contentWidth2 = Math.max(columns.length, availableWidth - gapWidth);
|
|
15597
|
+
const widths = columns.map((column) => column.minWidth);
|
|
15598
|
+
let remaining = contentWidth2 - widths.reduce((total, width) => total + width, 0);
|
|
15599
|
+
while (remaining > 0) {
|
|
15600
|
+
let changed = false;
|
|
15601
|
+
for (let index = 0; index < columns.length && remaining > 0; index += 1) {
|
|
15602
|
+
if (widths[index] >= columns[index].maxWidth) {
|
|
15603
|
+
continue;
|
|
15604
|
+
}
|
|
15605
|
+
widths[index] += 1;
|
|
15606
|
+
remaining -= 1;
|
|
15607
|
+
changed = true;
|
|
15608
|
+
}
|
|
15609
|
+
if (!changed) {
|
|
15610
|
+
break;
|
|
15611
|
+
}
|
|
14757
15612
|
}
|
|
14758
|
-
|
|
14759
|
-
|
|
14760
|
-
|
|
15613
|
+
return widths;
|
|
15614
|
+
}
|
|
15615
|
+
function renderTableRows(rows, terminalWidth) {
|
|
15616
|
+
const columns = tableColumns();
|
|
15617
|
+
const availableWidth = contentWidth(terminalWidth);
|
|
15618
|
+
const widths = distributeWidths(columns, availableWidth);
|
|
15619
|
+
const headerRow = columns.map((column, index) => formatCell2(column.label, widths[index])).join(COLUMN_GAP2).slice(0, availableWidth);
|
|
15620
|
+
const separatorRow = "-".repeat(headerRow.length).slice(0, availableWidth);
|
|
15621
|
+
const bodyRows = rows.map(
|
|
15622
|
+
(row) => columns.map((column, index) => formatCell2(column.value(row), widths[index])).join(COLUMN_GAP2).slice(0, availableWidth)
|
|
14761
15623
|
);
|
|
14762
|
-
return
|
|
15624
|
+
return { headerRow, separatorRow, bodyRows };
|
|
14763
15625
|
}
|
|
14764
|
-
|
|
15626
|
+
function contentWidth(terminalWidth) {
|
|
15627
|
+
return Math.max(1, terminalWidth - HORIZONTAL_PADDING);
|
|
15628
|
+
}
|
|
15629
|
+
var SourcesList = ({
|
|
14765
15630
|
resource,
|
|
15631
|
+
params,
|
|
14766
15632
|
onComplete
|
|
14767
15633
|
}) => {
|
|
14768
|
-
const action =
|
|
14769
|
-
() => resource.
|
|
14770
|
-
[resource]
|
|
15634
|
+
const action = useCallback6(
|
|
15635
|
+
() => resource.listSources(params),
|
|
15636
|
+
[resource, params]
|
|
15637
|
+
);
|
|
15638
|
+
const { status, data: page, error } = useAsyncAction(action, onComplete);
|
|
15639
|
+
const sources = page?.data ?? [];
|
|
15640
|
+
const nextCursor = page?.has_more && sources.length > 0 ? sources[sources.length - 1].id : null;
|
|
15641
|
+
const rows = sources.map(sourceRow);
|
|
15642
|
+
const terminalWidth = process.stdout.columns ?? 140;
|
|
15643
|
+
const { headerRow, separatorRow, bodyRows } = renderTableRows(
|
|
15644
|
+
rows,
|
|
15645
|
+
terminalWidth
|
|
14771
15646
|
);
|
|
14772
|
-
const {
|
|
14773
|
-
status,
|
|
14774
|
-
data: shippingAddresses,
|
|
14775
|
-
error
|
|
14776
|
-
} = useAsyncAction(action, onComplete);
|
|
14777
15647
|
if (status === "loading") {
|
|
14778
|
-
return /* @__PURE__ */
|
|
14779
|
-
/* @__PURE__ */
|
|
14780
|
-
" Loading
|
|
15648
|
+
return /* @__PURE__ */ jsx23(Box15, { children: /* @__PURE__ */ jsxs15(Text17, { color: "cyan", children: [
|
|
15649
|
+
/* @__PURE__ */ jsx23(Spinner7, { type: "dots" }),
|
|
15650
|
+
" Loading sources..."
|
|
14781
15651
|
] }) });
|
|
14782
15652
|
}
|
|
14783
15653
|
if (status === "error") {
|
|
14784
|
-
return /* @__PURE__ */
|
|
14785
|
-
/* @__PURE__ */
|
|
14786
|
-
/* @__PURE__ */
|
|
15654
|
+
return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", children: [
|
|
15655
|
+
/* @__PURE__ */ jsx23(Text17, { color: "red", children: "Failed to load sources" }),
|
|
15656
|
+
/* @__PURE__ */ jsx23(Text17, { color: "red", children: error })
|
|
14787
15657
|
] });
|
|
14788
15658
|
}
|
|
14789
|
-
if (
|
|
14790
|
-
return /* @__PURE__ */
|
|
15659
|
+
if (sources.length === 0) {
|
|
15660
|
+
return /* @__PURE__ */ jsx23(Box15, { children: /* @__PURE__ */ jsx23(Text17, { dimColor: true, children: "No sources found" }) });
|
|
14791
15661
|
}
|
|
14792
|
-
return /* @__PURE__ */
|
|
14793
|
-
/* @__PURE__ */
|
|
14794
|
-
/* @__PURE__ */
|
|
14795
|
-
|
|
14796
|
-
|
|
14797
|
-
|
|
14798
|
-
|
|
14799
|
-
|
|
14800
|
-
|
|
14801
|
-
|
|
14802
|
-
|
|
14803
|
-
|
|
14804
|
-
|
|
14805
|
-
|
|
14806
|
-
nickname,
|
|
14807
|
-
shippingAddress.is_default ? /* @__PURE__ */ jsx19(Text15, { color: "green", children: " (default)" }) : null
|
|
14808
|
-
] }),
|
|
14809
|
-
/* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", marginTop: 1, children: [
|
|
14810
|
-
addressName ? /* @__PURE__ */ jsx19(Text15, { bold: true, children: addressName }) : null,
|
|
14811
|
-
formatAddressLines(shippingAddress).map((line) => /* @__PURE__ */ jsx19(Text15, { children: line }, `${shippingAddress.id}:${line}`))
|
|
14812
|
-
] })
|
|
14813
|
-
]
|
|
14814
|
-
},
|
|
14815
|
-
shippingAddress.id
|
|
14816
|
-
);
|
|
14817
|
-
}) })
|
|
15662
|
+
return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", children: [
|
|
15663
|
+
/* @__PURE__ */ jsx23(Text17, { bold: true, children: "Sources" }),
|
|
15664
|
+
/* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
15665
|
+
/* @__PURE__ */ jsx23(Text17, { bold: true, children: headerRow }),
|
|
15666
|
+
/* @__PURE__ */ jsx23(Text17, { dimColor: true, children: separatorRow }),
|
|
15667
|
+
bodyRows.map((row, index) => /* @__PURE__ */ jsx23(Text17, { children: row }, rows[index].key))
|
|
15668
|
+
] }),
|
|
15669
|
+
page?.has_more !== void 0 ? /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", marginTop: 1, children: [
|
|
15670
|
+
/* @__PURE__ */ jsxs15(Text17, { dimColor: true, children: [
|
|
15671
|
+
"has_more: ",
|
|
15672
|
+
String(page.has_more)
|
|
15673
|
+
] }),
|
|
15674
|
+
typeof nextCursor === "string" && nextCursor.length > 0 ? /* @__PURE__ */ jsx23(Text17, { dimColor: true, children: `next page: --starting-after ${nextCursor}` }) : null
|
|
15675
|
+
] }) : null
|
|
14818
15676
|
] });
|
|
14819
15677
|
};
|
|
14820
15678
|
|
|
14821
|
-
// src/commands/
|
|
14822
|
-
import {
|
|
14823
|
-
|
|
14824
|
-
|
|
14825
|
-
|
|
15679
|
+
// src/commands/sources/schema.ts
|
|
15680
|
+
import { z as z8 } from "incur";
|
|
15681
|
+
var listOptions2 = z8.object({
|
|
15682
|
+
limit: z8.coerce.number().int().positive().max(100).optional().describe("Maximum number of sources to return (1-100)."),
|
|
15683
|
+
startingAfter: z8.string().optional().describe("Cursor: return sources after this source ID."),
|
|
15684
|
+
endingBefore: z8.string().optional().describe("Cursor: return sources before this source ID.")
|
|
15685
|
+
});
|
|
15686
|
+
|
|
15687
|
+
// src/commands/sources/index.tsx
|
|
15688
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
15689
|
+
function createSourcesCli(createResource, authStorage2, envAccessToken2) {
|
|
15690
|
+
const cli2 = Cli10.create("sources", {
|
|
15691
|
+
description: "List sources from your Link wallet"
|
|
14826
15692
|
});
|
|
14827
15693
|
cli2.command("list", {
|
|
14828
|
-
description: "List
|
|
15694
|
+
description: "List sources from your Link wallet",
|
|
15695
|
+
options: listOptions2,
|
|
14829
15696
|
outputPolicy: "agent-only",
|
|
14830
15697
|
middleware: [requireAuth(authStorage2, envAccessToken2)],
|
|
14831
15698
|
async run(c) {
|
|
15699
|
+
const opts = c.options;
|
|
14832
15700
|
const resource = createResource();
|
|
15701
|
+
const params = {};
|
|
15702
|
+
if (opts.limit !== void 0) params.limit = opts.limit;
|
|
15703
|
+
if (opts.startingAfter !== void 0)
|
|
15704
|
+
params.starting_after = opts.startingAfter;
|
|
15705
|
+
if (opts.endingBefore !== void 0)
|
|
15706
|
+
params.ending_before = opts.endingBefore;
|
|
14833
15707
|
if (!c.agent && !c.formatExplicit) {
|
|
14834
15708
|
return renderInteractive(
|
|
14835
|
-
/* @__PURE__ */
|
|
14836
|
-
|
|
14837
|
-
|
|
15709
|
+
/* @__PURE__ */ jsx24(
|
|
15710
|
+
SourcesList,
|
|
15711
|
+
{
|
|
15712
|
+
resource,
|
|
15713
|
+
params,
|
|
15714
|
+
onComplete: () => {
|
|
15715
|
+
}
|
|
15716
|
+
}
|
|
15717
|
+
),
|
|
15718
|
+
() => resource.listSources(params)
|
|
14838
15719
|
);
|
|
14839
15720
|
}
|
|
14840
|
-
return resource.
|
|
15721
|
+
return resource.listSources(params);
|
|
14841
15722
|
}
|
|
14842
15723
|
});
|
|
14843
15724
|
return cli2;
|
|
14844
15725
|
}
|
|
14845
15726
|
|
|
14846
15727
|
// src/commands/spend-request/index.tsx
|
|
14847
|
-
import { Cli as
|
|
15728
|
+
import { Cli as Cli11, z as z11 } from "incur";
|
|
14848
15729
|
|
|
14849
15730
|
// src/utils/credential-output.ts
|
|
14850
15731
|
import { constants } from "fs";
|
|
@@ -14902,21 +15783,21 @@ async function writeCredentialFile(filePath, data, force) {
|
|
|
14902
15783
|
}
|
|
14903
15784
|
|
|
14904
15785
|
// src/utils/line-item-parser.ts
|
|
14905
|
-
import { z as
|
|
14906
|
-
var LineItemSchema =
|
|
14907
|
-
name:
|
|
14908
|
-
url:
|
|
14909
|
-
image_url:
|
|
14910
|
-
description:
|
|
14911
|
-
sku:
|
|
14912
|
-
quantity:
|
|
14913
|
-
unit_amount:
|
|
14914
|
-
product_url:
|
|
15786
|
+
import { z as z9 } from "zod";
|
|
15787
|
+
var LineItemSchema = z9.object({
|
|
15788
|
+
name: z9.string(),
|
|
15789
|
+
url: z9.string().optional(),
|
|
15790
|
+
image_url: z9.string().optional(),
|
|
15791
|
+
description: z9.string().optional(),
|
|
15792
|
+
sku: z9.string().optional(),
|
|
15793
|
+
quantity: z9.coerce.number().optional(),
|
|
15794
|
+
unit_amount: z9.coerce.number().optional(),
|
|
15795
|
+
product_url: z9.string().optional()
|
|
14915
15796
|
}).strict();
|
|
14916
|
-
var TotalSchema =
|
|
14917
|
-
type:
|
|
14918
|
-
display_text:
|
|
14919
|
-
amount:
|
|
15797
|
+
var TotalSchema = z9.object({
|
|
15798
|
+
type: z9.string(),
|
|
15799
|
+
display_text: z9.string(),
|
|
15800
|
+
amount: z9.coerce.number()
|
|
14920
15801
|
}).strict();
|
|
14921
15802
|
function parseKvString(raw) {
|
|
14922
15803
|
const result = {};
|
|
@@ -14946,7 +15827,7 @@ function parseLineItemFlag(raw) {
|
|
|
14946
15827
|
try {
|
|
14947
15828
|
return LineItemSchema.parse(obj);
|
|
14948
15829
|
} catch (err) {
|
|
14949
|
-
if (err instanceof
|
|
15830
|
+
if (err instanceof z9.ZodError)
|
|
14950
15831
|
throw formatZodError(err, "Line item", LineItemSchema);
|
|
14951
15832
|
throw err;
|
|
14952
15833
|
}
|
|
@@ -14956,65 +15837,65 @@ function parseTotalFlag(raw) {
|
|
|
14956
15837
|
try {
|
|
14957
15838
|
return TotalSchema.parse(obj);
|
|
14958
15839
|
} catch (err) {
|
|
14959
|
-
if (err instanceof
|
|
15840
|
+
if (err instanceof z9.ZodError)
|
|
14960
15841
|
throw formatZodError(err, "Total", TotalSchema);
|
|
14961
15842
|
throw err;
|
|
14962
15843
|
}
|
|
14963
15844
|
}
|
|
14964
15845
|
|
|
14965
15846
|
// src/commands/spend-request/cancel.tsx
|
|
14966
|
-
import { Box as
|
|
14967
|
-
import
|
|
14968
|
-
import { useCallback as
|
|
14969
|
-
import { jsx as
|
|
15847
|
+
import { Box as Box16, Text as Text18 } from "ink";
|
|
15848
|
+
import Spinner8 from "ink-spinner";
|
|
15849
|
+
import { useCallback as useCallback7 } from "react";
|
|
15850
|
+
import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
14970
15851
|
var CancelSpendRequest = ({
|
|
14971
15852
|
repository,
|
|
14972
15853
|
id,
|
|
14973
15854
|
onComplete
|
|
14974
15855
|
}) => {
|
|
14975
|
-
const action =
|
|
15856
|
+
const action = useCallback7(
|
|
14976
15857
|
() => repository.cancelSpendRequest(id),
|
|
14977
15858
|
[repository, id]
|
|
14978
15859
|
);
|
|
14979
15860
|
const { status, data: request, error } = useAsyncAction(action, onComplete);
|
|
14980
15861
|
if (status === "loading") {
|
|
14981
|
-
return /* @__PURE__ */
|
|
14982
|
-
/* @__PURE__ */
|
|
15862
|
+
return /* @__PURE__ */ jsx25(Box16, { children: /* @__PURE__ */ jsxs16(Text18, { color: "cyan", children: [
|
|
15863
|
+
/* @__PURE__ */ jsx25(Spinner8, { type: "dots" }),
|
|
14983
15864
|
" Canceling spend request ",
|
|
14984
15865
|
id,
|
|
14985
15866
|
"..."
|
|
14986
15867
|
] }) });
|
|
14987
15868
|
}
|
|
14988
15869
|
if (status === "error") {
|
|
14989
|
-
return /* @__PURE__ */
|
|
14990
|
-
/* @__PURE__ */
|
|
14991
|
-
/* @__PURE__ */
|
|
15870
|
+
return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
|
|
15871
|
+
/* @__PURE__ */ jsx25(Text18, { color: "red", children: "\u2717 Failed to cancel spend request" }),
|
|
15872
|
+
/* @__PURE__ */ jsx25(Text18, { color: "red", children: error })
|
|
14992
15873
|
] });
|
|
14993
15874
|
}
|
|
14994
|
-
return /* @__PURE__ */
|
|
14995
|
-
/* @__PURE__ */
|
|
14996
|
-
/* @__PURE__ */
|
|
15875
|
+
return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
|
|
15876
|
+
/* @__PURE__ */ jsx25(Text18, { color: "green", children: "\u2713 Spend request canceled" }),
|
|
15877
|
+
/* @__PURE__ */ jsx25(Box16, { flexDirection: "column", marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsxs16(Text18, { children: [
|
|
14997
15878
|
"ID: ",
|
|
14998
|
-
/* @__PURE__ */
|
|
15879
|
+
/* @__PURE__ */ jsx25(Text18, { bold: true, children: request?.id })
|
|
14999
15880
|
] }) })
|
|
15000
15881
|
] });
|
|
15001
15882
|
};
|
|
15002
15883
|
|
|
15003
15884
|
// src/commands/spend-request/create.tsx
|
|
15004
|
-
import { Box as
|
|
15005
|
-
import
|
|
15006
|
-
import { useCallback as
|
|
15885
|
+
import { Box as Box18, Text as Text20, useApp as useApp4 } from "ink";
|
|
15886
|
+
import Spinner10 from "ink-spinner";
|
|
15887
|
+
import { useCallback as useCallback8, useEffect as useEffect9, useState as useState9 } from "react";
|
|
15007
15888
|
|
|
15008
15889
|
// src/commands/spend-request/approval-waiting-view.tsx
|
|
15009
|
-
import { Box as
|
|
15010
|
-
import
|
|
15011
|
-
import { jsx as
|
|
15890
|
+
import { Box as Box17, Text as Text19 } from "ink";
|
|
15891
|
+
import Spinner9 from "ink-spinner";
|
|
15892
|
+
import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
15012
15893
|
var ApprovalWaitingView = ({
|
|
15013
15894
|
status,
|
|
15014
15895
|
approvalUrl
|
|
15015
|
-
}) => /* @__PURE__ */
|
|
15016
|
-
/* @__PURE__ */
|
|
15017
|
-
|
|
15896
|
+
}) => /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", paddingY: 1, children: [
|
|
15897
|
+
/* @__PURE__ */ jsxs17(
|
|
15898
|
+
Box17,
|
|
15018
15899
|
{
|
|
15019
15900
|
flexDirection: "column",
|
|
15020
15901
|
borderStyle: "round",
|
|
@@ -15022,20 +15903,20 @@ var ApprovalWaitingView = ({
|
|
|
15022
15903
|
paddingX: 2,
|
|
15023
15904
|
paddingY: 1,
|
|
15024
15905
|
children: [
|
|
15025
|
-
/* @__PURE__ */
|
|
15906
|
+
/* @__PURE__ */ jsxs17(Text19, { children: [
|
|
15026
15907
|
"Approve at:",
|
|
15027
15908
|
" ",
|
|
15028
|
-
/* @__PURE__ */
|
|
15909
|
+
/* @__PURE__ */ jsx26(Text19, { bold: true, color: "cyan", children: approvalUrl })
|
|
15029
15910
|
] }),
|
|
15030
|
-
/* @__PURE__ */
|
|
15911
|
+
/* @__PURE__ */ jsx26(Text19, { dimColor: true, children: "Press Enter to open in browser" })
|
|
15031
15912
|
]
|
|
15032
15913
|
}
|
|
15033
15914
|
),
|
|
15034
|
-
/* @__PURE__ */
|
|
15035
|
-
/* @__PURE__ */
|
|
15036
|
-
/* @__PURE__ */
|
|
15915
|
+
/* @__PURE__ */ jsx26(AppDownloadQrCodes, {}),
|
|
15916
|
+
/* @__PURE__ */ jsx26(Box17, { marginTop: 1, children: status === "polling" ? /* @__PURE__ */ jsxs17(Text19, { color: "cyan", children: [
|
|
15917
|
+
/* @__PURE__ */ jsx26(Spinner9, { type: "dots" }),
|
|
15037
15918
|
" Waiting for approval..."
|
|
15038
|
-
] }) : /* @__PURE__ */
|
|
15919
|
+
] }) : /* @__PURE__ */ jsx26(Text19, { dimColor: true, children: "Waiting..." }) })
|
|
15039
15920
|
] });
|
|
15040
15921
|
|
|
15041
15922
|
// src/commands/spend-request/use-approval-polling.ts
|
|
@@ -15104,7 +15985,7 @@ function useApprovalPolling({
|
|
|
15104
15985
|
}
|
|
15105
15986
|
|
|
15106
15987
|
// src/commands/spend-request/create.tsx
|
|
15107
|
-
import { Fragment as Fragment4, jsx as
|
|
15988
|
+
import { Fragment as Fragment4, jsx as jsx27, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
15108
15989
|
var CreateSpendRequest = ({
|
|
15109
15990
|
repository,
|
|
15110
15991
|
params,
|
|
@@ -15121,18 +16002,18 @@ var CreateSpendRequest = ({
|
|
|
15121
16002
|
const [fileError, setFileError] = useState9("");
|
|
15122
16003
|
const approvalUrl = request?.approval_url ?? "";
|
|
15123
16004
|
const { exit } = useApp4();
|
|
15124
|
-
const completeAndExit =
|
|
16005
|
+
const completeAndExit = useCallback8(
|
|
15125
16006
|
(result) => {
|
|
15126
16007
|
onComplete(result);
|
|
15127
16008
|
exit();
|
|
15128
16009
|
},
|
|
15129
16010
|
[onComplete, exit]
|
|
15130
16011
|
);
|
|
15131
|
-
const onSuccess =
|
|
16012
|
+
const onSuccess = useCallback8(
|
|
15132
16013
|
(result) => setRequest(result),
|
|
15133
16014
|
[]
|
|
15134
16015
|
);
|
|
15135
|
-
const onError =
|
|
16016
|
+
const onError = useCallback8((msg) => setError(msg), []);
|
|
15136
16017
|
useApprovalPolling({
|
|
15137
16018
|
status,
|
|
15138
16019
|
setStatus,
|
|
@@ -15179,105 +16060,105 @@ var CreateSpendRequest = ({
|
|
|
15179
16060
|
writeCredentialFile(outputFile, fileData, force ?? false).then((path7) => setOutputFilePath(path7)).catch((err) => setFileError(err.message));
|
|
15180
16061
|
}, [status, outputFile, force, request]);
|
|
15181
16062
|
if (status === "creating") {
|
|
15182
|
-
return /* @__PURE__ */
|
|
15183
|
-
/* @__PURE__ */
|
|
16063
|
+
return /* @__PURE__ */ jsx27(Box18, { children: /* @__PURE__ */ jsxs18(Text20, { color: "cyan", children: [
|
|
16064
|
+
/* @__PURE__ */ jsx27(Spinner10, { type: "dots" }),
|
|
15184
16065
|
" Creating spend request..."
|
|
15185
16066
|
] }) });
|
|
15186
16067
|
}
|
|
15187
16068
|
if (status === "error") {
|
|
15188
|
-
return /* @__PURE__ */
|
|
15189
|
-
/* @__PURE__ */
|
|
15190
|
-
/* @__PURE__ */
|
|
15191
|
-
verificationUrl && /* @__PURE__ */
|
|
16069
|
+
return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", children: [
|
|
16070
|
+
/* @__PURE__ */ jsx27(Text20, { color: "red", children: "\u2717 Failed to create spend request" }),
|
|
16071
|
+
/* @__PURE__ */ jsx27(Text20, { color: "red", children: error }),
|
|
16072
|
+
verificationUrl && /* @__PURE__ */ jsxs18(Text20, { color: "red", children: [
|
|
15192
16073
|
"Complete additional verification at: ",
|
|
15193
16074
|
verificationUrl
|
|
15194
16075
|
] })
|
|
15195
16076
|
] });
|
|
15196
16077
|
}
|
|
15197
16078
|
if (status === "success") {
|
|
15198
|
-
return /* @__PURE__ */
|
|
15199
|
-
/* @__PURE__ */
|
|
15200
|
-
/* @__PURE__ */
|
|
15201
|
-
/* @__PURE__ */
|
|
16079
|
+
return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", children: [
|
|
16080
|
+
/* @__PURE__ */ jsx27(Text20, { color: "green", children: "\u2713 Spend request created" }),
|
|
16081
|
+
/* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
16082
|
+
/* @__PURE__ */ jsxs18(Text20, { children: [
|
|
15202
16083
|
"ID: ",
|
|
15203
|
-
/* @__PURE__ */
|
|
16084
|
+
/* @__PURE__ */ jsx27(Text20, { bold: true, children: request?.id })
|
|
15204
16085
|
] }),
|
|
15205
|
-
/* @__PURE__ */
|
|
16086
|
+
/* @__PURE__ */ jsxs18(Text20, { children: [
|
|
15206
16087
|
"Status: ",
|
|
15207
|
-
/* @__PURE__ */
|
|
16088
|
+
/* @__PURE__ */ jsx27(Text20, { bold: true, children: request?.status })
|
|
15208
16089
|
] }),
|
|
15209
|
-
/* @__PURE__ */
|
|
16090
|
+
/* @__PURE__ */ jsxs18(Text20, { children: [
|
|
15210
16091
|
"Amount:",
|
|
15211
16092
|
" ",
|
|
15212
|
-
/* @__PURE__ */
|
|
16093
|
+
/* @__PURE__ */ jsx27(Text20, { bold: true, children: request?.amount != null ? `${request.amount} ${request.currency?.toUpperCase() ?? ""}`.trim() : "N/A" })
|
|
15213
16094
|
] }),
|
|
15214
|
-
/* @__PURE__ */
|
|
16095
|
+
/* @__PURE__ */ jsxs18(Text20, { children: [
|
|
15215
16096
|
"Merchant: ",
|
|
15216
|
-
/* @__PURE__ */
|
|
16097
|
+
/* @__PURE__ */ jsx27(Text20, { bold: true, children: request?.merchant_name })
|
|
15217
16098
|
] }),
|
|
15218
|
-
/* @__PURE__ */
|
|
16099
|
+
/* @__PURE__ */ jsxs18(Text20, { children: [
|
|
15219
16100
|
"Line Items:",
|
|
15220
16101
|
" ",
|
|
15221
|
-
/* @__PURE__ */
|
|
16102
|
+
/* @__PURE__ */ jsx27(Text20, { bold: true, children: request?.line_items.map((li) => li.name).join(", ") || "N/A" })
|
|
15222
16103
|
] }),
|
|
15223
|
-
request?.credential_type === "shared_payment_token" && request.shared_payment_token && /* @__PURE__ */
|
|
16104
|
+
request?.credential_type === "shared_payment_token" && request.shared_payment_token && /* @__PURE__ */ jsxs18(Text20, { children: [
|
|
15224
16105
|
"Token: ",
|
|
15225
|
-
/* @__PURE__ */
|
|
16106
|
+
/* @__PURE__ */ jsx27(Text20, { bold: true, children: request.shared_payment_token.id })
|
|
15226
16107
|
] })
|
|
15227
16108
|
] }),
|
|
15228
|
-
request?.card && !outputFile && /* @__PURE__ */
|
|
15229
|
-
/* @__PURE__ */
|
|
15230
|
-
/* @__PURE__ */
|
|
16109
|
+
request?.card && !outputFile && /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", marginTop: 1, children: [
|
|
16110
|
+
/* @__PURE__ */ jsx27(Text20, { bold: true, children: "Card Details:" }),
|
|
16111
|
+
/* @__PURE__ */ jsxs18(Text20, { children: [
|
|
15231
16112
|
" ",
|
|
15232
16113
|
"Number: ",
|
|
15233
|
-
/* @__PURE__ */
|
|
16114
|
+
/* @__PURE__ */ jsx27(Text20, { bold: true, children: request.card.number })
|
|
15234
16115
|
] }),
|
|
15235
|
-
/* @__PURE__ */
|
|
16116
|
+
/* @__PURE__ */ jsxs18(Text20, { children: [
|
|
15236
16117
|
" ",
|
|
15237
16118
|
"Brand: ",
|
|
15238
|
-
/* @__PURE__ */
|
|
16119
|
+
/* @__PURE__ */ jsx27(Text20, { bold: true, children: request.card.brand })
|
|
15239
16120
|
] }),
|
|
15240
|
-
/* @__PURE__ */
|
|
16121
|
+
/* @__PURE__ */ jsxs18(Text20, { children: [
|
|
15241
16122
|
" ",
|
|
15242
16123
|
"Expiry:",
|
|
15243
16124
|
" ",
|
|
15244
|
-
/* @__PURE__ */
|
|
16125
|
+
/* @__PURE__ */ jsxs18(Text20, { bold: true, children: [
|
|
15245
16126
|
String(request.card.exp_month).padStart(2, "0"),
|
|
15246
16127
|
"/",
|
|
15247
16128
|
request.card.exp_year
|
|
15248
16129
|
] })
|
|
15249
16130
|
] }),
|
|
15250
|
-
request.card.cvc && /* @__PURE__ */
|
|
16131
|
+
request.card.cvc && /* @__PURE__ */ jsxs18(Text20, { children: [
|
|
15251
16132
|
" ",
|
|
15252
16133
|
"CVC: ",
|
|
15253
|
-
/* @__PURE__ */
|
|
16134
|
+
/* @__PURE__ */ jsx27(Text20, { bold: true, children: request.card.cvc })
|
|
15254
16135
|
] }),
|
|
15255
|
-
request.card.valid_until && /* @__PURE__ */
|
|
16136
|
+
request.card.valid_until && /* @__PURE__ */ jsxs18(Text20, { children: [
|
|
15256
16137
|
" ",
|
|
15257
16138
|
"Valid Until: ",
|
|
15258
|
-
/* @__PURE__ */
|
|
16139
|
+
/* @__PURE__ */ jsx27(Text20, { bold: true, children: request.card.valid_until })
|
|
15259
16140
|
] })
|
|
15260
16141
|
] }),
|
|
15261
|
-
request?.card && outputFile && /* @__PURE__ */
|
|
15262
|
-
outputFilePath && /* @__PURE__ */
|
|
16142
|
+
request?.card && outputFile && /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", marginTop: 1, children: [
|
|
16143
|
+
outputFilePath && /* @__PURE__ */ jsxs18(Text20, { color: "green", children: [
|
|
15263
16144
|
"Card credentials written to ",
|
|
15264
|
-
/* @__PURE__ */
|
|
16145
|
+
/* @__PURE__ */ jsx27(Text20, { bold: true, children: outputFilePath })
|
|
15265
16146
|
] }),
|
|
15266
|
-
fileError && /* @__PURE__ */
|
|
16147
|
+
fileError && /* @__PURE__ */ jsxs18(Text20, { color: "red", children: [
|
|
15267
16148
|
"Failed to write card file: ",
|
|
15268
16149
|
fileError
|
|
15269
16150
|
] })
|
|
15270
16151
|
] }),
|
|
15271
|
-
/* @__PURE__ */
|
|
16152
|
+
/* @__PURE__ */ jsx27(AppDownloadQrCodes, {})
|
|
15272
16153
|
] });
|
|
15273
16154
|
}
|
|
15274
|
-
return /* @__PURE__ */
|
|
15275
|
-
/* @__PURE__ */
|
|
16155
|
+
return /* @__PURE__ */ jsxs18(Fragment4, { children: [
|
|
16156
|
+
/* @__PURE__ */ jsx27(Box18, { children: /* @__PURE__ */ jsxs18(Text20, { color: "green", children: [
|
|
15276
16157
|
"\u2713 Spend request created (ID: ",
|
|
15277
|
-
/* @__PURE__ */
|
|
16158
|
+
/* @__PURE__ */ jsx27(Text20, { bold: true, children: request?.id }),
|
|
15278
16159
|
")"
|
|
15279
16160
|
] }) }),
|
|
15280
|
-
/* @__PURE__ */
|
|
16161
|
+
/* @__PURE__ */ jsx27(
|
|
15281
16162
|
ApprovalWaitingView,
|
|
15282
16163
|
{
|
|
15283
16164
|
status,
|
|
@@ -15288,21 +16169,21 @@ var CreateSpendRequest = ({
|
|
|
15288
16169
|
};
|
|
15289
16170
|
|
|
15290
16171
|
// src/commands/spend-request/list.tsx
|
|
15291
|
-
import { Box as
|
|
15292
|
-
import
|
|
15293
|
-
import { useCallback as
|
|
15294
|
-
import { jsx as
|
|
16172
|
+
import { Box as Box19, Text as Text21, useApp as useApp5 } from "ink";
|
|
16173
|
+
import Spinner11 from "ink-spinner";
|
|
16174
|
+
import { useCallback as useCallback9 } from "react";
|
|
16175
|
+
import { jsx as jsx28, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
15295
16176
|
var SpendRequestList = ({
|
|
15296
16177
|
repository,
|
|
15297
16178
|
includeHistory = false,
|
|
15298
16179
|
onComplete
|
|
15299
16180
|
}) => {
|
|
15300
16181
|
const { exit } = useApp5();
|
|
15301
|
-
const action =
|
|
16182
|
+
const action = useCallback9(
|
|
15302
16183
|
() => repository.listSpendRequests({ includeHistory }),
|
|
15303
16184
|
[repository, includeHistory]
|
|
15304
16185
|
);
|
|
15305
|
-
const wrappedOnComplete =
|
|
16186
|
+
const wrappedOnComplete = useCallback9(
|
|
15306
16187
|
(result) => {
|
|
15307
16188
|
onComplete(result);
|
|
15308
16189
|
exit();
|
|
@@ -15315,29 +16196,29 @@ var SpendRequestList = ({
|
|
|
15315
16196
|
error
|
|
15316
16197
|
} = useAsyncAction(action, wrappedOnComplete);
|
|
15317
16198
|
if (status === "loading") {
|
|
15318
|
-
return /* @__PURE__ */
|
|
15319
|
-
/* @__PURE__ */
|
|
16199
|
+
return /* @__PURE__ */ jsx28(Box19, { children: /* @__PURE__ */ jsxs19(Text21, { color: "cyan", children: [
|
|
16200
|
+
/* @__PURE__ */ jsx28(Spinner11, { type: "dots" }),
|
|
15320
16201
|
" Loading spend requests..."
|
|
15321
16202
|
] }) });
|
|
15322
16203
|
}
|
|
15323
16204
|
if (status === "error") {
|
|
15324
|
-
return /* @__PURE__ */
|
|
15325
|
-
/* @__PURE__ */
|
|
15326
|
-
/* @__PURE__ */
|
|
16205
|
+
return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", children: [
|
|
16206
|
+
/* @__PURE__ */ jsx28(Text21, { color: "red", children: "\u2717 Failed to load spend requests" }),
|
|
16207
|
+
/* @__PURE__ */ jsx28(Text21, { color: "red", children: error })
|
|
15327
16208
|
] });
|
|
15328
16209
|
}
|
|
15329
16210
|
if (!requests || requests.length === 0) {
|
|
15330
|
-
return /* @__PURE__ */
|
|
16211
|
+
return /* @__PURE__ */ jsx28(Box19, { children: /* @__PURE__ */ jsx28(Text21, { dimColor: true, children: includeHistory ? "No spend requests found" : "No active spend requests found" }) });
|
|
15331
16212
|
}
|
|
15332
|
-
return /* @__PURE__ */
|
|
15333
|
-
/* @__PURE__ */
|
|
15334
|
-
/* @__PURE__ */
|
|
16213
|
+
return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", children: [
|
|
16214
|
+
/* @__PURE__ */ jsx28(Text21, { bold: true, children: includeHistory ? "All Spend Requests" : "Active Spend Requests" }),
|
|
16215
|
+
/* @__PURE__ */ jsx28(Box19, { flexDirection: "column", marginTop: 1, children: requests.map((sr) => {
|
|
15335
16216
|
const statusColor = sr.status === "approved" ? "green" : sr.status === "pending_approval" ? "yellow" : "white";
|
|
15336
16217
|
const amount = sr.amount != null ? `$${(sr.amount / 100).toFixed(2)} ${(sr.currency ?? "usd").toUpperCase()}` : "";
|
|
15337
|
-
return /* @__PURE__ */
|
|
15338
|
-
/* @__PURE__ */
|
|
16218
|
+
return /* @__PURE__ */ jsx28(Box19, { paddingX: 2, children: /* @__PURE__ */ jsxs19(Text21, { children: [
|
|
16219
|
+
/* @__PURE__ */ jsx28(Text21, { dimColor: true, children: sr.id }),
|
|
15339
16220
|
" ",
|
|
15340
|
-
/* @__PURE__ */
|
|
16221
|
+
/* @__PURE__ */ jsx28(Text21, { color: statusColor, children: sr.status }),
|
|
15341
16222
|
sr.merchant_name ? ` ${sr.merchant_name}` : "",
|
|
15342
16223
|
amount ? ` ${amount}` : ""
|
|
15343
16224
|
] }) }, sr.id);
|
|
@@ -15346,10 +16227,10 @@ var SpendRequestList = ({
|
|
|
15346
16227
|
};
|
|
15347
16228
|
|
|
15348
16229
|
// src/commands/spend-request/request-approval.tsx
|
|
15349
|
-
import { Box as
|
|
15350
|
-
import
|
|
15351
|
-
import { useCallback as
|
|
15352
|
-
import { jsx as
|
|
16230
|
+
import { Box as Box20, Text as Text22, useApp as useApp6 } from "ink";
|
|
16231
|
+
import Spinner12 from "ink-spinner";
|
|
16232
|
+
import { useCallback as useCallback10, useEffect as useEffect10, useState as useState10 } from "react";
|
|
16233
|
+
import { jsx as jsx29, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
15353
16234
|
var RequestApproval = ({
|
|
15354
16235
|
repository,
|
|
15355
16236
|
id,
|
|
@@ -15361,15 +16242,15 @@ var RequestApproval = ({
|
|
|
15361
16242
|
const [error, setError] = useState10("");
|
|
15362
16243
|
const [verificationUrl, setVerificationUrl] = useState10("");
|
|
15363
16244
|
const { exit } = useApp6();
|
|
15364
|
-
const completeAndExit =
|
|
16245
|
+
const completeAndExit = useCallback10(
|
|
15365
16246
|
(result2) => {
|
|
15366
16247
|
onComplete(result2);
|
|
15367
16248
|
exit();
|
|
15368
16249
|
},
|
|
15369
16250
|
[onComplete, exit]
|
|
15370
16251
|
);
|
|
15371
|
-
const onSuccess =
|
|
15372
|
-
const onError =
|
|
16252
|
+
const onSuccess = useCallback10((r) => setResult(r), []);
|
|
16253
|
+
const onError = useCallback10((msg) => setError(msg), []);
|
|
15373
16254
|
useApprovalPolling({
|
|
15374
16255
|
status,
|
|
15375
16256
|
setStatus,
|
|
@@ -15402,50 +16283,50 @@ var RequestApproval = ({
|
|
|
15402
16283
|
request();
|
|
15403
16284
|
}, [repository, id, exit, onComplete]);
|
|
15404
16285
|
if (status === "requesting") {
|
|
15405
|
-
return /* @__PURE__ */
|
|
15406
|
-
/* @__PURE__ */
|
|
16286
|
+
return /* @__PURE__ */ jsx29(Box20, { children: /* @__PURE__ */ jsxs20(Text22, { color: "cyan", children: [
|
|
16287
|
+
/* @__PURE__ */ jsx29(Spinner12, { type: "dots" }),
|
|
15407
16288
|
" Requesting approval..."
|
|
15408
16289
|
] }) });
|
|
15409
16290
|
}
|
|
15410
16291
|
if (status === "error") {
|
|
15411
|
-
return /* @__PURE__ */
|
|
15412
|
-
/* @__PURE__ */
|
|
15413
|
-
/* @__PURE__ */
|
|
15414
|
-
verificationUrl && /* @__PURE__ */
|
|
16292
|
+
return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", children: [
|
|
16293
|
+
/* @__PURE__ */ jsx29(Text22, { color: "red", children: "\u2717 Failed to request approval" }),
|
|
16294
|
+
/* @__PURE__ */ jsx29(Text22, { color: "red", children: error }),
|
|
16295
|
+
verificationUrl && /* @__PURE__ */ jsxs20(Text22, { color: "red", children: [
|
|
15415
16296
|
"Complete additional verification at: ",
|
|
15416
16297
|
verificationUrl
|
|
15417
16298
|
] })
|
|
15418
16299
|
] });
|
|
15419
16300
|
}
|
|
15420
16301
|
if (status === "success") {
|
|
15421
|
-
return /* @__PURE__ */
|
|
15422
|
-
/* @__PURE__ */
|
|
15423
|
-
/* @__PURE__ */
|
|
15424
|
-
/* @__PURE__ */
|
|
16302
|
+
return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", children: [
|
|
16303
|
+
/* @__PURE__ */ jsx29(Text22, { color: "green", children: "\u2713 Approval completed" }),
|
|
16304
|
+
/* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
16305
|
+
/* @__PURE__ */ jsxs20(Text22, { children: [
|
|
15425
16306
|
"ID: ",
|
|
15426
|
-
/* @__PURE__ */
|
|
16307
|
+
/* @__PURE__ */ jsx29(Text22, { bold: true, children: result?.id })
|
|
15427
16308
|
] }),
|
|
15428
|
-
/* @__PURE__ */
|
|
16309
|
+
/* @__PURE__ */ jsxs20(Text22, { children: [
|
|
15429
16310
|
"Status: ",
|
|
15430
|
-
/* @__PURE__ */
|
|
16311
|
+
/* @__PURE__ */ jsx29(Text22, { bold: true, children: result?.status })
|
|
15431
16312
|
] }),
|
|
15432
|
-
/* @__PURE__ */
|
|
16313
|
+
/* @__PURE__ */ jsxs20(Text22, { children: [
|
|
15433
16314
|
"Amount:",
|
|
15434
16315
|
" ",
|
|
15435
|
-
/* @__PURE__ */
|
|
16316
|
+
/* @__PURE__ */ jsx29(Text22, { bold: true, children: result?.amount != null ? `${result.amount} ${result.currency?.toUpperCase() ?? ""}`.trim() : "N/A" })
|
|
15436
16317
|
] }),
|
|
15437
|
-
/* @__PURE__ */
|
|
16318
|
+
/* @__PURE__ */ jsxs20(Text22, { children: [
|
|
15438
16319
|
"Merchant: ",
|
|
15439
|
-
/* @__PURE__ */
|
|
16320
|
+
/* @__PURE__ */ jsx29(Text22, { bold: true, children: result?.merchant_name })
|
|
15440
16321
|
] }),
|
|
15441
|
-
result?.credential_type === "shared_payment_token" && result.shared_payment_token && /* @__PURE__ */
|
|
16322
|
+
result?.credential_type === "shared_payment_token" && result.shared_payment_token && /* @__PURE__ */ jsxs20(Text22, { children: [
|
|
15442
16323
|
"Token: ",
|
|
15443
|
-
/* @__PURE__ */
|
|
16324
|
+
/* @__PURE__ */ jsx29(Text22, { bold: true, children: result.shared_payment_token.id })
|
|
15444
16325
|
] })
|
|
15445
16326
|
] })
|
|
15446
16327
|
] });
|
|
15447
16328
|
}
|
|
15448
|
-
return /* @__PURE__ */
|
|
16329
|
+
return /* @__PURE__ */ jsx29(
|
|
15449
16330
|
ApprovalWaitingView,
|
|
15450
16331
|
{
|
|
15451
16332
|
status,
|
|
@@ -15455,10 +16336,10 @@ var RequestApproval = ({
|
|
|
15455
16336
|
};
|
|
15456
16337
|
|
|
15457
16338
|
// src/commands/spend-request/retrieve.tsx
|
|
15458
|
-
import { Box as
|
|
15459
|
-
import
|
|
16339
|
+
import { Box as Box21, Text as Text23 } from "ink";
|
|
16340
|
+
import Spinner13 from "ink-spinner";
|
|
15460
16341
|
import { useEffect as useEffect11, useRef as useRef5, useState as useState11 } from "react";
|
|
15461
|
-
import { jsx as
|
|
16342
|
+
import { jsx as jsx30, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
15462
16343
|
var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
15463
16344
|
"approved",
|
|
15464
16345
|
"denied",
|
|
@@ -15582,121 +16463,121 @@ var RetrieveSpendRequest = ({
|
|
|
15582
16463
|
};
|
|
15583
16464
|
}, [phase, repository, id, include, timeout, onComplete]);
|
|
15584
16465
|
if (phase === "fetching") {
|
|
15585
|
-
return /* @__PURE__ */
|
|
15586
|
-
/* @__PURE__ */
|
|
16466
|
+
return /* @__PURE__ */ jsx30(Box21, { children: /* @__PURE__ */ jsxs21(Text23, { color: "cyan", children: [
|
|
16467
|
+
/* @__PURE__ */ jsx30(Spinner13, { type: "dots" }),
|
|
15587
16468
|
" Retrieving spend request ",
|
|
15588
16469
|
id,
|
|
15589
16470
|
"..."
|
|
15590
16471
|
] }) });
|
|
15591
16472
|
}
|
|
15592
16473
|
if (phase === "error") {
|
|
15593
|
-
return /* @__PURE__ */
|
|
16474
|
+
return /* @__PURE__ */ jsx30(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsxs21(Text23, { color: "red", children: [
|
|
15594
16475
|
"\u2717 ",
|
|
15595
16476
|
error
|
|
15596
16477
|
] }) });
|
|
15597
16478
|
}
|
|
15598
16479
|
if (phase === "timeout") {
|
|
15599
|
-
return /* @__PURE__ */
|
|
15600
|
-
/* @__PURE__ */
|
|
16480
|
+
return /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", children: [
|
|
16481
|
+
/* @__PURE__ */ jsxs21(Text23, { color: "yellow", children: [
|
|
15601
16482
|
"\u2717 Timed out waiting for approval after ",
|
|
15602
16483
|
timeout,
|
|
15603
16484
|
"s"
|
|
15604
16485
|
] }),
|
|
15605
|
-
request && /* @__PURE__ */
|
|
15606
|
-
/* @__PURE__ */
|
|
16486
|
+
request && /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
16487
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15607
16488
|
"ID: ",
|
|
15608
|
-
/* @__PURE__ */
|
|
16489
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: request.id })
|
|
15609
16490
|
] }),
|
|
15610
|
-
/* @__PURE__ */
|
|
16491
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15611
16492
|
"Status: ",
|
|
15612
|
-
/* @__PURE__ */
|
|
16493
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: request.status })
|
|
15613
16494
|
] })
|
|
15614
16495
|
] })
|
|
15615
16496
|
] });
|
|
15616
16497
|
}
|
|
15617
16498
|
if (phase === "polling") {
|
|
15618
|
-
return /* @__PURE__ */
|
|
15619
|
-
/* @__PURE__ */
|
|
15620
|
-
/* @__PURE__ */
|
|
16499
|
+
return /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", children: [
|
|
16500
|
+
/* @__PURE__ */ jsx30(Box21, { children: /* @__PURE__ */ jsxs21(Text23, { color: "cyan", children: [
|
|
16501
|
+
/* @__PURE__ */ jsx30(Spinner13, { type: "dots" }),
|
|
15621
16502
|
" Awaiting approval... (",
|
|
15622
16503
|
elapsed,
|
|
15623
16504
|
"s elapsed)"
|
|
15624
16505
|
] }) }),
|
|
15625
|
-
request?.approval_url && /* @__PURE__ */
|
|
16506
|
+
request?.approval_url && /* @__PURE__ */ jsx30(Box21, { marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsxs21(Text23, { dimColor: true, children: [
|
|
15626
16507
|
"Approval URL: ",
|
|
15627
|
-
/* @__PURE__ */
|
|
16508
|
+
/* @__PURE__ */ jsx30(Text23, { color: "cyan", children: request.approval_url })
|
|
15628
16509
|
] }) })
|
|
15629
16510
|
] });
|
|
15630
16511
|
}
|
|
15631
16512
|
if (phase === "finalized") {
|
|
15632
16513
|
const psd = request?.payment_status_details;
|
|
15633
|
-
return /* @__PURE__ */
|
|
15634
|
-
/* @__PURE__ */
|
|
16514
|
+
return /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", children: [
|
|
16515
|
+
/* @__PURE__ */ jsxs21(Text23, { color: "yellow", children: [
|
|
15635
16516
|
"Spend request reached terminal status: ",
|
|
15636
16517
|
request?.status
|
|
15637
16518
|
] }),
|
|
15638
|
-
/* @__PURE__ */
|
|
15639
|
-
/* @__PURE__ */
|
|
16519
|
+
/* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
16520
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15640
16521
|
"ID: ",
|
|
15641
|
-
/* @__PURE__ */
|
|
16522
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: request?.id })
|
|
15642
16523
|
] }),
|
|
15643
|
-
/* @__PURE__ */
|
|
16524
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15644
16525
|
"Status: ",
|
|
15645
|
-
/* @__PURE__ */
|
|
16526
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: request?.status })
|
|
15646
16527
|
] }),
|
|
15647
|
-
psd && /* @__PURE__ */
|
|
15648
|
-
/* @__PURE__ */
|
|
15649
|
-
/* @__PURE__ */
|
|
16528
|
+
psd && /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", marginTop: 1, children: [
|
|
16529
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: "Payment Details:" }),
|
|
16530
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15650
16531
|
" ",
|
|
15651
16532
|
"Outcome:",
|
|
15652
16533
|
" ",
|
|
15653
|
-
/* @__PURE__ */
|
|
16534
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, color: psd.outcome === "success" ? "green" : "red", children: psd.outcome })
|
|
15654
16535
|
] }),
|
|
15655
|
-
psd.code && /* @__PURE__ */
|
|
16536
|
+
psd.code && /* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15656
16537
|
" ",
|
|
15657
16538
|
"Code: ",
|
|
15658
|
-
/* @__PURE__ */
|
|
16539
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: psd.code })
|
|
15659
16540
|
] }),
|
|
15660
|
-
psd.decline_code && /* @__PURE__ */
|
|
16541
|
+
psd.decline_code && /* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15661
16542
|
" ",
|
|
15662
16543
|
"Decline Reason: ",
|
|
15663
|
-
/* @__PURE__ */
|
|
16544
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: psd.decline_code })
|
|
15664
16545
|
] }),
|
|
15665
|
-
/* @__PURE__ */
|
|
16546
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15666
16547
|
" ",
|
|
15667
16548
|
"Amount:",
|
|
15668
16549
|
" ",
|
|
15669
|
-
/* @__PURE__ */
|
|
16550
|
+
/* @__PURE__ */ jsxs21(Text23, { bold: true, children: [
|
|
15670
16551
|
psd.amount,
|
|
15671
16552
|
" ",
|
|
15672
16553
|
psd.currency
|
|
15673
16554
|
] })
|
|
15674
16555
|
] }),
|
|
15675
|
-
psd.created && /* @__PURE__ */
|
|
16556
|
+
psd.created && /* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15676
16557
|
" ",
|
|
15677
16558
|
"Charged At:",
|
|
15678
16559
|
" ",
|
|
15679
|
-
/* @__PURE__ */
|
|
16560
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: new Date(psd.created * 1e3).toISOString() })
|
|
15680
16561
|
] }),
|
|
15681
|
-
psd.refund_details && /* @__PURE__ */
|
|
15682
|
-
/* @__PURE__ */
|
|
16562
|
+
psd.refund_details && /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", marginTop: 1, children: [
|
|
16563
|
+
/* @__PURE__ */ jsxs21(Text23, { bold: true, children: [
|
|
15683
16564
|
" ",
|
|
15684
16565
|
"Refund:"
|
|
15685
16566
|
] }),
|
|
15686
|
-
/* @__PURE__ */
|
|
16567
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15687
16568
|
" ",
|
|
15688
16569
|
"Amount:",
|
|
15689
16570
|
" ",
|
|
15690
|
-
/* @__PURE__ */
|
|
16571
|
+
/* @__PURE__ */ jsxs21(Text23, { bold: true, children: [
|
|
15691
16572
|
psd.refund_details.amount,
|
|
15692
16573
|
" ",
|
|
15693
16574
|
psd.refund_details.currency
|
|
15694
16575
|
] })
|
|
15695
16576
|
] }),
|
|
15696
|
-
/* @__PURE__ */
|
|
16577
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15697
16578
|
" ",
|
|
15698
16579
|
"State: ",
|
|
15699
|
-
/* @__PURE__ */
|
|
16580
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: psd.refund_details.state })
|
|
15700
16581
|
] })
|
|
15701
16582
|
] })
|
|
15702
16583
|
] })
|
|
@@ -15704,71 +16585,71 @@ var RetrieveSpendRequest = ({
|
|
|
15704
16585
|
] });
|
|
15705
16586
|
}
|
|
15706
16587
|
if (phase === "declined") {
|
|
15707
|
-
return /* @__PURE__ */
|
|
15708
|
-
/* @__PURE__ */
|
|
15709
|
-
/* @__PURE__ */
|
|
15710
|
-
/* @__PURE__ */
|
|
16588
|
+
return /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", children: [
|
|
16589
|
+
/* @__PURE__ */ jsx30(Text23, { color: "red", children: "\u2717 Spend request declined" }),
|
|
16590
|
+
/* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
16591
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15711
16592
|
"ID: ",
|
|
15712
|
-
/* @__PURE__ */
|
|
16593
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: request?.id })
|
|
15713
16594
|
] }),
|
|
15714
|
-
/* @__PURE__ */
|
|
16595
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15715
16596
|
"Status:",
|
|
15716
16597
|
" ",
|
|
15717
|
-
/* @__PURE__ */
|
|
16598
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, color: "red", children: request?.status })
|
|
15718
16599
|
] }),
|
|
15719
|
-
/* @__PURE__ */
|
|
16600
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15720
16601
|
"Amount:",
|
|
15721
16602
|
" ",
|
|
15722
|
-
/* @__PURE__ */
|
|
16603
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: request?.amount != null ? String(request.amount) : "N/A" })
|
|
15723
16604
|
] }),
|
|
15724
|
-
/* @__PURE__ */
|
|
16605
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15725
16606
|
"Merchant: ",
|
|
15726
|
-
/* @__PURE__ */
|
|
16607
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: request?.merchant_name })
|
|
15727
16608
|
] })
|
|
15728
16609
|
] })
|
|
15729
16610
|
] });
|
|
15730
16611
|
}
|
|
15731
|
-
return /* @__PURE__ */
|
|
15732
|
-
/* @__PURE__ */
|
|
15733
|
-
/* @__PURE__ */
|
|
15734
|
-
/* @__PURE__ */
|
|
16612
|
+
return /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", children: [
|
|
16613
|
+
/* @__PURE__ */ jsx30(Text23, { color: "green", children: "\u2713 Spend request approved" }),
|
|
16614
|
+
/* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
16615
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15735
16616
|
"ID: ",
|
|
15736
|
-
/* @__PURE__ */
|
|
16617
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: request?.id })
|
|
15737
16618
|
] }),
|
|
15738
|
-
/* @__PURE__ */
|
|
16619
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15739
16620
|
"Status:",
|
|
15740
16621
|
" ",
|
|
15741
|
-
/* @__PURE__ */
|
|
16622
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, color: "green", children: request?.status })
|
|
15742
16623
|
] }),
|
|
15743
|
-
/* @__PURE__ */
|
|
16624
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15744
16625
|
"Amount:",
|
|
15745
16626
|
" ",
|
|
15746
|
-
/* @__PURE__ */
|
|
16627
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: request?.amount != null ? String(request.amount) : "N/A" })
|
|
15747
16628
|
] }),
|
|
15748
|
-
/* @__PURE__ */
|
|
16629
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15749
16630
|
"Merchant: ",
|
|
15750
|
-
/* @__PURE__ */
|
|
16631
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: request?.merchant_name })
|
|
15751
16632
|
] }),
|
|
15752
|
-
/* @__PURE__ */
|
|
16633
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15753
16634
|
"Line Items:",
|
|
15754
16635
|
" ",
|
|
15755
|
-
/* @__PURE__ */
|
|
16636
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: request?.line_items.map((li) => li.name).join(", ") })
|
|
15756
16637
|
] }),
|
|
15757
|
-
request?.link_pay_token && /* @__PURE__ */
|
|
15758
|
-
/* @__PURE__ */
|
|
15759
|
-
/* @__PURE__ */
|
|
16638
|
+
request?.link_pay_token && /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", marginTop: 1, children: [
|
|
16639
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: "Link Pay Token:" }),
|
|
16640
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15760
16641
|
" ",
|
|
15761
|
-
/* @__PURE__ */
|
|
16642
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: request.link_pay_token })
|
|
15762
16643
|
] })
|
|
15763
16644
|
] }),
|
|
15764
|
-
request?.payment_status_details && /* @__PURE__ */
|
|
15765
|
-
/* @__PURE__ */
|
|
15766
|
-
/* @__PURE__ */
|
|
16645
|
+
request?.payment_status_details && /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", marginTop: 1, children: [
|
|
16646
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: "Last Payment Attempt:" }),
|
|
16647
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15767
16648
|
" ",
|
|
15768
16649
|
"Outcome:",
|
|
15769
16650
|
" ",
|
|
15770
|
-
/* @__PURE__ */
|
|
15771
|
-
|
|
16651
|
+
/* @__PURE__ */ jsx30(
|
|
16652
|
+
Text23,
|
|
15772
16653
|
{
|
|
15773
16654
|
bold: true,
|
|
15774
16655
|
color: request.payment_status_details.outcome === "success" ? "green" : "red",
|
|
@@ -15776,79 +16657,79 @@ var RetrieveSpendRequest = ({
|
|
|
15776
16657
|
}
|
|
15777
16658
|
)
|
|
15778
16659
|
] }),
|
|
15779
|
-
request.payment_status_details.code && /* @__PURE__ */
|
|
16660
|
+
request.payment_status_details.code && /* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15780
16661
|
" ",
|
|
15781
16662
|
"Code:",
|
|
15782
16663
|
" ",
|
|
15783
|
-
/* @__PURE__ */
|
|
16664
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: request.payment_status_details.code })
|
|
15784
16665
|
] }),
|
|
15785
|
-
request.payment_status_details.decline_code && /* @__PURE__ */
|
|
16666
|
+
request.payment_status_details.decline_code && /* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15786
16667
|
" ",
|
|
15787
16668
|
"Decline Reason:",
|
|
15788
16669
|
" ",
|
|
15789
|
-
/* @__PURE__ */
|
|
16670
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: request.payment_status_details.decline_code })
|
|
15790
16671
|
] })
|
|
15791
16672
|
] }),
|
|
15792
|
-
request?.shared_payment_token && /* @__PURE__ */
|
|
15793
|
-
/* @__PURE__ */
|
|
16673
|
+
request?.shared_payment_token && /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", marginTop: 1, children: [
|
|
16674
|
+
/* @__PURE__ */ jsxs21(Text23, { bold: true, children: [
|
|
15794
16675
|
"\x1B]8;;https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens\x07",
|
|
15795
16676
|
"Shared Payment Token",
|
|
15796
16677
|
"\x1B]8;;\x07",
|
|
15797
16678
|
":"
|
|
15798
16679
|
] }),
|
|
15799
|
-
/* @__PURE__ */
|
|
16680
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15800
16681
|
" ",
|
|
15801
16682
|
"Token: ",
|
|
15802
|
-
/* @__PURE__ */
|
|
16683
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: request.shared_payment_token.id })
|
|
15803
16684
|
] })
|
|
15804
16685
|
] }),
|
|
15805
|
-
request?.card && !outputFile && /* @__PURE__ */
|
|
15806
|
-
/* @__PURE__ */
|
|
15807
|
-
/* @__PURE__ */
|
|
16686
|
+
request?.card && !outputFile && /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", marginTop: 1, children: [
|
|
16687
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: "Card Details:" }),
|
|
16688
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15808
16689
|
" ",
|
|
15809
16690
|
"Number: ",
|
|
15810
|
-
/* @__PURE__ */
|
|
16691
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: request?.card.number })
|
|
15811
16692
|
] }),
|
|
15812
|
-
/* @__PURE__ */
|
|
16693
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15813
16694
|
" ",
|
|
15814
16695
|
"Brand: ",
|
|
15815
|
-
/* @__PURE__ */
|
|
16696
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: request?.card.brand })
|
|
15816
16697
|
] }),
|
|
15817
|
-
/* @__PURE__ */
|
|
16698
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15818
16699
|
" ",
|
|
15819
16700
|
"Expiry:",
|
|
15820
16701
|
" ",
|
|
15821
|
-
/* @__PURE__ */
|
|
16702
|
+
/* @__PURE__ */ jsxs21(Text23, { bold: true, children: [
|
|
15822
16703
|
String(request?.card.exp_month).padStart(2, "0"),
|
|
15823
16704
|
"/",
|
|
15824
16705
|
request?.card.exp_year
|
|
15825
16706
|
] })
|
|
15826
16707
|
] }),
|
|
15827
|
-
request?.card.cvc && /* @__PURE__ */
|
|
16708
|
+
request?.card.cvc && /* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15828
16709
|
" ",
|
|
15829
16710
|
"CVC: ",
|
|
15830
|
-
/* @__PURE__ */
|
|
16711
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: request.card.cvc })
|
|
15831
16712
|
] }),
|
|
15832
|
-
request?.card.valid_until && /* @__PURE__ */
|
|
16713
|
+
request?.card.valid_until && /* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15833
16714
|
" ",
|
|
15834
16715
|
"Valid Until: ",
|
|
15835
|
-
/* @__PURE__ */
|
|
16716
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: request.card.valid_until })
|
|
15836
16717
|
] }),
|
|
15837
|
-
request?.card.billing_address && /* @__PURE__ */
|
|
15838
|
-
/* @__PURE__ */
|
|
15839
|
-
/* @__PURE__ */
|
|
16718
|
+
request?.card.billing_address && /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", marginTop: 1, children: [
|
|
16719
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: " Billing Address:" }),
|
|
16720
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15840
16721
|
" ",
|
|
15841
16722
|
request.card.billing_address.name
|
|
15842
16723
|
] }),
|
|
15843
|
-
/* @__PURE__ */
|
|
16724
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15844
16725
|
" ",
|
|
15845
16726
|
request.card.billing_address.line1
|
|
15846
16727
|
] }),
|
|
15847
|
-
request.card.billing_address.line2 && /* @__PURE__ */
|
|
16728
|
+
request.card.billing_address.line2 && /* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15848
16729
|
" ",
|
|
15849
16730
|
request.card.billing_address.line2
|
|
15850
16731
|
] }),
|
|
15851
|
-
/* @__PURE__ */
|
|
16732
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15852
16733
|
" ",
|
|
15853
16734
|
[
|
|
15854
16735
|
request.card.billing_address.city,
|
|
@@ -15856,18 +16737,18 @@ var RetrieveSpendRequest = ({
|
|
|
15856
16737
|
request.card.billing_address.postal_code
|
|
15857
16738
|
].filter(Boolean).join(", ")
|
|
15858
16739
|
] }),
|
|
15859
|
-
/* @__PURE__ */
|
|
16740
|
+
/* @__PURE__ */ jsxs21(Text23, { children: [
|
|
15860
16741
|
" ",
|
|
15861
16742
|
request.card.billing_address.country
|
|
15862
16743
|
] })
|
|
15863
16744
|
] })
|
|
15864
16745
|
] }),
|
|
15865
|
-
request?.card && outputFile && /* @__PURE__ */
|
|
15866
|
-
outputFilePath && /* @__PURE__ */
|
|
16746
|
+
request?.card && outputFile && /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", marginTop: 1, children: [
|
|
16747
|
+
outputFilePath && /* @__PURE__ */ jsxs21(Text23, { color: "green", children: [
|
|
15867
16748
|
"Card credentials written to ",
|
|
15868
|
-
/* @__PURE__ */
|
|
16749
|
+
/* @__PURE__ */ jsx30(Text23, { bold: true, children: outputFilePath })
|
|
15869
16750
|
] }),
|
|
15870
|
-
fileError && /* @__PURE__ */
|
|
16751
|
+
fileError && /* @__PURE__ */ jsxs21(Text23, { color: "red", children: [
|
|
15871
16752
|
"Failed to write card file: ",
|
|
15872
16753
|
fileError
|
|
15873
16754
|
] })
|
|
@@ -15877,140 +16758,143 @@ var RetrieveSpendRequest = ({
|
|
|
15877
16758
|
};
|
|
15878
16759
|
|
|
15879
16760
|
// src/commands/spend-request/schema.ts
|
|
15880
|
-
import { z as
|
|
15881
|
-
var createOptions =
|
|
15882
|
-
paymentMethodId:
|
|
15883
|
-
credentialType:
|
|
16761
|
+
import { z as z10 } from "incur";
|
|
16762
|
+
var createOptions = z10.object({
|
|
16763
|
+
paymentMethodId: z10.string().optional().describe("Payment method ID"),
|
|
16764
|
+
credentialType: z10.enum(["shared_payment_token", "card"]).default("card").describe(
|
|
15884
16765
|
'"card" for checkout forms/Stripe Elements; "shared_payment_token" for HTTP 402/machine payment flows'
|
|
15885
16766
|
),
|
|
15886
|
-
networkId:
|
|
16767
|
+
networkId: z10.string().optional().describe(
|
|
15887
16768
|
"Network ID (required for shared_payment_token) \u2014 use `link-cli mpp decode` to extract"
|
|
15888
16769
|
),
|
|
15889
|
-
amount:
|
|
15890
|
-
currency:
|
|
15891
|
-
merchantName:
|
|
16770
|
+
amount: z10.coerce.number().int().positive().max(5e5).describe("Amount in cents, max 500000 ($5,000.00)"),
|
|
16771
|
+
currency: z10.string().length(3).default("usd").describe("Currency code"),
|
|
16772
|
+
merchantName: z10.string().optional().describe(
|
|
15892
16773
|
"Merchant name (required for card; forbidden for shared_payment_token)"
|
|
15893
16774
|
),
|
|
15894
|
-
merchantUrl:
|
|
16775
|
+
merchantUrl: z10.string().optional().describe(
|
|
15895
16776
|
"Merchant URL (required for card; forbidden for shared_payment_token)"
|
|
15896
16777
|
),
|
|
15897
|
-
context:
|
|
16778
|
+
context: z10.string().min(100).describe(
|
|
15898
16779
|
"Min 100 chars \u2014 describe the purchase and rationale; the user reads this when approving"
|
|
15899
16780
|
),
|
|
15900
|
-
lineItem:
|
|
16781
|
+
lineItem: z10.array(z10.union([z10.string(), z10.record(z10.string(), z10.unknown())])).default([]).describe(
|
|
15901
16782
|
'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"'
|
|
15902
16783
|
),
|
|
15903
|
-
total:
|
|
16784
|
+
total: z10.array(z10.union([z10.string(), z10.record(z10.string(), z10.unknown())])).default([]).describe(
|
|
15904
16785
|
'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"'
|
|
15905
16786
|
),
|
|
15906
|
-
requestApproval:
|
|
15907
|
-
test:
|
|
16787
|
+
requestApproval: z10.boolean().default(true).describe("Request approval and poll until approved/denied/expired"),
|
|
16788
|
+
test: z10.boolean().default(false).describe(
|
|
15908
16789
|
"Use test mode (creates testmode credentials from test card data)"
|
|
15909
16790
|
),
|
|
15910
|
-
approve:
|
|
15911
|
-
outputFile:
|
|
16791
|
+
approve: z10.boolean().default(false).describe(""),
|
|
16792
|
+
outputFile: z10.string().optional().describe(
|
|
15912
16793
|
"Write full card credentials to this file path; stdout shows redacted card data only"
|
|
15913
16794
|
),
|
|
15914
|
-
force:
|
|
16795
|
+
force: z10.boolean().default(false).describe("Overwrite output file if it already exists"),
|
|
16796
|
+
approvalDetail: z10.union([z10.string(), z10.record(z10.string(), z10.unknown())]).optional().describe(
|
|
16797
|
+
"Approval details object (MCP/agent: pass as object; CLI: pass as JSON string). Required fields: approved_at (unix timestamp), approval_method (click|programmatic|voice), app_name, external_user_id. Optional: ip_address, user_agent, device_type (mobile|web), agent_log_id, external_user_name, external_session_id, authentication_method (biometric_face|biometric_fingerprint|passkey)."
|
|
16798
|
+
)
|
|
15915
16799
|
});
|
|
15916
|
-
var
|
|
15917
|
-
includeHistory:
|
|
16800
|
+
var listOptions3 = z10.object({
|
|
16801
|
+
includeHistory: z10.boolean().default(false).describe("Include expired and terminal spend requests")
|
|
15918
16802
|
});
|
|
15919
|
-
var retrieveOptions =
|
|
15920
|
-
timeout:
|
|
16803
|
+
var retrieveOptions = z10.object({
|
|
16804
|
+
timeout: z10.coerce.number().default(600).describe(
|
|
15921
16805
|
"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."
|
|
15922
16806
|
),
|
|
15923
|
-
interval:
|
|
16807
|
+
interval: z10.coerce.number().default(0).describe(
|
|
15924
16808
|
"Poll interval in seconds. When > 0, polls until status is terminal, timeout is reached, or max attempts are exhausted."
|
|
15925
16809
|
),
|
|
15926
|
-
maxAttempts:
|
|
16810
|
+
maxAttempts: z10.coerce.number().default(0).describe(
|
|
15927
16811
|
"Max poll attempts. 0 = unlimited. Exhaustion during active polling exits non-zero with POLLING_TIMEOUT."
|
|
15928
16812
|
),
|
|
15929
|
-
include:
|
|
15930
|
-
outputFile:
|
|
16813
|
+
include: z10.array(z10.string()).default([]).describe("Include extra data (repeatable, e.g. --include card)"),
|
|
16814
|
+
outputFile: z10.string().optional().describe(
|
|
15931
16815
|
"Write full card credentials to this file path; stdout shows redacted card data only"
|
|
15932
16816
|
),
|
|
15933
|
-
force:
|
|
16817
|
+
force: z10.boolean().default(false).describe("Overwrite output file if it already exists")
|
|
15934
16818
|
});
|
|
15935
|
-
var updateOptions =
|
|
15936
|
-
paymentMethodId:
|
|
15937
|
-
amount:
|
|
15938
|
-
merchantUrl:
|
|
15939
|
-
profileId:
|
|
15940
|
-
merchantId:
|
|
15941
|
-
currency:
|
|
15942
|
-
lineItem:
|
|
16819
|
+
var updateOptions = z10.object({
|
|
16820
|
+
paymentMethodId: z10.string().optional().describe("Payment method ID"),
|
|
16821
|
+
amount: z10.coerce.number().optional().describe("Amount in cents"),
|
|
16822
|
+
merchantUrl: z10.string().optional().describe("Merchant URL"),
|
|
16823
|
+
profileId: z10.string().optional().describe("Profile ID"),
|
|
16824
|
+
merchantId: z10.string().optional().describe("Merchant ID"),
|
|
16825
|
+
currency: z10.string().optional().describe("Currency code"),
|
|
16826
|
+
lineItem: z10.array(z10.union([z10.string(), z10.record(z10.string(), z10.unknown())])).default([]).describe(
|
|
15943
16827
|
'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"'
|
|
15944
16828
|
),
|
|
15945
|
-
total:
|
|
16829
|
+
total: z10.array(z10.union([z10.string(), z10.record(z10.string(), z10.unknown())])).default([]).describe(
|
|
15946
16830
|
'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"'
|
|
15947
16831
|
)
|
|
15948
16832
|
});
|
|
15949
16833
|
|
|
15950
16834
|
// src/commands/spend-request/update.tsx
|
|
15951
|
-
import { Box as
|
|
15952
|
-
import
|
|
15953
|
-
import { useCallback as
|
|
15954
|
-
import { jsx as
|
|
16835
|
+
import { Box as Box22, Text as Text24 } from "ink";
|
|
16836
|
+
import Spinner14 from "ink-spinner";
|
|
16837
|
+
import { useCallback as useCallback11 } from "react";
|
|
16838
|
+
import { jsx as jsx31, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
15955
16839
|
var UpdateSpendRequest = ({
|
|
15956
16840
|
repository,
|
|
15957
16841
|
id,
|
|
15958
16842
|
params,
|
|
15959
16843
|
onComplete
|
|
15960
16844
|
}) => {
|
|
15961
|
-
const action =
|
|
16845
|
+
const action = useCallback11(
|
|
15962
16846
|
() => repository.updateSpendRequest(id, params),
|
|
15963
16847
|
[repository, id, params]
|
|
15964
16848
|
);
|
|
15965
16849
|
const { status, data: request, error } = useAsyncAction(action, onComplete);
|
|
15966
16850
|
if (status === "loading") {
|
|
15967
|
-
return /* @__PURE__ */
|
|
15968
|
-
/* @__PURE__ */
|
|
16851
|
+
return /* @__PURE__ */ jsx31(Box22, { children: /* @__PURE__ */ jsxs22(Text24, { color: "cyan", children: [
|
|
16852
|
+
/* @__PURE__ */ jsx31(Spinner14, { type: "dots" }),
|
|
15969
16853
|
" Updating spend request ",
|
|
15970
16854
|
id,
|
|
15971
16855
|
"..."
|
|
15972
16856
|
] }) });
|
|
15973
16857
|
}
|
|
15974
16858
|
if (status === "error") {
|
|
15975
|
-
return /* @__PURE__ */
|
|
15976
|
-
/* @__PURE__ */
|
|
15977
|
-
/* @__PURE__ */
|
|
16859
|
+
return /* @__PURE__ */ jsxs22(Box22, { flexDirection: "column", children: [
|
|
16860
|
+
/* @__PURE__ */ jsx31(Text24, { color: "red", children: "\u2717 Failed to update spend request" }),
|
|
16861
|
+
/* @__PURE__ */ jsx31(Text24, { color: "red", children: error })
|
|
15978
16862
|
] });
|
|
15979
16863
|
}
|
|
15980
|
-
return /* @__PURE__ */
|
|
15981
|
-
/* @__PURE__ */
|
|
15982
|
-
/* @__PURE__ */
|
|
15983
|
-
/* @__PURE__ */
|
|
16864
|
+
return /* @__PURE__ */ jsxs22(Box22, { flexDirection: "column", children: [
|
|
16865
|
+
/* @__PURE__ */ jsx31(Text24, { color: "green", children: "\u2713 Spend request updated" }),
|
|
16866
|
+
/* @__PURE__ */ jsxs22(Box22, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
16867
|
+
/* @__PURE__ */ jsxs22(Text24, { children: [
|
|
15984
16868
|
"ID: ",
|
|
15985
|
-
/* @__PURE__ */
|
|
16869
|
+
/* @__PURE__ */ jsx31(Text24, { bold: true, children: request?.id })
|
|
15986
16870
|
] }),
|
|
15987
|
-
/* @__PURE__ */
|
|
16871
|
+
/* @__PURE__ */ jsxs22(Text24, { children: [
|
|
15988
16872
|
"Status: ",
|
|
15989
|
-
/* @__PURE__ */
|
|
16873
|
+
/* @__PURE__ */ jsx31(Text24, { bold: true, children: request?.status })
|
|
15990
16874
|
] }),
|
|
15991
|
-
/* @__PURE__ */
|
|
16875
|
+
/* @__PURE__ */ jsxs22(Text24, { children: [
|
|
15992
16876
|
"Amount:",
|
|
15993
16877
|
" ",
|
|
15994
|
-
/* @__PURE__ */
|
|
16878
|
+
/* @__PURE__ */ jsx31(Text24, { bold: true, children: (() => {
|
|
15995
16879
|
const t = request?.totals.find((t2) => t2.type === "total");
|
|
15996
16880
|
return t ? String(t.amount) : "N/A";
|
|
15997
16881
|
})() })
|
|
15998
16882
|
] }),
|
|
15999
|
-
/* @__PURE__ */
|
|
16883
|
+
/* @__PURE__ */ jsxs22(Text24, { children: [
|
|
16000
16884
|
"Merchant: ",
|
|
16001
|
-
/* @__PURE__ */
|
|
16885
|
+
/* @__PURE__ */ jsx31(Text24, { bold: true, children: request?.merchant_name })
|
|
16002
16886
|
] }),
|
|
16003
|
-
/* @__PURE__ */
|
|
16887
|
+
/* @__PURE__ */ jsxs22(Text24, { children: [
|
|
16004
16888
|
"Line Items:",
|
|
16005
16889
|
" ",
|
|
16006
|
-
/* @__PURE__ */
|
|
16890
|
+
/* @__PURE__ */ jsx31(Text24, { bold: true, children: request?.line_items.map((li) => li.name).join(", ") })
|
|
16007
16891
|
] })
|
|
16008
16892
|
] })
|
|
16009
16893
|
] });
|
|
16010
16894
|
};
|
|
16011
16895
|
|
|
16012
16896
|
// src/commands/spend-request/index.tsx
|
|
16013
|
-
import { jsx as
|
|
16897
|
+
import { jsx as jsx32 } from "react/jsx-runtime";
|
|
16014
16898
|
async function applyOutputFile(request, outputFile, force) {
|
|
16015
16899
|
if (!outputFile || !request.card) return request;
|
|
16016
16900
|
const fileData = {
|
|
@@ -16029,19 +16913,19 @@ async function applyOutputFile(request, outputFile, force) {
|
|
|
16029
16913
|
};
|
|
16030
16914
|
}
|
|
16031
16915
|
function createSpendRequestCli(repository, authStorage2, envAccessToken2) {
|
|
16032
|
-
const cli2 =
|
|
16916
|
+
const cli2 = Cli11.create("spend-request", {
|
|
16033
16917
|
description: "Spend request management commands"
|
|
16034
16918
|
});
|
|
16035
16919
|
cli2.command("list", {
|
|
16036
16920
|
description: "List spend requests. By default returns only active requests (created, pending_approval, approved). Use --include-history to return all spend requests including expired and terminal states.",
|
|
16037
16921
|
outputPolicy: "agent-only",
|
|
16038
|
-
options:
|
|
16922
|
+
options: listOptions3,
|
|
16039
16923
|
middleware: [requireAuth(authStorage2, envAccessToken2)],
|
|
16040
16924
|
async run(c) {
|
|
16041
16925
|
const opts = { includeHistory: c.options.includeHistory ?? false };
|
|
16042
16926
|
if (!c.agent && !c.formatExplicit) {
|
|
16043
16927
|
return renderInteractive(
|
|
16044
|
-
/* @__PURE__ */
|
|
16928
|
+
/* @__PURE__ */ jsx32(
|
|
16045
16929
|
SpendRequestList,
|
|
16046
16930
|
{
|
|
16047
16931
|
repository,
|
|
@@ -16105,6 +16989,7 @@ function createSpendRequestCli(repository, authStorage2, envAccessToken2) {
|
|
|
16105
16989
|
const totals = opts.total?.length ? opts.total.map(
|
|
16106
16990
|
(item) => typeof item === "string" ? parseTotalFlag(item) : item
|
|
16107
16991
|
) : void 0;
|
|
16992
|
+
const approvalDetails = opts.approvalDetail !== void 0 ? typeof opts.approvalDetail === "string" ? JSON.parse(opts.approvalDetail) : opts.approvalDetail : void 0;
|
|
16108
16993
|
const createParams = {
|
|
16109
16994
|
payment_details: opts.paymentMethodId,
|
|
16110
16995
|
credential_type: credentialType,
|
|
@@ -16118,14 +17003,15 @@ function createSpendRequestCli(repository, authStorage2, envAccessToken2) {
|
|
|
16118
17003
|
totals,
|
|
16119
17004
|
request_approval: requestApproval || void 0,
|
|
16120
17005
|
test: opts.test ? true : void 0,
|
|
16121
|
-
approve: opts.approve ? true : void 0
|
|
17006
|
+
approve: opts.approve ? true : void 0,
|
|
17007
|
+
approval_details: approvalDetails
|
|
16122
17008
|
};
|
|
16123
17009
|
const outputFile = opts.outputFile;
|
|
16124
17010
|
const forceOverwrite = opts.force;
|
|
16125
17011
|
if (!c.agent && !c.formatExplicit) {
|
|
16126
17012
|
let capturedResult = void 0;
|
|
16127
17013
|
return renderInteractive(
|
|
16128
|
-
/* @__PURE__ */
|
|
17014
|
+
/* @__PURE__ */ jsx32(
|
|
16129
17015
|
CreateSpendRequest,
|
|
16130
17016
|
{
|
|
16131
17017
|
repository,
|
|
@@ -16185,8 +17071,8 @@ function createSpendRequestCli(repository, authStorage2, envAccessToken2) {
|
|
|
16185
17071
|
});
|
|
16186
17072
|
cli2.command("update", {
|
|
16187
17073
|
description: "Update a spend request",
|
|
16188
|
-
args:
|
|
16189
|
-
id:
|
|
17074
|
+
args: z11.object({
|
|
17075
|
+
id: z11.string().describe("Spend request ID")
|
|
16190
17076
|
}),
|
|
16191
17077
|
options: updateOptions,
|
|
16192
17078
|
outputPolicy: "agent-only",
|
|
@@ -16214,7 +17100,7 @@ function createSpendRequestCli(repository, authStorage2, envAccessToken2) {
|
|
|
16214
17100
|
if (!c.agent && !c.formatExplicit) {
|
|
16215
17101
|
let capturedResult = null;
|
|
16216
17102
|
return renderInteractive(
|
|
16217
|
-
/* @__PURE__ */
|
|
17103
|
+
/* @__PURE__ */ jsx32(
|
|
16218
17104
|
UpdateSpendRequest,
|
|
16219
17105
|
{
|
|
16220
17106
|
repository,
|
|
@@ -16237,8 +17123,8 @@ function createSpendRequestCli(repository, authStorage2, envAccessToken2) {
|
|
|
16237
17123
|
});
|
|
16238
17124
|
cli2.command("request-approval", {
|
|
16239
17125
|
description: "Request approval for a spend request",
|
|
16240
|
-
args:
|
|
16241
|
-
id:
|
|
17126
|
+
args: z11.object({
|
|
17127
|
+
id: z11.string().describe("Spend request ID")
|
|
16242
17128
|
}),
|
|
16243
17129
|
outputPolicy: "agent-only",
|
|
16244
17130
|
async *run(c) {
|
|
@@ -16247,7 +17133,7 @@ function createSpendRequestCli(repository, authStorage2, envAccessToken2) {
|
|
|
16247
17133
|
if (!c.agent && !c.formatExplicit) {
|
|
16248
17134
|
let capturedResult = void 0;
|
|
16249
17135
|
return renderInteractive(
|
|
16250
|
-
/* @__PURE__ */
|
|
17136
|
+
/* @__PURE__ */ jsx32(
|
|
16251
17137
|
RequestApproval,
|
|
16252
17138
|
{
|
|
16253
17139
|
repository,
|
|
@@ -16292,8 +17178,8 @@ function createSpendRequestCli(repository, authStorage2, envAccessToken2) {
|
|
|
16292
17178
|
});
|
|
16293
17179
|
cli2.command("retrieve", {
|
|
16294
17180
|
description: "Retrieve a spend request",
|
|
16295
|
-
args:
|
|
16296
|
-
id:
|
|
17181
|
+
args: z11.object({
|
|
17182
|
+
id: z11.string().describe("Spend request ID")
|
|
16297
17183
|
}),
|
|
16298
17184
|
options: retrieveOptions,
|
|
16299
17185
|
outputPolicy: "agent-only",
|
|
@@ -16311,7 +17197,7 @@ function createSpendRequestCli(repository, authStorage2, envAccessToken2) {
|
|
|
16311
17197
|
if (!c.agent && !c.formatExplicit) {
|
|
16312
17198
|
let capturedResult = null;
|
|
16313
17199
|
return renderInteractive(
|
|
16314
|
-
/* @__PURE__ */
|
|
17200
|
+
/* @__PURE__ */ jsx32(
|
|
16315
17201
|
RetrieveSpendRequest,
|
|
16316
17202
|
{
|
|
16317
17203
|
repository,
|
|
@@ -16383,8 +17269,8 @@ function createSpendRequestCli(repository, authStorage2, envAccessToken2) {
|
|
|
16383
17269
|
});
|
|
16384
17270
|
cli2.command("cancel", {
|
|
16385
17271
|
description: "Cancel a spend request",
|
|
16386
|
-
args:
|
|
16387
|
-
id:
|
|
17272
|
+
args: z11.object({
|
|
17273
|
+
id: z11.string().describe("Spend request ID")
|
|
16388
17274
|
}),
|
|
16389
17275
|
outputPolicy: "agent-only",
|
|
16390
17276
|
middleware: [requireAuth(authStorage2, envAccessToken2)],
|
|
@@ -16393,7 +17279,7 @@ function createSpendRequestCli(repository, authStorage2, envAccessToken2) {
|
|
|
16393
17279
|
if (!c.agent && !c.formatExplicit) {
|
|
16394
17280
|
let capturedResult = null;
|
|
16395
17281
|
return renderInteractive(
|
|
16396
|
-
/* @__PURE__ */
|
|
17282
|
+
/* @__PURE__ */ jsx32(
|
|
16397
17283
|
CancelSpendRequest,
|
|
16398
17284
|
{
|
|
16399
17285
|
repository,
|
|
@@ -16417,20 +17303,20 @@ function createSpendRequestCli(repository, authStorage2, envAccessToken2) {
|
|
|
16417
17303
|
}
|
|
16418
17304
|
|
|
16419
17305
|
// src/commands/transactions/index.tsx
|
|
16420
|
-
import { Cli as
|
|
17306
|
+
import { Cli as Cli12 } from "incur";
|
|
16421
17307
|
|
|
16422
17308
|
// src/commands/transactions/list.tsx
|
|
16423
|
-
import { Box as
|
|
16424
|
-
import
|
|
16425
|
-
import { useCallback as
|
|
16426
|
-
import { jsx as
|
|
16427
|
-
var
|
|
17309
|
+
import { Box as Box23, Text as Text25 } from "ink";
|
|
17310
|
+
import Spinner15 from "ink-spinner";
|
|
17311
|
+
import { useCallback as useCallback12 } from "react";
|
|
17312
|
+
import { jsx as jsx33, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
17313
|
+
var COLUMN_GAP3 = " ";
|
|
16428
17314
|
var DATE_WIDTH = 10;
|
|
16429
17315
|
var AMOUNT_WIDTH = 13;
|
|
16430
17316
|
var STATUS_WIDTH = 10;
|
|
16431
17317
|
var CATEGORY_WIDTH = 16;
|
|
16432
17318
|
var MIN_DESCRIPTION_WIDTH = 16;
|
|
16433
|
-
var
|
|
17319
|
+
var HORIZONTAL_PADDING2 = 4;
|
|
16434
17320
|
function formatAmount(amount, currency) {
|
|
16435
17321
|
const currencyCode = currency.toUpperCase();
|
|
16436
17322
|
try {
|
|
@@ -16444,7 +17330,7 @@ function formatAmount(amount, currency) {
|
|
|
16444
17330
|
return `${amount} ${currency}`;
|
|
16445
17331
|
}
|
|
16446
17332
|
}
|
|
16447
|
-
function
|
|
17333
|
+
function truncateCell3(value, width) {
|
|
16448
17334
|
if (value.length <= width) {
|
|
16449
17335
|
return value;
|
|
16450
17336
|
}
|
|
@@ -16453,8 +17339,8 @@ function truncateCell(value, width) {
|
|
|
16453
17339
|
}
|
|
16454
17340
|
return `${value.slice(0, width - 3)}...`;
|
|
16455
17341
|
}
|
|
16456
|
-
function
|
|
16457
|
-
const truncated =
|
|
17342
|
+
function formatCell3(value, width, align = "left") {
|
|
17343
|
+
const truncated = truncateCell3(value, width);
|
|
16458
17344
|
return align === "right" ? truncated.padStart(width) : truncated.padEnd(width);
|
|
16459
17345
|
}
|
|
16460
17346
|
var TransactionsList = ({
|
|
@@ -16462,7 +17348,7 @@ var TransactionsList = ({
|
|
|
16462
17348
|
params,
|
|
16463
17349
|
onComplete
|
|
16464
17350
|
}) => {
|
|
16465
|
-
const action =
|
|
17351
|
+
const action = useCallback12(
|
|
16466
17352
|
() => resource.listTransactions(params),
|
|
16467
17353
|
[resource, params]
|
|
16468
17354
|
);
|
|
@@ -16472,80 +17358,80 @@ var TransactionsList = ({
|
|
|
16472
17358
|
const terminalWidth = process.stdout.columns ?? 100;
|
|
16473
17359
|
const descriptionWidth = Math.max(
|
|
16474
17360
|
MIN_DESCRIPTION_WIDTH,
|
|
16475
|
-
terminalWidth -
|
|
17361
|
+
terminalWidth - HORIZONTAL_PADDING2 - DATE_WIDTH - AMOUNT_WIDTH - STATUS_WIDTH - CATEGORY_WIDTH - COLUMN_GAP3.length * 4
|
|
16476
17362
|
);
|
|
16477
17363
|
const headerRow = [
|
|
16478
|
-
|
|
16479
|
-
|
|
16480
|
-
|
|
16481
|
-
|
|
16482
|
-
|
|
16483
|
-
].join(
|
|
17364
|
+
formatCell3("Date", DATE_WIDTH),
|
|
17365
|
+
formatCell3("Amount", AMOUNT_WIDTH, "right"),
|
|
17366
|
+
formatCell3("Status", STATUS_WIDTH),
|
|
17367
|
+
formatCell3("Category", CATEGORY_WIDTH),
|
|
17368
|
+
formatCell3("Description", descriptionWidth)
|
|
17369
|
+
].join(COLUMN_GAP3);
|
|
16484
17370
|
const separatorRow = "-".repeat(headerRow.length);
|
|
16485
17371
|
const rows = transactions.map(
|
|
16486
17372
|
(txn) => [
|
|
16487
|
-
|
|
16488
|
-
|
|
16489
|
-
|
|
16490
|
-
|
|
16491
|
-
|
|
16492
|
-
].join(
|
|
17373
|
+
formatCell3(txn.created_date, DATE_WIDTH),
|
|
17374
|
+
formatCell3(formatAmount(txn.amount, txn.currency), AMOUNT_WIDTH, "right"),
|
|
17375
|
+
formatCell3(txn.status, STATUS_WIDTH),
|
|
17376
|
+
formatCell3(txn.category ?? "", CATEGORY_WIDTH),
|
|
17377
|
+
formatCell3(txn.description, descriptionWidth)
|
|
17378
|
+
].join(COLUMN_GAP3)
|
|
16493
17379
|
);
|
|
16494
17380
|
if (status === "loading") {
|
|
16495
|
-
return /* @__PURE__ */
|
|
16496
|
-
/* @__PURE__ */
|
|
17381
|
+
return /* @__PURE__ */ jsx33(Box23, { children: /* @__PURE__ */ jsxs23(Text25, { color: "cyan", children: [
|
|
17382
|
+
/* @__PURE__ */ jsx33(Spinner15, { type: "dots" }),
|
|
16497
17383
|
" Loading transactions..."
|
|
16498
17384
|
] }) });
|
|
16499
17385
|
}
|
|
16500
17386
|
if (status === "error") {
|
|
16501
|
-
return /* @__PURE__ */
|
|
16502
|
-
/* @__PURE__ */
|
|
16503
|
-
/* @__PURE__ */
|
|
17387
|
+
return /* @__PURE__ */ jsxs23(Box23, { flexDirection: "column", children: [
|
|
17388
|
+
/* @__PURE__ */ jsx33(Text25, { color: "red", children: "Failed to load transactions" }),
|
|
17389
|
+
/* @__PURE__ */ jsx33(Text25, { color: "red", children: error })
|
|
16504
17390
|
] });
|
|
16505
17391
|
}
|
|
16506
17392
|
if (transactions.length === 0) {
|
|
16507
|
-
return /* @__PURE__ */
|
|
16508
|
-
}
|
|
16509
|
-
return /* @__PURE__ */
|
|
16510
|
-
/* @__PURE__ */
|
|
16511
|
-
/* @__PURE__ */
|
|
16512
|
-
/* @__PURE__ */
|
|
16513
|
-
/* @__PURE__ */
|
|
16514
|
-
rows.map((row, index) => /* @__PURE__ */
|
|
17393
|
+
return /* @__PURE__ */ jsx33(Box23, { children: /* @__PURE__ */ jsx33(Text25, { dimColor: true, children: "No transactions found" }) });
|
|
17394
|
+
}
|
|
17395
|
+
return /* @__PURE__ */ jsxs23(Box23, { flexDirection: "column", children: [
|
|
17396
|
+
/* @__PURE__ */ jsx33(Text25, { bold: true, children: "Transactions" }),
|
|
17397
|
+
/* @__PURE__ */ jsxs23(Box23, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
17398
|
+
/* @__PURE__ */ jsx33(Text25, { bold: true, children: headerRow }),
|
|
17399
|
+
/* @__PURE__ */ jsx33(Text25, { dimColor: true, children: separatorRow }),
|
|
17400
|
+
rows.map((row, index) => /* @__PURE__ */ jsx33(Text25, { children: row }, transactions[index].id))
|
|
16515
17401
|
] }),
|
|
16516
|
-
page?.has_more !== void 0 ? /* @__PURE__ */
|
|
16517
|
-
/* @__PURE__ */
|
|
17402
|
+
page?.has_more !== void 0 ? /* @__PURE__ */ jsxs23(Box23, { flexDirection: "column", marginTop: 1, children: [
|
|
17403
|
+
/* @__PURE__ */ jsxs23(Text25, { dimColor: true, children: [
|
|
16518
17404
|
"has_more: ",
|
|
16519
17405
|
String(page.has_more)
|
|
16520
17406
|
] }),
|
|
16521
|
-
nextCursor ? /* @__PURE__ */
|
|
17407
|
+
nextCursor ? /* @__PURE__ */ jsx33(Text25, { dimColor: true, children: `next page: --starting-after ${nextCursor}` }) : null
|
|
16522
17408
|
] }) : null
|
|
16523
17409
|
] });
|
|
16524
17410
|
};
|
|
16525
17411
|
|
|
16526
17412
|
// src/commands/transactions/schema.ts
|
|
16527
|
-
import { z as
|
|
17413
|
+
import { z as z12 } from "incur";
|
|
16528
17414
|
var ISO_DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
|
16529
|
-
var
|
|
16530
|
-
limit:
|
|
16531
|
-
startingAfter:
|
|
16532
|
-
endingBefore:
|
|
16533
|
-
startDate:
|
|
16534
|
-
endDate:
|
|
16535
|
-
category:
|
|
16536
|
-
origin:
|
|
16537
|
-
source:
|
|
17415
|
+
var listOptions4 = z12.object({
|
|
17416
|
+
limit: z12.coerce.number().int().positive().max(100).optional().describe("Maximum number of transactions to return (1-100)."),
|
|
17417
|
+
startingAfter: z12.string().optional().describe("Cursor: return transactions after this transaction ID."),
|
|
17418
|
+
endingBefore: z12.string().optional().describe("Cursor: return transactions before this transaction ID."),
|
|
17419
|
+
startDate: z12.string().regex(ISO_DATE_REGEX, "Date must be in YYYY-MM-DD format.").optional().describe("Only include transactions on or after this YYYY-MM-DD date."),
|
|
17420
|
+
endDate: z12.string().regex(ISO_DATE_REGEX, "Date must be in YYYY-MM-DD format.").optional().describe("Only include transactions on or before this YYYY-MM-DD date."),
|
|
17421
|
+
category: z12.string().optional().describe("Filter by transaction category."),
|
|
17422
|
+
origin: z12.enum(["link", "external_connection"]).optional().describe("Filter by transaction origin: link or external_connection."),
|
|
17423
|
+
source: z12.array(z12.string()).default([]).describe("Filter by source ID. Repeat to include multiple sources.")
|
|
16538
17424
|
});
|
|
16539
17425
|
|
|
16540
17426
|
// src/commands/transactions/index.tsx
|
|
16541
|
-
import { jsx as
|
|
17427
|
+
import { jsx as jsx34 } from "react/jsx-runtime";
|
|
16542
17428
|
function createTransactionsCli(createResource, authStorage2, envAccessToken2) {
|
|
16543
|
-
const cli2 =
|
|
17429
|
+
const cli2 = Cli12.create("transactions", {
|
|
16544
17430
|
description: "List transactions from Link and external accounts"
|
|
16545
17431
|
});
|
|
16546
17432
|
cli2.command("list", {
|
|
16547
17433
|
description: "List transactions from Link and external accounts, including non-Link activity",
|
|
16548
|
-
options:
|
|
17434
|
+
options: listOptions4,
|
|
16549
17435
|
outputPolicy: "agent-only",
|
|
16550
17436
|
middleware: [requireAuth(authStorage2, envAccessToken2)],
|
|
16551
17437
|
async run(c) {
|
|
@@ -16564,7 +17450,7 @@ function createTransactionsCli(createResource, authStorage2, envAccessToken2) {
|
|
|
16564
17450
|
if (opts.source.length > 0) params.sources = opts.source;
|
|
16565
17451
|
if (!c.agent && !c.formatExplicit) {
|
|
16566
17452
|
return renderInteractive(
|
|
16567
|
-
/* @__PURE__ */
|
|
17453
|
+
/* @__PURE__ */ jsx34(
|
|
16568
17454
|
TransactionsList,
|
|
16569
17455
|
{
|
|
16570
17456
|
resource,
|
|
@@ -16583,54 +17469,54 @@ function createTransactionsCli(createResource, authStorage2, envAccessToken2) {
|
|
|
16583
17469
|
}
|
|
16584
17470
|
|
|
16585
17471
|
// src/commands/user-info/index.tsx
|
|
16586
|
-
import { Cli as
|
|
17472
|
+
import { Cli as Cli13 } from "incur";
|
|
16587
17473
|
|
|
16588
17474
|
// src/commands/user-info/retrieve.tsx
|
|
16589
|
-
import { Box as
|
|
16590
|
-
import
|
|
16591
|
-
import { useCallback as
|
|
16592
|
-
import { jsx as
|
|
17475
|
+
import { Box as Box24, Text as Text26 } from "ink";
|
|
17476
|
+
import Spinner16 from "ink-spinner";
|
|
17477
|
+
import { useCallback as useCallback13 } from "react";
|
|
17478
|
+
import { jsx as jsx35, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
16593
17479
|
var UserInfoRetrieve = ({
|
|
16594
17480
|
resource,
|
|
16595
17481
|
onComplete
|
|
16596
17482
|
}) => {
|
|
16597
|
-
const action =
|
|
17483
|
+
const action = useCallback13(() => resource.retrieve(), [resource]);
|
|
16598
17484
|
const { status, data: userInfo, error } = useAsyncAction(action, onComplete);
|
|
16599
17485
|
if (status === "loading") {
|
|
16600
|
-
return /* @__PURE__ */
|
|
16601
|
-
/* @__PURE__ */
|
|
17486
|
+
return /* @__PURE__ */ jsx35(Box24, { children: /* @__PURE__ */ jsxs24(Text26, { color: "cyan", children: [
|
|
17487
|
+
/* @__PURE__ */ jsx35(Spinner16, { type: "dots" }),
|
|
16602
17488
|
" Loading user info..."
|
|
16603
17489
|
] }) });
|
|
16604
17490
|
}
|
|
16605
17491
|
if (status === "error") {
|
|
16606
|
-
return /* @__PURE__ */
|
|
16607
|
-
/* @__PURE__ */
|
|
16608
|
-
/* @__PURE__ */
|
|
17492
|
+
return /* @__PURE__ */ jsxs24(Box24, { flexDirection: "column", children: [
|
|
17493
|
+
/* @__PURE__ */ jsx35(Text26, { color: "red", children: "\u2717 Failed to load user info" }),
|
|
17494
|
+
/* @__PURE__ */ jsx35(Text26, { color: "red", children: error })
|
|
16609
17495
|
] });
|
|
16610
17496
|
}
|
|
16611
|
-
return /* @__PURE__ */
|
|
16612
|
-
/* @__PURE__ */
|
|
16613
|
-
/* @__PURE__ */
|
|
16614
|
-
/* @__PURE__ */
|
|
16615
|
-
/* @__PURE__ */
|
|
16616
|
-
userInfo?.email ?? /* @__PURE__ */
|
|
17497
|
+
return /* @__PURE__ */ jsxs24(Box24, { flexDirection: "column", children: [
|
|
17498
|
+
/* @__PURE__ */ jsx35(Text26, { bold: true, children: "User Info" }),
|
|
17499
|
+
/* @__PURE__ */ jsxs24(Box24, { flexDirection: "column", marginTop: 1, paddingX: 2, children: [
|
|
17500
|
+
/* @__PURE__ */ jsxs24(Text26, { children: [
|
|
17501
|
+
/* @__PURE__ */ jsx35(Text26, { dimColor: true, children: "Email: " }),
|
|
17502
|
+
userInfo?.email ?? /* @__PURE__ */ jsx35(Text26, { dimColor: true, children: "Not set" })
|
|
16617
17503
|
] }),
|
|
16618
|
-
/* @__PURE__ */
|
|
16619
|
-
/* @__PURE__ */
|
|
16620
|
-
userInfo?.name ?? /* @__PURE__ */
|
|
17504
|
+
/* @__PURE__ */ jsxs24(Text26, { children: [
|
|
17505
|
+
/* @__PURE__ */ jsx35(Text26, { dimColor: true, children: "Name: " }),
|
|
17506
|
+
userInfo?.name ?? /* @__PURE__ */ jsx35(Text26, { dimColor: true, children: "Not set" })
|
|
16621
17507
|
] }),
|
|
16622
|
-
/* @__PURE__ */
|
|
16623
|
-
/* @__PURE__ */
|
|
16624
|
-
userInfo?.phone ?? /* @__PURE__ */
|
|
17508
|
+
/* @__PURE__ */ jsxs24(Text26, { children: [
|
|
17509
|
+
/* @__PURE__ */ jsx35(Text26, { dimColor: true, children: "Phone: " }),
|
|
17510
|
+
userInfo?.phone ?? /* @__PURE__ */ jsx35(Text26, { dimColor: true, children: "Not set" })
|
|
16625
17511
|
] })
|
|
16626
17512
|
] })
|
|
16627
17513
|
] });
|
|
16628
17514
|
};
|
|
16629
17515
|
|
|
16630
17516
|
// src/commands/user-info/index.tsx
|
|
16631
|
-
import { jsx as
|
|
17517
|
+
import { jsx as jsx36 } from "react/jsx-runtime";
|
|
16632
17518
|
function createUserInfoCli(createResource, authStorage2, envAccessToken2) {
|
|
16633
|
-
const cli2 =
|
|
17519
|
+
const cli2 = Cli13.create("user-info", {
|
|
16634
17520
|
description: "User information commands"
|
|
16635
17521
|
});
|
|
16636
17522
|
cli2.command("retrieve", {
|
|
@@ -16641,7 +17527,7 @@ function createUserInfoCli(createResource, authStorage2, envAccessToken2) {
|
|
|
16641
17527
|
const resource = createResource();
|
|
16642
17528
|
if (!c.agent && !c.formatExplicit) {
|
|
16643
17529
|
return renderInteractive(
|
|
16644
|
-
/* @__PURE__ */
|
|
17530
|
+
/* @__PURE__ */ jsx36(UserInfoRetrieve, { resource, onComplete: () => {
|
|
16645
17531
|
} }),
|
|
16646
17532
|
() => resource.retrieve()
|
|
16647
17533
|
);
|
|
@@ -16692,11 +17578,55 @@ function requireFetchImplementation2(config) {
|
|
|
16692
17578
|
|
|
16693
17579
|
// src/auth/auth-resource.ts
|
|
16694
17580
|
var CLIENT_ID = "lwlpk_U7Qy7ThG69STZk";
|
|
16695
|
-
var DEFAULT_SCOPE = "userinfo:read payment_methods.agentic";
|
|
16696
17581
|
function formatOAuthError(prefix, status, data, rawBody) {
|
|
16697
17582
|
const err = data;
|
|
16698
17583
|
return `${prefix} (${status}): ${err?.error_description ?? err?.error ?? (rawBody || "unknown error")}`;
|
|
16699
17584
|
}
|
|
17585
|
+
function appendAuthorizationDetailValue(params, key, value) {
|
|
17586
|
+
if (Array.isArray(value)) {
|
|
17587
|
+
for (const entry of value) {
|
|
17588
|
+
appendAuthorizationDetailValue(params, `${key}[]`, entry);
|
|
17589
|
+
}
|
|
17590
|
+
return;
|
|
17591
|
+
}
|
|
17592
|
+
if (value !== null && typeof value === "object") {
|
|
17593
|
+
for (const [entryKey, entryValue] of Object.entries(value)) {
|
|
17594
|
+
appendAuthorizationDetailValue(params, `${key}[${entryKey}]`, entryValue);
|
|
17595
|
+
}
|
|
17596
|
+
return;
|
|
17597
|
+
}
|
|
17598
|
+
params.append(key, String(value));
|
|
17599
|
+
}
|
|
17600
|
+
function buildDeviceCodeForm(clientName, options) {
|
|
17601
|
+
const connectionLabel = `${clientName} on ${hostname()}`;
|
|
17602
|
+
const params = new URLSearchParams({
|
|
17603
|
+
client_id: CLIENT_ID,
|
|
17604
|
+
scope: options.scope ?? DEFAULT_SCOPE,
|
|
17605
|
+
connection_label: connectionLabel,
|
|
17606
|
+
client_hint: clientName
|
|
17607
|
+
});
|
|
17608
|
+
const authorizationDetails = buildAuthorizationDetails(
|
|
17609
|
+
options.sourceActions,
|
|
17610
|
+
options.authorizationDetails
|
|
17611
|
+
);
|
|
17612
|
+
for (const detail of authorizationDetails) {
|
|
17613
|
+
appendAuthorizationDetailValue(params, "authorization_details[]", detail);
|
|
17614
|
+
}
|
|
17615
|
+
return params;
|
|
17616
|
+
}
|
|
17617
|
+
function serializeFormBody(params) {
|
|
17618
|
+
return params instanceof URLSearchParams ? params.toString() : new URLSearchParams(params).toString();
|
|
17619
|
+
}
|
|
17620
|
+
function serializeRedactedFormBody(params) {
|
|
17621
|
+
const redacted = new URLSearchParams(params);
|
|
17622
|
+
if (redacted.has("device_code")) {
|
|
17623
|
+
redacted.set("device_code", "<redacted>");
|
|
17624
|
+
}
|
|
17625
|
+
if (redacted.has("refresh_token")) {
|
|
17626
|
+
redacted.set("refresh_token", "<redacted>");
|
|
17627
|
+
}
|
|
17628
|
+
return redacted.toString();
|
|
17629
|
+
}
|
|
16700
17630
|
var LinkAuthResource = class {
|
|
16701
17631
|
config;
|
|
16702
17632
|
fetchImpl;
|
|
@@ -16706,12 +17636,9 @@ var LinkAuthResource = class {
|
|
|
16706
17636
|
}
|
|
16707
17637
|
async postForm(url, params) {
|
|
16708
17638
|
if (this.config.verbose) {
|
|
16709
|
-
const redacted = { ...params };
|
|
16710
|
-
if (redacted.device_code) redacted.device_code = "<redacted>";
|
|
16711
|
-
if (redacted.refresh_token) redacted.refresh_token = "<redacted>";
|
|
16712
17639
|
this.config.logger.debug(
|
|
16713
17640
|
`> POST ${url}
|
|
16714
|
-
${
|
|
17641
|
+
${serializeRedactedFormBody(params)}`
|
|
16715
17642
|
);
|
|
16716
17643
|
}
|
|
16717
17644
|
let response;
|
|
@@ -16722,7 +17649,7 @@ ${JSON.stringify(redacted, null, 2)}`
|
|
|
16722
17649
|
...this.config.defaultHeaders,
|
|
16723
17650
|
"Content-Type": "application/x-www-form-urlencoded"
|
|
16724
17651
|
},
|
|
16725
|
-
body:
|
|
17652
|
+
body: serializeFormBody(params)
|
|
16726
17653
|
});
|
|
16727
17654
|
} catch (error) {
|
|
16728
17655
|
throw new LinkTransportError(`Request failed: POST ${url}`, {
|
|
@@ -16744,16 +17671,12 @@ ${JSON.stringify(redacted, null, 2)}`
|
|
|
16744
17671
|
}
|
|
16745
17672
|
return { status: response.status, data, rawBody };
|
|
16746
17673
|
}
|
|
16747
|
-
async initiateDeviceAuth(
|
|
16748
|
-
const effectiveName = clientName ?? this.config.clientName;
|
|
17674
|
+
async initiateDeviceAuth(options = {}) {
|
|
17675
|
+
const effectiveName = options.clientName ?? this.config.clientName;
|
|
17676
|
+
const params = buildDeviceCodeForm(effectiveName, options);
|
|
16749
17677
|
const { status, data, rawBody } = await this.postForm(
|
|
16750
17678
|
`${this.config.authBaseUrl}/device/code`,
|
|
16751
|
-
|
|
16752
|
-
client_id: CLIENT_ID,
|
|
16753
|
-
scope: DEFAULT_SCOPE,
|
|
16754
|
-
connection_label: `${effectiveName} on ${hostname()}`,
|
|
16755
|
-
client_hint: effectiveName
|
|
16756
|
-
}
|
|
17679
|
+
params
|
|
16757
17680
|
);
|
|
16758
17681
|
if (status < 200 || status >= 300) {
|
|
16759
17682
|
throw new LinkApiError(
|
|
@@ -16933,6 +17856,8 @@ var ResourceFactory = class {
|
|
|
16933
17856
|
shippingAddressResource;
|
|
16934
17857
|
userInfoResource;
|
|
16935
17858
|
transactionsResource;
|
|
17859
|
+
sourcesResource;
|
|
17860
|
+
balancesResource;
|
|
16936
17861
|
webBotAuthResource;
|
|
16937
17862
|
reportResource;
|
|
16938
17863
|
constructor(options = {}) {
|
|
@@ -17061,6 +17986,34 @@ var ResourceFactory = class {
|
|
|
17061
17986
|
);
|
|
17062
17987
|
return this.transactionsResource;
|
|
17063
17988
|
}
|
|
17989
|
+
createSourcesResource() {
|
|
17990
|
+
if (this.sourcesResource) {
|
|
17991
|
+
return this.sourcesResource;
|
|
17992
|
+
}
|
|
17993
|
+
const getAccessToken = this.createSdkAccessTokenProvider();
|
|
17994
|
+
this.sourcesResource = sanitizeResource(
|
|
17995
|
+
new SourcesResource({
|
|
17996
|
+
verbose: this.verbose,
|
|
17997
|
+
defaultHeaders: this.defaultHeaders,
|
|
17998
|
+
getAccessToken
|
|
17999
|
+
})
|
|
18000
|
+
);
|
|
18001
|
+
return this.sourcesResource;
|
|
18002
|
+
}
|
|
18003
|
+
createBalancesResource() {
|
|
18004
|
+
if (this.balancesResource) {
|
|
18005
|
+
return this.balancesResource;
|
|
18006
|
+
}
|
|
18007
|
+
const getAccessToken = this.createSdkAccessTokenProvider();
|
|
18008
|
+
this.balancesResource = sanitizeResource(
|
|
18009
|
+
new BalancesResource({
|
|
18010
|
+
verbose: this.verbose,
|
|
18011
|
+
defaultHeaders: this.defaultHeaders,
|
|
18012
|
+
getAccessToken
|
|
18013
|
+
})
|
|
18014
|
+
);
|
|
18015
|
+
return this.balancesResource;
|
|
18016
|
+
}
|
|
17064
18017
|
createWebBotAuthResource() {
|
|
17065
18018
|
if (this.webBotAuthResource) {
|
|
17066
18019
|
return this.webBotAuthResource;
|
|
@@ -17162,7 +18115,7 @@ function cacheUpdateInfo(value, ttlMs = UPDATE_CACHE_TTL_MS) {
|
|
|
17162
18115
|
}
|
|
17163
18116
|
|
|
17164
18117
|
// src/cli.tsx
|
|
17165
|
-
var cliVersion = "0.
|
|
18118
|
+
var cliVersion = "0.10.0";
|
|
17166
18119
|
var cliName = "@stripe/link-cli";
|
|
17167
18120
|
var defaultHeaders = {
|
|
17168
18121
|
"User-Agent": `link-cli/${cliVersion}`
|
|
@@ -17192,15 +18145,23 @@ var factory = new ResourceFactory({
|
|
|
17192
18145
|
var authRepo = factory.createAuthResource();
|
|
17193
18146
|
var spendRequestRepo = factory.createSpendRequestResource();
|
|
17194
18147
|
var requestedCommand = process.argv[2];
|
|
17195
|
-
var
|
|
18148
|
+
var hiddenCli = requestedCommand === "transactions" ? createTransactionsCli(
|
|
17196
18149
|
() => factory.createTransactionsResource(),
|
|
17197
18150
|
authStorage,
|
|
17198
18151
|
envAccessToken
|
|
18152
|
+
) : requestedCommand === "sources" ? createSourcesCli(
|
|
18153
|
+
() => factory.createSourcesResource(),
|
|
18154
|
+
authStorage,
|
|
18155
|
+
envAccessToken
|
|
18156
|
+
) : requestedCommand === "balances" ? createBalancesCli(
|
|
18157
|
+
() => factory.createBalancesResource(),
|
|
18158
|
+
authStorage,
|
|
18159
|
+
envAccessToken
|
|
17199
18160
|
) : null;
|
|
17200
|
-
if (
|
|
18161
|
+
if (hiddenCli) {
|
|
17201
18162
|
process.argv.splice(2, 1);
|
|
17202
18163
|
}
|
|
17203
|
-
var cli =
|
|
18164
|
+
var cli = hiddenCli ?? Cli14.create("link-cli", {
|
|
17204
18165
|
description: "Create a secure, one-time payment credential from a Link wallet to let agents complete purchases on behalf of users.",
|
|
17205
18166
|
version: cliVersion
|
|
17206
18167
|
});
|
|
@@ -17217,7 +18178,7 @@ if (!isAgent && process.stdout.isTTY) {
|
|
|
17217
18178
|
process.stderr.write(renderInteractiveUpdateNotice(updateInfo));
|
|
17218
18179
|
}
|
|
17219
18180
|
}
|
|
17220
|
-
if (!
|
|
18181
|
+
if (!hiddenCli) {
|
|
17221
18182
|
cli.command(
|
|
17222
18183
|
createAuthCli(authRepo, getUpdateInfo, authStorage, envAccessToken)
|
|
17223
18184
|
);
|
|
@@ -17245,7 +18206,14 @@ if (!transactionsCli) {
|
|
|
17245
18206
|
envAccessToken
|
|
17246
18207
|
)
|
|
17247
18208
|
);
|
|
17248
|
-
cli.command(
|
|
18209
|
+
cli.command(
|
|
18210
|
+
createMppCli(
|
|
18211
|
+
spendRequestRepo,
|
|
18212
|
+
() => factory.createPaymentMethodsResource(),
|
|
18213
|
+
authStorage,
|
|
18214
|
+
envAccessToken
|
|
18215
|
+
)
|
|
18216
|
+
);
|
|
17249
18217
|
cli.command(
|
|
17250
18218
|
createReportCli(
|
|
17251
18219
|
() => factory.createReportResource(),
|