@conto_finance/sdk 0.6.0-beta.2 → 0.6.1

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/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.2",
20
+ version: "0.6.1",
21
21
  description: "Conto SDK for AI agent payment authorization",
22
22
  main: "./dist/index.js",
23
23
  module: "./dist/index.mjs",
@@ -42,16 +42,10 @@ var require_package = __commonJS({
42
42
  types: "./dist/checkout-verifier.d.ts",
43
43
  import: "./dist/checkout-verifier.mjs",
44
44
  require: "./dist/checkout-verifier.js"
45
- },
46
- "./link-testing": {
47
- types: "./dist/link-testing.d.ts",
48
- import: "./dist/link-testing.mjs",
49
- require: "./dist/link-testing.js"
50
45
  }
51
46
  },
52
47
  publishConfig: {
53
- access: "public",
54
- tag: "beta"
48
+ access: "public"
55
49
  },
56
50
  engines: {
57
51
  node: ">=20.19.0"
@@ -64,7 +58,7 @@ var require_package = __commonJS({
64
58
  dev: "tsup --watch",
65
59
  lint: "tsc --noEmit",
66
60
  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 test/checkout.test.mjs",
61
+ "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 test/purchases.test.mjs",
68
62
  "test:consumer": "npm run build && node --test test/consumer.test.mjs",
69
63
  "verify:release": "node scripts/verify-release.mjs",
70
64
  prepublishOnly: "npm run verify:release && npm run lint && npm run test:contract && npm run test:consumer"
@@ -129,6 +123,372 @@ var import_package_version2 = __toESM(require_package_version());
129
123
  import * as Sentry2 from "@sentry/node";
130
124
  import { randomUUID } from "crypto";
131
125
 
126
+ // src/purchases.ts
127
+ import { createHmac, timingSafeEqual } from "crypto";
128
+ var TERMINAL = /* @__PURE__ */ new Set(["succeeded", "blocked", "failed", "cancelled"]);
129
+ var isFinalPurchaseStatus = (status) => TERMINAL.has(status);
130
+ async function* parseServerSentEvents(body) {
131
+ const reader = body.getReader();
132
+ const decoder = new TextDecoder();
133
+ let buffer = "";
134
+ let frame = { data: [] };
135
+ try {
136
+ while (true) {
137
+ const { value, done } = await reader.read();
138
+ if (done) break;
139
+ buffer += decoder.decode(value, { stream: true });
140
+ let newline;
141
+ while ((newline = buffer.search(/\r?\n/)) >= 0) {
142
+ const line = buffer.slice(0, newline);
143
+ buffer = buffer.slice(newline + (buffer[newline] === "\r" ? 2 : 1));
144
+ if (line === "") {
145
+ if (frame.data.length || frame.event)
146
+ yield { id: frame.id, event: frame.event ?? "message", data: frame.data.join("\n") };
147
+ frame = { data: [] };
148
+ continue;
149
+ }
150
+ if (line.startsWith(":")) continue;
151
+ const colon = line.indexOf(":");
152
+ const field = colon < 0 ? line : line.slice(0, colon);
153
+ const raw = colon < 0 ? "" : line.slice(colon + 1).replace(/^ /, "");
154
+ if (field === "id") frame.id = raw;
155
+ else if (field === "event") frame.event = raw;
156
+ else if (field === "data") frame.data.push(raw);
157
+ }
158
+ }
159
+ } finally {
160
+ reader.releaseLock();
161
+ }
162
+ }
163
+ var sleep = (ms, signal) => new Promise((resolve) => {
164
+ const timer = setTimeout(resolve, ms);
165
+ signal?.addEventListener(
166
+ "abort",
167
+ () => {
168
+ clearTimeout(timer);
169
+ resolve();
170
+ },
171
+ { once: true }
172
+ );
173
+ });
174
+ function requirePurchaseId(id) {
175
+ if (!/^[a-z0-9]{8,64}$/i.test(id)) throw new TypeError("purchase id is not valid");
176
+ return encodeURIComponent(id);
177
+ }
178
+ function requireCycleKey(key) {
179
+ if (!/^[A-Za-z0-9._:-]{1,100}$/.test(key)) throw new TypeError("cycleKey is not valid");
180
+ return encodeURIComponent(key);
181
+ }
182
+ var _transport, _base;
183
+ var RecurringPurchasesClient = class {
184
+ constructor(transport, basePath = "/api/sdk/recurring-purchases") {
185
+ __privateAdd(this, _transport);
186
+ __privateAdd(this, _base);
187
+ __privateSet(this, _transport, transport);
188
+ __privateSet(this, _base, basePath);
189
+ }
190
+ async list(buyerId) {
191
+ return __privateGet(this, _transport).request(
192
+ "GET",
193
+ buyerId ? `${__privateGet(this, _base)}?buyerId=${encodeURIComponent(buyerId)}` : __privateGet(this, _base)
194
+ );
195
+ }
196
+ async get(id) {
197
+ return __privateGet(this, _transport).request("GET", `${__privateGet(this, _base)}/${requirePurchaseId(id)}`);
198
+ }
199
+ /** Starts one order. The same cycle key returns the same order. */
200
+ async startCycle(id, cycleKey) {
201
+ requireCycleKey(cycleKey);
202
+ return __privateGet(this, _transport).request(
203
+ "POST",
204
+ `${__privateGet(this, _base)}/${requirePurchaseId(id)}/cycles`,
205
+ { cycleKey },
206
+ { idempotent: true }
207
+ );
208
+ }
209
+ /** Skips one order, also before it starts. */
210
+ async skipCycle(id, cycleKey) {
211
+ return __privateGet(this, _transport).request(
212
+ "POST",
213
+ `${__privateGet(this, _base)}/${requirePurchaseId(id)}/cycles/${requireCycleKey(cycleKey)}/skip`
214
+ );
215
+ }
216
+ };
217
+ _transport = new WeakMap();
218
+ _base = new WeakMap();
219
+ var _client;
220
+ var OrganizationRecurringPurchasesClient = class extends RecurringPurchasesClient {
221
+ constructor(client) {
222
+ super(client, "/api/purchasing/recurring-purchases");
223
+ __privateAdd(this, _client);
224
+ __privateSet(this, _client, client);
225
+ }
226
+ /** Stops a repeat order. An order waiting for its payment time closes unpaid. */
227
+ async cancel(id) {
228
+ return __privateGet(this, _client).request(
229
+ "POST",
230
+ `/api/purchasing/recurring-purchases/${requirePurchaseId(id)}/cancel`
231
+ );
232
+ }
233
+ };
234
+ _client = new WeakMap();
235
+ var _transport2, _base2;
236
+ var PurchasesClient = class {
237
+ constructor(transport, basePath = "/api/sdk/purchases") {
238
+ __privateAdd(this, _transport2);
239
+ __privateAdd(this, _base2);
240
+ __privateSet(this, _transport2, transport);
241
+ __privateSet(this, _base2, basePath);
242
+ }
243
+ /**
244
+ * Starts a purchase and returns at once. Reusing the idempotency key with the
245
+ * same input returns the same purchase, so retrying after a lost response is safe.
246
+ */
247
+ async create(input, options) {
248
+ const idempotencyKey = options?.idempotencyKey?.trim();
249
+ if (!idempotencyKey || idempotencyKey.length < 8 || idempotencyKey.length > 255)
250
+ throw new TypeError("idempotencyKey must contain 8 to 255 characters");
251
+ if (!Number.isSafeInteger(input.maxCost?.amountMinor) || input.maxCost.amountMinor <= 0)
252
+ throw new TypeError("maxCost.amountMinor must be a positive integer");
253
+ return __privateGet(this, _transport2).request(
254
+ "POST",
255
+ __privateGet(this, _base2),
256
+ { ...input, idempotencyKey },
257
+ { idempotent: true }
258
+ );
259
+ }
260
+ async list(params = {}) {
261
+ const query = new URLSearchParams();
262
+ for (const [key, value] of Object.entries(params))
263
+ if (value !== void 0) query.set(key, String(value));
264
+ const suffix = query.toString();
265
+ return __privateGet(this, _transport2).request("GET", `${__privateGet(this, _base2)}${suffix ? `?${suffix}` : ""}`);
266
+ }
267
+ async get(id) {
268
+ return __privateGet(this, _transport2).request("GET", `${__privateGet(this, _base2)}/${requirePurchaseId(id)}`);
269
+ }
270
+ /**
271
+ * Answers an open action whose authority is `agent_or_buyer` with the fields
272
+ * it lists. The acknowledgment means recorded; the purchase shows the result.
273
+ * The same answer again returns the same acknowledgment.
274
+ */
275
+ async respond(id, input) {
276
+ return __privateGet(this, _transport2).request(
277
+ "POST",
278
+ `${__privateGet(this, _base2)}/${requirePurchaseId(id)}/responses`,
279
+ input,
280
+ { idempotent: true }
281
+ );
282
+ }
283
+ async events(id, params = {}) {
284
+ const query = new URLSearchParams({ after: String(params.after ?? 0) });
285
+ if (params.limit) query.set("limit", String(params.limit));
286
+ return __privateGet(this, _transport2).request("GET", `${__privateGet(this, _base2)}/${requirePurchaseId(id)}/events?${query}`);
287
+ }
288
+ /**
289
+ * Requests cancellation. Before payment the purchase stops. Once payment may
290
+ * have been submitted, `cancellationOutcome` is `too_late` and the purchase
291
+ * stays in reconciliation. Nothing is refunded by this call.
292
+ */
293
+ async cancel(id) {
294
+ return __privateGet(this, _transport2).request(
295
+ "POST",
296
+ `${__privateGet(this, _base2)}/${requirePurchaseId(id)}/cancel`,
297
+ void 0,
298
+ { idempotent: true }
299
+ );
300
+ }
301
+ /**
302
+ * Yields the purchase's events in version order until it reaches a final
303
+ * status. Streams with server-sent events and reconnects from the last
304
+ * version; falls back to polling where streaming is unavailable. A duplicate
305
+ * after a reconnect is dropped. A `purchase.resync` event carries the
306
+ * current purchase when the cursor could not be resumed.
307
+ */
308
+ async *watch(id, options = {}) {
309
+ const path = `${__privateGet(this, _base2)}/${requirePurchaseId(id)}`;
310
+ const mode = options.mode ?? "auto";
311
+ const interval = Math.max(500, options.pollIntervalMs ?? 2e3);
312
+ const deadline = options.maxWaitMs ? Date.now() + options.maxWaitMs : Infinity;
313
+ let cursor = Math.max(0, options.after ?? 0);
314
+ let streaming = mode !== "poll";
315
+ const emit = (event) => {
316
+ if (event.version <= cursor && event.type !== "purchase.resync") return null;
317
+ cursor = Math.max(cursor, event.version);
318
+ return event;
319
+ };
320
+ while (!options.signal?.aborted && Date.now() < deadline) {
321
+ if (streaming) {
322
+ try {
323
+ const response = await __privateGet(this, _transport2).openStream(
324
+ `${path}/events/stream?after=${cursor}`,
325
+ { signal: options.signal, lastEventId: String(cursor) }
326
+ );
327
+ if (!response.body) throw new Error("streaming unavailable");
328
+ for await (const frame of parseServerSentEvents(response.body)) {
329
+ if (frame.event === "end") return;
330
+ if (frame.event === "error") break;
331
+ if (frame.event === "resync") {
332
+ const purchase = JSON.parse(frame.data);
333
+ const event2 = {
334
+ id: `resync:${purchase.version}`,
335
+ purchaseId: purchase.id,
336
+ version: purchase.version,
337
+ type: "purchase.resync",
338
+ createdAt: purchase.updatedAt,
339
+ data: purchase
340
+ };
341
+ cursor = purchase.version;
342
+ yield event2;
343
+ if (isFinalPurchaseStatus(purchase.status)) return;
344
+ continue;
345
+ }
346
+ if (!frame.data) continue;
347
+ const event = emit(JSON.parse(frame.data));
348
+ if (!event) continue;
349
+ yield event;
350
+ if (isFinalPurchaseStatus(event.data.status)) return;
351
+ }
352
+ continue;
353
+ } catch (error) {
354
+ if (options.signal?.aborted) return;
355
+ if (isClientError(error)) throw error;
356
+ if (mode === "stream") {
357
+ await sleep(interval, options.signal);
358
+ continue;
359
+ }
360
+ streaming = false;
361
+ }
362
+ }
363
+ let page;
364
+ try {
365
+ page = await this.events(id, { after: cursor, limit: 100 });
366
+ } catch (error) {
367
+ if (codeOf(error) !== "CURSOR_INVALID") throw error;
368
+ const purchase = await this.get(id);
369
+ cursor = purchase.version;
370
+ yield {
371
+ id: `resync:${purchase.version}`,
372
+ purchaseId: purchase.id,
373
+ version: purchase.version,
374
+ type: "purchase.resync",
375
+ createdAt: purchase.updatedAt,
376
+ data: purchase
377
+ };
378
+ if (isFinalPurchaseStatus(purchase.status)) return;
379
+ continue;
380
+ }
381
+ for (const item of page.items) {
382
+ const event = emit(item);
383
+ if (!event) continue;
384
+ yield event;
385
+ if (isFinalPurchaseStatus(event.data.status)) return;
386
+ }
387
+ if (!page.hasMore) await sleep(interval, options.signal);
388
+ }
389
+ }
390
+ };
391
+ _transport2 = new WeakMap();
392
+ _base2 = new WeakMap();
393
+ var codeOf = (error) => error && typeof error === "object" && "code" in error ? String(error.code) : "";
394
+ var isClientError = (error) => {
395
+ const status = error && typeof error === "object" && "status" in error ? Number(error.status) : 0;
396
+ return status >= 400 && status < 500 && status !== 408 && status !== 429;
397
+ };
398
+ var enc = encodeURIComponent;
399
+ var _client2;
400
+ var OrganizationPurchasesClient = class extends PurchasesClient {
401
+ constructor(client) {
402
+ super(client, "/api/purchasing/purchases");
403
+ __privateAdd(this, _client2);
404
+ __privateSet(this, _client2, client);
405
+ }
406
+ async list(params = {}) {
407
+ const query = new URLSearchParams();
408
+ for (const [key, value] of Object.entries(params))
409
+ if (value !== void 0) query.set(key, String(value));
410
+ const suffix = query.toString();
411
+ return __privateGet(this, _client2).request("GET", `/api/purchasing/purchases${suffix ? `?${suffix}` : ""}`);
412
+ }
413
+ /** A single-use link that opens the purchase's buyer actions on Conto's hosted page. */
414
+ createActionLink(id, input = {}) {
415
+ return __privateGet(this, _client2).request(
416
+ "POST",
417
+ `/api/purchasing/purchases/${requirePurchaseId(id)}/action-sessions`,
418
+ input
419
+ );
420
+ }
421
+ };
422
+ _client2 = new WeakMap();
423
+ var _client3;
424
+ var AdminPurchasingClient = class {
425
+ constructor(client) {
426
+ __privateAdd(this, _client3);
427
+ this.buyers = {
428
+ /** Maps one of your users to a buyer with its own agent, or returns the existing one. */
429
+ create: (input) => __privateGet(this, _client3).request("POST", "/api/purchasing/buyers", input),
430
+ get: (id) => __privateGet(this, _client3).request("GET", `/api/purchasing/buyers/${enc(id)}`),
431
+ list: (params = {}) => __privateGet(this, _client3).request("GET", `/api/purchasing/buyers?limit=${params.limit ?? 20}&offset=${params.offset ?? 0}`),
432
+ /** Stops the buyer's agent. Purchases that may already be paid stay visible. */
433
+ stop: (id) => __privateGet(this, _client3).request("POST", `/api/purchasing/buyers/${enc(id)}/stop`)
434
+ };
435
+ this.paymentMethods = {
436
+ /** A single-use link to the hosted setup page: limits, card and delegation. */
437
+ createSetupLink: (input) => __privateGet(this, _client3).request(
438
+ "POST",
439
+ "/api/purchasing/payment-methods/setup-sessions",
440
+ input
441
+ ),
442
+ list: (buyerId) => __privateGet(this, _client3).request(
443
+ "GET",
444
+ `/api/purchasing/payment-methods?buyerId=${enc(buyerId)}`
445
+ ),
446
+ remove: (id) => __privateGet(this, _client3).request(
447
+ "DELETE",
448
+ `/api/purchasing/payment-methods/${enc(id)}`
449
+ )
450
+ };
451
+ this.delegations = {
452
+ list: (buyerId) => __privateGet(this, _client3).request(
453
+ "GET",
454
+ `/api/purchasing/delegations?buyerId=${enc(buyerId)}`
455
+ ),
456
+ get: (id) => __privateGet(this, _client3).request("GET", `/api/purchasing/delegations/${enc(id)}`),
457
+ revoke: (id) => __privateGet(this, _client3).request(
458
+ "POST",
459
+ `/api/purchasing/delegations/${enc(id)}/revoke`
460
+ )
461
+ };
462
+ this.settings = {
463
+ get: () => __privateGet(this, _client3).request("GET", "/api/purchasing/settings"),
464
+ update: (input) => __privateGet(this, _client3).request(
465
+ "PUT",
466
+ "/api/purchasing/settings",
467
+ input
468
+ )
469
+ };
470
+ __privateSet(this, _client3, client);
471
+ this.purchases = new OrganizationPurchasesClient(client);
472
+ this.recurringPurchases = new OrganizationRecurringPurchasesClient(client);
473
+ }
474
+ /** What this organization can run now: test mode always, live once Conto enables it. */
475
+ capabilities() {
476
+ return __privateGet(this, _client3).request("GET", "/api/purchasing/capabilities");
477
+ }
478
+ };
479
+ _client3 = new WeakMap();
480
+ function verifyPurchaseWebhook(input) {
481
+ const expected = createHmac("sha256", input.secret).update(input.body).digest();
482
+ const received = Buffer.from(input.signature ?? "", "hex");
483
+ if (received.length !== expected.length || !timingSafeEqual(received, expected))
484
+ throw new Error("Invalid webhook signature");
485
+ const payload = JSON.parse(input.body);
486
+ const age = ((input.now ?? /* @__PURE__ */ new Date()).getTime() - Date.parse(payload.timestamp)) / 1e3;
487
+ if (!Number.isFinite(age) || Math.abs(age) > (input.toleranceSeconds ?? 300))
488
+ throw new Error("Webhook timestamp is outside the tolerance");
489
+ return payload;
490
+ }
491
+
132
492
  // src/http.ts
133
493
  var PUBLIC_PAYMENT_REASONS = /* @__PURE__ */ new Set([
134
494
  "The available balance is insufficient for this payment.",
@@ -386,15 +746,51 @@ var ContoAdmin = class {
386
746
  this.cards = new AdminCardsClient(this);
387
747
  this.policies = new PoliciesClient(this);
388
748
  this.team = new TeamClient(this);
389
- this.paymentRails = new PaymentRailsClient(this);
749
+ this.purchasing = new AdminPurchasingClient(this);
390
750
  }
391
- /** Make an authenticated request to the Conto API */
392
- async request(method, path, body) {
751
+ /**
752
+ * Opens an authenticated server-sent event stream. Used by
753
+ * `purchasing.purchases.watch()`. The server closes it after about 50 seconds.
754
+ * @internal
755
+ */
756
+ async openStream(path, init = {}) {
757
+ const controller = new AbortController();
758
+ const abort = () => controller.abort();
759
+ init.signal?.addEventListener("abort", abort, { once: true });
760
+ const timeoutId = setTimeout(abort, Math.max(this.timeout, 7e4));
761
+ try {
762
+ const response = await fetch(`${this.baseUrl}${path}`, {
763
+ method: "GET",
764
+ headers: {
765
+ Authorization: `Bearer ${__privateGet(this, _orgApiKey)}`,
766
+ Accept: "text/event-stream",
767
+ "User-Agent": `@conto_finance/sdk-admin/${import_package_version.SDK_PACKAGE_VERSION}`,
768
+ ...init.lastEventId ? { "Last-Event-ID": init.lastEventId } : {}
769
+ },
770
+ signal: controller.signal
771
+ });
772
+ if (!response.ok) {
773
+ const data = await readResponseData(response);
774
+ throw new ContoAdminError(
775
+ responseErrorMessage(data, response.status),
776
+ responseErrorMetadata(response, data)
777
+ );
778
+ }
779
+ return response;
780
+ } finally {
781
+ clearTimeout(timeoutId);
782
+ }
783
+ }
784
+ /**
785
+ * Make an authenticated request to the Conto API. Reads retry. A write retries
786
+ * only when `idempotent` says the API deduplicates it, as purchase creation does.
787
+ */
788
+ async request(method, path, body, options = {}) {
393
789
  const url = `${this.baseUrl}${path}`;
394
790
  const controller = new AbortController();
395
791
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
396
792
  const normalizedMethod = method.toUpperCase();
397
- const retryable = ["GET", "HEAD", "OPTIONS"].includes(normalizedMethod);
793
+ const retryable = ["GET", "HEAD", "OPTIONS"].includes(normalizedMethod) || options.idempotent === true;
398
794
  try {
399
795
  const response = await fetchWithRetry(
400
796
  url,
@@ -442,22 +838,6 @@ var ContoAdmin = class {
442
838
  }
443
839
  };
444
840
  _orgApiKey = new WeakMap();
445
- var PaymentRailsClient = class {
446
- constructor(client) {
447
- this.client = client;
448
- }
449
- /** Read gate and configuration readiness without calling Stripe. */
450
- async getStripeLinkCheckoutReadiness() {
451
- return this.client.request("GET", "/api/stripe-link/checkout-readiness");
452
- }
453
- /**
454
- * Ask Conto to verify that its configured Stripe credential resolves to its
455
- * configured merchant account. This call never returns either identifier.
456
- */
457
- async verifyStripeLinkCheckoutAccount() {
458
- return this.client.request("POST", "/api/stripe-link/checkout-readiness");
459
- }
460
- };
461
841
  var AdminCardsClient = class {
462
842
  constructor(client) {
463
843
  this.client = client;
@@ -912,27 +1292,6 @@ var ContoError = class extends Error {
912
1292
  }
913
1293
  }
914
1294
  };
915
- var LinkPaymentExecutionError = class extends ContoError {
916
- constructor(executionId, error) {
917
- const original = error instanceof ContoError ? error : void 0;
918
- super(
919
- original?.message ?? "Link execution could not be confirmed",
920
- {
921
- code: original?.code ?? "LINK_EXECUTION_UNCONFIRMED",
922
- status: original?.status ?? 0,
923
- requestId: original?.requestId,
924
- retryAfter: original?.retryAfter,
925
- fieldErrors: original?.fieldErrors,
926
- reasons: original?.reasons,
927
- retryGuidance: "Call link.status(executionId) to reconcile. Do not create another purchase or retry execution blindly."
928
- },
929
- original?.diagnostics
930
- );
931
- this.nextAction = "RECONCILE";
932
- this.name = "LinkPaymentExecutionError";
933
- this.executionId = executionId;
934
- }
935
- };
936
1295
  var ExternalCardConfirmationPendingError = class extends ContoError {
937
1296
  constructor(requestId, confirmationInput, receipt) {
938
1297
  super("External card execution completed but confirmation is pending", {
@@ -960,6 +1319,52 @@ var BrowserActionFinalizationPendingError = class extends ContoError {
960
1319
  this.observation = input.observation;
961
1320
  }
962
1321
  };
1322
+ var CheckoutCheckpointClosedError = class extends ContoError {
1323
+ constructor(checkpoint, message = `The checkpoint is ${checkpoint.stage.toLowerCase().replace(/_/g, " ")}. Stop this checkout.`, code = "CHECKOUT_CHECKPOINT_CLOSED") {
1324
+ super(message, { code, status: 0 });
1325
+ this.name = "CheckoutCheckpointClosedError";
1326
+ this.checkpoint = checkpoint;
1327
+ this.stage = checkpoint.stage;
1328
+ }
1329
+ };
1330
+ var CheckoutApprovalDeniedError = class extends CheckoutCheckpointClosedError {
1331
+ constructor(checkpoint) {
1332
+ super(checkpoint, "The owner rejected this purchase. Do not pay.", "CHECKOUT_APPROVAL_DENIED");
1333
+ this.name = "CheckoutApprovalDeniedError";
1334
+ }
1335
+ };
1336
+ var CheckoutApprovalExpiredError = class extends CheckoutCheckpointClosedError {
1337
+ constructor(checkpoint) {
1338
+ super(
1339
+ checkpoint,
1340
+ "The owner did not approve this purchase in time. Do not pay.",
1341
+ "CHECKOUT_APPROVAL_EXPIRED"
1342
+ );
1343
+ this.name = "CheckoutApprovalExpiredError";
1344
+ }
1345
+ };
1346
+ var CheckoutApprovalPendingError = class extends ContoError {
1347
+ constructor(checkpoint) {
1348
+ super("The owner has not approved this purchase yet. Do not pay.", {
1349
+ code: "CHECKOUT_APPROVAL_PENDING",
1350
+ status: 0,
1351
+ retryGuidance: "Call checkout.waitForApproval(error.checkpoint), then confirm the approved checkpoint."
1352
+ });
1353
+ this.name = "CheckoutApprovalPendingError";
1354
+ this.checkpoint = checkpoint;
1355
+ }
1356
+ };
1357
+ var CheckoutApprovalTimeoutError = class extends ContoError {
1358
+ constructor(checkpoint) {
1359
+ super("The owner has not decided yet. Do not pay.", {
1360
+ code: "CHECKOUT_APPROVAL_TIMEOUT",
1361
+ status: 0,
1362
+ retryGuidance: "Wait again with checkout.waitForApproval, or call checkout.cancel to release the held spend."
1363
+ });
1364
+ this.name = "CheckoutApprovalTimeoutError";
1365
+ this.checkpoint = checkpoint;
1366
+ }
1367
+ };
963
1368
  function generatedIdempotencyKey(prefix) {
964
1369
  return `${prefix}_${randomUUID()}`;
965
1370
  }
@@ -1022,7 +1427,6 @@ var Conto = class {
1022
1427
  this.baseUrl = (config.baseUrl || "https://conto.finance").replace(/\/$/, "");
1023
1428
  assertSecureBaseUrl(this.baseUrl);
1024
1429
  this.timeout = config.timeout || 3e4;
1025
- this.link = new LinkClient(this, config.link);
1026
1430
  this.checkout = new CheckoutClient(this);
1027
1431
  this.payments = new PaymentsClient(this);
1028
1432
  this.cards = new CardsClient(this);
@@ -1030,31 +1434,8 @@ var Conto = class {
1030
1434
  this.testCards = new TestCardsClient(this);
1031
1435
  this.x402 = new X402Client(this);
1032
1436
  this.mpp = new MppClient(this);
1033
- }
1034
- /**
1035
- * List masked Link payment methods for a session-created connection that is
1036
- * explicitly bound to this agent. No Link token or payment artifact is
1037
- * returned through the agent SDK.
1038
- */
1039
- async listStripeLinkPaymentMethods(connectionId, options) {
1040
- return this.request(
1041
- "GET",
1042
- withQuery("/api/sdk/stripe-link/payment-methods", {
1043
- connectionId,
1044
- ...options?.mode ? { mode: options.mode } : {}
1045
- })
1046
- );
1047
- }
1048
- /** Read live Link configuration diagnostics without retrieving credentials or authorizing payment. */
1049
- async getLinkSetup(input = {}) {
1050
- return this.request(
1051
- "GET",
1052
- withQuery("/api/sdk/stripe-link/setup", {
1053
- connectionId: input.connectionId,
1054
- paymentMethodId: input.paymentMethodId,
1055
- merchantId: input.merchantId
1056
- })
1057
- );
1437
+ this.purchases = new PurchasesClient(this);
1438
+ this.recurringPurchases = new RecurringPurchasesClient(this);
1058
1439
  }
1059
1440
  /**
1060
1441
  * Normalize and durably revise a partial agent purchase proposal without
@@ -1136,6 +1517,22 @@ var Conto = class {
1136
1517
  rethrowAmbiguousCommerceMutation(error, executionId, "authorize");
1137
1518
  }
1138
1519
  }
1520
+ /**
1521
+ * Report whether an authorized guarded browser checkout was paid. PAID keeps
1522
+ * the held spend counted, NOT_PAID releases it, and UNKNOWN keeps it held for
1523
+ * the owner to review. Safe to repeat with the same outcome.
1524
+ */
1525
+ async reportCommerceExecutionOutcome(executionId, input) {
1526
+ return this.request(
1527
+ "POST",
1528
+ `/api/sdk/commerce-executions/${encodeURIComponent(executionId)}/outcome`,
1529
+ {
1530
+ outcome: input.outcome,
1531
+ ...input.reference ? { reference: input.reference } : {}
1532
+ },
1533
+ { idempotent: true }
1534
+ );
1535
+ }
1139
1536
  /** Claim a durable browser action for one stable privileged-runtime attempt. */
1140
1537
  async claimBrowserAction(authorizationId, dispatchAttemptId, browserSessionId, action) {
1141
1538
  return this.request(
@@ -1323,6 +1720,39 @@ var Conto = class {
1323
1720
  async setup() {
1324
1721
  return this.request("GET", "/api/sdk/setup");
1325
1722
  }
1723
+ /**
1724
+ * Opens an authenticated server-sent event stream. Used by
1725
+ * `purchases.watch()`. The server closes it after about 50 seconds.
1726
+ * @internal
1727
+ */
1728
+ async openStream(path, init = {}) {
1729
+ const controller = new AbortController();
1730
+ const abort = () => controller.abort();
1731
+ init.signal?.addEventListener("abort", abort, { once: true });
1732
+ const timeoutId = setTimeout(abort, Math.max(this.timeout, 7e4));
1733
+ try {
1734
+ const response = await fetch(`${this.baseUrl}${path}`, {
1735
+ method: "GET",
1736
+ headers: {
1737
+ Authorization: `Bearer ${__privateGet(this, _apiKey)}`,
1738
+ Accept: "text/event-stream",
1739
+ "User-Agent": `@conto_finance/sdk/${import_package_version2.SDK_PACKAGE_VERSION}`,
1740
+ ...init.lastEventId ? { "Last-Event-ID": init.lastEventId } : {}
1741
+ },
1742
+ signal: controller.signal
1743
+ });
1744
+ if (!response.ok) {
1745
+ const data = await readResponseData(response);
1746
+ throw new ContoError(
1747
+ responseErrorMessage(data, response.status),
1748
+ responseErrorMetadata(response, data)
1749
+ );
1750
+ }
1751
+ return response;
1752
+ } finally {
1753
+ clearTimeout(timeoutId);
1754
+ }
1755
+ }
1326
1756
  /** Make an authenticated request to the Conto API */
1327
1757
  async request(method, path, body, options = {}) {
1328
1758
  const url = `${this.baseUrl}${path}`;
@@ -1595,12 +2025,6 @@ var ConnectedCardsClient = class {
1595
2025
  currency: input.currency ?? "USD"
1596
2026
  });
1597
2027
  }
1598
- /**
1599
- * List the connected cards and active mandates this agent may draw against.
1600
- *
1601
- * The response is masked: no PAN and no provider tokens. This is a read-only
1602
- * GET, so transport retry on transient failures is safe.
1603
- */
1604
2028
  /** Record receipt after a fresh draw. Does not confirm checkout or payment settlement. */
1605
2029
  async acknowledgeDelivery(requestId) {
1606
2030
  return this.client.request(
@@ -1610,6 +2034,39 @@ var ConnectedCardsClient = class {
1610
2034
  { idempotent: true }
1611
2035
  );
1612
2036
  }
2037
+ /**
2038
+ * Report what happened with the card number after checkout.
2039
+ *
2040
+ * `USED` at the full approved amount closes the draw. `NOT_USED`, or `USED`
2041
+ * with a smaller `amountMinor`, is recorded and shown to a person, who
2042
+ * confirms it before the held amount is released. A report never releases
2043
+ * held spend by itself and does not confirm settlement. Safe to repeat with
2044
+ * the same report. A different second report gets HTTP 409.
2045
+ *
2046
+ * @example
2047
+ * ```typescript
2048
+ * await conto.connectedCards.reportOutcome(draw.requestId, { outcome: 'USED' });
2049
+ * await conto.connectedCards.reportOutcome(draw.requestId, { outcome: 'USED', amountMinor: 1850 });
2050
+ * await conto.connectedCards.reportOutcome(draw.requestId, { outcome: 'NOT_USED' });
2051
+ * ```
2052
+ */
2053
+ async reportOutcome(requestId, report) {
2054
+ return this.client.request(
2055
+ "POST",
2056
+ `/api/sdk/connected-cards/draws/${encodeURIComponent(requestId)}/outcome`,
2057
+ {
2058
+ outcome: report.outcome,
2059
+ ...report.amountMinor !== void 0 ? { amountMinor: report.amountMinor } : {}
2060
+ },
2061
+ { idempotent: true }
2062
+ );
2063
+ }
2064
+ /**
2065
+ * List the connected cards and active mandates this agent may draw against.
2066
+ *
2067
+ * The response is masked: no PAN and no provider tokens. This is a read-only
2068
+ * GET, so transport retry on transient failures is safe.
2069
+ */
1613
2070
  async list() {
1614
2071
  return this.client.request("GET", "/api/sdk/connected-cards");
1615
2072
  }
@@ -1998,13 +2455,49 @@ function checkpointCart(amountMinor, lineItems, totals) {
1998
2455
  totals: totals ?? [{ type: "total", label: "Total", amountMinor }]
1999
2456
  };
2000
2457
  }
2001
- var _client;
2458
+ var CLOSED_CHECKPOINT_STAGES = [
2459
+ "DENIED",
2460
+ "CANCELLED",
2461
+ "EXPIRED",
2462
+ "NOT_PAID"
2463
+ ];
2464
+ function closedCheckpointError(checkpoint) {
2465
+ if (checkpoint.approval?.status === "DENIED") return new CheckoutApprovalDeniedError(checkpoint);
2466
+ if (checkpoint.approval?.status === "EXPIRED") {
2467
+ return new CheckoutApprovalExpiredError(checkpoint);
2468
+ }
2469
+ return new CheckoutCheckpointClosedError(checkpoint);
2470
+ }
2471
+ function sleep2(ms, signal) {
2472
+ return new Promise((resolve, reject) => {
2473
+ if (signal?.aborted) {
2474
+ reject(signal.reason ?? new Error("Aborted"));
2475
+ return;
2476
+ }
2477
+ const onAbort = () => {
2478
+ clearTimeout(timer);
2479
+ reject(signal?.reason ?? new Error("Aborted"));
2480
+ };
2481
+ const timer = setTimeout(() => {
2482
+ signal?.removeEventListener("abort", onAbort);
2483
+ resolve();
2484
+ }, ms);
2485
+ signal?.addEventListener("abort", onAbort, { once: true });
2486
+ });
2487
+ }
2488
+ var _client4;
2002
2489
  var CheckoutClient = class {
2003
2490
  constructor(client) {
2004
- __privateAdd(this, _client);
2005
- __privateSet(this, _client, client);
2491
+ __privateAdd(this, _client4);
2492
+ __privateSet(this, _client4, client);
2006
2493
  }
2007
- /** First checkpoint. A ContoError means Conto did not approve: stop the checkout. */
2494
+ /**
2495
+ * First checkpoint. Open the payment method only when the stage is APPROVED.
2496
+ * AWAITING_APPROVAL means the owner must decide first: call waitForApproval().
2497
+ * A ContoError means Conto did not approve: stop the checkout. A
2498
+ * CheckoutCheckpointClosedError means this idempotency key belongs to a
2499
+ * checkpoint that already closed.
2500
+ */
2008
2501
  async begin(input) {
2009
2502
  const idempotencyKey = input.idempotencyKey?.trim();
2010
2503
  if (!idempotencyKey || idempotencyKey.length < 8 || idempotencyKey.length > 255) {
@@ -2016,7 +2509,7 @@ var CheckoutClient = class {
2016
2509
  if (input.currency !== void 0 && input.currency !== "USD") {
2017
2510
  throw checkoutError("Only USD checkouts are supported");
2018
2511
  }
2019
- const result = await __privateGet(this, _client).request(
2512
+ const result = await __privateGet(this, _client4).request(
2020
2513
  "POST",
2021
2514
  "/api/sdk/checkout-checkpoints",
2022
2515
  {
@@ -2031,13 +2524,40 @@ var CheckoutClient = class {
2031
2524
  },
2032
2525
  { idempotent: true }
2033
2526
  );
2527
+ if (CLOSED_CHECKPOINT_STAGES.includes(result.checkpoint.stage)) {
2528
+ throw closedCheckpointError(result.checkpoint);
2529
+ }
2034
2530
  return result.checkpoint;
2035
2531
  }
2532
+ /**
2533
+ * Waits while the owner decides on a checkpoint in AWAITING_APPROVAL and
2534
+ * resolves to the approved checkpoint. Throws CheckoutApprovalDeniedError,
2535
+ * CheckoutApprovalExpiredError, CheckoutCheckpointClosedError, or
2536
+ * CheckoutApprovalTimeoutError (the spend stays held until you cancel).
2537
+ */
2538
+ async waitForApproval(checkpoint, options = {}) {
2539
+ const timeoutMs = options.timeoutMs ?? 10 * 6e4;
2540
+ const pollIntervalMs = Math.max(1e3, options.pollIntervalMs ?? 5e3);
2541
+ const deadline = Date.now() + timeoutMs;
2542
+ let current = checkpoint;
2543
+ for (; ; ) {
2544
+ if (current.stage !== "AWAITING_APPROVAL") {
2545
+ if (CLOSED_CHECKPOINT_STAGES.includes(current.stage)) throw closedCheckpointError(current);
2546
+ return current;
2547
+ }
2548
+ const remaining = deadline - Date.now();
2549
+ if (remaining <= 0) throw new CheckoutApprovalTimeoutError(current);
2550
+ await sleep2(Math.min(pollIntervalMs, remaining), options.signal);
2551
+ current = await this.get(current.id);
2552
+ }
2553
+ }
2036
2554
  /**
2037
2555
  * Second checkpoint, right before the payment is submitted. If the total
2038
2556
  * changed since begin() (tax or shipping, for example), this cancels the
2039
2557
  * 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.
2558
+ * rules see the amount actually being paid. Pay only if this resolves. A
2559
+ * CheckoutApprovalPendingError means the owner must approve first: call
2560
+ * waitForApproval(error.checkpoint), then confirm the checkpoint it returns.
2041
2561
  */
2042
2562
  async confirm(checkpoint, input) {
2043
2563
  if (input.currency !== void 0 && input.currency !== "USD") {
@@ -2068,22 +2588,31 @@ var CheckoutClient = class {
2068
2588
  lineItems: input.lineItems ?? checkpoint.cart.lineItems,
2069
2589
  totals: input.totals
2070
2590
  });
2591
+ if (current.stage === "AWAITING_APPROVAL") throw new CheckoutApprovalPendingError(current);
2592
+ }
2593
+ try {
2594
+ const result = await __privateGet(this, _client4).request(
2595
+ "POST",
2596
+ `/api/sdk/checkout-checkpoints/${encodeURIComponent(current.id)}/confirm`,
2597
+ {
2598
+ amountMinor: input.amountMinor,
2599
+ currency: "USD",
2600
+ ...input.pageUrl ? { pageUrl: input.pageUrl } : {}
2601
+ },
2602
+ { idempotent: true }
2603
+ );
2604
+ return result.checkpoint;
2605
+ } catch (error) {
2606
+ if (error instanceof ContoError && error.status === 409 && error.code === "APPROVAL_REQUIRED") {
2607
+ const latest = await this.get(current.id);
2608
+ if (latest.stage === "AWAITING_APPROVAL") throw new CheckoutApprovalPendingError(latest);
2609
+ }
2610
+ throw error;
2071
2611
  }
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
2612
  }
2084
2613
  /** Report what happened after a confirmed checkpoint. Safe to repeat with the same outcome. */
2085
2614
  async reportOutcome(checkpointId, input) {
2086
- const result = await __privateGet(this, _client).request(
2615
+ const result = await __privateGet(this, _client4).request(
2087
2616
  "POST",
2088
2617
  `/api/sdk/checkout-checkpoints/${encodeURIComponent(checkpointId)}/outcome`,
2089
2618
  {
@@ -2094,9 +2623,12 @@ var CheckoutClient = class {
2094
2623
  );
2095
2624
  return result.checkpoint;
2096
2625
  }
2097
- /** Cancel a checkpoint that was not confirmed and release its spend. */
2626
+ /**
2627
+ * Cancel a checkpoint that was not confirmed and release its spend. A
2628
+ * checkpoint waiting for the owner can be cancelled too.
2629
+ */
2098
2630
  async cancel(checkpointId) {
2099
- const result = await __privateGet(this, _client).request(
2631
+ const result = await __privateGet(this, _client4).request(
2100
2632
  "POST",
2101
2633
  `/api/sdk/checkout-checkpoints/${encodeURIComponent(checkpointId)}/cancel`,
2102
2634
  {},
@@ -2105,188 +2637,24 @@ var CheckoutClient = class {
2105
2637
  return result.checkpoint;
2106
2638
  }
2107
2639
  async get(checkpointId) {
2108
- const result = await __privateGet(this, _client).request(
2640
+ const result = await __privateGet(this, _client4).request(
2109
2641
  "GET",
2110
2642
  `/api/sdk/checkout-checkpoints/${encodeURIComponent(checkpointId)}`
2111
2643
  );
2112
2644
  return result.checkpoint;
2113
2645
  }
2114
2646
  };
2115
- _client = new WeakMap();
2116
- var _client2, _defaults;
2117
- var LinkClient = class {
2118
- constructor(client, defaults) {
2119
- __privateAdd(this, _client2);
2120
- __privateAdd(this, _defaults);
2121
- __privateSet(this, _client2, client);
2122
- __privateSet(this, _defaults, defaults ? { ...defaults } : void 0);
2123
- }
2124
- /** Inspect the configured live path. This is not a payment authorization or provider connectivity test. */
2125
- async setup(input = {}) {
2126
- return __privateGet(this, _client2).getLinkSetup({
2127
- connectionId: input.connectionId ?? __privateGet(this, _defaults)?.connectionId,
2128
- paymentMethodId: input.paymentMethodId ?? __privateGet(this, _defaults)?.paymentMethodId,
2129
- merchantId: input.merchantId
2130
- });
2131
- }
2132
- /** Read masked LIVE funding sources; never selects a source or initiates payment. */
2133
- async paymentMethods(connectionId) {
2134
- return __privateGet(this, _client2).listStripeLinkPaymentMethods(
2135
- this.identifier(connectionId ?? __privateGet(this, _defaults)?.connectionId, "connectionId"),
2136
- { mode: "LIVE" }
2137
- );
2138
- }
2139
- /**
2140
- * Begin one exact intent and execute only if already READY. Otherwise return
2141
- * the owner's approval action or existing state immediately, without polling.
2142
- */
2143
- async pay(input) {
2144
- const connectionId = this.identifier(
2145
- input.connectionId ?? __privateGet(this, _defaults)?.connectionId,
2146
- "connectionId"
2147
- );
2148
- const paymentMethodId = this.identifier(
2149
- input.paymentMethodId ?? __privateGet(this, _defaults)?.paymentMethodId,
2150
- "paymentMethodId"
2151
- );
2152
- 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()) {
2153
- throw new ContoError("Supply a positive USD amount in cents, purpose, and line items", {
2154
- code: "INVALID_LINK_PURCHASE",
2155
- status: 0
2156
- });
2157
- }
2158
- const itemTotal = input.lineItems.reduce((sum, item) => {
2159
- if (!item || typeof item.name !== "string" || !item.name.trim() || !Number.isSafeInteger(item.quantity) || item.quantity <= 0 || !Number.isSafeInteger(item.unitAmountMinor) || item.unitAmountMinor < 0) {
2160
- throw new ContoError(
2161
- "Each line item needs a name, positive integer quantity, and price in cents",
2162
- {
2163
- code: "INVALID_LINK_PURCHASE",
2164
- status: 0
2165
- }
2166
- );
2167
- }
2168
- return sum + item.quantity * item.unitAmountMinor;
2169
- }, 0);
2170
- if (!input.totals && (!Number.isSafeInteger(itemTotal) || itemTotal !== input.amountMinor)) {
2171
- throw new ContoError(
2172
- "Supply the exact totals breakdown when the amount differs from the line items",
2173
- {
2174
- code: "LINK_TOTALS_REQUIRED",
2175
- status: 0
2176
- }
2177
- );
2178
- }
2179
- const result = await __privateGet(this, _client2).beginCommerceExecution({
2180
- executionMethod: "LINK_PAY_TOKEN",
2181
- connectionId,
2182
- paymentMethodId,
2183
- idempotencyKey: input.idempotencyKey,
2184
- amountMinor: input.amountMinor,
2185
- currency: input.currency ?? "USD",
2186
- purpose: input.purpose,
2187
- category: input.category,
2188
- counterparty: { canonicalId: input.merchantId, checkoutUrl: input.checkoutUrl },
2189
- cart: {
2190
- lineItems: input.lineItems,
2191
- totals: input.totals ?? [{ type: "total", label: "Total", amountMinor: input.amountMinor }]
2192
- },
2193
- providerPresentation: {
2194
- approvalSummary: input.purpose.trim().slice(0, 500),
2195
- lineItemLabels: input.lineItems.map((item) => item.name.trim().slice(0, 120))
2196
- }
2197
- });
2198
- return this.executeIfReady(result);
2199
- }
2200
- /**
2201
- * Continue the existing payment after approval. Reads before any mutation and
2202
- * never submits an execution already processing or requiring reconciliation.
2203
- */
2204
- async resume(executionId) {
2205
- const id = this.identifier(executionId, "executionId");
2206
- const current = await __privateGet(this, _client2).getCommerceExecution(id);
2207
- this.assertLinkExecution(current);
2208
- if (["AUTHORIZING", "AWAITING_APPROVAL", "ACTION_REQUIRED"].includes(current.execution.status)) {
2209
- return this.executeIfReady(await __privateGet(this, _client2).refreshCommerceExecution(id));
2210
- }
2211
- return this.executeIfReady(current);
2212
- }
2213
- /** Observe and reconcile provider state. This method never submits a payment. */
2214
- async status(executionId) {
2215
- const id = this.identifier(executionId, "executionId");
2216
- this.assertLinkExecution(await __privateGet(this, _client2).getCommerceExecution(id));
2217
- return this.result(await __privateGet(this, _client2).refreshCommerceExecution(id));
2218
- }
2219
- /** Request cancellation of this existing Link payment; never retried automatically. */
2220
- async cancel(executionId) {
2221
- const id = this.identifier(executionId, "executionId");
2222
- this.assertLinkExecution(await __privateGet(this, _client2).getCommerceExecution(id));
2223
- try {
2224
- return this.result(await __privateGet(this, _client2).cancelCommerceExecution(id));
2225
- } catch (error) {
2226
- throw new LinkPaymentExecutionError(id, error);
2227
- }
2228
- }
2229
- identifier(value, field) {
2230
- if (typeof value !== "string" || !value.trim() || value.length > 255) {
2231
- throw new ContoError(
2232
- 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`,
2233
- {
2234
- code: "LINK_CONFIGURATION_REQUIRED",
2235
- status: 0
2236
- }
2237
- );
2238
- }
2239
- return value.trim();
2240
- }
2241
- assertLinkExecution(result) {
2242
- const execution = result.execution;
2243
- 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") {
2244
- throw new ContoError("This execution is not a Link Pay Token checkout", {
2245
- code: "LINK_EXECUTION_MISMATCH",
2246
- status: 0
2247
- });
2248
- }
2249
- }
2250
- async executeIfReady(result) {
2251
- this.assertLinkExecution(result);
2252
- if (result.execution.status !== "READY") return this.result(result);
2253
- try {
2254
- return this.result(await __privateGet(this, _client2).executeCommerceExecution(result.execution.id));
2255
- } catch (error) {
2256
- throw new LinkPaymentExecutionError(result.execution.id, error);
2257
- }
2258
- }
2259
- result(result) {
2260
- this.assertLinkExecution(result);
2261
- const { execution } = result;
2262
- const awaitingApproval = ["AUTHORIZING", "AWAITING_APPROVAL", "ACTION_REQUIRED"].includes(
2263
- execution.status
2264
- );
2265
- const nextAction = execution.status === "READY" ? "RESUME" : execution.status === "NEEDS_RECONCILIATION" ? "RECONCILE" : awaitingApproval && execution.approvalUrl ? "APPROVE_IN_LINK" : awaitingApproval || ["DRAFT", "PROCESSING"].includes(execution.status) ? "WAIT" : [
2266
- "SETTLED",
2267
- "COMPLETED",
2268
- "DENIED",
2269
- "CANCELLED",
2270
- "FAILED",
2271
- "RETURNED",
2272
- "EXPIRED"
2273
- ].includes(execution.status) ? "NONE" : "RECONCILE";
2274
- return {
2275
- executionId: execution.id,
2276
- status: execution.status,
2277
- nextAction,
2278
- ...nextAction === "APPROVE_IN_LINK" ? { approvalUrl: execution.approvalUrl } : {},
2279
- execution,
2280
- ..."checkout" in result ? { checkout: result.checkout } : {}
2281
- };
2282
- }
2283
- };
2284
- _client2 = new WeakMap();
2285
- _defaults = new WeakMap();
2647
+ _client4 = new WeakMap();
2286
2648
  export {
2649
+ AdminPurchasingClient,
2287
2650
  BrowserActionFinalizationPendingError,
2288
2651
  BrowserCheckoutTargetVerificationError,
2289
2652
  CardsClient,
2653
+ CheckoutApprovalDeniedError,
2654
+ CheckoutApprovalExpiredError,
2655
+ CheckoutApprovalPendingError,
2656
+ CheckoutApprovalTimeoutError,
2657
+ CheckoutCheckpointClosedError,
2290
2658
  CheckoutClient,
2291
2659
  ConnectedCardsClient,
2292
2660
  Conto,
@@ -2296,11 +2664,16 @@ export {
2296
2664
  ControlledExternalCardPaymentTool,
2297
2665
  ExternalCardConfirmationPendingError,
2298
2666
  Conto as Giro,
2299
- LinkClient,
2300
- LinkPaymentExecutionError,
2667
+ OrganizationPurchasesClient,
2668
+ OrganizationRecurringPurchasesClient,
2669
+ PurchasesClient,
2670
+ RecurringPurchasesClient,
2301
2671
  TestCardsClient,
2302
2672
  canonicalizeBrowserCheckoutTarget,
2303
2673
  createVerifiedBrowserCheckoutDriver,
2304
2674
  index_default as default,
2305
- fingerprintBrowserCheckoutTarget
2675
+ fingerprintBrowserCheckoutTarget,
2676
+ isFinalPurchaseStatus,
2677
+ parseServerSentEvents,
2678
+ verifyPurchaseWebhook
2306
2679
  };