@conto_finance/sdk 0.6.0-beta.2 → 0.6.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 +48 -171
- package/dist/index.d.mts +92 -174
- package/dist/index.d.ts +92 -174
- package/dist/index.js +164 -261
- package/dist/index.mjs +159 -259
- package/package.json +3 -9
- package/dist/link-testing.d.mts +0 -49
- package/dist/link-testing.d.ts +0 -49
- package/dist/link-testing.js +0 -285
- package/dist/link-testing.mjs +0 -265
package/dist/index.js
CHANGED
|
@@ -46,7 +46,7 @@ var require_package = __commonJS({
|
|
|
46
46
|
"package.json"(exports2, module2) {
|
|
47
47
|
module2.exports = {
|
|
48
48
|
name: "@conto_finance/sdk",
|
|
49
|
-
version: "0.6.0
|
|
49
|
+
version: "0.6.0",
|
|
50
50
|
description: "Conto SDK for AI agent payment authorization",
|
|
51
51
|
main: "./dist/index.js",
|
|
52
52
|
module: "./dist/index.mjs",
|
|
@@ -71,16 +71,10 @@ var require_package = __commonJS({
|
|
|
71
71
|
types: "./dist/checkout-verifier.d.ts",
|
|
72
72
|
import: "./dist/checkout-verifier.mjs",
|
|
73
73
|
require: "./dist/checkout-verifier.js"
|
|
74
|
-
},
|
|
75
|
-
"./link-testing": {
|
|
76
|
-
types: "./dist/link-testing.d.ts",
|
|
77
|
-
import: "./dist/link-testing.mjs",
|
|
78
|
-
require: "./dist/link-testing.js"
|
|
79
74
|
}
|
|
80
75
|
},
|
|
81
76
|
publishConfig: {
|
|
82
|
-
access: "public"
|
|
83
|
-
tag: "beta"
|
|
77
|
+
access: "public"
|
|
84
78
|
},
|
|
85
79
|
engines: {
|
|
86
80
|
node: ">=20.19.0"
|
|
@@ -93,7 +87,7 @@ var require_package = __commonJS({
|
|
|
93
87
|
dev: "tsup --watch",
|
|
94
88
|
lint: "tsc --noEmit",
|
|
95
89
|
test: "npm run lint && npm run test:contract && npm run test:consumer",
|
|
96
|
-
"test:contract": "npm run build && node --test test/contract.test.mjs test/playwright.test.mjs test/browserbase.test.mjs test/checkout-verifier.test.mjs test/developer-experience.test.mjs test/
|
|
90
|
+
"test:contract": "npm run build && node --test test/contract.test.mjs test/playwright.test.mjs test/browserbase.test.mjs test/checkout-verifier.test.mjs test/developer-experience.test.mjs test/checkout.test.mjs",
|
|
97
91
|
"test:consumer": "npm run build && node --test test/consumer.test.mjs",
|
|
98
92
|
"verify:release": "node scripts/verify-release.mjs",
|
|
99
93
|
prepublishOnly: "npm run verify:release && npm run lint && npm run test:contract && npm run test:consumer"
|
|
@@ -159,6 +153,11 @@ __export(index_exports, {
|
|
|
159
153
|
BrowserActionFinalizationPendingError: () => BrowserActionFinalizationPendingError,
|
|
160
154
|
BrowserCheckoutTargetVerificationError: () => BrowserCheckoutTargetVerificationError,
|
|
161
155
|
CardsClient: () => CardsClient,
|
|
156
|
+
CheckoutApprovalDeniedError: () => CheckoutApprovalDeniedError,
|
|
157
|
+
CheckoutApprovalExpiredError: () => CheckoutApprovalExpiredError,
|
|
158
|
+
CheckoutApprovalPendingError: () => CheckoutApprovalPendingError,
|
|
159
|
+
CheckoutApprovalTimeoutError: () => CheckoutApprovalTimeoutError,
|
|
160
|
+
CheckoutCheckpointClosedError: () => CheckoutCheckpointClosedError,
|
|
162
161
|
CheckoutClient: () => CheckoutClient,
|
|
163
162
|
ConnectedCardsClient: () => ConnectedCardsClient,
|
|
164
163
|
Conto: () => Conto,
|
|
@@ -168,8 +167,6 @@ __export(index_exports, {
|
|
|
168
167
|
ControlledExternalCardPaymentTool: () => ControlledExternalCardPaymentTool,
|
|
169
168
|
ExternalCardConfirmationPendingError: () => ExternalCardConfirmationPendingError,
|
|
170
169
|
Giro: () => Conto,
|
|
171
|
-
LinkClient: () => LinkClient,
|
|
172
|
-
LinkPaymentExecutionError: () => LinkPaymentExecutionError,
|
|
173
170
|
TestCardsClient: () => TestCardsClient,
|
|
174
171
|
canonicalizeBrowserCheckoutTarget: () => canonicalizeBrowserCheckoutTarget,
|
|
175
172
|
createVerifiedBrowserCheckoutDriver: () => createVerifiedBrowserCheckoutDriver,
|
|
@@ -555,7 +552,6 @@ var ContoAdmin = class {
|
|
|
555
552
|
this.cards = new AdminCardsClient(this);
|
|
556
553
|
this.policies = new PoliciesClient(this);
|
|
557
554
|
this.team = new TeamClient(this);
|
|
558
|
-
this.paymentRails = new PaymentRailsClient(this);
|
|
559
555
|
}
|
|
560
556
|
/** Make an authenticated request to the Conto API */
|
|
561
557
|
async request(method, path, body) {
|
|
@@ -611,22 +607,6 @@ var ContoAdmin = class {
|
|
|
611
607
|
}
|
|
612
608
|
};
|
|
613
609
|
_orgApiKey = new WeakMap();
|
|
614
|
-
var PaymentRailsClient = class {
|
|
615
|
-
constructor(client) {
|
|
616
|
-
this.client = client;
|
|
617
|
-
}
|
|
618
|
-
/** Read gate and configuration readiness without calling Stripe. */
|
|
619
|
-
async getStripeLinkCheckoutReadiness() {
|
|
620
|
-
return this.client.request("GET", "/api/stripe-link/checkout-readiness");
|
|
621
|
-
}
|
|
622
|
-
/**
|
|
623
|
-
* Ask Conto to verify that its configured Stripe credential resolves to its
|
|
624
|
-
* configured merchant account. This call never returns either identifier.
|
|
625
|
-
*/
|
|
626
|
-
async verifyStripeLinkCheckoutAccount() {
|
|
627
|
-
return this.client.request("POST", "/api/stripe-link/checkout-readiness");
|
|
628
|
-
}
|
|
629
|
-
};
|
|
630
610
|
var AdminCardsClient = class {
|
|
631
611
|
constructor(client) {
|
|
632
612
|
this.client = client;
|
|
@@ -1081,27 +1061,6 @@ var ContoError = class extends Error {
|
|
|
1081
1061
|
}
|
|
1082
1062
|
}
|
|
1083
1063
|
};
|
|
1084
|
-
var LinkPaymentExecutionError = class extends ContoError {
|
|
1085
|
-
constructor(executionId, error) {
|
|
1086
|
-
const original = error instanceof ContoError ? error : void 0;
|
|
1087
|
-
super(
|
|
1088
|
-
original?.message ?? "Link execution could not be confirmed",
|
|
1089
|
-
{
|
|
1090
|
-
code: original?.code ?? "LINK_EXECUTION_UNCONFIRMED",
|
|
1091
|
-
status: original?.status ?? 0,
|
|
1092
|
-
requestId: original?.requestId,
|
|
1093
|
-
retryAfter: original?.retryAfter,
|
|
1094
|
-
fieldErrors: original?.fieldErrors,
|
|
1095
|
-
reasons: original?.reasons,
|
|
1096
|
-
retryGuidance: "Call link.status(executionId) to reconcile. Do not create another purchase or retry execution blindly."
|
|
1097
|
-
},
|
|
1098
|
-
original?.diagnostics
|
|
1099
|
-
);
|
|
1100
|
-
this.nextAction = "RECONCILE";
|
|
1101
|
-
this.name = "LinkPaymentExecutionError";
|
|
1102
|
-
this.executionId = executionId;
|
|
1103
|
-
}
|
|
1104
|
-
};
|
|
1105
1064
|
var ExternalCardConfirmationPendingError = class extends ContoError {
|
|
1106
1065
|
constructor(requestId, confirmationInput, receipt) {
|
|
1107
1066
|
super("External card execution completed but confirmation is pending", {
|
|
@@ -1129,6 +1088,52 @@ var BrowserActionFinalizationPendingError = class extends ContoError {
|
|
|
1129
1088
|
this.observation = input.observation;
|
|
1130
1089
|
}
|
|
1131
1090
|
};
|
|
1091
|
+
var CheckoutCheckpointClosedError = class extends ContoError {
|
|
1092
|
+
constructor(checkpoint, message = `The checkpoint is ${checkpoint.stage.toLowerCase().replace(/_/g, " ")}. Stop this checkout.`, code = "CHECKOUT_CHECKPOINT_CLOSED") {
|
|
1093
|
+
super(message, { code, status: 0 });
|
|
1094
|
+
this.name = "CheckoutCheckpointClosedError";
|
|
1095
|
+
this.checkpoint = checkpoint;
|
|
1096
|
+
this.stage = checkpoint.stage;
|
|
1097
|
+
}
|
|
1098
|
+
};
|
|
1099
|
+
var CheckoutApprovalDeniedError = class extends CheckoutCheckpointClosedError {
|
|
1100
|
+
constructor(checkpoint) {
|
|
1101
|
+
super(checkpoint, "The owner rejected this purchase. Do not pay.", "CHECKOUT_APPROVAL_DENIED");
|
|
1102
|
+
this.name = "CheckoutApprovalDeniedError";
|
|
1103
|
+
}
|
|
1104
|
+
};
|
|
1105
|
+
var CheckoutApprovalExpiredError = class extends CheckoutCheckpointClosedError {
|
|
1106
|
+
constructor(checkpoint) {
|
|
1107
|
+
super(
|
|
1108
|
+
checkpoint,
|
|
1109
|
+
"The owner did not approve this purchase in time. Do not pay.",
|
|
1110
|
+
"CHECKOUT_APPROVAL_EXPIRED"
|
|
1111
|
+
);
|
|
1112
|
+
this.name = "CheckoutApprovalExpiredError";
|
|
1113
|
+
}
|
|
1114
|
+
};
|
|
1115
|
+
var CheckoutApprovalPendingError = class extends ContoError {
|
|
1116
|
+
constructor(checkpoint) {
|
|
1117
|
+
super("The owner has not approved this purchase yet. Do not pay.", {
|
|
1118
|
+
code: "CHECKOUT_APPROVAL_PENDING",
|
|
1119
|
+
status: 0,
|
|
1120
|
+
retryGuidance: "Call checkout.waitForApproval(error.checkpoint), then confirm the approved checkpoint."
|
|
1121
|
+
});
|
|
1122
|
+
this.name = "CheckoutApprovalPendingError";
|
|
1123
|
+
this.checkpoint = checkpoint;
|
|
1124
|
+
}
|
|
1125
|
+
};
|
|
1126
|
+
var CheckoutApprovalTimeoutError = class extends ContoError {
|
|
1127
|
+
constructor(checkpoint) {
|
|
1128
|
+
super("The owner has not decided yet. Do not pay.", {
|
|
1129
|
+
code: "CHECKOUT_APPROVAL_TIMEOUT",
|
|
1130
|
+
status: 0,
|
|
1131
|
+
retryGuidance: "Wait again with checkout.waitForApproval, or call checkout.cancel to release the held spend."
|
|
1132
|
+
});
|
|
1133
|
+
this.name = "CheckoutApprovalTimeoutError";
|
|
1134
|
+
this.checkpoint = checkpoint;
|
|
1135
|
+
}
|
|
1136
|
+
};
|
|
1132
1137
|
function generatedIdempotencyKey(prefix) {
|
|
1133
1138
|
return `${prefix}_${(0, import_node_crypto2.randomUUID)()}`;
|
|
1134
1139
|
}
|
|
@@ -1191,7 +1196,6 @@ var Conto = class {
|
|
|
1191
1196
|
this.baseUrl = (config.baseUrl || "https://conto.finance").replace(/\/$/, "");
|
|
1192
1197
|
assertSecureBaseUrl(this.baseUrl);
|
|
1193
1198
|
this.timeout = config.timeout || 3e4;
|
|
1194
|
-
this.link = new LinkClient(this, config.link);
|
|
1195
1199
|
this.checkout = new CheckoutClient(this);
|
|
1196
1200
|
this.payments = new PaymentsClient(this);
|
|
1197
1201
|
this.cards = new CardsClient(this);
|
|
@@ -1200,31 +1204,6 @@ var Conto = class {
|
|
|
1200
1204
|
this.x402 = new X402Client(this);
|
|
1201
1205
|
this.mpp = new MppClient(this);
|
|
1202
1206
|
}
|
|
1203
|
-
/**
|
|
1204
|
-
* List masked Link payment methods for a session-created connection that is
|
|
1205
|
-
* explicitly bound to this agent. No Link token or payment artifact is
|
|
1206
|
-
* returned through the agent SDK.
|
|
1207
|
-
*/
|
|
1208
|
-
async listStripeLinkPaymentMethods(connectionId, options) {
|
|
1209
|
-
return this.request(
|
|
1210
|
-
"GET",
|
|
1211
|
-
withQuery("/api/sdk/stripe-link/payment-methods", {
|
|
1212
|
-
connectionId,
|
|
1213
|
-
...options?.mode ? { mode: options.mode } : {}
|
|
1214
|
-
})
|
|
1215
|
-
);
|
|
1216
|
-
}
|
|
1217
|
-
/** Read live Link configuration diagnostics without retrieving credentials or authorizing payment. */
|
|
1218
|
-
async getLinkSetup(input = {}) {
|
|
1219
|
-
return this.request(
|
|
1220
|
-
"GET",
|
|
1221
|
-
withQuery("/api/sdk/stripe-link/setup", {
|
|
1222
|
-
connectionId: input.connectionId,
|
|
1223
|
-
paymentMethodId: input.paymentMethodId,
|
|
1224
|
-
merchantId: input.merchantId
|
|
1225
|
-
})
|
|
1226
|
-
);
|
|
1227
|
-
}
|
|
1228
1207
|
/**
|
|
1229
1208
|
* Normalize and durably revise a partial agent purchase proposal without
|
|
1230
1209
|
* creating a payment side effect. Missing facts return as NEEDS_CONTEXT
|
|
@@ -1305,6 +1284,22 @@ var Conto = class {
|
|
|
1305
1284
|
rethrowAmbiguousCommerceMutation(error, executionId, "authorize");
|
|
1306
1285
|
}
|
|
1307
1286
|
}
|
|
1287
|
+
/**
|
|
1288
|
+
* Report whether an authorized guarded browser checkout was paid. PAID keeps
|
|
1289
|
+
* the held spend counted, NOT_PAID releases it, and UNKNOWN keeps it held for
|
|
1290
|
+
* the owner to review. Safe to repeat with the same outcome.
|
|
1291
|
+
*/
|
|
1292
|
+
async reportCommerceExecutionOutcome(executionId, input) {
|
|
1293
|
+
return this.request(
|
|
1294
|
+
"POST",
|
|
1295
|
+
`/api/sdk/commerce-executions/${encodeURIComponent(executionId)}/outcome`,
|
|
1296
|
+
{
|
|
1297
|
+
outcome: input.outcome,
|
|
1298
|
+
...input.reference ? { reference: input.reference } : {}
|
|
1299
|
+
},
|
|
1300
|
+
{ idempotent: true }
|
|
1301
|
+
);
|
|
1302
|
+
}
|
|
1308
1303
|
/** Claim a durable browser action for one stable privileged-runtime attempt. */
|
|
1309
1304
|
async claimBrowserAction(authorizationId, dispatchAttemptId, browserSessionId, action) {
|
|
1310
1305
|
return this.request(
|
|
@@ -2167,13 +2162,49 @@ function checkpointCart(amountMinor, lineItems, totals) {
|
|
|
2167
2162
|
totals: totals ?? [{ type: "total", label: "Total", amountMinor }]
|
|
2168
2163
|
};
|
|
2169
2164
|
}
|
|
2165
|
+
var CLOSED_CHECKPOINT_STAGES = [
|
|
2166
|
+
"DENIED",
|
|
2167
|
+
"CANCELLED",
|
|
2168
|
+
"EXPIRED",
|
|
2169
|
+
"NOT_PAID"
|
|
2170
|
+
];
|
|
2171
|
+
function closedCheckpointError(checkpoint) {
|
|
2172
|
+
if (checkpoint.approval?.status === "DENIED") return new CheckoutApprovalDeniedError(checkpoint);
|
|
2173
|
+
if (checkpoint.approval?.status === "EXPIRED") {
|
|
2174
|
+
return new CheckoutApprovalExpiredError(checkpoint);
|
|
2175
|
+
}
|
|
2176
|
+
return new CheckoutCheckpointClosedError(checkpoint);
|
|
2177
|
+
}
|
|
2178
|
+
function sleep(ms, signal) {
|
|
2179
|
+
return new Promise((resolve, reject) => {
|
|
2180
|
+
if (signal?.aborted) {
|
|
2181
|
+
reject(signal.reason ?? new Error("Aborted"));
|
|
2182
|
+
return;
|
|
2183
|
+
}
|
|
2184
|
+
const onAbort = () => {
|
|
2185
|
+
clearTimeout(timer);
|
|
2186
|
+
reject(signal?.reason ?? new Error("Aborted"));
|
|
2187
|
+
};
|
|
2188
|
+
const timer = setTimeout(() => {
|
|
2189
|
+
signal?.removeEventListener("abort", onAbort);
|
|
2190
|
+
resolve();
|
|
2191
|
+
}, ms);
|
|
2192
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
2193
|
+
});
|
|
2194
|
+
}
|
|
2170
2195
|
var _client;
|
|
2171
2196
|
var CheckoutClient = class {
|
|
2172
2197
|
constructor(client) {
|
|
2173
2198
|
__privateAdd(this, _client);
|
|
2174
2199
|
__privateSet(this, _client, client);
|
|
2175
2200
|
}
|
|
2176
|
-
/**
|
|
2201
|
+
/**
|
|
2202
|
+
* First checkpoint. Open the payment method only when the stage is APPROVED.
|
|
2203
|
+
* AWAITING_APPROVAL means the owner must decide first: call waitForApproval().
|
|
2204
|
+
* A ContoError means Conto did not approve: stop the checkout. A
|
|
2205
|
+
* CheckoutCheckpointClosedError means this idempotency key belongs to a
|
|
2206
|
+
* checkpoint that already closed.
|
|
2207
|
+
*/
|
|
2177
2208
|
async begin(input) {
|
|
2178
2209
|
const idempotencyKey = input.idempotencyKey?.trim();
|
|
2179
2210
|
if (!idempotencyKey || idempotencyKey.length < 8 || idempotencyKey.length > 255) {
|
|
@@ -2200,13 +2231,40 @@ var CheckoutClient = class {
|
|
|
2200
2231
|
},
|
|
2201
2232
|
{ idempotent: true }
|
|
2202
2233
|
);
|
|
2234
|
+
if (CLOSED_CHECKPOINT_STAGES.includes(result.checkpoint.stage)) {
|
|
2235
|
+
throw closedCheckpointError(result.checkpoint);
|
|
2236
|
+
}
|
|
2203
2237
|
return result.checkpoint;
|
|
2204
2238
|
}
|
|
2239
|
+
/**
|
|
2240
|
+
* Waits while the owner decides on a checkpoint in AWAITING_APPROVAL and
|
|
2241
|
+
* resolves to the approved checkpoint. Throws CheckoutApprovalDeniedError,
|
|
2242
|
+
* CheckoutApprovalExpiredError, CheckoutCheckpointClosedError, or
|
|
2243
|
+
* CheckoutApprovalTimeoutError (the spend stays held until you cancel).
|
|
2244
|
+
*/
|
|
2245
|
+
async waitForApproval(checkpoint, options = {}) {
|
|
2246
|
+
const timeoutMs = options.timeoutMs ?? 10 * 6e4;
|
|
2247
|
+
const pollIntervalMs = Math.max(1e3, options.pollIntervalMs ?? 5e3);
|
|
2248
|
+
const deadline = Date.now() + timeoutMs;
|
|
2249
|
+
let current = checkpoint;
|
|
2250
|
+
for (; ; ) {
|
|
2251
|
+
if (current.stage !== "AWAITING_APPROVAL") {
|
|
2252
|
+
if (CLOSED_CHECKPOINT_STAGES.includes(current.stage)) throw closedCheckpointError(current);
|
|
2253
|
+
return current;
|
|
2254
|
+
}
|
|
2255
|
+
const remaining = deadline - Date.now();
|
|
2256
|
+
if (remaining <= 0) throw new CheckoutApprovalTimeoutError(current);
|
|
2257
|
+
await sleep(Math.min(pollIntervalMs, remaining), options.signal);
|
|
2258
|
+
current = await this.get(current.id);
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2205
2261
|
/**
|
|
2206
2262
|
* Second checkpoint, right before the payment is submitted. If the total
|
|
2207
2263
|
* changed since begin() (tax or shipping, for example), this cancels the
|
|
2208
2264
|
* approved checkpoint and starts a new one at the final total, so the agent's
|
|
2209
|
-
* rules see the amount actually being paid. Pay only if this resolves.
|
|
2265
|
+
* rules see the amount actually being paid. Pay only if this resolves. A
|
|
2266
|
+
* CheckoutApprovalPendingError means the owner must approve first: call
|
|
2267
|
+
* waitForApproval(error.checkpoint), then confirm the checkpoint it returns.
|
|
2210
2268
|
*/
|
|
2211
2269
|
async confirm(checkpoint, input) {
|
|
2212
2270
|
if (input.currency !== void 0 && input.currency !== "USD") {
|
|
@@ -2237,18 +2295,27 @@ var CheckoutClient = class {
|
|
|
2237
2295
|
lineItems: input.lineItems ?? checkpoint.cart.lineItems,
|
|
2238
2296
|
totals: input.totals
|
|
2239
2297
|
});
|
|
2298
|
+
if (current.stage === "AWAITING_APPROVAL") throw new CheckoutApprovalPendingError(current);
|
|
2299
|
+
}
|
|
2300
|
+
try {
|
|
2301
|
+
const result = await __privateGet(this, _client).request(
|
|
2302
|
+
"POST",
|
|
2303
|
+
`/api/sdk/checkout-checkpoints/${encodeURIComponent(current.id)}/confirm`,
|
|
2304
|
+
{
|
|
2305
|
+
amountMinor: input.amountMinor,
|
|
2306
|
+
currency: "USD",
|
|
2307
|
+
...input.pageUrl ? { pageUrl: input.pageUrl } : {}
|
|
2308
|
+
},
|
|
2309
|
+
{ idempotent: true }
|
|
2310
|
+
);
|
|
2311
|
+
return result.checkpoint;
|
|
2312
|
+
} catch (error) {
|
|
2313
|
+
if (error instanceof ContoError && error.status === 409 && error.code === "APPROVAL_REQUIRED") {
|
|
2314
|
+
const latest = await this.get(current.id);
|
|
2315
|
+
if (latest.stage === "AWAITING_APPROVAL") throw new CheckoutApprovalPendingError(latest);
|
|
2316
|
+
}
|
|
2317
|
+
throw error;
|
|
2240
2318
|
}
|
|
2241
|
-
const result = await __privateGet(this, _client).request(
|
|
2242
|
-
"POST",
|
|
2243
|
-
`/api/sdk/checkout-checkpoints/${encodeURIComponent(current.id)}/confirm`,
|
|
2244
|
-
{
|
|
2245
|
-
amountMinor: input.amountMinor,
|
|
2246
|
-
currency: "USD",
|
|
2247
|
-
...input.pageUrl ? { pageUrl: input.pageUrl } : {}
|
|
2248
|
-
},
|
|
2249
|
-
{ idempotent: true }
|
|
2250
|
-
);
|
|
2251
|
-
return result.checkpoint;
|
|
2252
2319
|
}
|
|
2253
2320
|
/** Report what happened after a confirmed checkpoint. Safe to repeat with the same outcome. */
|
|
2254
2321
|
async reportOutcome(checkpointId, input) {
|
|
@@ -2263,7 +2330,10 @@ var CheckoutClient = class {
|
|
|
2263
2330
|
);
|
|
2264
2331
|
return result.checkpoint;
|
|
2265
2332
|
}
|
|
2266
|
-
/**
|
|
2333
|
+
/**
|
|
2334
|
+
* Cancel a checkpoint that was not confirmed and release its spend. A
|
|
2335
|
+
* checkpoint waiting for the owner can be cancelled too.
|
|
2336
|
+
*/
|
|
2267
2337
|
async cancel(checkpointId) {
|
|
2268
2338
|
const result = await __privateGet(this, _client).request(
|
|
2269
2339
|
"POST",
|
|
@@ -2282,181 +2352,16 @@ var CheckoutClient = class {
|
|
|
2282
2352
|
}
|
|
2283
2353
|
};
|
|
2284
2354
|
_client = new WeakMap();
|
|
2285
|
-
var _client2, _defaults;
|
|
2286
|
-
var LinkClient = class {
|
|
2287
|
-
constructor(client, defaults) {
|
|
2288
|
-
__privateAdd(this, _client2);
|
|
2289
|
-
__privateAdd(this, _defaults);
|
|
2290
|
-
__privateSet(this, _client2, client);
|
|
2291
|
-
__privateSet(this, _defaults, defaults ? { ...defaults } : void 0);
|
|
2292
|
-
}
|
|
2293
|
-
/** Inspect the configured live path. This is not a payment authorization or provider connectivity test. */
|
|
2294
|
-
async setup(input = {}) {
|
|
2295
|
-
return __privateGet(this, _client2).getLinkSetup({
|
|
2296
|
-
connectionId: input.connectionId ?? __privateGet(this, _defaults)?.connectionId,
|
|
2297
|
-
paymentMethodId: input.paymentMethodId ?? __privateGet(this, _defaults)?.paymentMethodId,
|
|
2298
|
-
merchantId: input.merchantId
|
|
2299
|
-
});
|
|
2300
|
-
}
|
|
2301
|
-
/** Read masked LIVE funding sources; never selects a source or initiates payment. */
|
|
2302
|
-
async paymentMethods(connectionId) {
|
|
2303
|
-
return __privateGet(this, _client2).listStripeLinkPaymentMethods(
|
|
2304
|
-
this.identifier(connectionId ?? __privateGet(this, _defaults)?.connectionId, "connectionId"),
|
|
2305
|
-
{ mode: "LIVE" }
|
|
2306
|
-
);
|
|
2307
|
-
}
|
|
2308
|
-
/**
|
|
2309
|
-
* Begin one exact intent and execute only if already READY. Otherwise return
|
|
2310
|
-
* the owner's approval action or existing state immediately, without polling.
|
|
2311
|
-
*/
|
|
2312
|
-
async pay(input) {
|
|
2313
|
-
const connectionId = this.identifier(
|
|
2314
|
-
input.connectionId ?? __privateGet(this, _defaults)?.connectionId,
|
|
2315
|
-
"connectionId"
|
|
2316
|
-
);
|
|
2317
|
-
const paymentMethodId = this.identifier(
|
|
2318
|
-
input.paymentMethodId ?? __privateGet(this, _defaults)?.paymentMethodId,
|
|
2319
|
-
"paymentMethodId"
|
|
2320
|
-
);
|
|
2321
|
-
if (!Number.isSafeInteger(input.amountMinor) || input.amountMinor <= 0 || input.currency !== void 0 && input.currency !== "USD" || !Array.isArray(input.lineItems) || input.lineItems.length === 0 || typeof input.purpose !== "string" || !input.purpose.trim()) {
|
|
2322
|
-
throw new ContoError("Supply a positive USD amount in cents, purpose, and line items", {
|
|
2323
|
-
code: "INVALID_LINK_PURCHASE",
|
|
2324
|
-
status: 0
|
|
2325
|
-
});
|
|
2326
|
-
}
|
|
2327
|
-
const itemTotal = input.lineItems.reduce((sum, item) => {
|
|
2328
|
-
if (!item || typeof item.name !== "string" || !item.name.trim() || !Number.isSafeInteger(item.quantity) || item.quantity <= 0 || !Number.isSafeInteger(item.unitAmountMinor) || item.unitAmountMinor < 0) {
|
|
2329
|
-
throw new ContoError(
|
|
2330
|
-
"Each line item needs a name, positive integer quantity, and price in cents",
|
|
2331
|
-
{
|
|
2332
|
-
code: "INVALID_LINK_PURCHASE",
|
|
2333
|
-
status: 0
|
|
2334
|
-
}
|
|
2335
|
-
);
|
|
2336
|
-
}
|
|
2337
|
-
return sum + item.quantity * item.unitAmountMinor;
|
|
2338
|
-
}, 0);
|
|
2339
|
-
if (!input.totals && (!Number.isSafeInteger(itemTotal) || itemTotal !== input.amountMinor)) {
|
|
2340
|
-
throw new ContoError(
|
|
2341
|
-
"Supply the exact totals breakdown when the amount differs from the line items",
|
|
2342
|
-
{
|
|
2343
|
-
code: "LINK_TOTALS_REQUIRED",
|
|
2344
|
-
status: 0
|
|
2345
|
-
}
|
|
2346
|
-
);
|
|
2347
|
-
}
|
|
2348
|
-
const result = await __privateGet(this, _client2).beginCommerceExecution({
|
|
2349
|
-
executionMethod: "LINK_PAY_TOKEN",
|
|
2350
|
-
connectionId,
|
|
2351
|
-
paymentMethodId,
|
|
2352
|
-
idempotencyKey: input.idempotencyKey,
|
|
2353
|
-
amountMinor: input.amountMinor,
|
|
2354
|
-
currency: input.currency ?? "USD",
|
|
2355
|
-
purpose: input.purpose,
|
|
2356
|
-
category: input.category,
|
|
2357
|
-
counterparty: { canonicalId: input.merchantId, checkoutUrl: input.checkoutUrl },
|
|
2358
|
-
cart: {
|
|
2359
|
-
lineItems: input.lineItems,
|
|
2360
|
-
totals: input.totals ?? [{ type: "total", label: "Total", amountMinor: input.amountMinor }]
|
|
2361
|
-
},
|
|
2362
|
-
providerPresentation: {
|
|
2363
|
-
approvalSummary: input.purpose.trim().slice(0, 500),
|
|
2364
|
-
lineItemLabels: input.lineItems.map((item) => item.name.trim().slice(0, 120))
|
|
2365
|
-
}
|
|
2366
|
-
});
|
|
2367
|
-
return this.executeIfReady(result);
|
|
2368
|
-
}
|
|
2369
|
-
/**
|
|
2370
|
-
* Continue the existing payment after approval. Reads before any mutation and
|
|
2371
|
-
* never submits an execution already processing or requiring reconciliation.
|
|
2372
|
-
*/
|
|
2373
|
-
async resume(executionId) {
|
|
2374
|
-
const id = this.identifier(executionId, "executionId");
|
|
2375
|
-
const current = await __privateGet(this, _client2).getCommerceExecution(id);
|
|
2376
|
-
this.assertLinkExecution(current);
|
|
2377
|
-
if (["AUTHORIZING", "AWAITING_APPROVAL", "ACTION_REQUIRED"].includes(current.execution.status)) {
|
|
2378
|
-
return this.executeIfReady(await __privateGet(this, _client2).refreshCommerceExecution(id));
|
|
2379
|
-
}
|
|
2380
|
-
return this.executeIfReady(current);
|
|
2381
|
-
}
|
|
2382
|
-
/** Observe and reconcile provider state. This method never submits a payment. */
|
|
2383
|
-
async status(executionId) {
|
|
2384
|
-
const id = this.identifier(executionId, "executionId");
|
|
2385
|
-
this.assertLinkExecution(await __privateGet(this, _client2).getCommerceExecution(id));
|
|
2386
|
-
return this.result(await __privateGet(this, _client2).refreshCommerceExecution(id));
|
|
2387
|
-
}
|
|
2388
|
-
/** Request cancellation of this existing Link payment; never retried automatically. */
|
|
2389
|
-
async cancel(executionId) {
|
|
2390
|
-
const id = this.identifier(executionId, "executionId");
|
|
2391
|
-
this.assertLinkExecution(await __privateGet(this, _client2).getCommerceExecution(id));
|
|
2392
|
-
try {
|
|
2393
|
-
return this.result(await __privateGet(this, _client2).cancelCommerceExecution(id));
|
|
2394
|
-
} catch (error) {
|
|
2395
|
-
throw new LinkPaymentExecutionError(id, error);
|
|
2396
|
-
}
|
|
2397
|
-
}
|
|
2398
|
-
identifier(value, field) {
|
|
2399
|
-
if (typeof value !== "string" || !value.trim() || value.length > 255) {
|
|
2400
|
-
throw new ContoError(
|
|
2401
|
-
field === "executionId" ? "executionId is required; use the existing ID returned by link.pay()" : `${field} is required; configure the owner-provisioned Link IDs or supply them explicitly`,
|
|
2402
|
-
{
|
|
2403
|
-
code: "LINK_CONFIGURATION_REQUIRED",
|
|
2404
|
-
status: 0
|
|
2405
|
-
}
|
|
2406
|
-
);
|
|
2407
|
-
}
|
|
2408
|
-
return value.trim();
|
|
2409
|
-
}
|
|
2410
|
-
assertLinkExecution(result) {
|
|
2411
|
-
const execution = result.execution;
|
|
2412
|
-
if (execution?.provider !== "STRIPE_LINK" || execution.executionAdapter !== "STRIPE_LINK" || execution.executionChannel !== "BROWSER" || execution.artifactKind !== void 0 && execution.artifactKind !== "LINK_PAY_TOKEN" || execution.deliveryMode !== void 0 && execution.deliveryMode !== "SERVER_ONLY_ARTIFACT") {
|
|
2413
|
-
throw new ContoError("This execution is not a Link Pay Token checkout", {
|
|
2414
|
-
code: "LINK_EXECUTION_MISMATCH",
|
|
2415
|
-
status: 0
|
|
2416
|
-
});
|
|
2417
|
-
}
|
|
2418
|
-
}
|
|
2419
|
-
async executeIfReady(result) {
|
|
2420
|
-
this.assertLinkExecution(result);
|
|
2421
|
-
if (result.execution.status !== "READY") return this.result(result);
|
|
2422
|
-
try {
|
|
2423
|
-
return this.result(await __privateGet(this, _client2).executeCommerceExecution(result.execution.id));
|
|
2424
|
-
} catch (error) {
|
|
2425
|
-
throw new LinkPaymentExecutionError(result.execution.id, error);
|
|
2426
|
-
}
|
|
2427
|
-
}
|
|
2428
|
-
result(result) {
|
|
2429
|
-
this.assertLinkExecution(result);
|
|
2430
|
-
const { execution } = result;
|
|
2431
|
-
const awaitingApproval = ["AUTHORIZING", "AWAITING_APPROVAL", "ACTION_REQUIRED"].includes(
|
|
2432
|
-
execution.status
|
|
2433
|
-
);
|
|
2434
|
-
const nextAction = execution.status === "READY" ? "RESUME" : execution.status === "NEEDS_RECONCILIATION" ? "RECONCILE" : awaitingApproval && execution.approvalUrl ? "APPROVE_IN_LINK" : awaitingApproval || ["DRAFT", "PROCESSING"].includes(execution.status) ? "WAIT" : [
|
|
2435
|
-
"SETTLED",
|
|
2436
|
-
"COMPLETED",
|
|
2437
|
-
"DENIED",
|
|
2438
|
-
"CANCELLED",
|
|
2439
|
-
"FAILED",
|
|
2440
|
-
"RETURNED",
|
|
2441
|
-
"EXPIRED"
|
|
2442
|
-
].includes(execution.status) ? "NONE" : "RECONCILE";
|
|
2443
|
-
return {
|
|
2444
|
-
executionId: execution.id,
|
|
2445
|
-
status: execution.status,
|
|
2446
|
-
nextAction,
|
|
2447
|
-
...nextAction === "APPROVE_IN_LINK" ? { approvalUrl: execution.approvalUrl } : {},
|
|
2448
|
-
execution,
|
|
2449
|
-
..."checkout" in result ? { checkout: result.checkout } : {}
|
|
2450
|
-
};
|
|
2451
|
-
}
|
|
2452
|
-
};
|
|
2453
|
-
_client2 = new WeakMap();
|
|
2454
|
-
_defaults = new WeakMap();
|
|
2455
2355
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2456
2356
|
0 && (module.exports = {
|
|
2457
2357
|
BrowserActionFinalizationPendingError,
|
|
2458
2358
|
BrowserCheckoutTargetVerificationError,
|
|
2459
2359
|
CardsClient,
|
|
2360
|
+
CheckoutApprovalDeniedError,
|
|
2361
|
+
CheckoutApprovalExpiredError,
|
|
2362
|
+
CheckoutApprovalPendingError,
|
|
2363
|
+
CheckoutApprovalTimeoutError,
|
|
2364
|
+
CheckoutCheckpointClosedError,
|
|
2460
2365
|
CheckoutClient,
|
|
2461
2366
|
ConnectedCardsClient,
|
|
2462
2367
|
Conto,
|
|
@@ -2466,8 +2371,6 @@ _defaults = new WeakMap();
|
|
|
2466
2371
|
ControlledExternalCardPaymentTool,
|
|
2467
2372
|
ExternalCardConfirmationPendingError,
|
|
2468
2373
|
Giro,
|
|
2469
|
-
LinkClient,
|
|
2470
|
-
LinkPaymentExecutionError,
|
|
2471
2374
|
TestCardsClient,
|
|
2472
2375
|
canonicalizeBrowserCheckoutTarget,
|
|
2473
2376
|
createVerifiedBrowserCheckoutDriver,
|