@brainerce/mcp-server 3.11.1 → 3.12.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/bin/http.js +198 -24
- package/dist/bin/stdio.js +198 -24
- package/dist/index.js +198 -24
- package/dist/index.mjs +198 -24
- package/package.json +54 -53
package/dist/index.js
CHANGED
|
@@ -744,17 +744,19 @@ function getPaymentProvidersSection() {
|
|
|
744
744
|
return `## Payment Provider Detection (DO THIS FIRST on checkout page!)
|
|
745
745
|
|
|
746
746
|
\`\`\`typescript
|
|
747
|
-
const { hasPayments, providers } = await client.getPaymentProviders();
|
|
747
|
+
const { hasPayments, providers, defaultProvider } = await client.getPaymentProviders();
|
|
748
748
|
if (!hasPayments) {
|
|
749
749
|
// Show error: "Payment is not configured for this store"
|
|
750
750
|
return;
|
|
751
751
|
}
|
|
752
|
-
|
|
753
|
-
const
|
|
754
|
-
const
|
|
752
|
+
// Primary vs additive (Shopify-parity): render wallets as express buttons ABOVE the card form.
|
|
753
|
+
const expressMethods = providers.filter(p => p.isAdditive); // e.g. PayPal (WALLET)
|
|
754
|
+
const primary = defaultProvider && !defaultProvider.isAdditive ? defaultProvider : undefined;
|
|
755
755
|
\`\`\`
|
|
756
756
|
|
|
757
|
-
Each provider has: \`id\`, \`provider\` (flexible string \u2014 \`'stripe'\`, \`'grow'\`, \`'paypal'\`, \`'cardcom'\`, \`'morning'\`, \`'takbull'\`, \`'sandbox'\`, and future providers), \`name\`, \`publicKey\`, \`stripeAccountId\` (Stripe only), \`supportedMethods\`, \`testMode\`, \`isDefault
|
|
757
|
+
Each provider has: \`id\`, \`provider\` (flexible string \u2014 \`'stripe'\`, \`'grow'\`, \`'paypal'\`, \`'cardcom'\`, \`'morning'\`, \`'takbull'\`, \`'sandbox'\`, and future providers), \`name\`, \`publicKey\`, \`stripeAccountId\` (Stripe only), \`supportedMethods\`, \`testMode\`, \`isDefault\`, plus the taxonomy fields \`methodType\` (\`'CREDIT_CARD'\` = the single primary card processor that settles the order; \`'WALLET'\`/other = additive), \`isAdditive\`, and \`presentation\` (\`'card_form'\` | \`'express_button'\` | \u2026).
|
|
758
|
+
|
|
759
|
+
**Primary vs. additive:** there is one primary card processor (the \`defaultProvider\`, \`isAdditive: false\`) plus any additive methods (\`isAdditive: true\`, e.g. PayPal). Render additive methods as accelerated-checkout **express buttons above** the card form \u2014 they sit alongside the primary, never replace it. Create the intent with the tapped provider's \`id\`. (Exception: a wallet-only store has no card processor, so its wallet becomes the \`defaultProvider\` and stands alone.)
|
|
758
760
|
|
|
759
761
|
The payment intent returned from \`createPaymentIntent()\` includes a \`clientSdk\` object whose \`renderType\` tells you exactly how to render \u2014 **branch on THAT, not on the provider name**:
|
|
760
762
|
|
|
@@ -1142,11 +1144,22 @@ client-side overlay needed. Swatch colors are language-agnostic.
|
|
|
1142
1144
|
function ProductDescription({ product }: { product: Product }) {
|
|
1143
1145
|
const content = getDescriptionContent(product);
|
|
1144
1146
|
if (!content) return null;
|
|
1145
|
-
|
|
1147
|
+
// Descriptions are merchant HTML and may contain <video> + host-locked
|
|
1148
|
+
// YouTube/Vimeo <iframe> embeds. NEVER render unsanitized \u2014 sanitize and
|
|
1149
|
+
// allowlist video/source + iframe (restricted to youtube/vimeo hosts).
|
|
1150
|
+
if ('html' in content) {
|
|
1151
|
+
return <div dangerouslySetInnerHTML={{ __html: sanitizeProductHtml(content.html) }} />;
|
|
1152
|
+
}
|
|
1146
1153
|
return <p>{content.text}</p>;
|
|
1147
1154
|
}
|
|
1148
1155
|
\`\`\`
|
|
1149
1156
|
|
|
1157
|
+
**Sanitize descriptions.** \`sanitizeProductHtml\` is the host-locked sanitizer the
|
|
1158
|
+
\`create-brainerce-store\` scaffold ships at \`src/lib/sanitize-html.ts\`. If you roll
|
|
1159
|
+
your own, allow \`video\`/\`source\` and \`iframe\` **restricted** to \`www.youtube.com\`,
|
|
1160
|
+
\`www.youtube-nocookie.com\`, \`player.vimeo.com\` (never arbitrary iframes), and add
|
|
1161
|
+
those hosts to your CSP \`frame-src\` or embeds render blank.
|
|
1162
|
+
|
|
1150
1163
|
### Metafields (Custom Product Fields) \u2014 display on product detail!
|
|
1151
1164
|
|
|
1152
1165
|
**IMPORTANT: Render metafield values based on \`mf.type\`!** Don't just display \`mf.value\` as text for all types.
|
|
@@ -1229,7 +1242,28 @@ const { url } = await client.uploadCustomizationFile(file);
|
|
|
1229
1242
|
// Then use the URL in metadata: metadata: { logo: url }
|
|
1230
1243
|
\`\`\`
|
|
1231
1244
|
|
|
1232
|
-
**Customization field properties:** \`key\`, \`name\` (display label), \`type\`, \`required\`, \`minLength\`, \`maxLength\`, \`minValue\`, \`maxValue\`, \`enumValues
|
|
1245
|
+
**Customization field properties:** \`key\`, \`name\` (display label), \`type\`, \`required\`, \`minLength\`, \`maxLength\`, \`minValue\`, \`maxValue\`, \`enumValues\` (array of \`{label, value, swatchColor?, swatchImageUrl?}\`), \`defaultValue\`, \`position\`
|
|
1246
|
+
|
|
1247
|
+
**SELECT / MULTI_SELECT \u2014 use \`option.value\` to submit, \`option.label\` to display:**
|
|
1248
|
+
|
|
1249
|
+
\`\`\`typescript
|
|
1250
|
+
for (const option of field.enumValues ?? []) {
|
|
1251
|
+
// option.value \u2192 what to submit in metadata
|
|
1252
|
+
// option.label \u2192 what to show the customer
|
|
1253
|
+
// option.swatchColor \u2192 optional hex color for color swatches
|
|
1254
|
+
}
|
|
1255
|
+
\`\`\`
|
|
1256
|
+
|
|
1257
|
+
**Display customizations in cart / checkout \u2014 no extra API call needed:**
|
|
1258
|
+
|
|
1259
|
+
CartItem and CheckoutLineItem both include a \`customizations\` object alongside \`metadata\`. Use \`customizations\` for display \u2014 it contains resolved labels, not raw keys.
|
|
1260
|
+
|
|
1261
|
+
\`\`\`typescript
|
|
1262
|
+
// Works for CartItem, CheckoutLineItem, and OrderItem \u2014 same shape
|
|
1263
|
+
const lines = Object.values(item.customizations ?? {})
|
|
1264
|
+
.map(c => \`\${c.label}: \${Array.isArray(c.value) ? c.value.join(', ') : c.value}\`);
|
|
1265
|
+
// e.g. ["Frame color: Gold", "Add-ons: Gift wrap"]
|
|
1266
|
+
\`\`\`
|
|
1233
1267
|
|
|
1234
1268
|
### Downloadable / Digital Products
|
|
1235
1269
|
|
|
@@ -2560,8 +2594,9 @@ await admin.createTaxRate({ name: 'VAT (Food)', rate: 0, country: 'GB', taxClass
|
|
|
2560
2594
|
await admin.mergeTaxClasses(food.id, standardClassId);
|
|
2561
2595
|
\`\`\`
|
|
2562
2596
|
|
|
2563
|
-
Storefront (public, no apiKey \u2014 \`storeId\` mode
|
|
2564
|
-
the
|
|
2597
|
+
Storefront (public, no apiKey \u2014 \`storeId\` mode OR vibe-coded mode \`vc_*\`, gated
|
|
2598
|
+
on the \`products:read\` scope every connection already has): \`getStoreTaxClasses()\`
|
|
2599
|
+
lists the store's classes (storefront-safe fields only) for a transparency badge.
|
|
2565
2600
|
|
|
2566
2601
|
For a buyer-facing tax preview on PDP / PLP / cart, \`estimateTax({ country,
|
|
2567
2602
|
subtotal })\` returns the tax portion at the Standard rate for the buyer's
|
|
@@ -2583,8 +2618,10 @@ A region binds countries \u2192 currency + tax-display mode + enabled payment
|
|
|
2583
2618
|
providers. Manage them via the SDK (scopes \`regions:read\` / \`regions:write\`).
|
|
2584
2619
|
\`detectRegion\` is a pure client-side helper to map a buyer's country to a
|
|
2585
2620
|
region; pass the resolved \`regionId\` to \`createCheckout\` to associate the
|
|
2586
|
-
checkout with a region (recorded for reporting + provider scoping
|
|
2587
|
-
|
|
2621
|
+
checkout with a region (recorded for reporting + provider scoping). FX-at-checkout:
|
|
2622
|
+
presentment-enabled regions (Stripe today) charge in the region currency and the
|
|
2623
|
+
checkout response carries a \`presentment\` overlay with the charged amounts;
|
|
2624
|
+
otherwise the checkout is charged in the store base currency.
|
|
2588
2625
|
|
|
2589
2626
|
\`\`\`typescript
|
|
2590
2627
|
const eu = await admin.createRegion({
|
|
@@ -2597,9 +2634,12 @@ const { data: regions } = await admin.getRegions();
|
|
|
2597
2634
|
const region = admin.detectRegion('DE', regions); // \u2192 eu, else default, else null
|
|
2598
2635
|
\`\`\`
|
|
2599
2636
|
|
|
2600
|
-
Storefront (public, no apiKey \u2014 \`storeId\` mode
|
|
2601
|
-
|
|
2602
|
-
|
|
2637
|
+
Storefront (public, no apiKey \u2014 \`storeId\` mode OR vibe-coded mode \`vc_*\`, gated
|
|
2638
|
+
on the \`products:read\` scope every connection already has): \`getStoreRegions()\`
|
|
2639
|
+
lists active regions, \`getStoreRegion(id)\` returns one region + its payment
|
|
2640
|
+
providers. \`getAutoRegion(country)\` and \`estimateTax({ country, subtotal })\` work
|
|
2641
|
+
in both modes too. Pair with \`detectRegion\` to pick the buyer's region for
|
|
2642
|
+
currency display.
|
|
2603
2643
|
|
|
2604
2644
|
\`\`\`typescript
|
|
2605
2645
|
const store = new BrainerceClient({ storeId: 'store_123' });
|
|
@@ -3223,6 +3263,76 @@ Rules:
|
|
|
3223
3263
|
count updates when the bot adds items.
|
|
3224
3264
|
`;
|
|
3225
3265
|
}
|
|
3266
|
+
function getStorefrontAnalyticsSection(connectionId) {
|
|
3267
|
+
return `## Storefront Traffic Analytics (visits, countries, sources)
|
|
3268
|
+
|
|
3269
|
+
Brainerce can track cookieless storefront traffic \u2014 how many people visit the
|
|
3270
|
+
store, from which countries, and from which traffic sources \u2014 and surface it in
|
|
3271
|
+
the merchant dashboard alongside sales (so the merchant gets a REAL conversion
|
|
3272
|
+
rate: visits \u2192 orders).
|
|
3273
|
+
|
|
3274
|
+
Add ONE line to the storefront's root layout (\`<head>\` or end of \`<body>\`):
|
|
3275
|
+
|
|
3276
|
+
\`\`\`html
|
|
3277
|
+
<script defer src="https://api.brainerce.com/t.js" data-channel="${connectionId}"></script>
|
|
3278
|
+
\`\`\`
|
|
3279
|
+
|
|
3280
|
+
That's it \u2014 the pixel auto-sends a pageview beacon on load and on SPA route
|
|
3281
|
+
changes. Stores scaffolded with \`create-brainerce-store\` already include it.
|
|
3282
|
+
|
|
3283
|
+
Privacy: the pixel is cookieless and stores NO personal data \u2014 no cookie, no
|
|
3284
|
+
cross-site/cross-day tracking, and the visitor IP is resolved to a country
|
|
3285
|
+
server-side then discarded. No cookie-consent banner is required for it under
|
|
3286
|
+
GDPR/ePrivacy.
|
|
3287
|
+
|
|
3288
|
+
CSP: if the storefront sets a Content-Security-Policy, allow the script + beacon:
|
|
3289
|
+
- \`script-src\` \u2026 \`https://api.brainerce.com\`
|
|
3290
|
+
- \`connect-src\` \u2026 \`https://api.brainerce.com\`
|
|
3291
|
+
|
|
3292
|
+
The merchant can toggle tracking per sales channel in the dashboard. The data
|
|
3293
|
+
shows up under Dashboard \u2192 Analytics (visits over time, by country, by source,
|
|
3294
|
+
by device) and can also be asked of the AI assistant ("how many visits did I get
|
|
3295
|
+
this month and from where?").
|
|
3296
|
+
`;
|
|
3297
|
+
}
|
|
3298
|
+
function getShippingAppSection() {
|
|
3299
|
+
return `## App Store Shipping (Shippo)
|
|
3300
|
+
|
|
3301
|
+
Merchants install Shippo from the Brainerce App Store. After connecting their own Shippo account
|
|
3302
|
+
(OAuth), live carrier rates appear automatically at checkout alongside any manually configured
|
|
3303
|
+
zone rates. **Billing goes directly to the merchant's Shippo account \u2014 Brainerce never charges.**
|
|
3304
|
+
|
|
3305
|
+
### Checkout \u2014 live carrier rates
|
|
3306
|
+
|
|
3307
|
+
No SDK changes needed. Once Shippo is installed and configured, the existing
|
|
3308
|
+
\`getShippingRates()\` call returns both manual zone rates and live Shippo quotes:
|
|
3309
|
+
|
|
3310
|
+
\`\`\`typescript
|
|
3311
|
+
const { rates } = await client.setShippingAddress(checkoutId, { ... });
|
|
3312
|
+
// rates may include:
|
|
3313
|
+
// { id: 'shippo:rate_8f123abc', name: 'USPS Priority Mail', price: '8.50', currency: 'USD', source: 'carrier' }
|
|
3314
|
+
\`\`\`
|
|
3315
|
+
|
|
3316
|
+
Rates prefixed \`shippo:\` are live Shippo quotes. Pass the full \`id\` as \`shippingRateId\`
|
|
3317
|
+
when calling \`selectShippingMethod()\`.
|
|
3318
|
+
|
|
3319
|
+
### Admin \u2014 purchase a shipping label
|
|
3320
|
+
|
|
3321
|
+
After the order is placed, the merchant purchases a label by passing the Shippo rate object_id:
|
|
3322
|
+
|
|
3323
|
+
\`\`\`typescript
|
|
3324
|
+
const label = await admin.createShippingLabel(orderId, {
|
|
3325
|
+
shippoRateObjectId: 'rate_8f123456789abcdef',
|
|
3326
|
+
});
|
|
3327
|
+
console.log(label.labelUrl); // PDF ready to print
|
|
3328
|
+
console.log(label.trackingNumber); // auto-populated on the order
|
|
3329
|
+
\`\`\`
|
|
3330
|
+
|
|
3331
|
+
The \`trackingNumber\` is stored on the \`Order\` and returned in \`getMyOrders()\`
|
|
3332
|
+
so customers can track their shipment automatically.
|
|
3333
|
+
|
|
3334
|
+
**SDK mode:** \`createShippingLabel()\` requires \`apiKey\` (admin mode only).`;
|
|
3335
|
+
}
|
|
3226
3336
|
function getSectionByTopic(topic, connectionId, currency) {
|
|
3227
3337
|
const cid = connectionId || "vc_YOUR_CONNECTION_ID";
|
|
3228
3338
|
const cur = currency || "USD";
|
|
@@ -3279,6 +3389,12 @@ function getSectionByTopic(topic, connectionId, currency) {
|
|
|
3279
3389
|
return getBlogSection();
|
|
3280
3390
|
case "storefront-bot":
|
|
3281
3391
|
return getStorefrontBotSection(cid);
|
|
3392
|
+
case "analytics":
|
|
3393
|
+
case "traffic-analytics":
|
|
3394
|
+
return getStorefrontAnalyticsSection(cid);
|
|
3395
|
+
case "shipping-app":
|
|
3396
|
+
case "shippo":
|
|
3397
|
+
return getShippingAppSection();
|
|
3282
3398
|
case "all":
|
|
3283
3399
|
return [
|
|
3284
3400
|
"# Brainerce SDK \u2014 full topic dump",
|
|
@@ -3347,6 +3463,10 @@ function getSectionByTopic(topic, connectionId, currency) {
|
|
|
3347
3463
|
"",
|
|
3348
3464
|
"---",
|
|
3349
3465
|
"",
|
|
3466
|
+
getStorefrontAnalyticsSection(cid),
|
|
3467
|
+
"",
|
|
3468
|
+
"---",
|
|
3469
|
+
"",
|
|
3350
3470
|
getProductCustomizationFieldsSection(),
|
|
3351
3471
|
"",
|
|
3352
3472
|
"---",
|
|
@@ -3416,6 +3536,7 @@ var GET_SDK_DOCS_SCHEMA = {
|
|
|
3416
3536
|
"inquiries",
|
|
3417
3537
|
"content",
|
|
3418
3538
|
"storefront-bot",
|
|
3539
|
+
"analytics",
|
|
3419
3540
|
"all"
|
|
3420
3541
|
]).describe("The SDK documentation topic to retrieve"),
|
|
3421
3542
|
salesChannelId: import_zod.z.string().optional().describe("Sales channel ID (starts with vc_). Used to personalize setup code."),
|
|
@@ -3453,7 +3574,7 @@ interface Product {
|
|
|
3453
3574
|
priceMin?: string | null; // Lowest variant price (VARIABLE products) \u2014 same as basePrice for VARIABLE, kept for back-compat and JSON-LD range display.
|
|
3454
3575
|
priceMax?: string | null; // Highest variant price (VARIABLE products). Use with priceMin for "\u20AA49 \u2013 \u20AA199" range.
|
|
3455
3576
|
priceVaries?: boolean; // true when variant prices differ \u2014 show "\u20AA49 \u2013 \u20AA199" range.
|
|
3456
|
-
// FX DISPLAY overlay (PRD \xA723). Set only when getProducts({ regionId }) was called AND region.currency !== store.currency. basePrice/salePrice above stay in store currency \u2014 these are additive
|
|
3577
|
+
// FX DISPLAY overlay (PRD \xA723). Set only when getProducts({ regionId }) was called AND region.currency !== store.currency. basePrice/salePrice above stay in store currency \u2014 these are additive. For presentment-enabled regions (Stripe) the displayPrice uses the same buffered rate the checkout charges (browsed == checkout); for display-only regions it is mid-market and the buyer is charged in store currency at checkout (payment provider handles customer-side FX).
|
|
3457
3578
|
displayPrice?: string; // basePrice \xD7 daily FX rate, in displayCurrency.
|
|
3458
3579
|
displaySalePrice?: string; // salePrice \xD7 rate (if salePrice present).
|
|
3459
3580
|
displayPriceMin?: string; // priceMin \xD7 rate (VARIABLE products).
|
|
@@ -3556,11 +3677,18 @@ interface ProductCustomizationField {
|
|
|
3556
3677
|
maxLength?: number | null;
|
|
3557
3678
|
minValue?: number | null; // NUMBER bounds
|
|
3558
3679
|
maxValue?: number | null;
|
|
3559
|
-
enumValues?:
|
|
3680
|
+
enumValues?: CustomizationFieldOption[]; // REQUIRED for SELECT / MULTI_SELECT
|
|
3560
3681
|
defaultValue?: string | null;
|
|
3561
3682
|
position: number; // Render order
|
|
3562
3683
|
}
|
|
3563
3684
|
|
|
3685
|
+
interface CustomizationFieldOption {
|
|
3686
|
+
label: string; // Display label (e.g., "Rose Gold")
|
|
3687
|
+
value: string; // Value stored in CartItem.metadata
|
|
3688
|
+
swatchColor?: string | null; // Optional hex color (e.g., "#B76E79")
|
|
3689
|
+
swatchImageUrl?: string | null; // Optional swatch image URL
|
|
3690
|
+
}
|
|
3691
|
+
|
|
3564
3692
|
interface ProductQueryParams {
|
|
3565
3693
|
page?: number;
|
|
3566
3694
|
limit?: number;
|
|
@@ -3654,6 +3782,7 @@ interface CartItem {
|
|
|
3654
3782
|
image?: ProductImage | string | null;
|
|
3655
3783
|
} | null;
|
|
3656
3784
|
metadata?: Record<string, unknown> | null; // Buyer-submitted customization values, keyed by ProductCustomizationField.key
|
|
3785
|
+
customizations?: Record<string, { label: string; value: string | string[]; type: string }>; // Resolved labels \u2014 use this to display "Color: Silver" without extra getProduct() call
|
|
3657
3786
|
createdAt: string;
|
|
3658
3787
|
updatedAt: string;
|
|
3659
3788
|
}
|
|
@@ -3707,7 +3836,7 @@ interface Checkout {
|
|
|
3707
3836
|
status: CheckoutStatus;
|
|
3708
3837
|
email?: string | null;
|
|
3709
3838
|
customerId?: string | null;
|
|
3710
|
-
regionId?: string | null; // multi-region: recorded for reporting + provider scoping (currency
|
|
3839
|
+
regionId?: string | null; // multi-region: recorded for reporting + provider scoping. FX-at-checkout: presentment-enabled regions (Stripe) charge in the region currency \u2014 see the presentment field below; else charged in store base currency
|
|
3711
3840
|
shippingAddress?: CheckoutAddress | null;
|
|
3712
3841
|
billingAddress?: CheckoutAddress | null;
|
|
3713
3842
|
shippingRateId?: string | null;
|
|
@@ -3727,6 +3856,18 @@ interface Checkout {
|
|
|
3727
3856
|
itemCount: number;
|
|
3728
3857
|
availableShippingRates?: ShippingRate[];
|
|
3729
3858
|
reservation?: ReservationInfo;
|
|
3859
|
+
// FX-at-checkout: present ONLY when the region charges in its own currency (presentment-enabled \u2014 Stripe today). The amounts the buyer is actually CHARGED, in presentment.currency; presentment.total equals the payment intent amount. Render these (not total/currency above) when present. Absent = charged in store base currency. The fields above stay the base reference.
|
|
3860
|
+
presentment?: {
|
|
3861
|
+
currency: string; // ISO-4217 charged currency, e.g. "EUR"
|
|
3862
|
+
subtotal: string;
|
|
3863
|
+
discountAmount: string;
|
|
3864
|
+
shippingAmount: string;
|
|
3865
|
+
taxAmount: string;
|
|
3866
|
+
surchargeAmount: string;
|
|
3867
|
+
total: string; // equals the charged amount, to the cent
|
|
3868
|
+
fxChargingRate: string; // base\u2192presentment rate (buffer included)
|
|
3869
|
+
fxBufferPercent: string | null;
|
|
3870
|
+
};
|
|
3730
3871
|
createdAt: string;
|
|
3731
3872
|
updatedAt: string;
|
|
3732
3873
|
}
|
|
@@ -3741,6 +3882,7 @@ interface CheckoutLineItem {
|
|
|
3741
3882
|
product: { id: string; name: string; sku: string; images?: ProductImage[]; };
|
|
3742
3883
|
variant?: { id: string; name?: string | null; sku?: string | null; image?: ProductImage | string | null; } | null;
|
|
3743
3884
|
metadata?: Record<string, unknown> | null; // Copied from CartItem.metadata \u2014 buyer customization values
|
|
3885
|
+
customizations?: Record<string, { label: string; value: string | string[]; type: string }>; // Resolved labels \u2014 same shape as OrderItem.customizations
|
|
3744
3886
|
}
|
|
3745
3887
|
|
|
3746
3888
|
interface CheckoutAddress {
|
|
@@ -3977,7 +4119,10 @@ interface PaymentProviderConfig {
|
|
|
3977
4119
|
stripeAccountId?: string; // Stripe Connect only
|
|
3978
4120
|
supportedMethods: string[];
|
|
3979
4121
|
testMode: boolean;
|
|
3980
|
-
isDefault: boolean;
|
|
4122
|
+
isDefault: boolean; // only a primary (CREDIT_CARD) is ever the default
|
|
4123
|
+
methodType: 'CREDIT_CARD' | 'WALLET' | 'OFFSITE' | 'LOCAL' | 'REDEEMABLE';
|
|
4124
|
+
presentation: 'card_form' | 'express_button' | 'redirect' | 'local_option' | 'redeemable_field';
|
|
4125
|
+
isAdditive: boolean; // wallet/alt method shown ALONGSIDE the primary (e.g. PayPal)
|
|
3981
4126
|
}
|
|
3982
4127
|
type PaymentProvider = PaymentProviderConfig;
|
|
3983
4128
|
|
|
@@ -4104,10 +4249,22 @@ interface CartAppliedDiscount {
|
|
|
4104
4249
|
}
|
|
4105
4250
|
|
|
4106
4251
|
// Recommendation types
|
|
4252
|
+
interface RecommendationVariant {
|
|
4253
|
+
id: string; name?: string; price?: string; salePrice?: string;
|
|
4254
|
+
attributes?: Record<string, string>; image?: ProductImage | string; inventory?: InventoryInfo;
|
|
4255
|
+
}
|
|
4107
4256
|
interface ProductRecommendation {
|
|
4108
|
-
id: string; name: string; slug: string;
|
|
4257
|
+
id: string; name: string; slug: string;
|
|
4258
|
+
// For a VARIABLE target, basePrice is the pinned variant's price (when
|
|
4259
|
+
// targetVariantId is set) or the "from {min variant}" range \u2014 never 0.
|
|
4260
|
+
basePrice: string; salePrice?: string;
|
|
4109
4261
|
images: ProductImage[]; type: 'SIMPLE' | 'VARIABLE'; inventory?: InventoryInfo;
|
|
4110
4262
|
relationType: string;
|
|
4263
|
+
// Variant context (VARIABLE targets):
|
|
4264
|
+
targetVariantId?: string | null; // merchant-pinned variant, or null
|
|
4265
|
+
requiresVariantSelection?: boolean; // true \u2192 customer must pick from variants
|
|
4266
|
+
pinnedVariant?: { id: string; name?: string; attributes?: Record<string, string> } | null;
|
|
4267
|
+
variants?: RecommendationVariant[]; // present when requiresVariantSelection
|
|
4111
4268
|
}
|
|
4112
4269
|
interface ProductRecommendationsResponse {
|
|
4113
4270
|
crossSells: ProductRecommendation[];
|
|
@@ -4141,6 +4298,12 @@ interface CartBundleOfferOfferedProduct {
|
|
|
4141
4298
|
salePrice: string | null;
|
|
4142
4299
|
images: Array<{ url: string }>;
|
|
4143
4300
|
type: string;
|
|
4301
|
+
// Variant context (VARIABLE offered products):
|
|
4302
|
+
variantId?: string | null; // merchant-pinned variant for this slot
|
|
4303
|
+
requiresVariantSelection?: boolean; // true \u2192 customer must pick from variants
|
|
4304
|
+
pinnedVariant?: { id: string; name?: string; attributes?: Record<string, string> } | null;
|
|
4305
|
+
variants?: RecommendationVariant[]; // present when requiresVariantSelection
|
|
4306
|
+
// originalPrice = pinned/cheapest variant price for VARIABLE (not a 0 parent base).
|
|
4144
4307
|
originalPrice: string;
|
|
4145
4308
|
discountedPrice: string;
|
|
4146
4309
|
}
|
|
@@ -4624,10 +4787,12 @@ interface UpdateRegionDto extends Partial<CreateRegionDto> { isActive?: boolean
|
|
|
4624
4787
|
// client.detectRegion(country, regions): Region | null \u2014 pure, no network.
|
|
4625
4788
|
// \u2192 region whose countries includes the code, else the default region, else null.
|
|
4626
4789
|
// Pass the resolved regionId to createCheckout to associate the checkout with a
|
|
4627
|
-
// region (recorded for reporting + provider scoping
|
|
4628
|
-
//
|
|
4790
|
+
// region (recorded for reporting + provider scoping). FX-at-checkout:
|
|
4791
|
+
// presentment-enabled regions (Stripe) charge in the region currency and the
|
|
4792
|
+
// response carries a presentment overlay; else charged in store base currency.
|
|
4629
4793
|
//
|
|
4630
|
-
// Storefront (public, no apiKey \u2014 storeId mode
|
|
4794
|
+
// Storefront (public, no apiKey \u2014 storeId mode OR vibe-coded mode, salesChannelId 'vc_*';
|
|
4795
|
+
// the vc routes are gated on products:read, which every connection already has):
|
|
4631
4796
|
interface PublicRegion {
|
|
4632
4797
|
id: string; name: string; slug: string; currency: string;
|
|
4633
4798
|
countries: string[]; taxInclusive: boolean; isDefault: boolean;
|
|
@@ -4679,7 +4844,8 @@ interface AssignTaxClassDto { productIds?: string[]; variantIds?: string[]; cate
|
|
|
4679
4844
|
// deleteTaxClass(id), setDefaultTaxClass(id), assignTaxClass(id, dto),
|
|
4680
4845
|
// mergeTaxClasses(id, targetId)
|
|
4681
4846
|
//
|
|
4682
|
-
// SDK methods (storefront, public \u2014 storeId mode, no apiKey
|
|
4847
|
+
// SDK methods (storefront, public \u2014 storeId mode OR vibe-coded mode 'vc_*', no apiKey;
|
|
4848
|
+
// the vc routes are gated on products:read, which every connection already has):
|
|
4683
4849
|
// getStoreRegions(), getStoreRegion(id), getAutoRegion(country)
|
|
4684
4850
|
// getStoreTaxClasses(), estimateTax({ country?, subtotal })
|
|
4685
4851
|
//
|
|
@@ -5004,7 +5170,15 @@ const checkout = await client.getCheckout(checkoutId);
|
|
|
5004
5170
|
import { client } from './brainerce';
|
|
5005
5171
|
|
|
5006
5172
|
const { providers, hasPayments, defaultProvider } = await client.getPaymentProviders();
|
|
5007
|
-
// each provider: { id, provider, name, publicKey, supportedMethods, testMode,
|
|
5173
|
+
// each provider: { id, provider, name, publicKey, supportedMethods, testMode,
|
|
5174
|
+
// isDefault, methodType, presentation, isAdditive, clientSdk? }
|
|
5175
|
+
//
|
|
5176
|
+
// methodType splits providers into ONE primary card processor (CREDIT_CARD, the
|
|
5177
|
+
// defaultProvider that settles the order) and additive methods (isAdditive:true,
|
|
5178
|
+
// e.g. PayPal as a WALLET). Render additive methods as express buttons ABOVE the
|
|
5179
|
+
// card form \u2014 they sit alongside the primary, never replace it. Call
|
|
5180
|
+
// createPaymentIntent({ providerId }) with the tapped provider's id. (Wallet-only
|
|
5181
|
+
// store: with no card processor, the wallet becomes defaultProvider and stands alone.)
|
|
5008
5182
|
//
|
|
5009
5183
|
// After createPaymentIntent, the response carries a clientSdk.renderType that
|
|
5010
5184
|
// tells your UI how to render the payment step. The 5 possible values:
|