@conto_finance/sdk 0.6.1 → 0.7.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 CHANGED
@@ -80,6 +80,9 @@ if (checkpoint.stage === 'AWAITING_APPROVAL') {
80
80
  // The agent's rules need the owner. Throws if the owner rejects or the approval expires.
81
81
  checkpoint = await conto.checkout.waitForApproval(checkpoint, { timeoutMs: 15 * 60_000 });
82
82
  }
83
+ if (checkpoint.stage !== 'APPROVED') {
84
+ throw new Error('Inspect the existing purchase before continuing.');
85
+ }
83
86
  // Open Link. The buyer signs in and the final total appears.
84
87
 
85
88
  const confirmed = await conto.checkout.confirm(checkpoint, {
@@ -107,6 +110,68 @@ await conto.checkout.reportOutcome(confirmed.id, { outcome: 'PAID', reference: o
107
110
  - Conto records what your checkout reports and does not see the charge. For control at the
108
111
  moment of payment, pay with a Conto-managed wallet or a card Conto authorizes.
109
112
 
113
+ ## Stripe Link cards
114
+
115
+ The Stripe Link card integration ships in SDK 0.7.0 and later (`npm install @conto_finance/sdk`).
116
+ The Link controls integration kit bundles the same SDK.
117
+ The [minimal trusted-runtime example](https://github.com/Conto-Finance/conto/tree/main/examples/link-wallet-agent)
118
+ uses the existing agent SDK key, requires no shopping frontend, and never pays.
119
+
120
+ Stripe Link is Stripe's payment wallet, and Conto integrates with it. `conto.checkout.getLinkCard()`
121
+ asks Conto first, then asks Stripe Link for a card only after Conto approves the purchase, for
122
+ exactly the approved amount at that store. Stripe Link issues the card. It runs Stripe's `link-cli`
123
+ on your machine with your own Link login (`npm i -g @stripe/link-cli`, then `link-cli auth login`).
124
+ The person approves each card in Link, in the app or on the web. Conto does not receive the card. It stores only the
125
+ Link request ID.
126
+
127
+ ```typescript
128
+ import { linkCliWallet } from '@conto_finance/sdk/link-wallet';
129
+
130
+ const wallet = linkCliWallet({ test: true });
131
+
132
+ // At the payment step, once the final total with shipping and tax is known.
133
+ const result = await conto.checkout.getLinkCard({
134
+ idempotencyKey: order.id,
135
+ merchant: { id: 'acme-retail', name: 'ACME Retail', checkoutUrl: page.url() },
136
+ amountMinor: 8532,
137
+ purpose: 'Drip coffee maker the shopper chose',
138
+ lineItems: [{ name: 'Drip coffee maker', quantity: 1, unitAmountMinor: 7900 }],
139
+ wallet,
140
+ });
141
+
142
+ // Fill in result.card in the store's card form, then right before paying:
143
+ const confirmed = await conto.checkout.confirm(result.checkpoint, {
144
+ amountMinor: 8532,
145
+ lineItems: observedItems,
146
+ totals: observedCharges,
147
+ paymentReference: result.paymentReference,
148
+ });
149
+ // Pay, then report the outcome with the same paymentReference.
150
+ ```
151
+
152
+ - Link is never asked for a card before Conto approves. A denial at Conto throws before any Link
153
+ call. When a rule requires approval, `getLinkCard()` waits for the owner first.
154
+ - When the person declines in Link, the request expires, the wait passes `linkApprovalTimeoutMs`,
155
+ or `link-cli` is missing or logged out, `getLinkCard()` cancels the checkpoint to release the
156
+ held spend and throws `LinkCardDeniedError`, `LinkCardExpiredError`, `LinkCardTimeoutError`, or
157
+ `LinkWalletUnavailableError`. All extend `LinkCardError`. Do not pay.
158
+ - Retrying with the same input resumes the same checkpoint and Link request.
159
+ - The card (`number`, `securityValue` for the CVC, `expMonth`, `expYear`, `validUntil`, `last4`,
160
+ `brand`) stays in this process. Printing or serializing the result shows only the last four
161
+ digits. It never appears in an error.
162
+ - The card covers the approved total, so `confirm()` with a `paymentReference` refuses a
163
+ different total. Call `conto.checkout.replaceLinkCard(result, { wallet, amountMinor })` to
164
+ cancel the old card and checkpoint and get a card for the final total.
165
+ - Any `LinkWallet` works in place of `linkCliWallet()`: it creates a card request, waits for
166
+ approval, retrieves the card, and cancels.
167
+ - The protection holds only when the agent cannot also run `link-cli`, use a shell, or call Link
168
+ with your credentials itself.
169
+ - Pass observed final items and charges to `confirm()` even when the total is unchanged.
170
+ The server rejects a changed cart against the approved intent. The trusted host must
171
+ validate the actual merchant and checkout, own a durable one-use payment dispatch
172
+ claim, and keep card use outside model tools. Replaying a confirmed checkpoint is
173
+ not permission to submit payment again.
174
+
110
175
  ## External-card Policy Overlay
111
176
 
112
177
  The admin client registers only a masked card alias and assigns cooperative
@@ -1,6 +1,7 @@
1
1
  import { Browser } from 'playwright-core';
2
2
  import { GuardedPlaywrightCheckoutHttpHandler, PlaywrightSessionObservation, GuardedPlaywrightCheckoutClient, PlaywrightCdpSessionRegistryConfig, EncryptedPlaywrightCheckoutTargetStoreConfig, GuardedPlaywrightCheckoutRuntimeConfig } from './playwright.mjs';
3
3
  import './index.mjs';
4
+ import './link-wallet.mjs';
4
5
 
5
6
  /** Exact provider endpoints verified against Browserbase's session API; never use a wildcard. */
6
7
  declare const BROWSERBASE_CONNECT_ORIGINS: readonly string[];
@@ -150,4 +151,5 @@ declare function createBrowserbaseSessionManager(config: BrowserbaseSessionConfi
150
151
  */
151
152
  declare function createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost(config: BrowserbaseGuardedPlaywrightCheckoutRuntimeHostConfig): BrowserbaseGuardedPlaywrightCheckoutRuntimeHost;
152
153
 
153
- export { BROWSERBASE_CONNECT_ORIGINS, type BrowserbaseAttachedSession, type BrowserbaseGuardedPlaywrightCheckoutRuntimeHost, type BrowserbaseGuardedPlaywrightCheckoutRuntimeHostConfig, type BrowserbaseOwnedLiveView, type BrowserbaseOwnedSession, type BrowserbaseSessionBinding, type BrowserbaseSessionBindingState, type BrowserbaseSessionBindingStore, type BrowserbaseSessionConfig, BrowserbaseSessionError, type BrowserbaseSessionErrorCode, type BrowserbaseSessionHandoff, type BrowserbaseSessionHandoffAssertionInput, type BrowserbaseSessionLifecycleOwner, type BrowserbaseSessionManager, type BrowserbaseSessionStatus, createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost, createBrowserbaseSessionHandoffAssertion, createBrowserbaseSessionManager };
154
+ export { BROWSERBASE_CONNECT_ORIGINS, BrowserbaseSessionError, createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost, createBrowserbaseSessionHandoffAssertion, createBrowserbaseSessionManager };
155
+ export type { BrowserbaseAttachedSession, BrowserbaseGuardedPlaywrightCheckoutRuntimeHost, BrowserbaseGuardedPlaywrightCheckoutRuntimeHostConfig, BrowserbaseOwnedLiveView, BrowserbaseOwnedSession, BrowserbaseSessionBinding, BrowserbaseSessionBindingState, BrowserbaseSessionBindingStore, BrowserbaseSessionConfig, BrowserbaseSessionErrorCode, BrowserbaseSessionHandoff, BrowserbaseSessionHandoffAssertionInput, BrowserbaseSessionLifecycleOwner, BrowserbaseSessionManager, BrowserbaseSessionStatus };
@@ -1,6 +1,7 @@
1
1
  import { Browser } from 'playwright-core';
2
2
  import { GuardedPlaywrightCheckoutHttpHandler, PlaywrightSessionObservation, GuardedPlaywrightCheckoutClient, PlaywrightCdpSessionRegistryConfig, EncryptedPlaywrightCheckoutTargetStoreConfig, GuardedPlaywrightCheckoutRuntimeConfig } from './playwright.js';
3
3
  import './index.js';
4
+ import './link-wallet.js';
4
5
 
5
6
  /** Exact provider endpoints verified against Browserbase's session API; never use a wildcard. */
6
7
  declare const BROWSERBASE_CONNECT_ORIGINS: readonly string[];
@@ -150,4 +151,5 @@ declare function createBrowserbaseSessionManager(config: BrowserbaseSessionConfi
150
151
  */
151
152
  declare function createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost(config: BrowserbaseGuardedPlaywrightCheckoutRuntimeHostConfig): BrowserbaseGuardedPlaywrightCheckoutRuntimeHost;
152
153
 
153
- export { BROWSERBASE_CONNECT_ORIGINS, type BrowserbaseAttachedSession, type BrowserbaseGuardedPlaywrightCheckoutRuntimeHost, type BrowserbaseGuardedPlaywrightCheckoutRuntimeHostConfig, type BrowserbaseOwnedLiveView, type BrowserbaseOwnedSession, type BrowserbaseSessionBinding, type BrowserbaseSessionBindingState, type BrowserbaseSessionBindingStore, type BrowserbaseSessionConfig, BrowserbaseSessionError, type BrowserbaseSessionErrorCode, type BrowserbaseSessionHandoff, type BrowserbaseSessionHandoffAssertionInput, type BrowserbaseSessionLifecycleOwner, type BrowserbaseSessionManager, type BrowserbaseSessionStatus, createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost, createBrowserbaseSessionHandoffAssertion, createBrowserbaseSessionManager };
154
+ export { BROWSERBASE_CONNECT_ORIGINS, BrowserbaseSessionError, createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost, createBrowserbaseSessionHandoffAssertion, createBrowserbaseSessionManager };
155
+ export type { BrowserbaseAttachedSession, BrowserbaseGuardedPlaywrightCheckoutRuntimeHost, BrowserbaseGuardedPlaywrightCheckoutRuntimeHostConfig, BrowserbaseOwnedLiveView, BrowserbaseOwnedSession, BrowserbaseSessionBinding, BrowserbaseSessionBindingState, BrowserbaseSessionBindingStore, BrowserbaseSessionConfig, BrowserbaseSessionErrorCode, BrowserbaseSessionHandoff, BrowserbaseSessionHandoffAssertionInput, BrowserbaseSessionLifecycleOwner, BrowserbaseSessionManager, BrowserbaseSessionStatus };
@@ -322,13 +322,16 @@ function createEncryptedPlaywrightCheckoutTargetStore(config) {
322
322
  if (envelope.version !== TARGET_STORE_ENVELOPE_VERSION || typeof envelope.iv !== "string" || typeof envelope.ciphertext !== "string" || typeof envelope.tag !== "string") {
323
323
  throw new Error("invalid envelope");
324
324
  }
325
+ const tag = Buffer.from(envelope.tag, "base64url");
326
+ if (tag.length !== 16) throw new Error("invalid envelope");
325
327
  const decipher = (0, import_node_crypto2.createDecipheriv)(
326
328
  "aes-256-gcm",
327
329
  key,
328
- Buffer.from(envelope.iv, "base64url")
330
+ Buffer.from(envelope.iv, "base64url"),
331
+ { authTagLength: 16 }
329
332
  );
330
333
  decipher.setAAD(Buffer.from(storageKey));
331
- decipher.setAuthTag(Buffer.from(envelope.tag, "base64url"));
334
+ decipher.setAuthTag(tag);
332
335
  const plaintext = Buffer.concat([
333
336
  decipher.update(Buffer.from(envelope.ciphertext, "base64url")),
334
337
  decipher.final()
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  createGuardedPlaywrightCheckoutRuntimeHost
3
- } from "./chunk-VSIO6PYA.mjs";
3
+ } from "./chunk-JBTJXIMI.mjs";
4
4
  import "./chunk-O5RAAB2U.mjs";
5
- import "./chunk-WSIKPUZJ.mjs";
5
+ import "./chunk-TGOYFBKZ.mjs";
6
6
 
7
7
  // src/browserbase.ts
8
8
  import { createHmac, timingSafeEqual } from "crypto";
@@ -92,4 +92,5 @@ interface VerifyCheckoutIntegrationOptions {
92
92
  */
93
93
  declare function verifyCheckoutIntegration(value: CheckoutCapabilityManifest | unknown, options?: VerifyCheckoutIntegrationOptions): Promise<CheckoutIntegrationVerificationReport>;
94
94
 
95
- export { CHECKOUT_CAPABILITY_KINDS, CHECKOUT_CAPABILITY_MANIFEST_VERSION, CHECKOUT_CONFORMANCE_PROBE_IDS, CHECKOUT_METHOD_IDS, CHECKOUT_VERIFICATION_REPORT_VERSION, type CheckoutCapabilityDescriptor, type CheckoutCapabilityExposure, type CheckoutCapabilityInventoryScope, type CheckoutCapabilityKind, type CheckoutCapabilityManifest, type CheckoutCapabilityPaymentBoundary, type CheckoutConformanceProbeId, type CheckoutConformanceProbeObservation, type CheckoutConformanceProbeOutcome, type CheckoutConformanceProbeRequest, type CheckoutConformanceProbeResult, type CheckoutConformanceProbeRunner, type CheckoutIntegrationComponent, type CheckoutIntegrationStatus, type CheckoutIntegrationVerificationReport, type CheckoutMethodId, type CheckoutSessionBinding, type CheckoutVerificationFinding, type CheckoutVerificationFindingCode, type VerifyCheckoutIntegrationOptions, verifyCheckoutIntegration };
95
+ export { CHECKOUT_CAPABILITY_KINDS, CHECKOUT_CAPABILITY_MANIFEST_VERSION, CHECKOUT_CONFORMANCE_PROBE_IDS, CHECKOUT_METHOD_IDS, CHECKOUT_VERIFICATION_REPORT_VERSION, verifyCheckoutIntegration };
96
+ export type { CheckoutCapabilityDescriptor, CheckoutCapabilityExposure, CheckoutCapabilityInventoryScope, CheckoutCapabilityKind, CheckoutCapabilityManifest, CheckoutCapabilityPaymentBoundary, CheckoutConformanceProbeId, CheckoutConformanceProbeObservation, CheckoutConformanceProbeOutcome, CheckoutConformanceProbeRequest, CheckoutConformanceProbeResult, CheckoutConformanceProbeRunner, CheckoutIntegrationComponent, CheckoutIntegrationStatus, CheckoutIntegrationVerificationReport, CheckoutMethodId, CheckoutSessionBinding, CheckoutVerificationFinding, CheckoutVerificationFindingCode, VerifyCheckoutIntegrationOptions };
@@ -92,4 +92,5 @@ interface VerifyCheckoutIntegrationOptions {
92
92
  */
93
93
  declare function verifyCheckoutIntegration(value: CheckoutCapabilityManifest | unknown, options?: VerifyCheckoutIntegrationOptions): Promise<CheckoutIntegrationVerificationReport>;
94
94
 
95
- export { CHECKOUT_CAPABILITY_KINDS, CHECKOUT_CAPABILITY_MANIFEST_VERSION, CHECKOUT_CONFORMANCE_PROBE_IDS, CHECKOUT_METHOD_IDS, CHECKOUT_VERIFICATION_REPORT_VERSION, type CheckoutCapabilityDescriptor, type CheckoutCapabilityExposure, type CheckoutCapabilityInventoryScope, type CheckoutCapabilityKind, type CheckoutCapabilityManifest, type CheckoutCapabilityPaymentBoundary, type CheckoutConformanceProbeId, type CheckoutConformanceProbeObservation, type CheckoutConformanceProbeOutcome, type CheckoutConformanceProbeRequest, type CheckoutConformanceProbeResult, type CheckoutConformanceProbeRunner, type CheckoutIntegrationComponent, type CheckoutIntegrationStatus, type CheckoutIntegrationVerificationReport, type CheckoutMethodId, type CheckoutSessionBinding, type CheckoutVerificationFinding, type CheckoutVerificationFindingCode, type VerifyCheckoutIntegrationOptions, verifyCheckoutIntegration };
95
+ export { CHECKOUT_CAPABILITY_KINDS, CHECKOUT_CAPABILITY_MANIFEST_VERSION, CHECKOUT_CONFORMANCE_PROBE_IDS, CHECKOUT_METHOD_IDS, CHECKOUT_VERIFICATION_REPORT_VERSION, verifyCheckoutIntegration };
96
+ export type { CheckoutCapabilityDescriptor, CheckoutCapabilityExposure, CheckoutCapabilityInventoryScope, CheckoutCapabilityKind, CheckoutCapabilityManifest, CheckoutCapabilityPaymentBoundary, CheckoutConformanceProbeId, CheckoutConformanceProbeObservation, CheckoutConformanceProbeOutcome, CheckoutConformanceProbeRequest, CheckoutConformanceProbeResult, CheckoutConformanceProbeRunner, CheckoutIntegrationComponent, CheckoutIntegrationStatus, CheckoutIntegrationVerificationReport, CheckoutMethodId, CheckoutSessionBinding, CheckoutVerificationFinding, CheckoutVerificationFindingCode, VerifyCheckoutIntegrationOptions };
@@ -1,4 +1,4 @@
1
- import "./chunk-WSIKPUZJ.mjs";
1
+ import "./chunk-TGOYFBKZ.mjs";
2
2
 
3
3
  // src/checkout-verifier.ts
4
4
  import { createHash, randomUUID } from "crypto";
@@ -184,13 +184,16 @@ function createEncryptedPlaywrightCheckoutTargetStore(config) {
184
184
  if (envelope.version !== TARGET_STORE_ENVELOPE_VERSION || typeof envelope.iv !== "string" || typeof envelope.ciphertext !== "string" || typeof envelope.tag !== "string") {
185
185
  throw new Error("invalid envelope");
186
186
  }
187
+ const tag = Buffer.from(envelope.tag, "base64url");
188
+ if (tag.length !== 16) throw new Error("invalid envelope");
187
189
  const decipher = createDecipheriv(
188
190
  "aes-256-gcm",
189
191
  key,
190
- Buffer.from(envelope.iv, "base64url")
192
+ Buffer.from(envelope.iv, "base64url"),
193
+ { authTagLength: 16 }
191
194
  );
192
195
  decipher.setAAD(Buffer.from(storageKey));
193
- decipher.setAuthTag(Buffer.from(envelope.tag, "base64url"));
196
+ decipher.setAuthTag(tag);
194
197
  const plaintext = Buffer.concat([
195
198
  decipher.update(Buffer.from(envelope.ciphertext, "base64url")),
196
199
  decipher.final()
@@ -34,11 +34,13 @@ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot
34
34
  var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
35
35
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
36
36
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
37
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
37
38
 
38
39
  export {
39
40
  __commonJS,
40
41
  __toESM,
41
42
  __privateGet,
42
43
  __privateAdd,
43
- __privateSet
44
+ __privateSet,
45
+ __privateMethod
44
46
  };