@conto_finance/sdk 0.6.0-beta.1 → 0.6.0-beta.2
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 +25 -60
- package/dist/index.d.mts +98 -4
- package/dist/index.d.ts +98 -4
- package/dist/index.js +154 -18
- package/dist/index.mjs +153 -18
- package/dist/link-testing.d.mts +15 -3
- package/dist/link-testing.d.ts +15 -3
- package/dist/link-testing.js +66 -45
- package/dist/link-testing.mjs +66 -45
- package/package.json +2 -2
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-beta.
|
|
49
|
+
version: "0.6.0-beta.2",
|
|
50
50
|
description: "Conto SDK for AI agent payment authorization",
|
|
51
51
|
main: "./dist/index.js",
|
|
52
52
|
module: "./dist/index.mjs",
|
|
@@ -93,7 +93,7 @@ var require_package = __commonJS({
|
|
|
93
93
|
dev: "tsup --watch",
|
|
94
94
|
lint: "tsc --noEmit",
|
|
95
95
|
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/link.test.mjs test/link-testing.test.mjs",
|
|
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/link.test.mjs test/link-testing.test.mjs test/checkout.test.mjs",
|
|
97
97
|
"test:consumer": "npm run build && node --test test/consumer.test.mjs",
|
|
98
98
|
"verify:release": "node scripts/verify-release.mjs",
|
|
99
99
|
prepublishOnly: "npm run verify:release && npm run lint && npm run test:contract && npm run test:consumer"
|
|
@@ -159,6 +159,7 @@ __export(index_exports, {
|
|
|
159
159
|
BrowserActionFinalizationPendingError: () => BrowserActionFinalizationPendingError,
|
|
160
160
|
BrowserCheckoutTargetVerificationError: () => BrowserCheckoutTargetVerificationError,
|
|
161
161
|
CardsClient: () => CardsClient,
|
|
162
|
+
CheckoutClient: () => CheckoutClient,
|
|
162
163
|
ConnectedCardsClient: () => ConnectedCardsClient,
|
|
163
164
|
Conto: () => Conto,
|
|
164
165
|
ContoAdmin: () => ContoAdmin,
|
|
@@ -696,8 +697,11 @@ var AdminCardsClient = class {
|
|
|
696
697
|
return this.client.request("GET", `/api/external-cards/requests${suffix ? `?${suffix}` : ""}`);
|
|
697
698
|
}
|
|
698
699
|
/**
|
|
699
|
-
*
|
|
700
|
-
*
|
|
700
|
+
* @deprecated Resolution requires a signed-in user. SDK admin keys and
|
|
701
|
+
* organization API keys receive HTTP 403 INSUFFICIENT_PERMISSIONS from this
|
|
702
|
+
* endpoint. Have a signed-in organization owner or admin review the processor
|
|
703
|
+
* evidence and resolve the request through Conto's authenticated interface.
|
|
704
|
+
* Retained for source compatibility; this method does not bypass that restriction.
|
|
701
705
|
*/
|
|
702
706
|
async resolveRequest(requestId, input) {
|
|
703
707
|
return this.client.request(
|
|
@@ -1188,6 +1192,7 @@ var Conto = class {
|
|
|
1188
1192
|
assertSecureBaseUrl(this.baseUrl);
|
|
1189
1193
|
this.timeout = config.timeout || 3e4;
|
|
1190
1194
|
this.link = new LinkClient(this, config.link);
|
|
1195
|
+
this.checkout = new CheckoutClient(this);
|
|
1191
1196
|
this.payments = new PaymentsClient(this);
|
|
1192
1197
|
this.cards = new CardsClient(this);
|
|
1193
1198
|
this.connectedCards = new ConnectedCardsClient(this);
|
|
@@ -2147,17 +2152,147 @@ var MppClient = class {
|
|
|
2147
2152
|
}
|
|
2148
2153
|
};
|
|
2149
2154
|
var index_default = Conto;
|
|
2150
|
-
|
|
2155
|
+
function checkoutError(message, code = "INVALID_CHECKOUT_CHECKPOINT") {
|
|
2156
|
+
return new ContoError(message, { code, status: 0 });
|
|
2157
|
+
}
|
|
2158
|
+
function checkpointCart(amountMinor, lineItems, totals) {
|
|
2159
|
+
if (!Number.isSafeInteger(amountMinor) || amountMinor <= 0) {
|
|
2160
|
+
throw checkoutError("amountMinor must be a positive integer number of cents");
|
|
2161
|
+
}
|
|
2162
|
+
if (!Array.isArray(lineItems) || lineItems.length === 0) {
|
|
2163
|
+
throw checkoutError("Supply at least one line item");
|
|
2164
|
+
}
|
|
2165
|
+
return {
|
|
2166
|
+
lineItems,
|
|
2167
|
+
totals: totals ?? [{ type: "total", label: "Total", amountMinor }]
|
|
2168
|
+
};
|
|
2169
|
+
}
|
|
2170
|
+
var _client;
|
|
2171
|
+
var CheckoutClient = class {
|
|
2172
|
+
constructor(client) {
|
|
2173
|
+
__privateAdd(this, _client);
|
|
2174
|
+
__privateSet(this, _client, client);
|
|
2175
|
+
}
|
|
2176
|
+
/** First checkpoint. A ContoError means Conto did not approve: stop the checkout. */
|
|
2177
|
+
async begin(input) {
|
|
2178
|
+
const idempotencyKey = input.idempotencyKey?.trim();
|
|
2179
|
+
if (!idempotencyKey || idempotencyKey.length < 8 || idempotencyKey.length > 255) {
|
|
2180
|
+
throw checkoutError(
|
|
2181
|
+
"idempotencyKey must contain 8 to 255 characters",
|
|
2182
|
+
"INVALID_IDEMPOTENCY_KEY"
|
|
2183
|
+
);
|
|
2184
|
+
}
|
|
2185
|
+
if (input.currency !== void 0 && input.currency !== "USD") {
|
|
2186
|
+
throw checkoutError("Only USD checkouts are supported");
|
|
2187
|
+
}
|
|
2188
|
+
const result = await __privateGet(this, _client).request(
|
|
2189
|
+
"POST",
|
|
2190
|
+
"/api/sdk/checkout-checkpoints",
|
|
2191
|
+
{
|
|
2192
|
+
idempotencyKey,
|
|
2193
|
+
merchant: input.merchant,
|
|
2194
|
+
amountMinor: input.amountMinor,
|
|
2195
|
+
currency: "USD",
|
|
2196
|
+
purpose: input.purpose,
|
|
2197
|
+
...input.category ? { category: input.category } : {},
|
|
2198
|
+
...input.checkoutMethod ? { checkoutMethod: input.checkoutMethod } : {},
|
|
2199
|
+
cart: checkpointCart(input.amountMinor, input.lineItems, input.totals)
|
|
2200
|
+
},
|
|
2201
|
+
{ idempotent: true }
|
|
2202
|
+
);
|
|
2203
|
+
return result.checkpoint;
|
|
2204
|
+
}
|
|
2205
|
+
/**
|
|
2206
|
+
* Second checkpoint, right before the payment is submitted. If the total
|
|
2207
|
+
* changed since begin() (tax or shipping, for example), this cancels the
|
|
2208
|
+
* 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.
|
|
2210
|
+
*/
|
|
2211
|
+
async confirm(checkpoint, input) {
|
|
2212
|
+
if (input.currency !== void 0 && input.currency !== "USD") {
|
|
2213
|
+
throw checkoutError("Only USD checkouts are supported");
|
|
2214
|
+
}
|
|
2215
|
+
if (!Number.isSafeInteger(input.amountMinor) || input.amountMinor <= 0) {
|
|
2216
|
+
throw checkoutError("amountMinor must be a positive integer number of cents");
|
|
2217
|
+
}
|
|
2218
|
+
let current = checkpoint;
|
|
2219
|
+
if (input.amountMinor !== checkpoint.amountMinor) {
|
|
2220
|
+
try {
|
|
2221
|
+
await this.cancel(checkpoint.id);
|
|
2222
|
+
} catch (error) {
|
|
2223
|
+
const closed = error instanceof ContoError && error.status === 409 && ["CANCELLED", "EXPIRED", "DENIED"].includes((await this.get(checkpoint.id)).stage);
|
|
2224
|
+
if (!closed) throw error;
|
|
2225
|
+
}
|
|
2226
|
+
current = await this.begin({
|
|
2227
|
+
idempotencyKey: `${checkpoint.idempotencyKey.slice(0, 200)}:final-${input.amountMinor}`,
|
|
2228
|
+
merchant: {
|
|
2229
|
+
id: checkpoint.merchant.id,
|
|
2230
|
+
name: checkpoint.merchant.name,
|
|
2231
|
+
checkoutUrl: checkpoint.merchant.checkoutUrl ?? ""
|
|
2232
|
+
},
|
|
2233
|
+
amountMinor: input.amountMinor,
|
|
2234
|
+
purpose: checkpoint.purpose,
|
|
2235
|
+
...checkpoint.category ? { category: checkpoint.category } : {},
|
|
2236
|
+
checkoutMethod: checkpoint.checkoutMethod,
|
|
2237
|
+
lineItems: input.lineItems ?? checkpoint.cart.lineItems,
|
|
2238
|
+
totals: input.totals
|
|
2239
|
+
});
|
|
2240
|
+
}
|
|
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
|
+
}
|
|
2253
|
+
/** Report what happened after a confirmed checkpoint. Safe to repeat with the same outcome. */
|
|
2254
|
+
async reportOutcome(checkpointId, input) {
|
|
2255
|
+
const result = await __privateGet(this, _client).request(
|
|
2256
|
+
"POST",
|
|
2257
|
+
`/api/sdk/checkout-checkpoints/${encodeURIComponent(checkpointId)}/outcome`,
|
|
2258
|
+
{
|
|
2259
|
+
outcome: input.outcome,
|
|
2260
|
+
...input.reference ? { reference: input.reference } : {}
|
|
2261
|
+
},
|
|
2262
|
+
{ idempotent: true }
|
|
2263
|
+
);
|
|
2264
|
+
return result.checkpoint;
|
|
2265
|
+
}
|
|
2266
|
+
/** Cancel a checkpoint that was not confirmed and release its spend. */
|
|
2267
|
+
async cancel(checkpointId) {
|
|
2268
|
+
const result = await __privateGet(this, _client).request(
|
|
2269
|
+
"POST",
|
|
2270
|
+
`/api/sdk/checkout-checkpoints/${encodeURIComponent(checkpointId)}/cancel`,
|
|
2271
|
+
{},
|
|
2272
|
+
{ idempotent: true }
|
|
2273
|
+
);
|
|
2274
|
+
return result.checkpoint;
|
|
2275
|
+
}
|
|
2276
|
+
async get(checkpointId) {
|
|
2277
|
+
const result = await __privateGet(this, _client).request(
|
|
2278
|
+
"GET",
|
|
2279
|
+
`/api/sdk/checkout-checkpoints/${encodeURIComponent(checkpointId)}`
|
|
2280
|
+
);
|
|
2281
|
+
return result.checkpoint;
|
|
2282
|
+
}
|
|
2283
|
+
};
|
|
2284
|
+
_client = new WeakMap();
|
|
2285
|
+
var _client2, _defaults;
|
|
2151
2286
|
var LinkClient = class {
|
|
2152
2287
|
constructor(client, defaults) {
|
|
2153
|
-
__privateAdd(this,
|
|
2288
|
+
__privateAdd(this, _client2);
|
|
2154
2289
|
__privateAdd(this, _defaults);
|
|
2155
|
-
__privateSet(this,
|
|
2290
|
+
__privateSet(this, _client2, client);
|
|
2156
2291
|
__privateSet(this, _defaults, defaults ? { ...defaults } : void 0);
|
|
2157
2292
|
}
|
|
2158
2293
|
/** Inspect the configured live path. This is not a payment authorization or provider connectivity test. */
|
|
2159
2294
|
async setup(input = {}) {
|
|
2160
|
-
return __privateGet(this,
|
|
2295
|
+
return __privateGet(this, _client2).getLinkSetup({
|
|
2161
2296
|
connectionId: input.connectionId ?? __privateGet(this, _defaults)?.connectionId,
|
|
2162
2297
|
paymentMethodId: input.paymentMethodId ?? __privateGet(this, _defaults)?.paymentMethodId,
|
|
2163
2298
|
merchantId: input.merchantId
|
|
@@ -2165,7 +2300,7 @@ var LinkClient = class {
|
|
|
2165
2300
|
}
|
|
2166
2301
|
/** Read masked LIVE funding sources; never selects a source or initiates payment. */
|
|
2167
2302
|
async paymentMethods(connectionId) {
|
|
2168
|
-
return __privateGet(this,
|
|
2303
|
+
return __privateGet(this, _client2).listStripeLinkPaymentMethods(
|
|
2169
2304
|
this.identifier(connectionId ?? __privateGet(this, _defaults)?.connectionId, "connectionId"),
|
|
2170
2305
|
{ mode: "LIVE" }
|
|
2171
2306
|
);
|
|
@@ -2210,7 +2345,7 @@ var LinkClient = class {
|
|
|
2210
2345
|
}
|
|
2211
2346
|
);
|
|
2212
2347
|
}
|
|
2213
|
-
const result = await __privateGet(this,
|
|
2348
|
+
const result = await __privateGet(this, _client2).beginCommerceExecution({
|
|
2214
2349
|
executionMethod: "LINK_PAY_TOKEN",
|
|
2215
2350
|
connectionId,
|
|
2216
2351
|
paymentMethodId,
|
|
@@ -2237,25 +2372,25 @@ var LinkClient = class {
|
|
|
2237
2372
|
*/
|
|
2238
2373
|
async resume(executionId) {
|
|
2239
2374
|
const id = this.identifier(executionId, "executionId");
|
|
2240
|
-
const current = await __privateGet(this,
|
|
2375
|
+
const current = await __privateGet(this, _client2).getCommerceExecution(id);
|
|
2241
2376
|
this.assertLinkExecution(current);
|
|
2242
2377
|
if (["AUTHORIZING", "AWAITING_APPROVAL", "ACTION_REQUIRED"].includes(current.execution.status)) {
|
|
2243
|
-
return this.executeIfReady(await __privateGet(this,
|
|
2378
|
+
return this.executeIfReady(await __privateGet(this, _client2).refreshCommerceExecution(id));
|
|
2244
2379
|
}
|
|
2245
2380
|
return this.executeIfReady(current);
|
|
2246
2381
|
}
|
|
2247
2382
|
/** Observe and reconcile provider state. This method never submits a payment. */
|
|
2248
2383
|
async status(executionId) {
|
|
2249
2384
|
const id = this.identifier(executionId, "executionId");
|
|
2250
|
-
this.assertLinkExecution(await __privateGet(this,
|
|
2251
|
-
return this.result(await __privateGet(this,
|
|
2385
|
+
this.assertLinkExecution(await __privateGet(this, _client2).getCommerceExecution(id));
|
|
2386
|
+
return this.result(await __privateGet(this, _client2).refreshCommerceExecution(id));
|
|
2252
2387
|
}
|
|
2253
2388
|
/** Request cancellation of this existing Link payment; never retried automatically. */
|
|
2254
2389
|
async cancel(executionId) {
|
|
2255
2390
|
const id = this.identifier(executionId, "executionId");
|
|
2256
|
-
this.assertLinkExecution(await __privateGet(this,
|
|
2391
|
+
this.assertLinkExecution(await __privateGet(this, _client2).getCommerceExecution(id));
|
|
2257
2392
|
try {
|
|
2258
|
-
return this.result(await __privateGet(this,
|
|
2393
|
+
return this.result(await __privateGet(this, _client2).cancelCommerceExecution(id));
|
|
2259
2394
|
} catch (error) {
|
|
2260
2395
|
throw new LinkPaymentExecutionError(id, error);
|
|
2261
2396
|
}
|
|
@@ -2285,7 +2420,7 @@ var LinkClient = class {
|
|
|
2285
2420
|
this.assertLinkExecution(result);
|
|
2286
2421
|
if (result.execution.status !== "READY") return this.result(result);
|
|
2287
2422
|
try {
|
|
2288
|
-
return this.result(await __privateGet(this,
|
|
2423
|
+
return this.result(await __privateGet(this, _client2).executeCommerceExecution(result.execution.id));
|
|
2289
2424
|
} catch (error) {
|
|
2290
2425
|
throw new LinkPaymentExecutionError(result.execution.id, error);
|
|
2291
2426
|
}
|
|
@@ -2315,13 +2450,14 @@ var LinkClient = class {
|
|
|
2315
2450
|
};
|
|
2316
2451
|
}
|
|
2317
2452
|
};
|
|
2318
|
-
|
|
2453
|
+
_client2 = new WeakMap();
|
|
2319
2454
|
_defaults = new WeakMap();
|
|
2320
2455
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2321
2456
|
0 && (module.exports = {
|
|
2322
2457
|
BrowserActionFinalizationPendingError,
|
|
2323
2458
|
BrowserCheckoutTargetVerificationError,
|
|
2324
2459
|
CardsClient,
|
|
2460
|
+
CheckoutClient,
|
|
2325
2461
|
ConnectedCardsClient,
|
|
2326
2462
|
Conto,
|
|
2327
2463
|
ContoAdmin,
|
package/dist/index.mjs
CHANGED
|
@@ -17,7 +17,7 @@ var require_package = __commonJS({
|
|
|
17
17
|
"package.json"(exports, module) {
|
|
18
18
|
module.exports = {
|
|
19
19
|
name: "@conto_finance/sdk",
|
|
20
|
-
version: "0.6.0-beta.
|
|
20
|
+
version: "0.6.0-beta.2",
|
|
21
21
|
description: "Conto SDK for AI agent payment authorization",
|
|
22
22
|
main: "./dist/index.js",
|
|
23
23
|
module: "./dist/index.mjs",
|
|
@@ -64,7 +64,7 @@ var require_package = __commonJS({
|
|
|
64
64
|
dev: "tsup --watch",
|
|
65
65
|
lint: "tsc --noEmit",
|
|
66
66
|
test: "npm run lint && npm run test:contract && npm run test:consumer",
|
|
67
|
-
"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/link.test.mjs test/link-testing.test.mjs",
|
|
67
|
+
"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/link.test.mjs test/link-testing.test.mjs test/checkout.test.mjs",
|
|
68
68
|
"test:consumer": "npm run build && node --test test/consumer.test.mjs",
|
|
69
69
|
"verify:release": "node scripts/verify-release.mjs",
|
|
70
70
|
prepublishOnly: "npm run verify:release && npm run lint && npm run test:contract && npm run test:consumer"
|
|
@@ -528,8 +528,11 @@ var AdminCardsClient = class {
|
|
|
528
528
|
return this.client.request("GET", `/api/external-cards/requests${suffix ? `?${suffix}` : ""}`);
|
|
529
529
|
}
|
|
530
530
|
/**
|
|
531
|
-
*
|
|
532
|
-
*
|
|
531
|
+
* @deprecated Resolution requires a signed-in user. SDK admin keys and
|
|
532
|
+
* organization API keys receive HTTP 403 INSUFFICIENT_PERMISSIONS from this
|
|
533
|
+
* endpoint. Have a signed-in organization owner or admin review the processor
|
|
534
|
+
* evidence and resolve the request through Conto's authenticated interface.
|
|
535
|
+
* Retained for source compatibility; this method does not bypass that restriction.
|
|
533
536
|
*/
|
|
534
537
|
async resolveRequest(requestId, input) {
|
|
535
538
|
return this.client.request(
|
|
@@ -1020,6 +1023,7 @@ var Conto = class {
|
|
|
1020
1023
|
assertSecureBaseUrl(this.baseUrl);
|
|
1021
1024
|
this.timeout = config.timeout || 3e4;
|
|
1022
1025
|
this.link = new LinkClient(this, config.link);
|
|
1026
|
+
this.checkout = new CheckoutClient(this);
|
|
1023
1027
|
this.payments = new PaymentsClient(this);
|
|
1024
1028
|
this.cards = new CardsClient(this);
|
|
1025
1029
|
this.connectedCards = new ConnectedCardsClient(this);
|
|
@@ -1979,17 +1983,147 @@ var MppClient = class {
|
|
|
1979
1983
|
}
|
|
1980
1984
|
};
|
|
1981
1985
|
var index_default = Conto;
|
|
1982
|
-
|
|
1986
|
+
function checkoutError(message, code = "INVALID_CHECKOUT_CHECKPOINT") {
|
|
1987
|
+
return new ContoError(message, { code, status: 0 });
|
|
1988
|
+
}
|
|
1989
|
+
function checkpointCart(amountMinor, lineItems, totals) {
|
|
1990
|
+
if (!Number.isSafeInteger(amountMinor) || amountMinor <= 0) {
|
|
1991
|
+
throw checkoutError("amountMinor must be a positive integer number of cents");
|
|
1992
|
+
}
|
|
1993
|
+
if (!Array.isArray(lineItems) || lineItems.length === 0) {
|
|
1994
|
+
throw checkoutError("Supply at least one line item");
|
|
1995
|
+
}
|
|
1996
|
+
return {
|
|
1997
|
+
lineItems,
|
|
1998
|
+
totals: totals ?? [{ type: "total", label: "Total", amountMinor }]
|
|
1999
|
+
};
|
|
2000
|
+
}
|
|
2001
|
+
var _client;
|
|
2002
|
+
var CheckoutClient = class {
|
|
2003
|
+
constructor(client) {
|
|
2004
|
+
__privateAdd(this, _client);
|
|
2005
|
+
__privateSet(this, _client, client);
|
|
2006
|
+
}
|
|
2007
|
+
/** First checkpoint. A ContoError means Conto did not approve: stop the checkout. */
|
|
2008
|
+
async begin(input) {
|
|
2009
|
+
const idempotencyKey = input.idempotencyKey?.trim();
|
|
2010
|
+
if (!idempotencyKey || idempotencyKey.length < 8 || idempotencyKey.length > 255) {
|
|
2011
|
+
throw checkoutError(
|
|
2012
|
+
"idempotencyKey must contain 8 to 255 characters",
|
|
2013
|
+
"INVALID_IDEMPOTENCY_KEY"
|
|
2014
|
+
);
|
|
2015
|
+
}
|
|
2016
|
+
if (input.currency !== void 0 && input.currency !== "USD") {
|
|
2017
|
+
throw checkoutError("Only USD checkouts are supported");
|
|
2018
|
+
}
|
|
2019
|
+
const result = await __privateGet(this, _client).request(
|
|
2020
|
+
"POST",
|
|
2021
|
+
"/api/sdk/checkout-checkpoints",
|
|
2022
|
+
{
|
|
2023
|
+
idempotencyKey,
|
|
2024
|
+
merchant: input.merchant,
|
|
2025
|
+
amountMinor: input.amountMinor,
|
|
2026
|
+
currency: "USD",
|
|
2027
|
+
purpose: input.purpose,
|
|
2028
|
+
...input.category ? { category: input.category } : {},
|
|
2029
|
+
...input.checkoutMethod ? { checkoutMethod: input.checkoutMethod } : {},
|
|
2030
|
+
cart: checkpointCart(input.amountMinor, input.lineItems, input.totals)
|
|
2031
|
+
},
|
|
2032
|
+
{ idempotent: true }
|
|
2033
|
+
);
|
|
2034
|
+
return result.checkpoint;
|
|
2035
|
+
}
|
|
2036
|
+
/**
|
|
2037
|
+
* Second checkpoint, right before the payment is submitted. If the total
|
|
2038
|
+
* changed since begin() (tax or shipping, for example), this cancels the
|
|
2039
|
+
* approved checkpoint and starts a new one at the final total, so the agent's
|
|
2040
|
+
* rules see the amount actually being paid. Pay only if this resolves.
|
|
2041
|
+
*/
|
|
2042
|
+
async confirm(checkpoint, input) {
|
|
2043
|
+
if (input.currency !== void 0 && input.currency !== "USD") {
|
|
2044
|
+
throw checkoutError("Only USD checkouts are supported");
|
|
2045
|
+
}
|
|
2046
|
+
if (!Number.isSafeInteger(input.amountMinor) || input.amountMinor <= 0) {
|
|
2047
|
+
throw checkoutError("amountMinor must be a positive integer number of cents");
|
|
2048
|
+
}
|
|
2049
|
+
let current = checkpoint;
|
|
2050
|
+
if (input.amountMinor !== checkpoint.amountMinor) {
|
|
2051
|
+
try {
|
|
2052
|
+
await this.cancel(checkpoint.id);
|
|
2053
|
+
} catch (error) {
|
|
2054
|
+
const closed = error instanceof ContoError && error.status === 409 && ["CANCELLED", "EXPIRED", "DENIED"].includes((await this.get(checkpoint.id)).stage);
|
|
2055
|
+
if (!closed) throw error;
|
|
2056
|
+
}
|
|
2057
|
+
current = await this.begin({
|
|
2058
|
+
idempotencyKey: `${checkpoint.idempotencyKey.slice(0, 200)}:final-${input.amountMinor}`,
|
|
2059
|
+
merchant: {
|
|
2060
|
+
id: checkpoint.merchant.id,
|
|
2061
|
+
name: checkpoint.merchant.name,
|
|
2062
|
+
checkoutUrl: checkpoint.merchant.checkoutUrl ?? ""
|
|
2063
|
+
},
|
|
2064
|
+
amountMinor: input.amountMinor,
|
|
2065
|
+
purpose: checkpoint.purpose,
|
|
2066
|
+
...checkpoint.category ? { category: checkpoint.category } : {},
|
|
2067
|
+
checkoutMethod: checkpoint.checkoutMethod,
|
|
2068
|
+
lineItems: input.lineItems ?? checkpoint.cart.lineItems,
|
|
2069
|
+
totals: input.totals
|
|
2070
|
+
});
|
|
2071
|
+
}
|
|
2072
|
+
const result = await __privateGet(this, _client).request(
|
|
2073
|
+
"POST",
|
|
2074
|
+
`/api/sdk/checkout-checkpoints/${encodeURIComponent(current.id)}/confirm`,
|
|
2075
|
+
{
|
|
2076
|
+
amountMinor: input.amountMinor,
|
|
2077
|
+
currency: "USD",
|
|
2078
|
+
...input.pageUrl ? { pageUrl: input.pageUrl } : {}
|
|
2079
|
+
},
|
|
2080
|
+
{ idempotent: true }
|
|
2081
|
+
);
|
|
2082
|
+
return result.checkpoint;
|
|
2083
|
+
}
|
|
2084
|
+
/** Report what happened after a confirmed checkpoint. Safe to repeat with the same outcome. */
|
|
2085
|
+
async reportOutcome(checkpointId, input) {
|
|
2086
|
+
const result = await __privateGet(this, _client).request(
|
|
2087
|
+
"POST",
|
|
2088
|
+
`/api/sdk/checkout-checkpoints/${encodeURIComponent(checkpointId)}/outcome`,
|
|
2089
|
+
{
|
|
2090
|
+
outcome: input.outcome,
|
|
2091
|
+
...input.reference ? { reference: input.reference } : {}
|
|
2092
|
+
},
|
|
2093
|
+
{ idempotent: true }
|
|
2094
|
+
);
|
|
2095
|
+
return result.checkpoint;
|
|
2096
|
+
}
|
|
2097
|
+
/** Cancel a checkpoint that was not confirmed and release its spend. */
|
|
2098
|
+
async cancel(checkpointId) {
|
|
2099
|
+
const result = await __privateGet(this, _client).request(
|
|
2100
|
+
"POST",
|
|
2101
|
+
`/api/sdk/checkout-checkpoints/${encodeURIComponent(checkpointId)}/cancel`,
|
|
2102
|
+
{},
|
|
2103
|
+
{ idempotent: true }
|
|
2104
|
+
);
|
|
2105
|
+
return result.checkpoint;
|
|
2106
|
+
}
|
|
2107
|
+
async get(checkpointId) {
|
|
2108
|
+
const result = await __privateGet(this, _client).request(
|
|
2109
|
+
"GET",
|
|
2110
|
+
`/api/sdk/checkout-checkpoints/${encodeURIComponent(checkpointId)}`
|
|
2111
|
+
);
|
|
2112
|
+
return result.checkpoint;
|
|
2113
|
+
}
|
|
2114
|
+
};
|
|
2115
|
+
_client = new WeakMap();
|
|
2116
|
+
var _client2, _defaults;
|
|
1983
2117
|
var LinkClient = class {
|
|
1984
2118
|
constructor(client, defaults) {
|
|
1985
|
-
__privateAdd(this,
|
|
2119
|
+
__privateAdd(this, _client2);
|
|
1986
2120
|
__privateAdd(this, _defaults);
|
|
1987
|
-
__privateSet(this,
|
|
2121
|
+
__privateSet(this, _client2, client);
|
|
1988
2122
|
__privateSet(this, _defaults, defaults ? { ...defaults } : void 0);
|
|
1989
2123
|
}
|
|
1990
2124
|
/** Inspect the configured live path. This is not a payment authorization or provider connectivity test. */
|
|
1991
2125
|
async setup(input = {}) {
|
|
1992
|
-
return __privateGet(this,
|
|
2126
|
+
return __privateGet(this, _client2).getLinkSetup({
|
|
1993
2127
|
connectionId: input.connectionId ?? __privateGet(this, _defaults)?.connectionId,
|
|
1994
2128
|
paymentMethodId: input.paymentMethodId ?? __privateGet(this, _defaults)?.paymentMethodId,
|
|
1995
2129
|
merchantId: input.merchantId
|
|
@@ -1997,7 +2131,7 @@ var LinkClient = class {
|
|
|
1997
2131
|
}
|
|
1998
2132
|
/** Read masked LIVE funding sources; never selects a source or initiates payment. */
|
|
1999
2133
|
async paymentMethods(connectionId) {
|
|
2000
|
-
return __privateGet(this,
|
|
2134
|
+
return __privateGet(this, _client2).listStripeLinkPaymentMethods(
|
|
2001
2135
|
this.identifier(connectionId ?? __privateGet(this, _defaults)?.connectionId, "connectionId"),
|
|
2002
2136
|
{ mode: "LIVE" }
|
|
2003
2137
|
);
|
|
@@ -2042,7 +2176,7 @@ var LinkClient = class {
|
|
|
2042
2176
|
}
|
|
2043
2177
|
);
|
|
2044
2178
|
}
|
|
2045
|
-
const result = await __privateGet(this,
|
|
2179
|
+
const result = await __privateGet(this, _client2).beginCommerceExecution({
|
|
2046
2180
|
executionMethod: "LINK_PAY_TOKEN",
|
|
2047
2181
|
connectionId,
|
|
2048
2182
|
paymentMethodId,
|
|
@@ -2069,25 +2203,25 @@ var LinkClient = class {
|
|
|
2069
2203
|
*/
|
|
2070
2204
|
async resume(executionId) {
|
|
2071
2205
|
const id = this.identifier(executionId, "executionId");
|
|
2072
|
-
const current = await __privateGet(this,
|
|
2206
|
+
const current = await __privateGet(this, _client2).getCommerceExecution(id);
|
|
2073
2207
|
this.assertLinkExecution(current);
|
|
2074
2208
|
if (["AUTHORIZING", "AWAITING_APPROVAL", "ACTION_REQUIRED"].includes(current.execution.status)) {
|
|
2075
|
-
return this.executeIfReady(await __privateGet(this,
|
|
2209
|
+
return this.executeIfReady(await __privateGet(this, _client2).refreshCommerceExecution(id));
|
|
2076
2210
|
}
|
|
2077
2211
|
return this.executeIfReady(current);
|
|
2078
2212
|
}
|
|
2079
2213
|
/** Observe and reconcile provider state. This method never submits a payment. */
|
|
2080
2214
|
async status(executionId) {
|
|
2081
2215
|
const id = this.identifier(executionId, "executionId");
|
|
2082
|
-
this.assertLinkExecution(await __privateGet(this,
|
|
2083
|
-
return this.result(await __privateGet(this,
|
|
2216
|
+
this.assertLinkExecution(await __privateGet(this, _client2).getCommerceExecution(id));
|
|
2217
|
+
return this.result(await __privateGet(this, _client2).refreshCommerceExecution(id));
|
|
2084
2218
|
}
|
|
2085
2219
|
/** Request cancellation of this existing Link payment; never retried automatically. */
|
|
2086
2220
|
async cancel(executionId) {
|
|
2087
2221
|
const id = this.identifier(executionId, "executionId");
|
|
2088
|
-
this.assertLinkExecution(await __privateGet(this,
|
|
2222
|
+
this.assertLinkExecution(await __privateGet(this, _client2).getCommerceExecution(id));
|
|
2089
2223
|
try {
|
|
2090
|
-
return this.result(await __privateGet(this,
|
|
2224
|
+
return this.result(await __privateGet(this, _client2).cancelCommerceExecution(id));
|
|
2091
2225
|
} catch (error) {
|
|
2092
2226
|
throw new LinkPaymentExecutionError(id, error);
|
|
2093
2227
|
}
|
|
@@ -2117,7 +2251,7 @@ var LinkClient = class {
|
|
|
2117
2251
|
this.assertLinkExecution(result);
|
|
2118
2252
|
if (result.execution.status !== "READY") return this.result(result);
|
|
2119
2253
|
try {
|
|
2120
|
-
return this.result(await __privateGet(this,
|
|
2254
|
+
return this.result(await __privateGet(this, _client2).executeCommerceExecution(result.execution.id));
|
|
2121
2255
|
} catch (error) {
|
|
2122
2256
|
throw new LinkPaymentExecutionError(result.execution.id, error);
|
|
2123
2257
|
}
|
|
@@ -2147,12 +2281,13 @@ var LinkClient = class {
|
|
|
2147
2281
|
};
|
|
2148
2282
|
}
|
|
2149
2283
|
};
|
|
2150
|
-
|
|
2284
|
+
_client2 = new WeakMap();
|
|
2151
2285
|
_defaults = new WeakMap();
|
|
2152
2286
|
export {
|
|
2153
2287
|
BrowserActionFinalizationPendingError,
|
|
2154
2288
|
BrowserCheckoutTargetVerificationError,
|
|
2155
2289
|
CardsClient,
|
|
2290
|
+
CheckoutClient,
|
|
2156
2291
|
ConnectedCardsClient,
|
|
2157
2292
|
Conto,
|
|
2158
2293
|
ContoAdmin,
|
package/dist/link-testing.d.mts
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
import { LinkPaymentResult, LinkSetupInput, LinkSetupResult, ListStripeLinkPaymentMethodsResult, LinkPaymentInput } from './index.mjs';
|
|
1
|
+
import { CommerceExecution, CommerceExecutionEvidence, LinkPaymentResult, LinkSetupInput, LinkSetupResult, ListStripeLinkPaymentMethodsResult, LinkPaymentInput } from './index.mjs';
|
|
2
2
|
|
|
3
3
|
type LinkTestScenario = 'approved' | 'denied' | 'expired' | 'interrupted';
|
|
4
|
+
/** Evidence created by the local simulator. It is never a receipt. */
|
|
5
|
+
type SimulatedCommerceExecutionEvidence = CommerceExecutionEvidence & {
|
|
6
|
+
mode: 'SIMULATED';
|
|
7
|
+
};
|
|
8
|
+
/** Execution record created by the local simulator. It does not exist on any Conto server. */
|
|
9
|
+
type SimulatedCommerceExecution = CommerceExecution & {
|
|
10
|
+
mode: 'SIMULATED';
|
|
11
|
+
evidence: SimulatedCommerceExecutionEvidence;
|
|
12
|
+
};
|
|
4
13
|
type SimulatedLinkPaymentResult = LinkPaymentResult & {
|
|
5
14
|
mode: 'SIMULATED';
|
|
6
15
|
settlementVerified: false;
|
|
16
|
+
execution: SimulatedCommerceExecution;
|
|
7
17
|
};
|
|
8
18
|
interface LinkTestOptions {
|
|
9
19
|
scenario?: LinkTestScenario;
|
|
@@ -12,7 +22,9 @@ interface LinkTestOptions {
|
|
|
12
22
|
}
|
|
13
23
|
/**
|
|
14
24
|
* Create an isolated in-memory test account with the same pay/resume/status API.
|
|
15
|
-
* Approval is explicit through link.approve(), a test-only method.
|
|
25
|
+
* Approval is explicit through link.approve(), a test-only method. Like the live
|
|
26
|
+
* API, an accepted submission is PROCESSING and only a later status() call
|
|
27
|
+
* reports SETTLED. No money moves, and every result has settlementVerified false.
|
|
16
28
|
*/
|
|
17
29
|
declare function createLinkTestClient(options?: LinkTestOptions): {
|
|
18
30
|
mode: "SIMULATED";
|
|
@@ -34,4 +46,4 @@ declare function createLinkTestClient(options?: LinkTestOptions): {
|
|
|
34
46
|
};
|
|
35
47
|
};
|
|
36
48
|
|
|
37
|
-
export { type LinkTestOptions, type LinkTestScenario, type SimulatedLinkPaymentResult, createLinkTestClient };
|
|
49
|
+
export { type LinkTestOptions, type LinkTestScenario, type SimulatedCommerceExecution, type SimulatedCommerceExecutionEvidence, type SimulatedLinkPaymentResult, createLinkTestClient };
|
package/dist/link-testing.d.ts
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
import { LinkPaymentResult, LinkSetupInput, LinkSetupResult, ListStripeLinkPaymentMethodsResult, LinkPaymentInput } from './index.js';
|
|
1
|
+
import { CommerceExecution, CommerceExecutionEvidence, LinkPaymentResult, LinkSetupInput, LinkSetupResult, ListStripeLinkPaymentMethodsResult, LinkPaymentInput } from './index.js';
|
|
2
2
|
|
|
3
3
|
type LinkTestScenario = 'approved' | 'denied' | 'expired' | 'interrupted';
|
|
4
|
+
/** Evidence created by the local simulator. It is never a receipt. */
|
|
5
|
+
type SimulatedCommerceExecutionEvidence = CommerceExecutionEvidence & {
|
|
6
|
+
mode: 'SIMULATED';
|
|
7
|
+
};
|
|
8
|
+
/** Execution record created by the local simulator. It does not exist on any Conto server. */
|
|
9
|
+
type SimulatedCommerceExecution = CommerceExecution & {
|
|
10
|
+
mode: 'SIMULATED';
|
|
11
|
+
evidence: SimulatedCommerceExecutionEvidence;
|
|
12
|
+
};
|
|
4
13
|
type SimulatedLinkPaymentResult = LinkPaymentResult & {
|
|
5
14
|
mode: 'SIMULATED';
|
|
6
15
|
settlementVerified: false;
|
|
16
|
+
execution: SimulatedCommerceExecution;
|
|
7
17
|
};
|
|
8
18
|
interface LinkTestOptions {
|
|
9
19
|
scenario?: LinkTestScenario;
|
|
@@ -12,7 +22,9 @@ interface LinkTestOptions {
|
|
|
12
22
|
}
|
|
13
23
|
/**
|
|
14
24
|
* Create an isolated in-memory test account with the same pay/resume/status API.
|
|
15
|
-
* Approval is explicit through link.approve(), a test-only method.
|
|
25
|
+
* Approval is explicit through link.approve(), a test-only method. Like the live
|
|
26
|
+
* API, an accepted submission is PROCESSING and only a later status() call
|
|
27
|
+
* reports SETTLED. No money moves, and every result has settlementVerified false.
|
|
16
28
|
*/
|
|
17
29
|
declare function createLinkTestClient(options?: LinkTestOptions): {
|
|
18
30
|
mode: "SIMULATED";
|
|
@@ -34,4 +46,4 @@ declare function createLinkTestClient(options?: LinkTestOptions): {
|
|
|
34
46
|
};
|
|
35
47
|
};
|
|
36
48
|
|
|
37
|
-
export { type LinkTestOptions, type LinkTestScenario, type SimulatedLinkPaymentResult, createLinkTestClient };
|
|
49
|
+
export { type LinkTestOptions, type LinkTestScenario, type SimulatedCommerceExecution, type SimulatedCommerceExecutionEvidence, type SimulatedLinkPaymentResult, createLinkTestClient };
|