@brainerce/mcp-server 3.11.1 → 3.12.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/bin/http.js +93 -14
- package/dist/bin/stdio.js +93 -14
- package/dist/index.js +93 -14
- package/dist/index.mjs +93 -14
- package/package.json +53 -53
package/dist/bin/http.js
CHANGED
|
@@ -2537,8 +2537,9 @@ await admin.createTaxRate({ name: 'VAT (Food)', rate: 0, country: 'GB', taxClass
|
|
|
2537
2537
|
await admin.mergeTaxClasses(food.id, standardClassId);
|
|
2538
2538
|
\`\`\`
|
|
2539
2539
|
|
|
2540
|
-
Storefront (public, no apiKey \u2014 \`storeId\` mode
|
|
2541
|
-
the
|
|
2540
|
+
Storefront (public, no apiKey \u2014 \`storeId\` mode OR vibe-coded mode \`vc_*\`, gated
|
|
2541
|
+
on the \`products:read\` scope every connection already has): \`getStoreTaxClasses()\`
|
|
2542
|
+
lists the store's classes (storefront-safe fields only) for a transparency badge.
|
|
2542
2543
|
|
|
2543
2544
|
For a buyer-facing tax preview on PDP / PLP / cart, \`estimateTax({ country,
|
|
2544
2545
|
subtotal })\` returns the tax portion at the Standard rate for the buyer's
|
|
@@ -2560,8 +2561,10 @@ A region binds countries \u2192 currency + tax-display mode + enabled payment
|
|
|
2560
2561
|
providers. Manage them via the SDK (scopes \`regions:read\` / \`regions:write\`).
|
|
2561
2562
|
\`detectRegion\` is a pure client-side helper to map a buyer's country to a
|
|
2562
2563
|
region; pass the resolved \`regionId\` to \`createCheckout\` to associate the
|
|
2563
|
-
checkout with a region (recorded for reporting + provider scoping
|
|
2564
|
-
|
|
2564
|
+
checkout with a region (recorded for reporting + provider scoping). FX-at-checkout:
|
|
2565
|
+
presentment-enabled regions (Stripe today) charge in the region currency and the
|
|
2566
|
+
checkout response carries a \`presentment\` overlay with the charged amounts;
|
|
2567
|
+
otherwise the checkout is charged in the store base currency.
|
|
2565
2568
|
|
|
2566
2569
|
\`\`\`typescript
|
|
2567
2570
|
const eu = await admin.createRegion({
|
|
@@ -2574,9 +2577,12 @@ const { data: regions } = await admin.getRegions();
|
|
|
2574
2577
|
const region = admin.detectRegion('DE', regions); // \u2192 eu, else default, else null
|
|
2575
2578
|
\`\`\`
|
|
2576
2579
|
|
|
2577
|
-
Storefront (public, no apiKey \u2014 \`storeId\` mode
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
+
Storefront (public, no apiKey \u2014 \`storeId\` mode OR vibe-coded mode \`vc_*\`, gated
|
|
2581
|
+
on the \`products:read\` scope every connection already has): \`getStoreRegions()\`
|
|
2582
|
+
lists active regions, \`getStoreRegion(id)\` returns one region + its payment
|
|
2583
|
+
providers. \`getAutoRegion(country)\` and \`estimateTax({ country, subtotal })\` work
|
|
2584
|
+
in both modes too. Pair with \`detectRegion\` to pick the buyer's region for
|
|
2585
|
+
currency display.
|
|
2580
2586
|
|
|
2581
2587
|
\`\`\`typescript
|
|
2582
2588
|
const store = new BrainerceClient({ storeId: 'store_123' });
|
|
@@ -3200,6 +3206,38 @@ Rules:
|
|
|
3200
3206
|
count updates when the bot adds items.
|
|
3201
3207
|
`;
|
|
3202
3208
|
}
|
|
3209
|
+
function getStorefrontAnalyticsSection(connectionId) {
|
|
3210
|
+
return `## Storefront Traffic Analytics (visits, countries, sources)
|
|
3211
|
+
|
|
3212
|
+
Brainerce can track cookieless storefront traffic \u2014 how many people visit the
|
|
3213
|
+
store, from which countries, and from which traffic sources \u2014 and surface it in
|
|
3214
|
+
the merchant dashboard alongside sales (so the merchant gets a REAL conversion
|
|
3215
|
+
rate: visits \u2192 orders).
|
|
3216
|
+
|
|
3217
|
+
Add ONE line to the storefront's root layout (\`<head>\` or end of \`<body>\`):
|
|
3218
|
+
|
|
3219
|
+
\`\`\`html
|
|
3220
|
+
<script defer src="https://api.brainerce.com/t.js" data-channel="${connectionId}"></script>
|
|
3221
|
+
\`\`\`
|
|
3222
|
+
|
|
3223
|
+
That's it \u2014 the pixel auto-sends a pageview beacon on load and on SPA route
|
|
3224
|
+
changes. Stores scaffolded with \`create-brainerce-store\` already include it.
|
|
3225
|
+
|
|
3226
|
+
Privacy: the pixel is cookieless and stores NO personal data \u2014 no cookie, no
|
|
3227
|
+
cross-site/cross-day tracking, and the visitor IP is resolved to a country
|
|
3228
|
+
server-side then discarded. No cookie-consent banner is required for it under
|
|
3229
|
+
GDPR/ePrivacy.
|
|
3230
|
+
|
|
3231
|
+
CSP: if the storefront sets a Content-Security-Policy, allow the script + beacon:
|
|
3232
|
+
- \`script-src\` \u2026 \`https://api.brainerce.com\`
|
|
3233
|
+
- \`connect-src\` \u2026 \`https://api.brainerce.com\`
|
|
3234
|
+
|
|
3235
|
+
The merchant can toggle tracking per sales channel in the dashboard. The data
|
|
3236
|
+
shows up under Dashboard \u2192 Analytics (visits over time, by country, by source,
|
|
3237
|
+
by device) and can also be asked of the AI assistant ("how many visits did I get
|
|
3238
|
+
this month and from where?").
|
|
3239
|
+
`;
|
|
3240
|
+
}
|
|
3203
3241
|
function getSectionByTopic(topic, connectionId, currency) {
|
|
3204
3242
|
const cid = connectionId || "vc_YOUR_CONNECTION_ID";
|
|
3205
3243
|
const cur = currency || "USD";
|
|
@@ -3256,6 +3294,9 @@ function getSectionByTopic(topic, connectionId, currency) {
|
|
|
3256
3294
|
return getBlogSection();
|
|
3257
3295
|
case "storefront-bot":
|
|
3258
3296
|
return getStorefrontBotSection(cid);
|
|
3297
|
+
case "analytics":
|
|
3298
|
+
case "traffic-analytics":
|
|
3299
|
+
return getStorefrontAnalyticsSection(cid);
|
|
3259
3300
|
case "all":
|
|
3260
3301
|
return [
|
|
3261
3302
|
"# Brainerce SDK \u2014 full topic dump",
|
|
@@ -3324,6 +3365,10 @@ function getSectionByTopic(topic, connectionId, currency) {
|
|
|
3324
3365
|
"",
|
|
3325
3366
|
"---",
|
|
3326
3367
|
"",
|
|
3368
|
+
getStorefrontAnalyticsSection(cid),
|
|
3369
|
+
"",
|
|
3370
|
+
"---",
|
|
3371
|
+
"",
|
|
3327
3372
|
getProductCustomizationFieldsSection(),
|
|
3328
3373
|
"",
|
|
3329
3374
|
"---",
|
|
@@ -3393,6 +3438,7 @@ var GET_SDK_DOCS_SCHEMA = {
|
|
|
3393
3438
|
"inquiries",
|
|
3394
3439
|
"content",
|
|
3395
3440
|
"storefront-bot",
|
|
3441
|
+
"analytics",
|
|
3396
3442
|
"all"
|
|
3397
3443
|
]).describe("The SDK documentation topic to retrieve"),
|
|
3398
3444
|
salesChannelId: import_zod.z.string().optional().describe("Sales channel ID (starts with vc_). Used to personalize setup code."),
|
|
@@ -3430,7 +3476,7 @@ interface Product {
|
|
|
3430
3476
|
priceMin?: string | null; // Lowest variant price (VARIABLE products) \u2014 same as basePrice for VARIABLE, kept for back-compat and JSON-LD range display.
|
|
3431
3477
|
priceMax?: string | null; // Highest variant price (VARIABLE products). Use with priceMin for "\u20AA49 \u2013 \u20AA199" range.
|
|
3432
3478
|
priceVaries?: boolean; // true when variant prices differ \u2014 show "\u20AA49 \u2013 \u20AA199" range.
|
|
3433
|
-
// 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
|
|
3479
|
+
// 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).
|
|
3434
3480
|
displayPrice?: string; // basePrice \xD7 daily FX rate, in displayCurrency.
|
|
3435
3481
|
displaySalePrice?: string; // salePrice \xD7 rate (if salePrice present).
|
|
3436
3482
|
displayPriceMin?: string; // priceMin \xD7 rate (VARIABLE products).
|
|
@@ -3684,7 +3730,7 @@ interface Checkout {
|
|
|
3684
3730
|
status: CheckoutStatus;
|
|
3685
3731
|
email?: string | null;
|
|
3686
3732
|
customerId?: string | null;
|
|
3687
|
-
regionId?: string | null; // multi-region: recorded for reporting + provider scoping (currency
|
|
3733
|
+
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
|
|
3688
3734
|
shippingAddress?: CheckoutAddress | null;
|
|
3689
3735
|
billingAddress?: CheckoutAddress | null;
|
|
3690
3736
|
shippingRateId?: string | null;
|
|
@@ -3704,6 +3750,18 @@ interface Checkout {
|
|
|
3704
3750
|
itemCount: number;
|
|
3705
3751
|
availableShippingRates?: ShippingRate[];
|
|
3706
3752
|
reservation?: ReservationInfo;
|
|
3753
|
+
// 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.
|
|
3754
|
+
presentment?: {
|
|
3755
|
+
currency: string; // ISO-4217 charged currency, e.g. "EUR"
|
|
3756
|
+
subtotal: string;
|
|
3757
|
+
discountAmount: string;
|
|
3758
|
+
shippingAmount: string;
|
|
3759
|
+
taxAmount: string;
|
|
3760
|
+
surchargeAmount: string;
|
|
3761
|
+
total: string; // equals the charged amount, to the cent
|
|
3762
|
+
fxChargingRate: string; // base\u2192presentment rate (buffer included)
|
|
3763
|
+
fxBufferPercent: string | null;
|
|
3764
|
+
};
|
|
3707
3765
|
createdAt: string;
|
|
3708
3766
|
updatedAt: string;
|
|
3709
3767
|
}
|
|
@@ -4081,10 +4139,22 @@ interface CartAppliedDiscount {
|
|
|
4081
4139
|
}
|
|
4082
4140
|
|
|
4083
4141
|
// Recommendation types
|
|
4142
|
+
interface RecommendationVariant {
|
|
4143
|
+
id: string; name?: string; price?: string; salePrice?: string;
|
|
4144
|
+
attributes?: Record<string, string>; image?: ProductImage | string; inventory?: InventoryInfo;
|
|
4145
|
+
}
|
|
4084
4146
|
interface ProductRecommendation {
|
|
4085
|
-
id: string; name: string; slug: string;
|
|
4147
|
+
id: string; name: string; slug: string;
|
|
4148
|
+
// For a VARIABLE target, basePrice is the pinned variant's price (when
|
|
4149
|
+
// targetVariantId is set) or the "from {min variant}" range \u2014 never 0.
|
|
4150
|
+
basePrice: string; salePrice?: string;
|
|
4086
4151
|
images: ProductImage[]; type: 'SIMPLE' | 'VARIABLE'; inventory?: InventoryInfo;
|
|
4087
4152
|
relationType: string;
|
|
4153
|
+
// Variant context (VARIABLE targets):
|
|
4154
|
+
targetVariantId?: string | null; // merchant-pinned variant, or null
|
|
4155
|
+
requiresVariantSelection?: boolean; // true \u2192 customer must pick from variants
|
|
4156
|
+
pinnedVariant?: { id: string; name?: string; attributes?: Record<string, string> } | null;
|
|
4157
|
+
variants?: RecommendationVariant[]; // present when requiresVariantSelection
|
|
4088
4158
|
}
|
|
4089
4159
|
interface ProductRecommendationsResponse {
|
|
4090
4160
|
crossSells: ProductRecommendation[];
|
|
@@ -4118,6 +4188,12 @@ interface CartBundleOfferOfferedProduct {
|
|
|
4118
4188
|
salePrice: string | null;
|
|
4119
4189
|
images: Array<{ url: string }>;
|
|
4120
4190
|
type: string;
|
|
4191
|
+
// Variant context (VARIABLE offered products):
|
|
4192
|
+
variantId?: string | null; // merchant-pinned variant for this slot
|
|
4193
|
+
requiresVariantSelection?: boolean; // true \u2192 customer must pick from variants
|
|
4194
|
+
pinnedVariant?: { id: string; name?: string; attributes?: Record<string, string> } | null;
|
|
4195
|
+
variants?: RecommendationVariant[]; // present when requiresVariantSelection
|
|
4196
|
+
// originalPrice = pinned/cheapest variant price for VARIABLE (not a 0 parent base).
|
|
4121
4197
|
originalPrice: string;
|
|
4122
4198
|
discountedPrice: string;
|
|
4123
4199
|
}
|
|
@@ -4601,10 +4677,12 @@ interface UpdateRegionDto extends Partial<CreateRegionDto> { isActive?: boolean
|
|
|
4601
4677
|
// client.detectRegion(country, regions): Region | null \u2014 pure, no network.
|
|
4602
4678
|
// \u2192 region whose countries includes the code, else the default region, else null.
|
|
4603
4679
|
// Pass the resolved regionId to createCheckout to associate the checkout with a
|
|
4604
|
-
// region (recorded for reporting + provider scoping
|
|
4605
|
-
//
|
|
4680
|
+
// region (recorded for reporting + provider scoping). FX-at-checkout:
|
|
4681
|
+
// presentment-enabled regions (Stripe) charge in the region currency and the
|
|
4682
|
+
// response carries a presentment overlay; else charged in store base currency.
|
|
4606
4683
|
//
|
|
4607
|
-
// Storefront (public, no apiKey \u2014 storeId mode
|
|
4684
|
+
// Storefront (public, no apiKey \u2014 storeId mode OR vibe-coded mode, salesChannelId 'vc_*';
|
|
4685
|
+
// the vc routes are gated on products:read, which every connection already has):
|
|
4608
4686
|
interface PublicRegion {
|
|
4609
4687
|
id: string; name: string; slug: string; currency: string;
|
|
4610
4688
|
countries: string[]; taxInclusive: boolean; isDefault: boolean;
|
|
@@ -4656,7 +4734,8 @@ interface AssignTaxClassDto { productIds?: string[]; variantIds?: string[]; cate
|
|
|
4656
4734
|
// deleteTaxClass(id), setDefaultTaxClass(id), assignTaxClass(id, dto),
|
|
4657
4735
|
// mergeTaxClasses(id, targetId)
|
|
4658
4736
|
//
|
|
4659
|
-
// SDK methods (storefront, public \u2014 storeId mode, no apiKey
|
|
4737
|
+
// SDK methods (storefront, public \u2014 storeId mode OR vibe-coded mode 'vc_*', no apiKey;
|
|
4738
|
+
// the vc routes are gated on products:read, which every connection already has):
|
|
4660
4739
|
// getStoreRegions(), getStoreRegion(id), getAutoRegion(country)
|
|
4661
4740
|
// getStoreTaxClasses(), estimateTax({ country?, subtotal })
|
|
4662
4741
|
//
|
package/dist/bin/stdio.js
CHANGED
|
@@ -2534,8 +2534,9 @@ await admin.createTaxRate({ name: 'VAT (Food)', rate: 0, country: 'GB', taxClass
|
|
|
2534
2534
|
await admin.mergeTaxClasses(food.id, standardClassId);
|
|
2535
2535
|
\`\`\`
|
|
2536
2536
|
|
|
2537
|
-
Storefront (public, no apiKey \u2014 \`storeId\` mode
|
|
2538
|
-
the
|
|
2537
|
+
Storefront (public, no apiKey \u2014 \`storeId\` mode OR vibe-coded mode \`vc_*\`, gated
|
|
2538
|
+
on the \`products:read\` scope every connection already has): \`getStoreTaxClasses()\`
|
|
2539
|
+
lists the store's classes (storefront-safe fields only) for a transparency badge.
|
|
2539
2540
|
|
|
2540
2541
|
For a buyer-facing tax preview on PDP / PLP / cart, \`estimateTax({ country,
|
|
2541
2542
|
subtotal })\` returns the tax portion at the Standard rate for the buyer's
|
|
@@ -2557,8 +2558,10 @@ A region binds countries \u2192 currency + tax-display mode + enabled payment
|
|
|
2557
2558
|
providers. Manage them via the SDK (scopes \`regions:read\` / \`regions:write\`).
|
|
2558
2559
|
\`detectRegion\` is a pure client-side helper to map a buyer's country to a
|
|
2559
2560
|
region; pass the resolved \`regionId\` to \`createCheckout\` to associate the
|
|
2560
|
-
checkout with a region (recorded for reporting + provider scoping
|
|
2561
|
-
|
|
2561
|
+
checkout with a region (recorded for reporting + provider scoping). FX-at-checkout:
|
|
2562
|
+
presentment-enabled regions (Stripe today) charge in the region currency and the
|
|
2563
|
+
checkout response carries a \`presentment\` overlay with the charged amounts;
|
|
2564
|
+
otherwise the checkout is charged in the store base currency.
|
|
2562
2565
|
|
|
2563
2566
|
\`\`\`typescript
|
|
2564
2567
|
const eu = await admin.createRegion({
|
|
@@ -2571,9 +2574,12 @@ const { data: regions } = await admin.getRegions();
|
|
|
2571
2574
|
const region = admin.detectRegion('DE', regions); // \u2192 eu, else default, else null
|
|
2572
2575
|
\`\`\`
|
|
2573
2576
|
|
|
2574
|
-
Storefront (public, no apiKey \u2014 \`storeId\` mode
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
+
Storefront (public, no apiKey \u2014 \`storeId\` mode OR vibe-coded mode \`vc_*\`, gated
|
|
2578
|
+
on the \`products:read\` scope every connection already has): \`getStoreRegions()\`
|
|
2579
|
+
lists active regions, \`getStoreRegion(id)\` returns one region + its payment
|
|
2580
|
+
providers. \`getAutoRegion(country)\` and \`estimateTax({ country, subtotal })\` work
|
|
2581
|
+
in both modes too. Pair with \`detectRegion\` to pick the buyer's region for
|
|
2582
|
+
currency display.
|
|
2577
2583
|
|
|
2578
2584
|
\`\`\`typescript
|
|
2579
2585
|
const store = new BrainerceClient({ storeId: 'store_123' });
|
|
@@ -3197,6 +3203,38 @@ Rules:
|
|
|
3197
3203
|
count updates when the bot adds items.
|
|
3198
3204
|
`;
|
|
3199
3205
|
}
|
|
3206
|
+
function getStorefrontAnalyticsSection(connectionId) {
|
|
3207
|
+
return `## Storefront Traffic Analytics (visits, countries, sources)
|
|
3208
|
+
|
|
3209
|
+
Brainerce can track cookieless storefront traffic \u2014 how many people visit the
|
|
3210
|
+
store, from which countries, and from which traffic sources \u2014 and surface it in
|
|
3211
|
+
the merchant dashboard alongside sales (so the merchant gets a REAL conversion
|
|
3212
|
+
rate: visits \u2192 orders).
|
|
3213
|
+
|
|
3214
|
+
Add ONE line to the storefront's root layout (\`<head>\` or end of \`<body>\`):
|
|
3215
|
+
|
|
3216
|
+
\`\`\`html
|
|
3217
|
+
<script defer src="https://api.brainerce.com/t.js" data-channel="${connectionId}"></script>
|
|
3218
|
+
\`\`\`
|
|
3219
|
+
|
|
3220
|
+
That's it \u2014 the pixel auto-sends a pageview beacon on load and on SPA route
|
|
3221
|
+
changes. Stores scaffolded with \`create-brainerce-store\` already include it.
|
|
3222
|
+
|
|
3223
|
+
Privacy: the pixel is cookieless and stores NO personal data \u2014 no cookie, no
|
|
3224
|
+
cross-site/cross-day tracking, and the visitor IP is resolved to a country
|
|
3225
|
+
server-side then discarded. No cookie-consent banner is required for it under
|
|
3226
|
+
GDPR/ePrivacy.
|
|
3227
|
+
|
|
3228
|
+
CSP: if the storefront sets a Content-Security-Policy, allow the script + beacon:
|
|
3229
|
+
- \`script-src\` \u2026 \`https://api.brainerce.com\`
|
|
3230
|
+
- \`connect-src\` \u2026 \`https://api.brainerce.com\`
|
|
3231
|
+
|
|
3232
|
+
The merchant can toggle tracking per sales channel in the dashboard. The data
|
|
3233
|
+
shows up under Dashboard \u2192 Analytics (visits over time, by country, by source,
|
|
3234
|
+
by device) and can also be asked of the AI assistant ("how many visits did I get
|
|
3235
|
+
this month and from where?").
|
|
3236
|
+
`;
|
|
3237
|
+
}
|
|
3200
3238
|
function getSectionByTopic(topic, connectionId, currency) {
|
|
3201
3239
|
const cid = connectionId || "vc_YOUR_CONNECTION_ID";
|
|
3202
3240
|
const cur = currency || "USD";
|
|
@@ -3253,6 +3291,9 @@ function getSectionByTopic(topic, connectionId, currency) {
|
|
|
3253
3291
|
return getBlogSection();
|
|
3254
3292
|
case "storefront-bot":
|
|
3255
3293
|
return getStorefrontBotSection(cid);
|
|
3294
|
+
case "analytics":
|
|
3295
|
+
case "traffic-analytics":
|
|
3296
|
+
return getStorefrontAnalyticsSection(cid);
|
|
3256
3297
|
case "all":
|
|
3257
3298
|
return [
|
|
3258
3299
|
"# Brainerce SDK \u2014 full topic dump",
|
|
@@ -3321,6 +3362,10 @@ function getSectionByTopic(topic, connectionId, currency) {
|
|
|
3321
3362
|
"",
|
|
3322
3363
|
"---",
|
|
3323
3364
|
"",
|
|
3365
|
+
getStorefrontAnalyticsSection(cid),
|
|
3366
|
+
"",
|
|
3367
|
+
"---",
|
|
3368
|
+
"",
|
|
3324
3369
|
getProductCustomizationFieldsSection(),
|
|
3325
3370
|
"",
|
|
3326
3371
|
"---",
|
|
@@ -3390,6 +3435,7 @@ var GET_SDK_DOCS_SCHEMA = {
|
|
|
3390
3435
|
"inquiries",
|
|
3391
3436
|
"content",
|
|
3392
3437
|
"storefront-bot",
|
|
3438
|
+
"analytics",
|
|
3393
3439
|
"all"
|
|
3394
3440
|
]).describe("The SDK documentation topic to retrieve"),
|
|
3395
3441
|
salesChannelId: import_zod.z.string().optional().describe("Sales channel ID (starts with vc_). Used to personalize setup code."),
|
|
@@ -3427,7 +3473,7 @@ interface Product {
|
|
|
3427
3473
|
priceMin?: string | null; // Lowest variant price (VARIABLE products) \u2014 same as basePrice for VARIABLE, kept for back-compat and JSON-LD range display.
|
|
3428
3474
|
priceMax?: string | null; // Highest variant price (VARIABLE products). Use with priceMin for "\u20AA49 \u2013 \u20AA199" range.
|
|
3429
3475
|
priceVaries?: boolean; // true when variant prices differ \u2014 show "\u20AA49 \u2013 \u20AA199" range.
|
|
3430
|
-
// 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
|
|
3476
|
+
// 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).
|
|
3431
3477
|
displayPrice?: string; // basePrice \xD7 daily FX rate, in displayCurrency.
|
|
3432
3478
|
displaySalePrice?: string; // salePrice \xD7 rate (if salePrice present).
|
|
3433
3479
|
displayPriceMin?: string; // priceMin \xD7 rate (VARIABLE products).
|
|
@@ -3681,7 +3727,7 @@ interface Checkout {
|
|
|
3681
3727
|
status: CheckoutStatus;
|
|
3682
3728
|
email?: string | null;
|
|
3683
3729
|
customerId?: string | null;
|
|
3684
|
-
regionId?: string | null; // multi-region: recorded for reporting + provider scoping (currency
|
|
3730
|
+
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
|
|
3685
3731
|
shippingAddress?: CheckoutAddress | null;
|
|
3686
3732
|
billingAddress?: CheckoutAddress | null;
|
|
3687
3733
|
shippingRateId?: string | null;
|
|
@@ -3701,6 +3747,18 @@ interface Checkout {
|
|
|
3701
3747
|
itemCount: number;
|
|
3702
3748
|
availableShippingRates?: ShippingRate[];
|
|
3703
3749
|
reservation?: ReservationInfo;
|
|
3750
|
+
// 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.
|
|
3751
|
+
presentment?: {
|
|
3752
|
+
currency: string; // ISO-4217 charged currency, e.g. "EUR"
|
|
3753
|
+
subtotal: string;
|
|
3754
|
+
discountAmount: string;
|
|
3755
|
+
shippingAmount: string;
|
|
3756
|
+
taxAmount: string;
|
|
3757
|
+
surchargeAmount: string;
|
|
3758
|
+
total: string; // equals the charged amount, to the cent
|
|
3759
|
+
fxChargingRate: string; // base\u2192presentment rate (buffer included)
|
|
3760
|
+
fxBufferPercent: string | null;
|
|
3761
|
+
};
|
|
3704
3762
|
createdAt: string;
|
|
3705
3763
|
updatedAt: string;
|
|
3706
3764
|
}
|
|
@@ -4078,10 +4136,22 @@ interface CartAppliedDiscount {
|
|
|
4078
4136
|
}
|
|
4079
4137
|
|
|
4080
4138
|
// Recommendation types
|
|
4139
|
+
interface RecommendationVariant {
|
|
4140
|
+
id: string; name?: string; price?: string; salePrice?: string;
|
|
4141
|
+
attributes?: Record<string, string>; image?: ProductImage | string; inventory?: InventoryInfo;
|
|
4142
|
+
}
|
|
4081
4143
|
interface ProductRecommendation {
|
|
4082
|
-
id: string; name: string; slug: string;
|
|
4144
|
+
id: string; name: string; slug: string;
|
|
4145
|
+
// For a VARIABLE target, basePrice is the pinned variant's price (when
|
|
4146
|
+
// targetVariantId is set) or the "from {min variant}" range \u2014 never 0.
|
|
4147
|
+
basePrice: string; salePrice?: string;
|
|
4083
4148
|
images: ProductImage[]; type: 'SIMPLE' | 'VARIABLE'; inventory?: InventoryInfo;
|
|
4084
4149
|
relationType: string;
|
|
4150
|
+
// Variant context (VARIABLE targets):
|
|
4151
|
+
targetVariantId?: string | null; // merchant-pinned variant, or null
|
|
4152
|
+
requiresVariantSelection?: boolean; // true \u2192 customer must pick from variants
|
|
4153
|
+
pinnedVariant?: { id: string; name?: string; attributes?: Record<string, string> } | null;
|
|
4154
|
+
variants?: RecommendationVariant[]; // present when requiresVariantSelection
|
|
4085
4155
|
}
|
|
4086
4156
|
interface ProductRecommendationsResponse {
|
|
4087
4157
|
crossSells: ProductRecommendation[];
|
|
@@ -4115,6 +4185,12 @@ interface CartBundleOfferOfferedProduct {
|
|
|
4115
4185
|
salePrice: string | null;
|
|
4116
4186
|
images: Array<{ url: string }>;
|
|
4117
4187
|
type: string;
|
|
4188
|
+
// Variant context (VARIABLE offered products):
|
|
4189
|
+
variantId?: string | null; // merchant-pinned variant for this slot
|
|
4190
|
+
requiresVariantSelection?: boolean; // true \u2192 customer must pick from variants
|
|
4191
|
+
pinnedVariant?: { id: string; name?: string; attributes?: Record<string, string> } | null;
|
|
4192
|
+
variants?: RecommendationVariant[]; // present when requiresVariantSelection
|
|
4193
|
+
// originalPrice = pinned/cheapest variant price for VARIABLE (not a 0 parent base).
|
|
4118
4194
|
originalPrice: string;
|
|
4119
4195
|
discountedPrice: string;
|
|
4120
4196
|
}
|
|
@@ -4598,10 +4674,12 @@ interface UpdateRegionDto extends Partial<CreateRegionDto> { isActive?: boolean
|
|
|
4598
4674
|
// client.detectRegion(country, regions): Region | null \u2014 pure, no network.
|
|
4599
4675
|
// \u2192 region whose countries includes the code, else the default region, else null.
|
|
4600
4676
|
// Pass the resolved regionId to createCheckout to associate the checkout with a
|
|
4601
|
-
// region (recorded for reporting + provider scoping
|
|
4602
|
-
//
|
|
4677
|
+
// region (recorded for reporting + provider scoping). FX-at-checkout:
|
|
4678
|
+
// presentment-enabled regions (Stripe) charge in the region currency and the
|
|
4679
|
+
// response carries a presentment overlay; else charged in store base currency.
|
|
4603
4680
|
//
|
|
4604
|
-
// Storefront (public, no apiKey \u2014 storeId mode
|
|
4681
|
+
// Storefront (public, no apiKey \u2014 storeId mode OR vibe-coded mode, salesChannelId 'vc_*';
|
|
4682
|
+
// the vc routes are gated on products:read, which every connection already has):
|
|
4605
4683
|
interface PublicRegion {
|
|
4606
4684
|
id: string; name: string; slug: string; currency: string;
|
|
4607
4685
|
countries: string[]; taxInclusive: boolean; isDefault: boolean;
|
|
@@ -4653,7 +4731,8 @@ interface AssignTaxClassDto { productIds?: string[]; variantIds?: string[]; cate
|
|
|
4653
4731
|
// deleteTaxClass(id), setDefaultTaxClass(id), assignTaxClass(id, dto),
|
|
4654
4732
|
// mergeTaxClasses(id, targetId)
|
|
4655
4733
|
//
|
|
4656
|
-
// SDK methods (storefront, public \u2014 storeId mode, no apiKey
|
|
4734
|
+
// SDK methods (storefront, public \u2014 storeId mode OR vibe-coded mode 'vc_*', no apiKey;
|
|
4735
|
+
// the vc routes are gated on products:read, which every connection already has):
|
|
4657
4736
|
// getStoreRegions(), getStoreRegion(id), getAutoRegion(country)
|
|
4658
4737
|
// getStoreTaxClasses(), estimateTax({ country?, subtotal })
|
|
4659
4738
|
//
|
package/dist/index.js
CHANGED
|
@@ -2560,8 +2560,9 @@ await admin.createTaxRate({ name: 'VAT (Food)', rate: 0, country: 'GB', taxClass
|
|
|
2560
2560
|
await admin.mergeTaxClasses(food.id, standardClassId);
|
|
2561
2561
|
\`\`\`
|
|
2562
2562
|
|
|
2563
|
-
Storefront (public, no apiKey \u2014 \`storeId\` mode
|
|
2564
|
-
the
|
|
2563
|
+
Storefront (public, no apiKey \u2014 \`storeId\` mode OR vibe-coded mode \`vc_*\`, gated
|
|
2564
|
+
on the \`products:read\` scope every connection already has): \`getStoreTaxClasses()\`
|
|
2565
|
+
lists the store's classes (storefront-safe fields only) for a transparency badge.
|
|
2565
2566
|
|
|
2566
2567
|
For a buyer-facing tax preview on PDP / PLP / cart, \`estimateTax({ country,
|
|
2567
2568
|
subtotal })\` returns the tax portion at the Standard rate for the buyer's
|
|
@@ -2583,8 +2584,10 @@ A region binds countries \u2192 currency + tax-display mode + enabled payment
|
|
|
2583
2584
|
providers. Manage them via the SDK (scopes \`regions:read\` / \`regions:write\`).
|
|
2584
2585
|
\`detectRegion\` is a pure client-side helper to map a buyer's country to a
|
|
2585
2586
|
region; pass the resolved \`regionId\` to \`createCheckout\` to associate the
|
|
2586
|
-
checkout with a region (recorded for reporting + provider scoping
|
|
2587
|
-
|
|
2587
|
+
checkout with a region (recorded for reporting + provider scoping). FX-at-checkout:
|
|
2588
|
+
presentment-enabled regions (Stripe today) charge in the region currency and the
|
|
2589
|
+
checkout response carries a \`presentment\` overlay with the charged amounts;
|
|
2590
|
+
otherwise the checkout is charged in the store base currency.
|
|
2588
2591
|
|
|
2589
2592
|
\`\`\`typescript
|
|
2590
2593
|
const eu = await admin.createRegion({
|
|
@@ -2597,9 +2600,12 @@ const { data: regions } = await admin.getRegions();
|
|
|
2597
2600
|
const region = admin.detectRegion('DE', regions); // \u2192 eu, else default, else null
|
|
2598
2601
|
\`\`\`
|
|
2599
2602
|
|
|
2600
|
-
Storefront (public, no apiKey \u2014 \`storeId\` mode
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
+
Storefront (public, no apiKey \u2014 \`storeId\` mode OR vibe-coded mode \`vc_*\`, gated
|
|
2604
|
+
on the \`products:read\` scope every connection already has): \`getStoreRegions()\`
|
|
2605
|
+
lists active regions, \`getStoreRegion(id)\` returns one region + its payment
|
|
2606
|
+
providers. \`getAutoRegion(country)\` and \`estimateTax({ country, subtotal })\` work
|
|
2607
|
+
in both modes too. Pair with \`detectRegion\` to pick the buyer's region for
|
|
2608
|
+
currency display.
|
|
2603
2609
|
|
|
2604
2610
|
\`\`\`typescript
|
|
2605
2611
|
const store = new BrainerceClient({ storeId: 'store_123' });
|
|
@@ -3223,6 +3229,38 @@ Rules:
|
|
|
3223
3229
|
count updates when the bot adds items.
|
|
3224
3230
|
`;
|
|
3225
3231
|
}
|
|
3232
|
+
function getStorefrontAnalyticsSection(connectionId) {
|
|
3233
|
+
return `## Storefront Traffic Analytics (visits, countries, sources)
|
|
3234
|
+
|
|
3235
|
+
Brainerce can track cookieless storefront traffic \u2014 how many people visit the
|
|
3236
|
+
store, from which countries, and from which traffic sources \u2014 and surface it in
|
|
3237
|
+
the merchant dashboard alongside sales (so the merchant gets a REAL conversion
|
|
3238
|
+
rate: visits \u2192 orders).
|
|
3239
|
+
|
|
3240
|
+
Add ONE line to the storefront's root layout (\`<head>\` or end of \`<body>\`):
|
|
3241
|
+
|
|
3242
|
+
\`\`\`html
|
|
3243
|
+
<script defer src="https://api.brainerce.com/t.js" data-channel="${connectionId}"></script>
|
|
3244
|
+
\`\`\`
|
|
3245
|
+
|
|
3246
|
+
That's it \u2014 the pixel auto-sends a pageview beacon on load and on SPA route
|
|
3247
|
+
changes. Stores scaffolded with \`create-brainerce-store\` already include it.
|
|
3248
|
+
|
|
3249
|
+
Privacy: the pixel is cookieless and stores NO personal data \u2014 no cookie, no
|
|
3250
|
+
cross-site/cross-day tracking, and the visitor IP is resolved to a country
|
|
3251
|
+
server-side then discarded. No cookie-consent banner is required for it under
|
|
3252
|
+
GDPR/ePrivacy.
|
|
3253
|
+
|
|
3254
|
+
CSP: if the storefront sets a Content-Security-Policy, allow the script + beacon:
|
|
3255
|
+
- \`script-src\` \u2026 \`https://api.brainerce.com\`
|
|
3256
|
+
- \`connect-src\` \u2026 \`https://api.brainerce.com\`
|
|
3257
|
+
|
|
3258
|
+
The merchant can toggle tracking per sales channel in the dashboard. The data
|
|
3259
|
+
shows up under Dashboard \u2192 Analytics (visits over time, by country, by source,
|
|
3260
|
+
by device) and can also be asked of the AI assistant ("how many visits did I get
|
|
3261
|
+
this month and from where?").
|
|
3262
|
+
`;
|
|
3263
|
+
}
|
|
3226
3264
|
function getSectionByTopic(topic, connectionId, currency) {
|
|
3227
3265
|
const cid = connectionId || "vc_YOUR_CONNECTION_ID";
|
|
3228
3266
|
const cur = currency || "USD";
|
|
@@ -3279,6 +3317,9 @@ function getSectionByTopic(topic, connectionId, currency) {
|
|
|
3279
3317
|
return getBlogSection();
|
|
3280
3318
|
case "storefront-bot":
|
|
3281
3319
|
return getStorefrontBotSection(cid);
|
|
3320
|
+
case "analytics":
|
|
3321
|
+
case "traffic-analytics":
|
|
3322
|
+
return getStorefrontAnalyticsSection(cid);
|
|
3282
3323
|
case "all":
|
|
3283
3324
|
return [
|
|
3284
3325
|
"# Brainerce SDK \u2014 full topic dump",
|
|
@@ -3347,6 +3388,10 @@ function getSectionByTopic(topic, connectionId, currency) {
|
|
|
3347
3388
|
"",
|
|
3348
3389
|
"---",
|
|
3349
3390
|
"",
|
|
3391
|
+
getStorefrontAnalyticsSection(cid),
|
|
3392
|
+
"",
|
|
3393
|
+
"---",
|
|
3394
|
+
"",
|
|
3350
3395
|
getProductCustomizationFieldsSection(),
|
|
3351
3396
|
"",
|
|
3352
3397
|
"---",
|
|
@@ -3416,6 +3461,7 @@ var GET_SDK_DOCS_SCHEMA = {
|
|
|
3416
3461
|
"inquiries",
|
|
3417
3462
|
"content",
|
|
3418
3463
|
"storefront-bot",
|
|
3464
|
+
"analytics",
|
|
3419
3465
|
"all"
|
|
3420
3466
|
]).describe("The SDK documentation topic to retrieve"),
|
|
3421
3467
|
salesChannelId: import_zod.z.string().optional().describe("Sales channel ID (starts with vc_). Used to personalize setup code."),
|
|
@@ -3453,7 +3499,7 @@ interface Product {
|
|
|
3453
3499
|
priceMin?: string | null; // Lowest variant price (VARIABLE products) \u2014 same as basePrice for VARIABLE, kept for back-compat and JSON-LD range display.
|
|
3454
3500
|
priceMax?: string | null; // Highest variant price (VARIABLE products). Use with priceMin for "\u20AA49 \u2013 \u20AA199" range.
|
|
3455
3501
|
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
|
|
3502
|
+
// 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
3503
|
displayPrice?: string; // basePrice \xD7 daily FX rate, in displayCurrency.
|
|
3458
3504
|
displaySalePrice?: string; // salePrice \xD7 rate (if salePrice present).
|
|
3459
3505
|
displayPriceMin?: string; // priceMin \xD7 rate (VARIABLE products).
|
|
@@ -3707,7 +3753,7 @@ interface Checkout {
|
|
|
3707
3753
|
status: CheckoutStatus;
|
|
3708
3754
|
email?: string | null;
|
|
3709
3755
|
customerId?: string | null;
|
|
3710
|
-
regionId?: string | null; // multi-region: recorded for reporting + provider scoping (currency
|
|
3756
|
+
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
3757
|
shippingAddress?: CheckoutAddress | null;
|
|
3712
3758
|
billingAddress?: CheckoutAddress | null;
|
|
3713
3759
|
shippingRateId?: string | null;
|
|
@@ -3727,6 +3773,18 @@ interface Checkout {
|
|
|
3727
3773
|
itemCount: number;
|
|
3728
3774
|
availableShippingRates?: ShippingRate[];
|
|
3729
3775
|
reservation?: ReservationInfo;
|
|
3776
|
+
// 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.
|
|
3777
|
+
presentment?: {
|
|
3778
|
+
currency: string; // ISO-4217 charged currency, e.g. "EUR"
|
|
3779
|
+
subtotal: string;
|
|
3780
|
+
discountAmount: string;
|
|
3781
|
+
shippingAmount: string;
|
|
3782
|
+
taxAmount: string;
|
|
3783
|
+
surchargeAmount: string;
|
|
3784
|
+
total: string; // equals the charged amount, to the cent
|
|
3785
|
+
fxChargingRate: string; // base\u2192presentment rate (buffer included)
|
|
3786
|
+
fxBufferPercent: string | null;
|
|
3787
|
+
};
|
|
3730
3788
|
createdAt: string;
|
|
3731
3789
|
updatedAt: string;
|
|
3732
3790
|
}
|
|
@@ -4104,10 +4162,22 @@ interface CartAppliedDiscount {
|
|
|
4104
4162
|
}
|
|
4105
4163
|
|
|
4106
4164
|
// Recommendation types
|
|
4165
|
+
interface RecommendationVariant {
|
|
4166
|
+
id: string; name?: string; price?: string; salePrice?: string;
|
|
4167
|
+
attributes?: Record<string, string>; image?: ProductImage | string; inventory?: InventoryInfo;
|
|
4168
|
+
}
|
|
4107
4169
|
interface ProductRecommendation {
|
|
4108
|
-
id: string; name: string; slug: string;
|
|
4170
|
+
id: string; name: string; slug: string;
|
|
4171
|
+
// For a VARIABLE target, basePrice is the pinned variant's price (when
|
|
4172
|
+
// targetVariantId is set) or the "from {min variant}" range \u2014 never 0.
|
|
4173
|
+
basePrice: string; salePrice?: string;
|
|
4109
4174
|
images: ProductImage[]; type: 'SIMPLE' | 'VARIABLE'; inventory?: InventoryInfo;
|
|
4110
4175
|
relationType: string;
|
|
4176
|
+
// Variant context (VARIABLE targets):
|
|
4177
|
+
targetVariantId?: string | null; // merchant-pinned variant, or null
|
|
4178
|
+
requiresVariantSelection?: boolean; // true \u2192 customer must pick from variants
|
|
4179
|
+
pinnedVariant?: { id: string; name?: string; attributes?: Record<string, string> } | null;
|
|
4180
|
+
variants?: RecommendationVariant[]; // present when requiresVariantSelection
|
|
4111
4181
|
}
|
|
4112
4182
|
interface ProductRecommendationsResponse {
|
|
4113
4183
|
crossSells: ProductRecommendation[];
|
|
@@ -4141,6 +4211,12 @@ interface CartBundleOfferOfferedProduct {
|
|
|
4141
4211
|
salePrice: string | null;
|
|
4142
4212
|
images: Array<{ url: string }>;
|
|
4143
4213
|
type: string;
|
|
4214
|
+
// Variant context (VARIABLE offered products):
|
|
4215
|
+
variantId?: string | null; // merchant-pinned variant for this slot
|
|
4216
|
+
requiresVariantSelection?: boolean; // true \u2192 customer must pick from variants
|
|
4217
|
+
pinnedVariant?: { id: string; name?: string; attributes?: Record<string, string> } | null;
|
|
4218
|
+
variants?: RecommendationVariant[]; // present when requiresVariantSelection
|
|
4219
|
+
// originalPrice = pinned/cheapest variant price for VARIABLE (not a 0 parent base).
|
|
4144
4220
|
originalPrice: string;
|
|
4145
4221
|
discountedPrice: string;
|
|
4146
4222
|
}
|
|
@@ -4624,10 +4700,12 @@ interface UpdateRegionDto extends Partial<CreateRegionDto> { isActive?: boolean
|
|
|
4624
4700
|
// client.detectRegion(country, regions): Region | null \u2014 pure, no network.
|
|
4625
4701
|
// \u2192 region whose countries includes the code, else the default region, else null.
|
|
4626
4702
|
// Pass the resolved regionId to createCheckout to associate the checkout with a
|
|
4627
|
-
// region (recorded for reporting + provider scoping
|
|
4628
|
-
//
|
|
4703
|
+
// region (recorded for reporting + provider scoping). FX-at-checkout:
|
|
4704
|
+
// presentment-enabled regions (Stripe) charge in the region currency and the
|
|
4705
|
+
// response carries a presentment overlay; else charged in store base currency.
|
|
4629
4706
|
//
|
|
4630
|
-
// Storefront (public, no apiKey \u2014 storeId mode
|
|
4707
|
+
// Storefront (public, no apiKey \u2014 storeId mode OR vibe-coded mode, salesChannelId 'vc_*';
|
|
4708
|
+
// the vc routes are gated on products:read, which every connection already has):
|
|
4631
4709
|
interface PublicRegion {
|
|
4632
4710
|
id: string; name: string; slug: string; currency: string;
|
|
4633
4711
|
countries: string[]; taxInclusive: boolean; isDefault: boolean;
|
|
@@ -4679,7 +4757,8 @@ interface AssignTaxClassDto { productIds?: string[]; variantIds?: string[]; cate
|
|
|
4679
4757
|
// deleteTaxClass(id), setDefaultTaxClass(id), assignTaxClass(id, dto),
|
|
4680
4758
|
// mergeTaxClasses(id, targetId)
|
|
4681
4759
|
//
|
|
4682
|
-
// SDK methods (storefront, public \u2014 storeId mode, no apiKey
|
|
4760
|
+
// SDK methods (storefront, public \u2014 storeId mode OR vibe-coded mode 'vc_*', no apiKey;
|
|
4761
|
+
// the vc routes are gated on products:read, which every connection already has):
|
|
4683
4762
|
// getStoreRegions(), getStoreRegion(id), getAutoRegion(country)
|
|
4684
4763
|
// getStoreTaxClasses(), estimateTax({ country?, subtotal })
|
|
4685
4764
|
//
|
package/dist/index.mjs
CHANGED
|
@@ -2528,8 +2528,9 @@ await admin.createTaxRate({ name: 'VAT (Food)', rate: 0, country: 'GB', taxClass
|
|
|
2528
2528
|
await admin.mergeTaxClasses(food.id, standardClassId);
|
|
2529
2529
|
\`\`\`
|
|
2530
2530
|
|
|
2531
|
-
Storefront (public, no apiKey \u2014 \`storeId\` mode
|
|
2532
|
-
the
|
|
2531
|
+
Storefront (public, no apiKey \u2014 \`storeId\` mode OR vibe-coded mode \`vc_*\`, gated
|
|
2532
|
+
on the \`products:read\` scope every connection already has): \`getStoreTaxClasses()\`
|
|
2533
|
+
lists the store's classes (storefront-safe fields only) for a transparency badge.
|
|
2533
2534
|
|
|
2534
2535
|
For a buyer-facing tax preview on PDP / PLP / cart, \`estimateTax({ country,
|
|
2535
2536
|
subtotal })\` returns the tax portion at the Standard rate for the buyer's
|
|
@@ -2551,8 +2552,10 @@ A region binds countries \u2192 currency + tax-display mode + enabled payment
|
|
|
2551
2552
|
providers. Manage them via the SDK (scopes \`regions:read\` / \`regions:write\`).
|
|
2552
2553
|
\`detectRegion\` is a pure client-side helper to map a buyer's country to a
|
|
2553
2554
|
region; pass the resolved \`regionId\` to \`createCheckout\` to associate the
|
|
2554
|
-
checkout with a region (recorded for reporting + provider scoping
|
|
2555
|
-
|
|
2555
|
+
checkout with a region (recorded for reporting + provider scoping). FX-at-checkout:
|
|
2556
|
+
presentment-enabled regions (Stripe today) charge in the region currency and the
|
|
2557
|
+
checkout response carries a \`presentment\` overlay with the charged amounts;
|
|
2558
|
+
otherwise the checkout is charged in the store base currency.
|
|
2556
2559
|
|
|
2557
2560
|
\`\`\`typescript
|
|
2558
2561
|
const eu = await admin.createRegion({
|
|
@@ -2565,9 +2568,12 @@ const { data: regions } = await admin.getRegions();
|
|
|
2565
2568
|
const region = admin.detectRegion('DE', regions); // \u2192 eu, else default, else null
|
|
2566
2569
|
\`\`\`
|
|
2567
2570
|
|
|
2568
|
-
Storefront (public, no apiKey \u2014 \`storeId\` mode
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
+
Storefront (public, no apiKey \u2014 \`storeId\` mode OR vibe-coded mode \`vc_*\`, gated
|
|
2572
|
+
on the \`products:read\` scope every connection already has): \`getStoreRegions()\`
|
|
2573
|
+
lists active regions, \`getStoreRegion(id)\` returns one region + its payment
|
|
2574
|
+
providers. \`getAutoRegion(country)\` and \`estimateTax({ country, subtotal })\` work
|
|
2575
|
+
in both modes too. Pair with \`detectRegion\` to pick the buyer's region for
|
|
2576
|
+
currency display.
|
|
2571
2577
|
|
|
2572
2578
|
\`\`\`typescript
|
|
2573
2579
|
const store = new BrainerceClient({ storeId: 'store_123' });
|
|
@@ -3191,6 +3197,38 @@ Rules:
|
|
|
3191
3197
|
count updates when the bot adds items.
|
|
3192
3198
|
`;
|
|
3193
3199
|
}
|
|
3200
|
+
function getStorefrontAnalyticsSection(connectionId) {
|
|
3201
|
+
return `## Storefront Traffic Analytics (visits, countries, sources)
|
|
3202
|
+
|
|
3203
|
+
Brainerce can track cookieless storefront traffic \u2014 how many people visit the
|
|
3204
|
+
store, from which countries, and from which traffic sources \u2014 and surface it in
|
|
3205
|
+
the merchant dashboard alongside sales (so the merchant gets a REAL conversion
|
|
3206
|
+
rate: visits \u2192 orders).
|
|
3207
|
+
|
|
3208
|
+
Add ONE line to the storefront's root layout (\`<head>\` or end of \`<body>\`):
|
|
3209
|
+
|
|
3210
|
+
\`\`\`html
|
|
3211
|
+
<script defer src="https://api.brainerce.com/t.js" data-channel="${connectionId}"></script>
|
|
3212
|
+
\`\`\`
|
|
3213
|
+
|
|
3214
|
+
That's it \u2014 the pixel auto-sends a pageview beacon on load and on SPA route
|
|
3215
|
+
changes. Stores scaffolded with \`create-brainerce-store\` already include it.
|
|
3216
|
+
|
|
3217
|
+
Privacy: the pixel is cookieless and stores NO personal data \u2014 no cookie, no
|
|
3218
|
+
cross-site/cross-day tracking, and the visitor IP is resolved to a country
|
|
3219
|
+
server-side then discarded. No cookie-consent banner is required for it under
|
|
3220
|
+
GDPR/ePrivacy.
|
|
3221
|
+
|
|
3222
|
+
CSP: if the storefront sets a Content-Security-Policy, allow the script + beacon:
|
|
3223
|
+
- \`script-src\` \u2026 \`https://api.brainerce.com\`
|
|
3224
|
+
- \`connect-src\` \u2026 \`https://api.brainerce.com\`
|
|
3225
|
+
|
|
3226
|
+
The merchant can toggle tracking per sales channel in the dashboard. The data
|
|
3227
|
+
shows up under Dashboard \u2192 Analytics (visits over time, by country, by source,
|
|
3228
|
+
by device) and can also be asked of the AI assistant ("how many visits did I get
|
|
3229
|
+
this month and from where?").
|
|
3230
|
+
`;
|
|
3231
|
+
}
|
|
3194
3232
|
function getSectionByTopic(topic, connectionId, currency) {
|
|
3195
3233
|
const cid = connectionId || "vc_YOUR_CONNECTION_ID";
|
|
3196
3234
|
const cur = currency || "USD";
|
|
@@ -3247,6 +3285,9 @@ function getSectionByTopic(topic, connectionId, currency) {
|
|
|
3247
3285
|
return getBlogSection();
|
|
3248
3286
|
case "storefront-bot":
|
|
3249
3287
|
return getStorefrontBotSection(cid);
|
|
3288
|
+
case "analytics":
|
|
3289
|
+
case "traffic-analytics":
|
|
3290
|
+
return getStorefrontAnalyticsSection(cid);
|
|
3250
3291
|
case "all":
|
|
3251
3292
|
return [
|
|
3252
3293
|
"# Brainerce SDK \u2014 full topic dump",
|
|
@@ -3315,6 +3356,10 @@ function getSectionByTopic(topic, connectionId, currency) {
|
|
|
3315
3356
|
"",
|
|
3316
3357
|
"---",
|
|
3317
3358
|
"",
|
|
3359
|
+
getStorefrontAnalyticsSection(cid),
|
|
3360
|
+
"",
|
|
3361
|
+
"---",
|
|
3362
|
+
"",
|
|
3318
3363
|
getProductCustomizationFieldsSection(),
|
|
3319
3364
|
"",
|
|
3320
3365
|
"---",
|
|
@@ -3384,6 +3429,7 @@ var GET_SDK_DOCS_SCHEMA = {
|
|
|
3384
3429
|
"inquiries",
|
|
3385
3430
|
"content",
|
|
3386
3431
|
"storefront-bot",
|
|
3432
|
+
"analytics",
|
|
3387
3433
|
"all"
|
|
3388
3434
|
]).describe("The SDK documentation topic to retrieve"),
|
|
3389
3435
|
salesChannelId: z.string().optional().describe("Sales channel ID (starts with vc_). Used to personalize setup code."),
|
|
@@ -3421,7 +3467,7 @@ interface Product {
|
|
|
3421
3467
|
priceMin?: string | null; // Lowest variant price (VARIABLE products) \u2014 same as basePrice for VARIABLE, kept for back-compat and JSON-LD range display.
|
|
3422
3468
|
priceMax?: string | null; // Highest variant price (VARIABLE products). Use with priceMin for "\u20AA49 \u2013 \u20AA199" range.
|
|
3423
3469
|
priceVaries?: boolean; // true when variant prices differ \u2014 show "\u20AA49 \u2013 \u20AA199" range.
|
|
3424
|
-
// 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
|
|
3470
|
+
// 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).
|
|
3425
3471
|
displayPrice?: string; // basePrice \xD7 daily FX rate, in displayCurrency.
|
|
3426
3472
|
displaySalePrice?: string; // salePrice \xD7 rate (if salePrice present).
|
|
3427
3473
|
displayPriceMin?: string; // priceMin \xD7 rate (VARIABLE products).
|
|
@@ -3675,7 +3721,7 @@ interface Checkout {
|
|
|
3675
3721
|
status: CheckoutStatus;
|
|
3676
3722
|
email?: string | null;
|
|
3677
3723
|
customerId?: string | null;
|
|
3678
|
-
regionId?: string | null; // multi-region: recorded for reporting + provider scoping (currency
|
|
3724
|
+
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
|
|
3679
3725
|
shippingAddress?: CheckoutAddress | null;
|
|
3680
3726
|
billingAddress?: CheckoutAddress | null;
|
|
3681
3727
|
shippingRateId?: string | null;
|
|
@@ -3695,6 +3741,18 @@ interface Checkout {
|
|
|
3695
3741
|
itemCount: number;
|
|
3696
3742
|
availableShippingRates?: ShippingRate[];
|
|
3697
3743
|
reservation?: ReservationInfo;
|
|
3744
|
+
// 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.
|
|
3745
|
+
presentment?: {
|
|
3746
|
+
currency: string; // ISO-4217 charged currency, e.g. "EUR"
|
|
3747
|
+
subtotal: string;
|
|
3748
|
+
discountAmount: string;
|
|
3749
|
+
shippingAmount: string;
|
|
3750
|
+
taxAmount: string;
|
|
3751
|
+
surchargeAmount: string;
|
|
3752
|
+
total: string; // equals the charged amount, to the cent
|
|
3753
|
+
fxChargingRate: string; // base\u2192presentment rate (buffer included)
|
|
3754
|
+
fxBufferPercent: string | null;
|
|
3755
|
+
};
|
|
3698
3756
|
createdAt: string;
|
|
3699
3757
|
updatedAt: string;
|
|
3700
3758
|
}
|
|
@@ -4072,10 +4130,22 @@ interface CartAppliedDiscount {
|
|
|
4072
4130
|
}
|
|
4073
4131
|
|
|
4074
4132
|
// Recommendation types
|
|
4133
|
+
interface RecommendationVariant {
|
|
4134
|
+
id: string; name?: string; price?: string; salePrice?: string;
|
|
4135
|
+
attributes?: Record<string, string>; image?: ProductImage | string; inventory?: InventoryInfo;
|
|
4136
|
+
}
|
|
4075
4137
|
interface ProductRecommendation {
|
|
4076
|
-
id: string; name: string; slug: string;
|
|
4138
|
+
id: string; name: string; slug: string;
|
|
4139
|
+
// For a VARIABLE target, basePrice is the pinned variant's price (when
|
|
4140
|
+
// targetVariantId is set) or the "from {min variant}" range \u2014 never 0.
|
|
4141
|
+
basePrice: string; salePrice?: string;
|
|
4077
4142
|
images: ProductImage[]; type: 'SIMPLE' | 'VARIABLE'; inventory?: InventoryInfo;
|
|
4078
4143
|
relationType: string;
|
|
4144
|
+
// Variant context (VARIABLE targets):
|
|
4145
|
+
targetVariantId?: string | null; // merchant-pinned variant, or null
|
|
4146
|
+
requiresVariantSelection?: boolean; // true \u2192 customer must pick from variants
|
|
4147
|
+
pinnedVariant?: { id: string; name?: string; attributes?: Record<string, string> } | null;
|
|
4148
|
+
variants?: RecommendationVariant[]; // present when requiresVariantSelection
|
|
4079
4149
|
}
|
|
4080
4150
|
interface ProductRecommendationsResponse {
|
|
4081
4151
|
crossSells: ProductRecommendation[];
|
|
@@ -4109,6 +4179,12 @@ interface CartBundleOfferOfferedProduct {
|
|
|
4109
4179
|
salePrice: string | null;
|
|
4110
4180
|
images: Array<{ url: string }>;
|
|
4111
4181
|
type: string;
|
|
4182
|
+
// Variant context (VARIABLE offered products):
|
|
4183
|
+
variantId?: string | null; // merchant-pinned variant for this slot
|
|
4184
|
+
requiresVariantSelection?: boolean; // true \u2192 customer must pick from variants
|
|
4185
|
+
pinnedVariant?: { id: string; name?: string; attributes?: Record<string, string> } | null;
|
|
4186
|
+
variants?: RecommendationVariant[]; // present when requiresVariantSelection
|
|
4187
|
+
// originalPrice = pinned/cheapest variant price for VARIABLE (not a 0 parent base).
|
|
4112
4188
|
originalPrice: string;
|
|
4113
4189
|
discountedPrice: string;
|
|
4114
4190
|
}
|
|
@@ -4592,10 +4668,12 @@ interface UpdateRegionDto extends Partial<CreateRegionDto> { isActive?: boolean
|
|
|
4592
4668
|
// client.detectRegion(country, regions): Region | null \u2014 pure, no network.
|
|
4593
4669
|
// \u2192 region whose countries includes the code, else the default region, else null.
|
|
4594
4670
|
// Pass the resolved regionId to createCheckout to associate the checkout with a
|
|
4595
|
-
// region (recorded for reporting + provider scoping
|
|
4596
|
-
//
|
|
4671
|
+
// region (recorded for reporting + provider scoping). FX-at-checkout:
|
|
4672
|
+
// presentment-enabled regions (Stripe) charge in the region currency and the
|
|
4673
|
+
// response carries a presentment overlay; else charged in store base currency.
|
|
4597
4674
|
//
|
|
4598
|
-
// Storefront (public, no apiKey \u2014 storeId mode
|
|
4675
|
+
// Storefront (public, no apiKey \u2014 storeId mode OR vibe-coded mode, salesChannelId 'vc_*';
|
|
4676
|
+
// the vc routes are gated on products:read, which every connection already has):
|
|
4599
4677
|
interface PublicRegion {
|
|
4600
4678
|
id: string; name: string; slug: string; currency: string;
|
|
4601
4679
|
countries: string[]; taxInclusive: boolean; isDefault: boolean;
|
|
@@ -4647,7 +4725,8 @@ interface AssignTaxClassDto { productIds?: string[]; variantIds?: string[]; cate
|
|
|
4647
4725
|
// deleteTaxClass(id), setDefaultTaxClass(id), assignTaxClass(id, dto),
|
|
4648
4726
|
// mergeTaxClasses(id, targetId)
|
|
4649
4727
|
//
|
|
4650
|
-
// SDK methods (storefront, public \u2014 storeId mode, no apiKey
|
|
4728
|
+
// SDK methods (storefront, public \u2014 storeId mode OR vibe-coded mode 'vc_*', no apiKey;
|
|
4729
|
+
// the vc routes are gated on products:read, which every connection already has):
|
|
4651
4730
|
// getStoreRegions(), getStoreRegion(id), getAutoRegion(country)
|
|
4652
4731
|
// getStoreTaxClasses(), estimateTax({ country?, subtotal })
|
|
4653
4732
|
//
|
package/package.json
CHANGED
|
@@ -1,53 +1,53 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@brainerce/mcp-server",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "Framework-agnostic domain knowledge API for Brainerce. Provides SDK docs, types, business flows, critical rules, and store capabilities to AI tools like Lovable, Cursor, Bolt, v0, and Claude Code. Does NOT provide framework-specific boilerplate — clients build in whatever framework fits.",
|
|
5
|
-
"bin": {
|
|
6
|
-
"brainerce-mcp": "dist/bin/stdio.js"
|
|
7
|
-
},
|
|
8
|
-
"main": "dist/index.js",
|
|
9
|
-
"module": "dist/index.mjs",
|
|
10
|
-
"types": "dist/index.d.ts",
|
|
11
|
-
"exports": {
|
|
12
|
-
".": {
|
|
13
|
-
"types": "./dist/index.d.ts",
|
|
14
|
-
"require": "./dist/index.js",
|
|
15
|
-
"import": "./dist/index.mjs"
|
|
16
|
-
}
|
|
17
|
-
},
|
|
18
|
-
"files": [
|
|
19
|
-
"dist",
|
|
20
|
-
"README.md"
|
|
21
|
-
],
|
|
22
|
-
"scripts": {
|
|
23
|
-
"build": "tsup",
|
|
24
|
-
"dev": "tsup --watch",
|
|
25
|
-
"start:stdio": "node dist/bin/stdio.js",
|
|
26
|
-
"start:http": "node dist/bin/http.js",
|
|
27
|
-
"prepublishOnly": "npm run build"
|
|
28
|
-
},
|
|
29
|
-
"dependencies": {
|
|
30
|
-
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
31
|
-
"zod": "^3.24.0"
|
|
32
|
-
},
|
|
33
|
-
"devDependencies": {
|
|
34
|
-
"@types/node": "^22.0.0",
|
|
35
|
-
"tsup": "^8.0.0",
|
|
36
|
-
"typescript": "^5.3.0"
|
|
37
|
-
},
|
|
38
|
-
"engines": {
|
|
39
|
-
"node": ">=18"
|
|
40
|
-
},
|
|
41
|
-
"keywords": [
|
|
42
|
-
"brainerce",
|
|
43
|
-
"mcp",
|
|
44
|
-
"model-context-protocol",
|
|
45
|
-
"ai",
|
|
46
|
-
"ecommerce",
|
|
47
|
-
"lovable",
|
|
48
|
-
"cursor",
|
|
49
|
-
"claude-code",
|
|
50
|
-
"vibe-coding"
|
|
51
|
-
],
|
|
52
|
-
"license": "MIT"
|
|
53
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@brainerce/mcp-server",
|
|
3
|
+
"version": "3.12.0",
|
|
4
|
+
"description": "Framework-agnostic domain knowledge API for Brainerce. Provides SDK docs, types, business flows, critical rules, and store capabilities to AI tools like Lovable, Cursor, Bolt, v0, and Claude Code. Does NOT provide framework-specific boilerplate — clients build in whatever framework fits.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"brainerce-mcp": "dist/bin/stdio.js"
|
|
7
|
+
},
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"module": "dist/index.mjs",
|
|
10
|
+
"types": "dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"require": "./dist/index.js",
|
|
15
|
+
"import": "./dist/index.mjs"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"README.md"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsup",
|
|
24
|
+
"dev": "tsup --watch",
|
|
25
|
+
"start:stdio": "node dist/bin/stdio.js",
|
|
26
|
+
"start:http": "node dist/bin/http.js",
|
|
27
|
+
"prepublishOnly": "npm run build"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
31
|
+
"zod": "^3.24.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^22.0.0",
|
|
35
|
+
"tsup": "^8.0.0",
|
|
36
|
+
"typescript": "^5.3.0"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18"
|
|
40
|
+
},
|
|
41
|
+
"keywords": [
|
|
42
|
+
"brainerce",
|
|
43
|
+
"mcp",
|
|
44
|
+
"model-context-protocol",
|
|
45
|
+
"ai",
|
|
46
|
+
"ecommerce",
|
|
47
|
+
"lovable",
|
|
48
|
+
"cursor",
|
|
49
|
+
"claude-code",
|
|
50
|
+
"vibe-coding"
|
|
51
|
+
],
|
|
52
|
+
"license": "MIT"
|
|
53
|
+
}
|