@agent-cards/sdk 0.24.2 → 0.25.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/dist/approvals.d.ts +44 -0
- package/dist/approvals.js +10 -0
- package/dist/card-fields.generated.js +4 -1
- package/dist/cdp.js +25 -13
- package/dist/datatrans.generated.js +3 -1
- package/dist/index.d.ts +1 -1
- package/dist/lifecycle.d.ts +13 -5
- package/dist/lifecycle.js +20 -22
- package/dist/merchant-card-endpoints.generated.js +30 -3
- package/dist/payrails.generated.js +3 -1
- package/dist/primer.generated.js +3 -1
- package/dist/stripe-checkout.generated.js +4 -1
- package/dist/stripe-continuation.d.ts +45 -0
- package/dist/stripe-continuation.js +106 -0
- package/dist/stripe-setup.d.ts +5 -10
- package/dist/stripe-setup.js +11 -39
- package/package.json +2 -2
package/dist/approvals.d.ts
CHANGED
|
@@ -39,6 +39,50 @@ export interface CreateAuthorizationInput {
|
|
|
39
39
|
checkout_origin?: string;
|
|
40
40
|
/** Pins the card that pays: one of the person's stored cards. Absent, the person's recommended card pays, else their only card, and `card` on the answer says which. */
|
|
41
41
|
card_id?: string;
|
|
42
|
+
/**
|
|
43
|
+
* The products the purchase is for, as your agent's cart has them (1 to 20 lines): the approval page lists them
|
|
44
|
+
* above the total, labelled as sent by your company. Shown, never charged: the person approves `amount`.
|
|
45
|
+
* Every amount is in the smallest unit of `currency`. A line the API cannot read is refused by name
|
|
46
|
+
* (`invalid_request`), never dropped.
|
|
47
|
+
*/
|
|
48
|
+
line_items?: OrderLineItem[];
|
|
49
|
+
/** The cart's subtotal, shipping, tax and discount, in the smallest unit of `currency`, each shown only when named. Need `line_items`. */
|
|
50
|
+
subtotal?: number;
|
|
51
|
+
shipping?: number;
|
|
52
|
+
tax?: number;
|
|
53
|
+
discount?: number;
|
|
54
|
+
/** Where the order ships, shown in the approval page's Ship to box. Needs `line_items`. Never returned on your reads. */
|
|
55
|
+
ship_to?: OrderShipTo;
|
|
56
|
+
}
|
|
57
|
+
/** One product of the cart an approval shows. */
|
|
58
|
+
export interface OrderLineItem {
|
|
59
|
+
/** The product's name as the store shows it. */
|
|
60
|
+
title: string;
|
|
61
|
+
/** A positive integer. */
|
|
62
|
+
quantity: number;
|
|
63
|
+
/** The price of one, in the smallest unit of the create's `currency`; the line shows `unit_amount × quantity`. */
|
|
64
|
+
unit_amount?: number;
|
|
65
|
+
/** The line's own total, in the smallest unit; shown over `unit_amount × quantity` when both are named. */
|
|
66
|
+
amount?: number;
|
|
67
|
+
brand?: string;
|
|
68
|
+
/** The options chosen, as one string (`'Size S · Pink'`) or by name (`{ Size: 'S', Color: 'Pink' }`, shown as `S · Pink`). */
|
|
69
|
+
options?: string | Record<string, string>;
|
|
70
|
+
/** An https picture of the product. Shown only from the image hosts the approval page loads; any other shows the line without one. */
|
|
71
|
+
image_url?: string;
|
|
72
|
+
}
|
|
73
|
+
/** Where an approval's order ships. */
|
|
74
|
+
export interface OrderShipTo {
|
|
75
|
+
name: string;
|
|
76
|
+
phone?: string;
|
|
77
|
+
/** `country` is a two-letter ISO code; absent means `US`. */
|
|
78
|
+
address: {
|
|
79
|
+
line1: string;
|
|
80
|
+
line2?: string;
|
|
81
|
+
city: string;
|
|
82
|
+
state?: string;
|
|
83
|
+
postal_code: string;
|
|
84
|
+
country?: string;
|
|
85
|
+
};
|
|
42
86
|
}
|
|
43
87
|
/** The card that pays, as every read names it. */
|
|
44
88
|
export interface PayingCard {
|
package/dist/approvals.js
CHANGED
|
@@ -99,6 +99,15 @@ function resultOf(a) {
|
|
|
99
99
|
...(approvalUrl && a.status === 'awaiting_approval' ? { approval_url: approvalUrl } : {}),
|
|
100
100
|
};
|
|
101
101
|
}
|
|
102
|
+
/** The cart fields a create names, passed as given: the API checks them and refuses a bad one by name. */
|
|
103
|
+
function orderFieldsOf(input) {
|
|
104
|
+
const out = {};
|
|
105
|
+
for (const key of ['line_items', 'subtotal', 'shipping', 'tax', 'discount', 'ship_to']) {
|
|
106
|
+
if (input[key] !== undefined)
|
|
107
|
+
out[key] = input[key];
|
|
108
|
+
}
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
102
111
|
/** A random idempotency key for one create, so a retried call makes one purchase. */
|
|
103
112
|
function idempotencyKey() {
|
|
104
113
|
const c = globalThis.crypto;
|
|
@@ -148,6 +157,7 @@ export class ApprovalsModule extends ApiModule {
|
|
|
148
157
|
body: {
|
|
149
158
|
user, merchant: input.merchant, amount: input.amount, currency: input.currency, psp: input.psp ?? 'stripe', mode: input.mode ?? 'token', request,
|
|
150
159
|
...(input.return_url ? { return_url: input.return_url } : {}), ...(checkoutOrigin ? { checkout_origin: checkoutOrigin } : {}), ...(input.card_id ? { card_id: input.card_id } : {}),
|
|
160
|
+
...orderFieldsOf(input),
|
|
151
161
|
},
|
|
152
162
|
headers: { 'idempotency-key': input.idempotency_key ?? idempotencyKey() },
|
|
153
163
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
// Generated from @agent-cards/payment-core. Do not edit.
|
|
3
|
-
// artifact-sha256:
|
|
3
|
+
// artifact-sha256: 59a78202e498531ace1ce3391b9ac8b385f55a86e332aca4ac7abdb807d506e7
|
|
4
4
|
// src/card-number-key.js
|
|
5
5
|
var CARD_NUMBER_KEY = /^(number|card_number|cardnumber|cardNum|card_num|pan)$/i;
|
|
6
6
|
// src/json-path.js
|
|
@@ -1965,6 +1965,9 @@ function multipartFormRefusal(body, contentType, rule) {
|
|
|
1965
1965
|
const read = judge(body, contentType, rule);
|
|
1966
1966
|
return read.refusal ?? null;
|
|
1967
1967
|
}
|
|
1968
|
+
// src/answer-card-leak.js
|
|
1969
|
+
var UTF8_SEQUENCE = "[\\x00-\\x7f]|[\\xc2-\\xdf][\\x80-\\xbf]|\\xe0[\\xa0-\\xbf][\\x80-\\xbf]|[\\xe1-\\xec\\xee\\xef][\\x80-\\xbf]{2}|\\xed[\\x80-\\x9f][\\x80-\\xbf]|\\xf0[\\x90-\\xbf][\\x80-\\xbf]{2}|[\\xf1-\\xf3][\\x80-\\xbf]{3}|\\xf4[\\x80-\\x8f][\\x80-\\xbf]{2}";
|
|
1970
|
+
var UTF8_WHOLE = /* @__PURE__ */ new RegExp(`^(?:${UTF8_SEQUENCE})*$`);
|
|
1968
1971
|
// src/pay-nl.js
|
|
1969
1972
|
var PAY_NL_PSP = "pay_nl";
|
|
1970
1973
|
var PAY_NL_TOKEN_URL = "https://payment.pay.nl/v1/Payment/getCardToken/json";
|
package/dist/cdp.js
CHANGED
|
@@ -44,6 +44,7 @@ import { CYBERSOURCE_SECURE_ACCEPTANCE_PATTERNS, CYBERSOURCE_SECURE_ACCEPTANCE_R
|
|
|
44
44
|
import { CheckoutAttachmentError, attachmentDeadline, attachmentFailure, withinAttachmentDeadline } from './attachment.js';
|
|
45
45
|
import { cseBody } from './cse-body.js';
|
|
46
46
|
import { STRIPE_SETUP_INTENT_CONFIRM, setupConfirmPayingWith } from './stripe-setup.js';
|
|
47
|
+
import { confirmPayingWith } from './stripe-continuation.js';
|
|
47
48
|
import { replayTemplatedUrl, reviewedMerchantProfileUrlPatterns } from './merchant-hosted.js';
|
|
48
49
|
import { verifoneTemplatedUrl } from './verifone.js';
|
|
49
50
|
import { MerchantHandoffWatch } from './merchant-handoff.js';
|
|
@@ -1113,30 +1114,41 @@ function claimStripeContinuation(opts, lifecycle, url, method, body) {
|
|
|
1113
1114
|
}
|
|
1114
1115
|
if (parsed.origin !== 'https://api.stripe.com')
|
|
1115
1116
|
return null;
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1117
|
+
const payment = STRIPE_PAYMENT_INTENT_CONFIRM.test(parsed.pathname);
|
|
1118
|
+
const setup = !payment && STRIPE_SETUP_INTENT_CONFIRM.test(parsed.pathname);
|
|
1119
|
+
if (!payment && !setup)
|
|
1120
|
+
return null;
|
|
1121
|
+
// Each kind needs the client method that judges it; an older client keeps the ordinary hold.
|
|
1122
|
+
if (payment && typeof opts.vault.checkStripeContinuation !== 'function')
|
|
1123
|
+
return null;
|
|
1124
|
+
if (setup && typeof opts.vault.checkStripeSetupContinuation !== 'function')
|
|
1123
1125
|
return null;
|
|
1124
1126
|
const withoutCard = opts.vault.withoutCard?.(url, body);
|
|
1125
1127
|
let send = null;
|
|
1126
1128
|
if (withoutCard === 'refuse')
|
|
1127
1129
|
send = body;
|
|
1128
1130
|
else if (withoutCard === null) {
|
|
1129
|
-
// The card again, inline: only the
|
|
1130
|
-
// and only when what is left carries no card at
|
|
1131
|
-
|
|
1132
|
-
|
|
1131
|
+
// The card again, inline: only the object the cardholder's approval
|
|
1132
|
+
// returned may replace it, and only when what is left carries no card at
|
|
1133
|
+
// all. A payment pays with whichever object its approval produced (a
|
|
1134
|
+
// confirmation token, for a store that creates one for a fraud check and
|
|
1135
|
+
// then confirms with the Payment Element); a card save pays with a payment
|
|
1136
|
+
// method alone, which is all a SetupIntent confirm takes.
|
|
1137
|
+
if (payment) {
|
|
1138
|
+
const way = lifecycle.approvedStripeWay();
|
|
1139
|
+
send = way ? confirmPayingWith(body, way) : null;
|
|
1140
|
+
}
|
|
1141
|
+
else {
|
|
1142
|
+
const paymentMethod = lifecycle.approvedStripePaymentMethod();
|
|
1143
|
+
send = paymentMethod ? setupConfirmPayingWith(body, paymentMethod) : null;
|
|
1144
|
+
}
|
|
1133
1145
|
if (send !== null && opts.vault.withoutCard?.(url, send) !== 'refuse')
|
|
1134
1146
|
send = null;
|
|
1135
1147
|
}
|
|
1136
1148
|
if (send === null)
|
|
1137
1149
|
return null;
|
|
1138
1150
|
const authorizationId = lifecycle.claimStripeContinuation();
|
|
1139
|
-
return authorizationId ? { authorizationId, kind: 'setup', body: send, rewritten: send !== body } : null;
|
|
1151
|
+
return authorizationId ? { authorizationId, kind: payment ? 'payment' : 'setup', body: send, rewritten: send !== body } : null;
|
|
1140
1152
|
}
|
|
1141
1153
|
/**
|
|
1142
1154
|
* Ask the API about a claimed continuation, with the body it would continue
|
|
@@ -1159,7 +1171,7 @@ async function checkStripeContinuation(opts, lifecycle, claim, request) {
|
|
|
1159
1171
|
if (proceed) {
|
|
1160
1172
|
opts.onEvent?.(kind === 'setup'
|
|
1161
1173
|
? { type: 'stripe_setup_continued', detail: { authorizationId, setupIntentId: intentId, rewritten: claim.rewritten } }
|
|
1162
|
-
: { type: 'stripe_payment_continued', detail: { authorizationId, paymentIntentId: intentId } });
|
|
1174
|
+
: { type: 'stripe_payment_continued', detail: { authorizationId, paymentIntentId: intentId, rewritten: claim.rewritten } });
|
|
1163
1175
|
}
|
|
1164
1176
|
else if (intentId !== null)
|
|
1165
1177
|
opts.onEvent?.({ type: 'blocked', detail: 'stripe_continuation_superseded' });
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
// Generated from @agent-cards/payment-core. Do not edit.
|
|
3
|
-
// artifact-sha256:
|
|
3
|
+
// artifact-sha256: c4280e1c95d016a93163f49d9d66178a9c4fdfae08e4570952c9c7f533a1c643
|
|
4
4
|
// src/answer-card-leak.js
|
|
5
5
|
var DECIMAL = /\p{Nd}/u;
|
|
6
6
|
function digitValue(char) {
|
|
@@ -20,6 +20,8 @@ function enclosedValue(char) {
|
|
|
20
20
|
var asciiDigits = (text2) => (typeof text2.normalize === "function" ? text2.normalize("NFKC") : text2).replace(ENCLOSED_CHAR, enclosedValue).replace(/\p{Nd}/gu, (char) => char >= "0" && char <= "9" ? char : digitValue(char));
|
|
21
21
|
var digitCount = (text2) => (asciiDigits(String(text2)).match(/\p{N}/gu) ?? []).length;
|
|
22
22
|
var NAME_DIGITS = 3;
|
|
23
|
+
var UTF8_SEQUENCE = "[\\x00-\\x7f]|[\\xc2-\\xdf][\\x80-\\xbf]|\\xe0[\\xa0-\\xbf][\\x80-\\xbf]|[\\xe1-\\xec\\xee\\xef][\\x80-\\xbf]{2}|\\xed[\\x80-\\x9f][\\x80-\\xbf]|\\xf0[\\x90-\\xbf][\\x80-\\xbf]{2}|[\\xf1-\\xf3][\\x80-\\xbf]{3}|\\xf4[\\x80-\\x8f][\\x80-\\xbf]{2}";
|
|
24
|
+
var UTF8_WHOLE = /* @__PURE__ */ new RegExp(`^(?:${UTF8_SEQUENCE})*$`);
|
|
23
25
|
// src/datatrans.js
|
|
24
26
|
var DATATRANS_HOSTS = Object.freeze(["pay.datatrans.com", "pay.sandbox.datatrans.com"]);
|
|
25
27
|
var DATATRANS_TOKENIZE_PATH = "/upp/payment/SecureFields/paymentField";
|
package/dist/index.d.ts
CHANGED
|
@@ -46,7 +46,7 @@ export type { ApiTransport } from './api-module.js';
|
|
|
46
46
|
export { BuyModule, BuyError, isBuyDeclined, BUY_TURN_TIMEOUT_MS } from './buy.js';
|
|
47
47
|
export type { BuyStatus, BuyCart, BuyCartLine, BuyDeliveryAddress, BuyPaymentSource, BuyOutcome, BuyPlacement, BuyCatalog, BuyUnmatched, BuyTurn, BuyDeclined, BuyOrder, BuyLastCheckout, BuyConversation, BuyAskInput, BuyConfirmInput, BuyConversationInput, BuyCheckoutHandoff, BuyOpenOffer, BuyBrowserCheckout, BuyApiAmount, } from './buy.js';
|
|
48
48
|
export { ApprovalsModule, CANCEL_REASONS, SANDBOX_REQUEST } from './approvals.js';
|
|
49
|
-
export type { CreateAuthorizationInput, Authorization, AuthorizationResult, AuthorizationFields, Cancelled, PayingCard, ChoosableCard } from './approvals.js';
|
|
49
|
+
export type { CreateAuthorizationInput, OrderLineItem, OrderShipTo, Authorization, AuthorizationResult, AuthorizationFields, Cancelled, PayingCard, ChoosableCard } from './approvals.js';
|
|
50
50
|
export { verifyWebhook, signWebhook, parseWebhookEvent, parseSignatureHeader, isCheckoutAuthorizationEvent, isVaultEvent, CHECKOUT_AUTHORIZATION_EVENT_TYPES, VAULT_EVENT_TYPES } from './webhooks.js';
|
|
51
51
|
export type { WebhookEvent, AgentcardEvent, CheckoutAuthorizationEvent, CheckoutAuthorizationEventType, CheckoutAuthorizationEventData, VaultEvent, VaultEventType, VaultEventData, OtherEvent, VerifyWebhookOptions } from './webhooks.js';
|
|
52
52
|
export { AgentcardError } from './api-types.js';
|
package/dist/lifecycle.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { ShijiStsUnsupportedReason } from './shiji-sts.js';
|
|
|
6
6
|
import type { PaddleVgsPayRefusal } from './paddle-vgs-pay.js';
|
|
7
7
|
import type { PaypalCardFormReason } from './paypal-card-forms.js';
|
|
8
8
|
import { type CardRequestHold, type HoldReleaseInput, type HoldReleaseOutcome } from './hold.js';
|
|
9
|
+
import { type StripeApprovedWay } from './stripe-continuation.js';
|
|
9
10
|
/** The application's resolver confirmed the payment for this checkout authorization. */
|
|
10
11
|
export interface MerchantPaymentConfirmation {
|
|
11
12
|
kind: 'merchant_payment';
|
|
@@ -104,7 +105,7 @@ export declare class CheckoutLifecycle implements CheckoutController {
|
|
|
104
105
|
private wspayChallenge;
|
|
105
106
|
private heldBeforeHandoff;
|
|
106
107
|
private stripeContinuedReason;
|
|
107
|
-
private
|
|
108
|
+
private approvedWay;
|
|
108
109
|
private ownedShopOrderId;
|
|
109
110
|
private orderRefusal;
|
|
110
111
|
private readonly handoffs;
|
|
@@ -268,12 +269,19 @@ export declare class CheckoutLifecycle implements CheckoutController {
|
|
|
268
269
|
* VaultClient.withoutCard, which then refuses a Nuvei payment without a card.
|
|
269
270
|
*/
|
|
270
271
|
cardHandoffs(): readonly string[];
|
|
272
|
+
/**
|
|
273
|
+
* The object a Stripe confirmation may pay with in place of the card it sends
|
|
274
|
+
* again (cdp.ts claimStripeContinuation): the one this attachment's approved
|
|
275
|
+
* tokenization returned, with the field that names it, while its continuation
|
|
276
|
+
* is still open. Null for a tokenization no confirmation names by id
|
|
277
|
+
* (`/v1/tokens`), and once the checkout was cancelled, aborted or reconciled.
|
|
278
|
+
*/
|
|
279
|
+
approvedStripeWay(): StripeApprovedWay | null;
|
|
271
280
|
/**
|
|
272
281
|
* The payment method a Stripe card save may pay with in place of the card
|
|
273
|
-
* it sends again
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
* checkout was cancelled, aborted or reconciled.
|
|
282
|
+
* it sends again: the `pm_` an approved `/v1/payment_methods` request
|
|
283
|
+
* returned. Null for every other approved object, since a SetupIntent
|
|
284
|
+
* confirm pays with a payment method alone.
|
|
277
285
|
*/
|
|
278
286
|
approvedStripePaymentMethod(): string | null;
|
|
279
287
|
/**
|
package/dist/lifecycle.js
CHANGED
|
@@ -3,6 +3,7 @@ import { CardEndpointRefusedError } from './card-endpoint.js';
|
|
|
3
3
|
import { parseOwnedShopReceipt, OWNED_SHOP_SKU, OWNED_SHOP_AMOUNT_CENTS, OWNED_SHOP_CURRENCY } from './owned-shop.generated.js';
|
|
4
4
|
import { isWspayChallenge } from './wspay.js';
|
|
5
5
|
import { HoldAnsweredError, HoldEndedError } from './hold.js';
|
|
6
|
+
import { stripeApprovedWay } from './stripe-continuation.js';
|
|
6
7
|
/**
|
|
7
8
|
* The statuses that end an attempt: its outcome is known (`completed`, `declined`, `failed`,
|
|
8
9
|
* `timed_out`, `unsupported`, `cancelled`), or the SDK already reported it unknown with its own
|
|
@@ -25,19 +26,6 @@ export const MAX_STRIPE_CONTINUATION_CHECKS = 3;
|
|
|
25
26
|
* the post becomes a new approval instead of hanging the checkout.
|
|
26
27
|
*/
|
|
27
28
|
export const MERCHANT_ORDER_READ_MS = 5_000;
|
|
28
|
-
const STRIPE_PAYMENT_METHOD_ID = /^pm_[A-Za-z0-9]{1,250}$/;
|
|
29
|
-
/** The `pm_` id in a Stripe `/v1/payment_methods` answer, or null for any other body. */
|
|
30
|
-
function stripePaymentMethodId(body) {
|
|
31
|
-
if (typeof body !== 'string')
|
|
32
|
-
return null;
|
|
33
|
-
try {
|
|
34
|
-
const id = JSON.parse(body)?.id;
|
|
35
|
-
return typeof id === 'string' && STRIPE_PAYMENT_METHOD_ID.test(id) ? id : null;
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
29
|
/** Shared by the raw CDP and Playwright transports. No browser ownership or payment execution lives here. */
|
|
42
30
|
export class CheckoutLifecycle {
|
|
43
31
|
options;
|
|
@@ -62,8 +50,9 @@ export class CheckoutLifecycle {
|
|
|
62
50
|
heldBeforeHandoff = false;
|
|
63
51
|
// What the continuation that went through confirmed: a payment, or a card save.
|
|
64
52
|
stripeContinuedReason = 'stripe_payment_continued';
|
|
65
|
-
// The
|
|
66
|
-
|
|
53
|
+
// The object a Stripe tokenization approval returned, and the field a confirmation
|
|
54
|
+
// names it by: see approvedStripeWay.
|
|
55
|
+
approvedWay = null;
|
|
67
56
|
ownedShopOrderId = null;
|
|
68
57
|
// The reason Nike's order was refused while this attempt was under way (merchantOrderRefused): its handoff keeps it failed.
|
|
69
58
|
orderRefusal = null;
|
|
@@ -367,8 +356,7 @@ export class CheckoutLifecycle {
|
|
|
367
356
|
this.unboundStripeToken = true;
|
|
368
357
|
this.stripeTokenPrepared = true;
|
|
369
358
|
this.held = true;
|
|
370
|
-
|
|
371
|
-
this.approvedPaymentMethod = stripePaymentMethodId(replay.body);
|
|
359
|
+
this.approvedWay = stripeApprovedWay(url.pathname, replay.body);
|
|
372
360
|
}
|
|
373
361
|
}
|
|
374
362
|
catch { /* unknown URL cannot establish a token binding */ }
|
|
@@ -382,15 +370,25 @@ export class CheckoutLifecycle {
|
|
|
382
370
|
* VaultClient.withoutCard, which then refuses a Nuvei payment without a card.
|
|
383
371
|
*/
|
|
384
372
|
cardHandoffs() { return [...this.handoffs]; }
|
|
373
|
+
/**
|
|
374
|
+
* The object a Stripe confirmation may pay with in place of the card it sends
|
|
375
|
+
* again (cdp.ts claimStripeContinuation): the one this attachment's approved
|
|
376
|
+
* tokenization returned, with the field that names it, while its continuation
|
|
377
|
+
* is still open. Null for a tokenization no confirmation names by id
|
|
378
|
+
* (`/v1/tokens`), and once the checkout was cancelled, aborted or reconciled.
|
|
379
|
+
*/
|
|
380
|
+
approvedStripeWay() {
|
|
381
|
+
return this.stripeContinuationOpen() ? this.approvedWay : null;
|
|
382
|
+
}
|
|
385
383
|
/**
|
|
386
384
|
* The payment method a Stripe card save may pay with in place of the card
|
|
387
|
-
* it sends again
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
* checkout was cancelled, aborted or reconciled.
|
|
385
|
+
* it sends again: the `pm_` an approved `/v1/payment_methods` request
|
|
386
|
+
* returned. Null for every other approved object, since a SetupIntent
|
|
387
|
+
* confirm pays with a payment method alone.
|
|
391
388
|
*/
|
|
392
389
|
approvedStripePaymentMethod() {
|
|
393
|
-
|
|
390
|
+
const way = this.approvedStripeWay();
|
|
391
|
+
return way?.field === 'payment_method' ? way.id : null;
|
|
394
392
|
}
|
|
395
393
|
/**
|
|
396
394
|
* The approval a page's card-free Stripe confirmation may continue, or null.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
// Generated from @agent-cards/payment-core. Do not edit.
|
|
3
|
-
// artifact-sha256:
|
|
3
|
+
// artifact-sha256: e2228c7919341a7b3615b285c3aa77948c247c13145a1e394a1bb1c64acbca06
|
|
4
4
|
// src/json-path.js
|
|
5
5
|
var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
6
6
|
function isPlainObject(v) {
|
|
@@ -318,17 +318,39 @@ function enclosedValue(char) {
|
|
|
318
318
|
}
|
|
319
319
|
var asciiDigits = (text) => (typeof text.normalize === "function" ? text.normalize("NFKC") : text).replace(ENCLOSED_CHAR, enclosedValue).replace(/\p{Nd}/gu, (char) => char >= "0" && char <= "9" ? char : digitValue(char));
|
|
320
320
|
var unescaped = (text) => text.replace(/\\u([0-9a-fA-F]{4})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)));
|
|
321
|
+
var UTF8_SEQUENCE = "[\\x00-\\x7f]|[\\xc2-\\xdf][\\x80-\\xbf]|\\xe0[\\xa0-\\xbf][\\x80-\\xbf]|[\\xe1-\\xec\\xee\\xef][\\x80-\\xbf]{2}|\\xed[\\x80-\\x9f][\\x80-\\xbf]|\\xf0[\\x90-\\xbf][\\x80-\\xbf]{2}|[\\xf1-\\xf3][\\x80-\\xbf]{3}|\\xf4[\\x80-\\x8f][\\x80-\\xbf]{2}";
|
|
322
|
+
var UTF8_WHOLE = /* @__PURE__ */ new RegExp(`^(?:${UTF8_SEQUENCE})*$`);
|
|
323
|
+
var UTF8_ONE = /* @__PURE__ */ new RegExp(UTF8_SEQUENCE, "g");
|
|
324
|
+
function utf8Of(bytes) {
|
|
325
|
+
if (!/[\x80-\xff]/.test(bytes) || !UTF8_WHOLE.test(bytes))
|
|
326
|
+
return null;
|
|
327
|
+
return bytes.replace(UTF8_ONE, (sequence) => {
|
|
328
|
+
if (sequence.length === 1)
|
|
329
|
+
return sequence;
|
|
330
|
+
const lead = sequence.charCodeAt(0);
|
|
331
|
+
let point = lead & (sequence.length === 2 ? 31 : sequence.length === 3 ? 15 : 7);
|
|
332
|
+
for (let i = 1; i < sequence.length; i += 1)
|
|
333
|
+
point = point << 6 | sequence.charCodeAt(i) & 63;
|
|
334
|
+
return String.fromCodePoint(point);
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
var utf8Runs = (text) => text.replace(/[\x80-\xff]+/g, (run) => utf8Of(run) ?? run);
|
|
321
338
|
var decodedInPlace = (text) => text.replace(BASE64_PIECE, (piece) => {
|
|
322
339
|
const bare = piece.replace(/=+$/, "");
|
|
323
340
|
for (let skip = 0; skip < 4 && skip < bare.length - 1; skip += 1) {
|
|
324
341
|
const bytes = base64Text(bare.slice(skip));
|
|
325
342
|
if (/^[\x20-\x7e]+$/.test(bytes))
|
|
326
343
|
return bare.slice(0, skip) + bytes;
|
|
344
|
+
const utf82 = utf8Of(bytes);
|
|
345
|
+
if (utf82 !== null && !/\p{C}/u.test(utf82))
|
|
346
|
+
return bare.slice(0, skip) + utf82;
|
|
327
347
|
}
|
|
328
348
|
return piece;
|
|
329
349
|
});
|
|
330
350
|
function collect(text, layers, streams, runs) {
|
|
331
351
|
const base = /* @__PURE__ */ new Set([...readings(text), ...readings(unescaped(text))]);
|
|
352
|
+
for (const reading of [...base])
|
|
353
|
+
base.add(utf8Runs(reading));
|
|
332
354
|
for (const reading of /* @__PURE__ */ new Set([...base, ...[...base].map(decodedInPlace)])) {
|
|
333
355
|
const digits = asciiDigits(reading);
|
|
334
356
|
const sequence = digits.match(/[0-9]+/g) ?? [];
|
|
@@ -341,8 +363,13 @@ function collect(text, layers, streams, runs) {
|
|
|
341
363
|
if (layers === 0)
|
|
342
364
|
continue;
|
|
343
365
|
for (const run of new Set(reading.match(BASE64_RUN))) {
|
|
344
|
-
for (let skip = 0; skip < 4; skip += 1)
|
|
345
|
-
|
|
366
|
+
for (let skip = 0; skip < 4; skip += 1) {
|
|
367
|
+
const bytes = base64Text(run.slice(skip));
|
|
368
|
+
collect(bytes, layers - 1, streams, runs);
|
|
369
|
+
const utf82 = utf8Of(bytes);
|
|
370
|
+
if (utf82 !== null)
|
|
371
|
+
collect(utf82, layers - 1, streams, runs);
|
|
372
|
+
}
|
|
346
373
|
}
|
|
347
374
|
}
|
|
348
375
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
// Generated from @agent-cards/payment-core. Do not edit.
|
|
3
|
-
// artifact-sha256:
|
|
3
|
+
// artifact-sha256: d5e732dd0bce3debee02e3f31107e65059e0d3888b54a605357a5817bb8909ce
|
|
4
4
|
// src/json-path.js
|
|
5
5
|
function roundTrips(parsed, body) {
|
|
6
6
|
try {
|
|
@@ -29,6 +29,8 @@ function enclosedValue(char) {
|
|
|
29
29
|
var asciiDigits = (text) => (typeof text.normalize === "function" ? text.normalize("NFKC") : text).replace(ENCLOSED_CHAR, enclosedValue).replace(/\p{Nd}/gu, (char) => char >= "0" && char <= "9" ? char : digitValue(char));
|
|
30
30
|
var digitCount = (text) => (asciiDigits(String(text)).match(/\p{N}/gu) ?? []).length;
|
|
31
31
|
var NAME_DIGITS = 3;
|
|
32
|
+
var UTF8_SEQUENCE = "[\\x00-\\x7f]|[\\xc2-\\xdf][\\x80-\\xbf]|\\xe0[\\xa0-\\xbf][\\x80-\\xbf]|[\\xe1-\\xec\\xee\\xef][\\x80-\\xbf]{2}|\\xed[\\x80-\\x9f][\\x80-\\xbf]|\\xf0[\\x90-\\xbf][\\x80-\\xbf]{2}|[\\xf1-\\xf3][\\x80-\\xbf]{3}|\\xf4[\\x80-\\x8f][\\x80-\\xbf]{2}";
|
|
33
|
+
var UTF8_WHOLE = /* @__PURE__ */ new RegExp(`^(?:${UTF8_SEQUENCE})*$`);
|
|
32
34
|
// src/sha256.js
|
|
33
35
|
var K = /* @__PURE__ */ new Uint32Array([
|
|
34
36
|
1116352408,
|
package/dist/primer.generated.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
// Generated from @agent-cards/payment-core. Do not edit.
|
|
3
|
-
// artifact-sha256:
|
|
3
|
+
// artifact-sha256: 8c51d9a96bc459152335ed188a90bb7d6b3548469c16938af3e384afdad5370b
|
|
4
4
|
// src/card-number-key.js
|
|
5
5
|
var CARD_NUMBER_KEY = /^(number|card_number|cardnumber|cardNum|card_num|pan)$/i;
|
|
6
6
|
// src/json-path.js
|
|
@@ -1992,6 +1992,8 @@ function enclosedValue(char) {
|
|
|
1992
1992
|
var asciiDigits = (text11) => (typeof text11.normalize === "function" ? text11.normalize("NFKC") : text11).replace(ENCLOSED_CHAR, enclosedValue).replace(/\p{Nd}/gu, (char) => char >= "0" && char <= "9" ? char : digitValue(char));
|
|
1993
1993
|
var digitCount = (text11) => (asciiDigits(String(text11)).match(/\p{N}/gu) ?? []).length;
|
|
1994
1994
|
var NAME_DIGITS = 3;
|
|
1995
|
+
var UTF8_SEQUENCE = "[\\x00-\\x7f]|[\\xc2-\\xdf][\\x80-\\xbf]|\\xe0[\\xa0-\\xbf][\\x80-\\xbf]|[\\xe1-\\xec\\xee\\xef][\\x80-\\xbf]{2}|\\xed[\\x80-\\x9f][\\x80-\\xbf]|\\xf0[\\x90-\\xbf][\\x80-\\xbf]{2}|[\\xf1-\\xf3][\\x80-\\xbf]{3}|\\xf4[\\x80-\\x8f][\\x80-\\xbf]{2}";
|
|
1996
|
+
var UTF8_WHOLE = /* @__PURE__ */ new RegExp(`^(?:${UTF8_SEQUENCE})*$`);
|
|
1995
1997
|
// src/pay-nl.js
|
|
1996
1998
|
var PAY_NL_PSP = "pay_nl";
|
|
1997
1999
|
var PAY_NL_TOKEN_URL = "https://payment.pay.nl/v1/Payment/getCardToken/json";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
// Generated from @agent-cards/payment-core. Do not edit.
|
|
3
|
-
// artifact-sha256:
|
|
3
|
+
// artifact-sha256: b2ba367a9b8d1758f1deea226abb2ca6637b40a88aa0c5ee7f359e074f4c017e
|
|
4
4
|
// src/deep-freeze.js
|
|
5
5
|
function deepFreeze(value) {
|
|
6
6
|
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
@@ -5797,6 +5797,9 @@ function trustedClientRecognizer(pspOrEntry) {
|
|
|
5797
5797
|
throw new Error("Refusing to pay: unknown payment processor.");
|
|
5798
5798
|
return definition;
|
|
5799
5799
|
}
|
|
5800
|
+
// src/answer-card-leak.js
|
|
5801
|
+
var UTF8_SEQUENCE = "[\\x00-\\x7f]|[\\xc2-\\xdf][\\x80-\\xbf]|\\xe0[\\xa0-\\xbf][\\x80-\\xbf]|[\\xe1-\\xec\\xee\\xef][\\x80-\\xbf]{2}|\\xed[\\x80-\\x9f][\\x80-\\xbf]|\\xf0[\\x90-\\xbf][\\x80-\\xbf]{2}|[\\xf1-\\xf3][\\x80-\\xbf]{3}|\\xf4[\\x80-\\x8f][\\x80-\\xbf]{2}";
|
|
5802
|
+
var UTF8_WHOLE = /* @__PURE__ */ new RegExp(`^(?:${UTF8_SEQUENCE})*$`);
|
|
5800
5803
|
// src/datatrans.js
|
|
5801
5804
|
var DATATRANS_HOSTS = Object.freeze(["pay.datatrans.com", "pay.sandbox.datatrans.com"]);
|
|
5802
5805
|
var DATATRANS_REFUSAL_REASONS = Object.freeze(["unsupported", "card_on_file", "brand_mismatch", "unregistered_merchant"]);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How an approved tokenization is named in the confirmation that pays with it,
|
|
3
|
+
* by the Stripe endpoint whose answer produced it. The same four endpoints mint
|
|
4
|
+
* an approved object (lifecycle.ts), and this table holds the three a
|
|
5
|
+
* confirmation names by id on its own. It mirrors APPROVED_OBJECT in the
|
|
6
|
+
* backend's checkout-continuation.ts, which judges exactly this shape: exactly
|
|
7
|
+
* one such field, and no payment_method_data field left beside it.
|
|
8
|
+
*
|
|
9
|
+
* `/v1/tokens` is deliberately absent. Its field lives inside the method data
|
|
10
|
+
* (payment_method_data[card][token]), so paying with a card token means writing
|
|
11
|
+
* into the method data this rewrite strips rather than replacing it, and no page
|
|
12
|
+
* has been seen doing that. A confirm carrying a card token keeps the ordinary
|
|
13
|
+
* hold until one is.
|
|
14
|
+
*/
|
|
15
|
+
export declare const STRIPE_APPROVED_WAY: Readonly<Record<string, Readonly<{
|
|
16
|
+
field: string;
|
|
17
|
+
prefix: string;
|
|
18
|
+
}>>>;
|
|
19
|
+
/** An approved object a confirmation can pay with: the field that names it, and its id. */
|
|
20
|
+
export type StripeApprovedWay = {
|
|
21
|
+
field: string;
|
|
22
|
+
id: string;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* The approved object a Stripe tokenization answer returned, for the endpoint
|
|
26
|
+
* that answered: its field and its id. Null for an endpoint no confirmation
|
|
27
|
+
* names by id, for a body that will not parse, and for an id that is not the
|
|
28
|
+
* one that endpoint mints, so a confirmation can never be sent paying with
|
|
29
|
+
* something another endpoint produced.
|
|
30
|
+
*/
|
|
31
|
+
export declare function stripeApprovedWay(pathname: string, body: unknown): StripeApprovedWay | null;
|
|
32
|
+
/**
|
|
33
|
+
* The page's confirmation, paying with `way` instead of the card it carries:
|
|
34
|
+
* every `payment_method_data[...]` field goes (the card, and the billing details
|
|
35
|
+
* and telemetry Stripe.js sends beside it; the approved object already carries
|
|
36
|
+
* the billing details of the approved request), and `<field>=<id>` takes the
|
|
37
|
+
* place of the first one. Every other field stays byte for byte as the page
|
|
38
|
+
* wrote it (client_secret, key, expected_payment_method_type, use_stripe_sdk,
|
|
39
|
+
* return_url, mandate and option fields). Null, and nothing is rewritten, when
|
|
40
|
+
* the field is not one a confirmation pays with, when the id is not one Stripe
|
|
41
|
+
* mints, when a key cannot be decoded, when the body already names a way to pay
|
|
42
|
+
* (payment_method, source, confirmation_token), or when it carries no
|
|
43
|
+
* payment_method_data at all.
|
|
44
|
+
*/
|
|
45
|
+
export declare function confirmPayingWith(body: string, way: StripeApprovedWay): string | null;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// What a Stripe confirmation the cardholder already approved may pay with,
|
|
2
|
+
// shared by the card save and the payment (cdp.ts claimStripeContinuation).
|
|
3
|
+
// Kept in its own module, outside the package's published entries, so its
|
|
4
|
+
// tests can reach it and lifecycle.ts can read the same table.
|
|
5
|
+
//
|
|
6
|
+
// A page tokenizes the card through an approval and then confirms. Some pages
|
|
7
|
+
// confirm with the object they got back, which carries no card. Others send
|
|
8
|
+
// the card again inline, as payment_method_data[card][number] in the confirm:
|
|
9
|
+
// confirmCardSetup with the Card Element after createPaymentMethod does on a
|
|
10
|
+
// SetupIntent, and a store that creates a confirmation token for a fraud check
|
|
11
|
+
// and then calls confirmPayment({ elements }) does on a PaymentIntent. The card
|
|
12
|
+
// in that second request is whatever the agent typed; the approved object holds
|
|
13
|
+
// the cardholder's card. So that confirm is sent paying with the approved
|
|
14
|
+
// object instead, with no card in it, and the API decides whether it is the
|
|
15
|
+
// payment the cardholder approved.
|
|
16
|
+
/**
|
|
17
|
+
* How an approved tokenization is named in the confirmation that pays with it,
|
|
18
|
+
* by the Stripe endpoint whose answer produced it. The same four endpoints mint
|
|
19
|
+
* an approved object (lifecycle.ts), and this table holds the three a
|
|
20
|
+
* confirmation names by id on its own. It mirrors APPROVED_OBJECT in the
|
|
21
|
+
* backend's checkout-continuation.ts, which judges exactly this shape: exactly
|
|
22
|
+
* one such field, and no payment_method_data field left beside it.
|
|
23
|
+
*
|
|
24
|
+
* `/v1/tokens` is deliberately absent. Its field lives inside the method data
|
|
25
|
+
* (payment_method_data[card][token]), so paying with a card token means writing
|
|
26
|
+
* into the method data this rewrite strips rather than replacing it, and no page
|
|
27
|
+
* has been seen doing that. A confirm carrying a card token keeps the ordinary
|
|
28
|
+
* hold until one is.
|
|
29
|
+
*/
|
|
30
|
+
export const STRIPE_APPROVED_WAY = Object.freeze({
|
|
31
|
+
'/v1/payment_methods': Object.freeze({ field: 'payment_method', prefix: 'pm_' }),
|
|
32
|
+
'/v1/confirmation_tokens': Object.freeze({ field: 'confirmation_token', prefix: 'ctoken_' }),
|
|
33
|
+
'/v1/sources': Object.freeze({ field: 'source', prefix: 'src_' }),
|
|
34
|
+
});
|
|
35
|
+
// The other ways a confirmation can say what it pays with. A body that already
|
|
36
|
+
// names one is not the shape rewritten here, the field about to be written
|
|
37
|
+
// included: there is then nothing to replace, and the body already names a way
|
|
38
|
+
// to pay, so the ordinary hold decides it.
|
|
39
|
+
const OTHER_WAYS_TO_PAY = new Set(['payment_method', 'source', 'confirmation_token']);
|
|
40
|
+
// An id as Stripe mints it, and as a form field can carry it unescaped.
|
|
41
|
+
const APPROVED_ID = /^[a-z]+_[A-Za-z0-9]{1,250}$/;
|
|
42
|
+
/**
|
|
43
|
+
* The approved object a Stripe tokenization answer returned, for the endpoint
|
|
44
|
+
* that answered: its field and its id. Null for an endpoint no confirmation
|
|
45
|
+
* names by id, for a body that will not parse, and for an id that is not the
|
|
46
|
+
* one that endpoint mints, so a confirmation can never be sent paying with
|
|
47
|
+
* something another endpoint produced.
|
|
48
|
+
*/
|
|
49
|
+
export function stripeApprovedWay(pathname, body) {
|
|
50
|
+
const way = Object.prototype.hasOwnProperty.call(STRIPE_APPROVED_WAY, pathname) ? STRIPE_APPROVED_WAY[pathname] : undefined;
|
|
51
|
+
if (!way || typeof body !== 'string')
|
|
52
|
+
return null;
|
|
53
|
+
let id;
|
|
54
|
+
try {
|
|
55
|
+
id = JSON.parse(body)?.id;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
if (typeof id !== 'string' || !id.startsWith(way.prefix) || !APPROVED_ID.test(id))
|
|
61
|
+
return null;
|
|
62
|
+
return { field: way.field, id };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The page's confirmation, paying with `way` instead of the card it carries:
|
|
66
|
+
* every `payment_method_data[...]` field goes (the card, and the billing details
|
|
67
|
+
* and telemetry Stripe.js sends beside it; the approved object already carries
|
|
68
|
+
* the billing details of the approved request), and `<field>=<id>` takes the
|
|
69
|
+
* place of the first one. Every other field stays byte for byte as the page
|
|
70
|
+
* wrote it (client_secret, key, expected_payment_method_type, use_stripe_sdk,
|
|
71
|
+
* return_url, mandate and option fields). Null, and nothing is rewritten, when
|
|
72
|
+
* the field is not one a confirmation pays with, when the id is not one Stripe
|
|
73
|
+
* mints, when a key cannot be decoded, when the body already names a way to pay
|
|
74
|
+
* (payment_method, source, confirmation_token), or when it carries no
|
|
75
|
+
* payment_method_data at all.
|
|
76
|
+
*/
|
|
77
|
+
export function confirmPayingWith(body, way) {
|
|
78
|
+
if (typeof body !== 'string' || body === '')
|
|
79
|
+
return null;
|
|
80
|
+
if (!way || !OTHER_WAYS_TO_PAY.has(way.field) || !APPROVED_ID.test(way.id))
|
|
81
|
+
return null;
|
|
82
|
+
const kept = [];
|
|
83
|
+
let replaced = false;
|
|
84
|
+
for (const chunk of body.split('&')) {
|
|
85
|
+
if (chunk === '')
|
|
86
|
+
continue;
|
|
87
|
+
const eq = chunk.indexOf('=');
|
|
88
|
+
let key;
|
|
89
|
+
try {
|
|
90
|
+
key = decodeURIComponent((eq < 0 ? chunk : chunk.slice(0, eq)).replace(/\+/g, ' '));
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
if (OTHER_WAYS_TO_PAY.has(key))
|
|
96
|
+
return null;
|
|
97
|
+
if (key.startsWith('payment_method_data[')) {
|
|
98
|
+
if (!replaced)
|
|
99
|
+
kept.push(`${way.field}=${way.id}`);
|
|
100
|
+
replaced = true;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
kept.push(chunk);
|
|
104
|
+
}
|
|
105
|
+
return replaced ? kept.join('&') : null;
|
|
106
|
+
}
|
package/dist/stripe-setup.d.ts
CHANGED
|
@@ -2,15 +2,10 @@
|
|
|
2
2
|
export declare const STRIPE_SETUP_INTENT_CONFIRM: RegExp;
|
|
3
3
|
/**
|
|
4
4
|
* The page's SetupIntent confirm, paying with `paymentMethod` instead of the
|
|
5
|
-
* card it carries
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* expected_payment_method_type, use_stripe_sdk, return_url, mandate and option
|
|
11
|
-
* fields). Null, and nothing is rewritten, when the id is not a payment
|
|
12
|
-
* method's, when a key cannot be decoded, when the body already names another
|
|
13
|
-
* way to pay (payment_method, source, confirmation_token), or when it carries
|
|
14
|
-
* no payment_method_data at all.
|
|
5
|
+
* card it carries (confirmPayingWith, with the payment method as the way to
|
|
6
|
+
* pay). Null, and nothing is rewritten, when the id is not a payment method's,
|
|
7
|
+
* when a key cannot be decoded, when the body already names another way to pay
|
|
8
|
+
* (payment_method, source, confirmation_token), or when it carries no
|
|
9
|
+
* payment_method_data at all.
|
|
15
10
|
*/
|
|
16
11
|
export declare function setupConfirmPayingWith(body: string, paymentMethod: string): string | null;
|
package/dist/stripe-setup.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// The SetupIntent confirm a Stripe card save continues with, shared by both
|
|
2
2
|
// adapters (cdp.ts claimStripeContinuation). Kept in its own module, outside the
|
|
3
|
-
// package's published entries, so its tests can reach it.
|
|
3
|
+
// package's published entries, so its tests can reach it. The rewrite itself,
|
|
4
|
+
// and the table of approved objects a confirmation can pay with, live in
|
|
5
|
+
// stripe-continuation.ts, which the payment side reads too.
|
|
4
6
|
//
|
|
5
7
|
// A page that creates the payment method first (createPaymentMethod, which the
|
|
6
8
|
// cardholder approves) and then confirms a SetupIntent usually pays with the
|
|
@@ -12,50 +14,20 @@
|
|
|
12
14
|
// agent typed; the approved payment method holds the cardholder's card. So that
|
|
13
15
|
// confirm continues paying with the approved payment method instead, once the
|
|
14
16
|
// API allows it.
|
|
17
|
+
import { confirmPayingWith } from './stripe-continuation.js';
|
|
15
18
|
/** A SetupIntent confirm's path, as Stripe.js sends it. */
|
|
16
19
|
export const STRIPE_SETUP_INTENT_CONFIRM = /^\/v1\/setup_intents\/seti_[A-Za-z0-9]+\/confirm$/;
|
|
17
20
|
const PAYMENT_METHOD_ID = /^pm_[A-Za-z0-9]{1,250}$/;
|
|
18
|
-
// The other ways a confirm can say what it pays with. A body that already names
|
|
19
|
-
// one is not the shape rewritten here.
|
|
20
|
-
const OTHER_WAYS_TO_PAY = new Set(['payment_method', 'source', 'confirmation_token']);
|
|
21
21
|
/**
|
|
22
22
|
* The page's SetupIntent confirm, paying with `paymentMethod` instead of the
|
|
23
|
-
* card it carries
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* expected_payment_method_type, use_stripe_sdk, return_url, mandate and option
|
|
29
|
-
* fields). Null, and nothing is rewritten, when the id is not a payment
|
|
30
|
-
* method's, when a key cannot be decoded, when the body already names another
|
|
31
|
-
* way to pay (payment_method, source, confirmation_token), or when it carries
|
|
32
|
-
* no payment_method_data at all.
|
|
23
|
+
* card it carries (confirmPayingWith, with the payment method as the way to
|
|
24
|
+
* pay). Null, and nothing is rewritten, when the id is not a payment method's,
|
|
25
|
+
* when a key cannot be decoded, when the body already names another way to pay
|
|
26
|
+
* (payment_method, source, confirmation_token), or when it carries no
|
|
27
|
+
* payment_method_data at all.
|
|
33
28
|
*/
|
|
34
29
|
export function setupConfirmPayingWith(body, paymentMethod) {
|
|
35
|
-
if (!PAYMENT_METHOD_ID.test(paymentMethod)
|
|
30
|
+
if (!PAYMENT_METHOD_ID.test(paymentMethod))
|
|
36
31
|
return null;
|
|
37
|
-
|
|
38
|
-
let replaced = false;
|
|
39
|
-
for (const chunk of body.split('&')) {
|
|
40
|
-
if (chunk === '')
|
|
41
|
-
continue;
|
|
42
|
-
const eq = chunk.indexOf('=');
|
|
43
|
-
let key;
|
|
44
|
-
try {
|
|
45
|
-
key = decodeURIComponent((eq < 0 ? chunk : chunk.slice(0, eq)).replace(/\+/g, ' '));
|
|
46
|
-
}
|
|
47
|
-
catch {
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
if (OTHER_WAYS_TO_PAY.has(key))
|
|
51
|
-
return null;
|
|
52
|
-
if (key.startsWith('payment_method_data[')) {
|
|
53
|
-
if (!replaced)
|
|
54
|
-
kept.push(`payment_method=${paymentMethod}`);
|
|
55
|
-
replaced = true;
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
kept.push(chunk);
|
|
59
|
-
}
|
|
60
|
-
return replaced ? kept.join('&') : null;
|
|
32
|
+
return confirmPayingWith(body, { field: 'payment_method', id: paymentMethod });
|
|
61
33
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-cards/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "Agentcard's SDK: one client, Agentcard, with two modules. checkout pauses a browser purchase and pays it with the person's own card; buy asks the Purchase API for a cart and places it. Card data never enters your process.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"_comment_test": "check:built runs first and names the command when a file the build generates (the copies in src/, the preflight contracts in dist/, the Kernel inventory) is missing or stale; verify:pack runs last, on the same dist.",
|
|
31
31
|
"check:built": "node scripts/generate-payment-core.mjs --check && node scripts/generate-url-masks.mjs --check && node scripts/generate-capabilities.mjs --check && node scripts/generate-agent-amount.mjs --check && node scripts/generate-preflight-contract.mjs --check && node scripts/generate-kernel-native-inventory.mjs --check",
|
|
32
32
|
"verify:pack": "node scripts/verify-pack.mjs",
|
|
33
|
-
"test": "npm run check:built && node test.mjs && node --test lifecycle.test.mjs merchant-abort.test.mjs preparation.test.mjs braintree.test.mjs pre-claim.test.mjs ekashu.test.mjs redsys.test.mjs quickpay.test.mjs paytrail.test.mjs paypal-hosted-fields.test.mjs paypal-card-forms.test.mjs cybersource-secure-acceptance.test.mjs ebanx.test.mjs payrexx.test.mjs payrexx-follow-ups.test.mjs payrexx-adapters.test.mjs nike-order.test.mjs nike-order-adapters.test.mjs autopilot.test.mjs stripe-checkout.test.mjs stripe-setup.test.mjs stripe-legacy-checkout.test.mjs payment-core.test.mjs prepared-processor.test.mjs merchant-hosted.test.mjs merchant-total.test.mjs sandbox-declaration.test.mjs minimum-delay.test.mjs paysafe.test.mjs wix-payments.test.mjs hipay.test.mjs openpay.test.mjs processout.test.mjs payu.test.mjs attachment.test.mjs worker-targets.test.mjs mercado-checkout.test.mjs mercado-polling.test.mjs amadeus.test.mjs pelecard.test.mjs aci.test.mjs primer.test.mjs payrails.test.mjs elavon-converge.test.mjs agentcard.test.mjs buy.test.mjs clean-dist.test.mjs approvals.test.mjs gmo.test.mjs cybersource-flex.test.mjs juspay-gate.test.mjs card-endpoint.test.mjs card-endpoint-fastspring.test.mjs card-endpoint-navigation.test.mjs merchant-session-probe.test.mjs datatrans.test.mjs authorize-net-dpm.test.mjs creditguard.test.mjs eprotect.test.mjs wspay.test.mjs shiji-sts.test.mjs worldline-mycheckout.test.mjs verifone.test.mjs gravy.test.mjs paddle-vgs.test.mjs sbps.test.mjs hold.test.mjs paddle-tokenex.test.mjs lyra.test.mjs gopay.test.mjs paygent.test.mjs twoc2p.test.mjs tap-payments.test.mjs pay-nl.test.mjs toast.test.mjs redact-url.test.mjs hosted-entry.test.mjs comgate.test.mjs przelewy24.test.mjs tokenex-iframe.test.mjs transbank.test.mjs sumup.test.mjs clover.test.mjs eximbay.test.mjs xendit.test.mjs omise.test.mjs fastspring.test.mjs amazon-payment-services.test.mjs barion.test.mjs paymob.test.mjs payu-latam.test.mjs nexi-checkout.test.mjs oceanpayment.test.mjs pin-payments.test.mjs payplug.test.mjs cardlink-vpos.test.mjs eghl.test.mjs paymentwall.test.mjs vtex-payments.test.mjs vtex-payments-window.test.mjs iyzico.test.mjs usaepay.test.mjs viva-wallet.test.mjs aurus.test.mjs monei.test.mjs paystack.test.mjs frisbii.test.mjs token-repeat.test.mjs && node --test preflight-package.test.mjs preflight-collector.test.mjs browser-tests.test.mjs && node --test kernel-native-qualification.test.mjs && node --test ../vault/scripts/recurly-validation/watch-duty-sdk-result.test.mjs && node scripts/verify-pack.mjs",
|
|
33
|
+
"test": "npm run check:built && node test.mjs && node --test lifecycle.test.mjs merchant-abort.test.mjs preparation.test.mjs braintree.test.mjs pre-claim.test.mjs ekashu.test.mjs redsys.test.mjs quickpay.test.mjs paytrail.test.mjs paypal-hosted-fields.test.mjs paypal-card-forms.test.mjs cybersource-secure-acceptance.test.mjs ebanx.test.mjs payrexx.test.mjs payrexx-follow-ups.test.mjs payrexx-adapters.test.mjs nike-order.test.mjs nike-order-adapters.test.mjs autopilot.test.mjs stripe-checkout.test.mjs stripe-setup.test.mjs stripe-payment-continuation.test.mjs stripe-legacy-checkout.test.mjs payment-core.test.mjs prepared-processor.test.mjs merchant-hosted.test.mjs merchant-total.test.mjs sandbox-declaration.test.mjs minimum-delay.test.mjs paysafe.test.mjs wix-payments.test.mjs hipay.test.mjs openpay.test.mjs processout.test.mjs payu.test.mjs attachment.test.mjs worker-targets.test.mjs mercado-checkout.test.mjs mercado-polling.test.mjs amadeus.test.mjs pelecard.test.mjs aci.test.mjs primer.test.mjs payrails.test.mjs elavon-converge.test.mjs agentcard.test.mjs buy.test.mjs clean-dist.test.mjs approvals.test.mjs gmo.test.mjs cybersource-flex.test.mjs juspay-gate.test.mjs card-endpoint.test.mjs card-endpoint-fastspring.test.mjs card-endpoint-navigation.test.mjs merchant-session-probe.test.mjs datatrans.test.mjs authorize-net-dpm.test.mjs creditguard.test.mjs eprotect.test.mjs wspay.test.mjs shiji-sts.test.mjs worldline-mycheckout.test.mjs verifone.test.mjs gravy.test.mjs paddle-vgs.test.mjs sbps.test.mjs hold.test.mjs paddle-tokenex.test.mjs lyra.test.mjs gopay.test.mjs paygent.test.mjs twoc2p.test.mjs tap-payments.test.mjs pay-nl.test.mjs toast.test.mjs redact-url.test.mjs hosted-entry.test.mjs comgate.test.mjs przelewy24.test.mjs tokenex-iframe.test.mjs transbank.test.mjs sumup.test.mjs clover.test.mjs eximbay.test.mjs xendit.test.mjs omise.test.mjs fastspring.test.mjs amazon-payment-services.test.mjs barion.test.mjs paymob.test.mjs payu-latam.test.mjs nexi-checkout.test.mjs oceanpayment.test.mjs pin-payments.test.mjs payplug.test.mjs cardlink-vpos.test.mjs eghl.test.mjs paymentwall.test.mjs vtex-payments.test.mjs vtex-payments-window.test.mjs iyzico.test.mjs usaepay.test.mjs viva-wallet.test.mjs aurus.test.mjs monei.test.mjs paystack.test.mjs frisbii.test.mjs token-repeat.test.mjs && node --test preflight-package.test.mjs preflight-collector.test.mjs browser-tests.test.mjs && node --test kernel-native-qualification.test.mjs && node --test ../vault/scripts/recurly-validation/watch-duty-sdk-result.test.mjs && node scripts/verify-pack.mjs",
|
|
34
34
|
"test:browser": "node browser-tests.mjs",
|
|
35
35
|
"check:payment-core": "node scripts/generate-payment-core.mjs --check",
|
|
36
36
|
"test:preflight": "node --test preflight-package.test.mjs preflight-collector.test.mjs kernel-native-qualification.test.mjs",
|