@brainerce/mcp-server 3.12.2 → 3.12.3
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 +45 -7
- package/dist/bin/stdio.js +45 -7
- package/dist/index.js +45 -7
- package/dist/index.mjs +45 -7
- package/package.json +1 -1
package/dist/bin/http.js
CHANGED
|
@@ -3324,11 +3324,18 @@ Points are earned automatically by the platform when an order is paid \u2014 the
|
|
|
3324
3324
|
\`\`\`typescript
|
|
3325
3325
|
// requires client.setCustomerToken(auth.token)
|
|
3326
3326
|
const status = await client.getLoyaltyStatus();
|
|
3327
|
-
// {
|
|
3327
|
+
// {
|
|
3328
|
+
// enrolled, pointsBalance, lifetimeEarned,
|
|
3329
|
+
// program: { pointsName, currencyRatio, status } | null,
|
|
3330
|
+
// tier: { id, name, level, pointsMultiplier } | null,
|
|
3331
|
+
// nextTier: { id, name, level, pointsMultiplier, qualificationType, qualificationThreshold } | null,
|
|
3332
|
+
// progressToNextTier, pointsToNextTier,
|
|
3333
|
+
// }
|
|
3328
3334
|
\`\`\`
|
|
3329
3335
|
|
|
3330
3336
|
- \`program === null\` \u2192 the store has no loyalty program; hide the loyalty UI.
|
|
3331
3337
|
- \`program.status !== 'ACTIVE'\` \u2192 program paused/draft; hide the loyalty UI.
|
|
3338
|
+
- \`tier\`/\`nextTier\` are \`null\` when the store hasn't configured tiers, or the customer hasn't qualified for one yet.
|
|
3332
3339
|
|
|
3333
3340
|
## Enroll (only if auto-enroll is off)
|
|
3334
3341
|
|
|
@@ -3336,19 +3343,30 @@ const status = await client.getLoyaltyStatus();
|
|
|
3336
3343
|
await client.enrollInLoyalty(); // same status shape; no-op if already enrolled
|
|
3337
3344
|
\`\`\`
|
|
3338
3345
|
|
|
3346
|
+
May grant a one-time "joined the program" bonus if configured \u2014 distinct from any account-signup bonus (granted automatically on registration, not by this call).
|
|
3347
|
+
|
|
3339
3348
|
## Rewards & redemption
|
|
3340
3349
|
|
|
3341
3350
|
\`\`\`typescript
|
|
3342
3351
|
const rewards = await client.getAvailableRewards();
|
|
3343
|
-
// [{ id, name, description, pointsCost, discountValue, minOrderAmount, maxUsesPerUser, isActive }]
|
|
3352
|
+
// [{ id, name, description, pointsCost, type, discountValue, minOrderAmount, maxUsesPerUser, minTierLevel, isActive }]
|
|
3353
|
+
// Already filtered to rewards the customer's current tier qualifies for.
|
|
3344
3354
|
|
|
3345
|
-
const { couponCode, discountValue, pointsBalance } =
|
|
3355
|
+
const { couponCode, discountType, discountValue, pointsBalance } =
|
|
3356
|
+
await client.redeemLoyaltyReward(rewardId);
|
|
3346
3357
|
await client.applyCoupon(cartId, couponCode); // applies via the normal coupon engine
|
|
3347
3358
|
\`\`\`
|
|
3348
3359
|
|
|
3349
|
-
- \`
|
|
3350
|
-
-
|
|
3360
|
+
- \`reward.type\` is \`'FIXED_DISCOUNT'\` (currency amount) or \`'PERCENT_DISCOUNT'\` (0-100 percent) \u2014 the redeem result's \`discountType\` matches.
|
|
3361
|
+
- \`redeemLoyaltyReward\` mints a one-time coupon (\`usageLimit: 1\`). Apply it with the normal \`applyCoupon\` flow.
|
|
3362
|
+
- Throws if the customer has insufficient points, or their tier is below \`reward.minTierLevel\`. If minting fails, points are refunded automatically.
|
|
3351
3363
|
- Disable a reward's redeem button when \`pointsBalance < reward.pointsCost\`.
|
|
3364
|
+
|
|
3365
|
+
## Social share (optional)
|
|
3366
|
+
|
|
3367
|
+
\`\`\`typescript
|
|
3368
|
+
await client.reportSocialShare('instagram'); // platform optional, self-reported, once per customer
|
|
3369
|
+
\`\`\`
|
|
3352
3370
|
`;
|
|
3353
3371
|
}
|
|
3354
3372
|
function getSectionByTopic(topic, connectionId, currency) {
|
|
@@ -4884,6 +4902,18 @@ interface TaxEstimateResponse {
|
|
|
4884
4902
|
// full shipping address. The country comes from your edge runtime
|
|
4885
4903
|
// (CF-IPCountry / request.geo.country / etc.), NOT the request IP.`;
|
|
4886
4904
|
var LOYALTY_TYPES = `// ---- Loyalty & Rewards (storefront mode only) ----
|
|
4905
|
+
interface LoyaltyTierSummary {
|
|
4906
|
+
id: string;
|
|
4907
|
+
name: string;
|
|
4908
|
+
level: number; // ordering; higher = better tier
|
|
4909
|
+
pointsMultiplier: number;
|
|
4910
|
+
}
|
|
4911
|
+
|
|
4912
|
+
interface LoyaltyNextTierSummary extends LoyaltyTierSummary {
|
|
4913
|
+
qualificationType: 'SPEND' | 'POINTS';
|
|
4914
|
+
qualificationThreshold: number;
|
|
4915
|
+
}
|
|
4916
|
+
|
|
4887
4917
|
interface LoyaltyStatus {
|
|
4888
4918
|
enrolled: boolean;
|
|
4889
4919
|
pointsBalance: number; // redeemable points (pending earns excluded)
|
|
@@ -4893,6 +4923,10 @@ interface LoyaltyStatus {
|
|
|
4893
4923
|
currencyRatio: number; // points needed to redeem 1 unit of store currency
|
|
4894
4924
|
status: 'DRAFT' | 'ACTIVE' | 'PAUSED';
|
|
4895
4925
|
} | null; // null when the store has no loyalty program
|
|
4926
|
+
tier: LoyaltyTierSummary | null; // null if untiered / no tiers configured
|
|
4927
|
+
nextTier: LoyaltyNextTierSummary | null; // null if at the top tier already
|
|
4928
|
+
progressToNextTier: number; // 0..1
|
|
4929
|
+
pointsToNextTier: number | null;
|
|
4896
4930
|
}
|
|
4897
4931
|
|
|
4898
4932
|
interface LoyaltyReward {
|
|
@@ -4900,16 +4934,19 @@ interface LoyaltyReward {
|
|
|
4900
4934
|
name: string;
|
|
4901
4935
|
description: string | null;
|
|
4902
4936
|
pointsCost: number;
|
|
4903
|
-
|
|
4937
|
+
type: 'FIXED_DISCOUNT' | 'PERCENT_DISCOUNT';
|
|
4938
|
+
discountValue: number; // currency amount (FIXED_DISCOUNT) or 0-100 percent (PERCENT_DISCOUNT)
|
|
4904
4939
|
minOrderAmount: number | null;
|
|
4905
4940
|
maxUsesPerUser: number;
|
|
4906
4941
|
isActive: boolean;
|
|
4942
|
+
minTierLevel: number | null; // minimum tier level required, or null for no restriction
|
|
4907
4943
|
createdAt: string;
|
|
4908
4944
|
updatedAt: string;
|
|
4909
4945
|
}
|
|
4910
4946
|
|
|
4911
4947
|
interface RedeemRewardResult {
|
|
4912
4948
|
couponCode: string; // one-time coupon to apply at checkout
|
|
4949
|
+
discountType: 'FIXED_DISCOUNT' | 'PERCENT_DISCOUNT';
|
|
4913
4950
|
discountValue: number;
|
|
4914
4951
|
pointsSpent: number;
|
|
4915
4952
|
pointsBalance: number; // remaining balance after redemption
|
|
@@ -4919,6 +4956,7 @@ interface RedeemRewardResult {
|
|
|
4919
4956
|
// client.enrollInLoyalty(): Promise<LoyaltyStatus>
|
|
4920
4957
|
// client.getAvailableRewards(): Promise<LoyaltyReward[]>
|
|
4921
4958
|
// client.redeemLoyaltyReward(rewardId: string): Promise<RedeemRewardResult>
|
|
4959
|
+
// client.reportSocialShare(platform?: string): Promise<{ awarded: boolean; points: number }>
|
|
4922
4960
|
`;
|
|
4923
4961
|
var TYPES_BY_DOMAIN = {
|
|
4924
4962
|
products: PRODUCTS_TYPES,
|
|
@@ -6464,7 +6502,7 @@ function formatCapabilities(caps) {
|
|
|
6464
6502
|
}
|
|
6465
6503
|
if (caps.features.hasLoyaltyProgram) {
|
|
6466
6504
|
suggestions.push(
|
|
6467
|
-
"A loyalty program is active. In a storefront-mode client (new BrainerceClient({ storeId })), show the logged-in customer their points balance and redeemable rewards, and let them redeem for a coupon at checkout. Use getLoyaltyStatus(), getAvailableRewards(),
|
|
6505
|
+
"A loyalty program is active. In a storefront-mode client (new BrainerceClient({ storeId })), show the logged-in customer their points balance, tier progress, and redeemable rewards, and let them redeem for a coupon at checkout. Use getLoyaltyStatus() (includes tier/nextTier/progressToNextTier), getAvailableRewards(), redeemLoyaltyReward(id), and optionally reportSocialShare(). Note: loyalty is NOT available in vibe-coded mode."
|
|
6468
6506
|
);
|
|
6469
6507
|
}
|
|
6470
6508
|
if (caps.features.hasCheckoutCustomFields) {
|
package/dist/bin/stdio.js
CHANGED
|
@@ -3321,11 +3321,18 @@ Points are earned automatically by the platform when an order is paid \u2014 the
|
|
|
3321
3321
|
\`\`\`typescript
|
|
3322
3322
|
// requires client.setCustomerToken(auth.token)
|
|
3323
3323
|
const status = await client.getLoyaltyStatus();
|
|
3324
|
-
// {
|
|
3324
|
+
// {
|
|
3325
|
+
// enrolled, pointsBalance, lifetimeEarned,
|
|
3326
|
+
// program: { pointsName, currencyRatio, status } | null,
|
|
3327
|
+
// tier: { id, name, level, pointsMultiplier } | null,
|
|
3328
|
+
// nextTier: { id, name, level, pointsMultiplier, qualificationType, qualificationThreshold } | null,
|
|
3329
|
+
// progressToNextTier, pointsToNextTier,
|
|
3330
|
+
// }
|
|
3325
3331
|
\`\`\`
|
|
3326
3332
|
|
|
3327
3333
|
- \`program === null\` \u2192 the store has no loyalty program; hide the loyalty UI.
|
|
3328
3334
|
- \`program.status !== 'ACTIVE'\` \u2192 program paused/draft; hide the loyalty UI.
|
|
3335
|
+
- \`tier\`/\`nextTier\` are \`null\` when the store hasn't configured tiers, or the customer hasn't qualified for one yet.
|
|
3329
3336
|
|
|
3330
3337
|
## Enroll (only if auto-enroll is off)
|
|
3331
3338
|
|
|
@@ -3333,19 +3340,30 @@ const status = await client.getLoyaltyStatus();
|
|
|
3333
3340
|
await client.enrollInLoyalty(); // same status shape; no-op if already enrolled
|
|
3334
3341
|
\`\`\`
|
|
3335
3342
|
|
|
3343
|
+
May grant a one-time "joined the program" bonus if configured \u2014 distinct from any account-signup bonus (granted automatically on registration, not by this call).
|
|
3344
|
+
|
|
3336
3345
|
## Rewards & redemption
|
|
3337
3346
|
|
|
3338
3347
|
\`\`\`typescript
|
|
3339
3348
|
const rewards = await client.getAvailableRewards();
|
|
3340
|
-
// [{ id, name, description, pointsCost, discountValue, minOrderAmount, maxUsesPerUser, isActive }]
|
|
3349
|
+
// [{ id, name, description, pointsCost, type, discountValue, minOrderAmount, maxUsesPerUser, minTierLevel, isActive }]
|
|
3350
|
+
// Already filtered to rewards the customer's current tier qualifies for.
|
|
3341
3351
|
|
|
3342
|
-
const { couponCode, discountValue, pointsBalance } =
|
|
3352
|
+
const { couponCode, discountType, discountValue, pointsBalance } =
|
|
3353
|
+
await client.redeemLoyaltyReward(rewardId);
|
|
3343
3354
|
await client.applyCoupon(cartId, couponCode); // applies via the normal coupon engine
|
|
3344
3355
|
\`\`\`
|
|
3345
3356
|
|
|
3346
|
-
- \`
|
|
3347
|
-
-
|
|
3357
|
+
- \`reward.type\` is \`'FIXED_DISCOUNT'\` (currency amount) or \`'PERCENT_DISCOUNT'\` (0-100 percent) \u2014 the redeem result's \`discountType\` matches.
|
|
3358
|
+
- \`redeemLoyaltyReward\` mints a one-time coupon (\`usageLimit: 1\`). Apply it with the normal \`applyCoupon\` flow.
|
|
3359
|
+
- Throws if the customer has insufficient points, or their tier is below \`reward.minTierLevel\`. If minting fails, points are refunded automatically.
|
|
3348
3360
|
- Disable a reward's redeem button when \`pointsBalance < reward.pointsCost\`.
|
|
3361
|
+
|
|
3362
|
+
## Social share (optional)
|
|
3363
|
+
|
|
3364
|
+
\`\`\`typescript
|
|
3365
|
+
await client.reportSocialShare('instagram'); // platform optional, self-reported, once per customer
|
|
3366
|
+
\`\`\`
|
|
3349
3367
|
`;
|
|
3350
3368
|
}
|
|
3351
3369
|
function getSectionByTopic(topic, connectionId, currency) {
|
|
@@ -4881,6 +4899,18 @@ interface TaxEstimateResponse {
|
|
|
4881
4899
|
// full shipping address. The country comes from your edge runtime
|
|
4882
4900
|
// (CF-IPCountry / request.geo.country / etc.), NOT the request IP.`;
|
|
4883
4901
|
var LOYALTY_TYPES = `// ---- Loyalty & Rewards (storefront mode only) ----
|
|
4902
|
+
interface LoyaltyTierSummary {
|
|
4903
|
+
id: string;
|
|
4904
|
+
name: string;
|
|
4905
|
+
level: number; // ordering; higher = better tier
|
|
4906
|
+
pointsMultiplier: number;
|
|
4907
|
+
}
|
|
4908
|
+
|
|
4909
|
+
interface LoyaltyNextTierSummary extends LoyaltyTierSummary {
|
|
4910
|
+
qualificationType: 'SPEND' | 'POINTS';
|
|
4911
|
+
qualificationThreshold: number;
|
|
4912
|
+
}
|
|
4913
|
+
|
|
4884
4914
|
interface LoyaltyStatus {
|
|
4885
4915
|
enrolled: boolean;
|
|
4886
4916
|
pointsBalance: number; // redeemable points (pending earns excluded)
|
|
@@ -4890,6 +4920,10 @@ interface LoyaltyStatus {
|
|
|
4890
4920
|
currencyRatio: number; // points needed to redeem 1 unit of store currency
|
|
4891
4921
|
status: 'DRAFT' | 'ACTIVE' | 'PAUSED';
|
|
4892
4922
|
} | null; // null when the store has no loyalty program
|
|
4923
|
+
tier: LoyaltyTierSummary | null; // null if untiered / no tiers configured
|
|
4924
|
+
nextTier: LoyaltyNextTierSummary | null; // null if at the top tier already
|
|
4925
|
+
progressToNextTier: number; // 0..1
|
|
4926
|
+
pointsToNextTier: number | null;
|
|
4893
4927
|
}
|
|
4894
4928
|
|
|
4895
4929
|
interface LoyaltyReward {
|
|
@@ -4897,16 +4931,19 @@ interface LoyaltyReward {
|
|
|
4897
4931
|
name: string;
|
|
4898
4932
|
description: string | null;
|
|
4899
4933
|
pointsCost: number;
|
|
4900
|
-
|
|
4934
|
+
type: 'FIXED_DISCOUNT' | 'PERCENT_DISCOUNT';
|
|
4935
|
+
discountValue: number; // currency amount (FIXED_DISCOUNT) or 0-100 percent (PERCENT_DISCOUNT)
|
|
4901
4936
|
minOrderAmount: number | null;
|
|
4902
4937
|
maxUsesPerUser: number;
|
|
4903
4938
|
isActive: boolean;
|
|
4939
|
+
minTierLevel: number | null; // minimum tier level required, or null for no restriction
|
|
4904
4940
|
createdAt: string;
|
|
4905
4941
|
updatedAt: string;
|
|
4906
4942
|
}
|
|
4907
4943
|
|
|
4908
4944
|
interface RedeemRewardResult {
|
|
4909
4945
|
couponCode: string; // one-time coupon to apply at checkout
|
|
4946
|
+
discountType: 'FIXED_DISCOUNT' | 'PERCENT_DISCOUNT';
|
|
4910
4947
|
discountValue: number;
|
|
4911
4948
|
pointsSpent: number;
|
|
4912
4949
|
pointsBalance: number; // remaining balance after redemption
|
|
@@ -4916,6 +4953,7 @@ interface RedeemRewardResult {
|
|
|
4916
4953
|
// client.enrollInLoyalty(): Promise<LoyaltyStatus>
|
|
4917
4954
|
// client.getAvailableRewards(): Promise<LoyaltyReward[]>
|
|
4918
4955
|
// client.redeemLoyaltyReward(rewardId: string): Promise<RedeemRewardResult>
|
|
4956
|
+
// client.reportSocialShare(platform?: string): Promise<{ awarded: boolean; points: number }>
|
|
4919
4957
|
`;
|
|
4920
4958
|
var TYPES_BY_DOMAIN = {
|
|
4921
4959
|
products: PRODUCTS_TYPES,
|
|
@@ -6461,7 +6499,7 @@ function formatCapabilities(caps) {
|
|
|
6461
6499
|
}
|
|
6462
6500
|
if (caps.features.hasLoyaltyProgram) {
|
|
6463
6501
|
suggestions.push(
|
|
6464
|
-
"A loyalty program is active. In a storefront-mode client (new BrainerceClient({ storeId })), show the logged-in customer their points balance and redeemable rewards, and let them redeem for a coupon at checkout. Use getLoyaltyStatus(), getAvailableRewards(),
|
|
6502
|
+
"A loyalty program is active. In a storefront-mode client (new BrainerceClient({ storeId })), show the logged-in customer their points balance, tier progress, and redeemable rewards, and let them redeem for a coupon at checkout. Use getLoyaltyStatus() (includes tier/nextTier/progressToNextTier), getAvailableRewards(), redeemLoyaltyReward(id), and optionally reportSocialShare(). Note: loyalty is NOT available in vibe-coded mode."
|
|
6465
6503
|
);
|
|
6466
6504
|
}
|
|
6467
6505
|
if (caps.features.hasCheckoutCustomFields) {
|
package/dist/index.js
CHANGED
|
@@ -3347,11 +3347,18 @@ Points are earned automatically by the platform when an order is paid \u2014 the
|
|
|
3347
3347
|
\`\`\`typescript
|
|
3348
3348
|
// requires client.setCustomerToken(auth.token)
|
|
3349
3349
|
const status = await client.getLoyaltyStatus();
|
|
3350
|
-
// {
|
|
3350
|
+
// {
|
|
3351
|
+
// enrolled, pointsBalance, lifetimeEarned,
|
|
3352
|
+
// program: { pointsName, currencyRatio, status } | null,
|
|
3353
|
+
// tier: { id, name, level, pointsMultiplier } | null,
|
|
3354
|
+
// nextTier: { id, name, level, pointsMultiplier, qualificationType, qualificationThreshold } | null,
|
|
3355
|
+
// progressToNextTier, pointsToNextTier,
|
|
3356
|
+
// }
|
|
3351
3357
|
\`\`\`
|
|
3352
3358
|
|
|
3353
3359
|
- \`program === null\` \u2192 the store has no loyalty program; hide the loyalty UI.
|
|
3354
3360
|
- \`program.status !== 'ACTIVE'\` \u2192 program paused/draft; hide the loyalty UI.
|
|
3361
|
+
- \`tier\`/\`nextTier\` are \`null\` when the store hasn't configured tiers, or the customer hasn't qualified for one yet.
|
|
3355
3362
|
|
|
3356
3363
|
## Enroll (only if auto-enroll is off)
|
|
3357
3364
|
|
|
@@ -3359,19 +3366,30 @@ const status = await client.getLoyaltyStatus();
|
|
|
3359
3366
|
await client.enrollInLoyalty(); // same status shape; no-op if already enrolled
|
|
3360
3367
|
\`\`\`
|
|
3361
3368
|
|
|
3369
|
+
May grant a one-time "joined the program" bonus if configured \u2014 distinct from any account-signup bonus (granted automatically on registration, not by this call).
|
|
3370
|
+
|
|
3362
3371
|
## Rewards & redemption
|
|
3363
3372
|
|
|
3364
3373
|
\`\`\`typescript
|
|
3365
3374
|
const rewards = await client.getAvailableRewards();
|
|
3366
|
-
// [{ id, name, description, pointsCost, discountValue, minOrderAmount, maxUsesPerUser, isActive }]
|
|
3375
|
+
// [{ id, name, description, pointsCost, type, discountValue, minOrderAmount, maxUsesPerUser, minTierLevel, isActive }]
|
|
3376
|
+
// Already filtered to rewards the customer's current tier qualifies for.
|
|
3367
3377
|
|
|
3368
|
-
const { couponCode, discountValue, pointsBalance } =
|
|
3378
|
+
const { couponCode, discountType, discountValue, pointsBalance } =
|
|
3379
|
+
await client.redeemLoyaltyReward(rewardId);
|
|
3369
3380
|
await client.applyCoupon(cartId, couponCode); // applies via the normal coupon engine
|
|
3370
3381
|
\`\`\`
|
|
3371
3382
|
|
|
3372
|
-
- \`
|
|
3373
|
-
-
|
|
3383
|
+
- \`reward.type\` is \`'FIXED_DISCOUNT'\` (currency amount) or \`'PERCENT_DISCOUNT'\` (0-100 percent) \u2014 the redeem result's \`discountType\` matches.
|
|
3384
|
+
- \`redeemLoyaltyReward\` mints a one-time coupon (\`usageLimit: 1\`). Apply it with the normal \`applyCoupon\` flow.
|
|
3385
|
+
- Throws if the customer has insufficient points, or their tier is below \`reward.minTierLevel\`. If minting fails, points are refunded automatically.
|
|
3374
3386
|
- Disable a reward's redeem button when \`pointsBalance < reward.pointsCost\`.
|
|
3387
|
+
|
|
3388
|
+
## Social share (optional)
|
|
3389
|
+
|
|
3390
|
+
\`\`\`typescript
|
|
3391
|
+
await client.reportSocialShare('instagram'); // platform optional, self-reported, once per customer
|
|
3392
|
+
\`\`\`
|
|
3375
3393
|
`;
|
|
3376
3394
|
}
|
|
3377
3395
|
function getSectionByTopic(topic, connectionId, currency) {
|
|
@@ -4907,6 +4925,18 @@ interface TaxEstimateResponse {
|
|
|
4907
4925
|
// full shipping address. The country comes from your edge runtime
|
|
4908
4926
|
// (CF-IPCountry / request.geo.country / etc.), NOT the request IP.`;
|
|
4909
4927
|
var LOYALTY_TYPES = `// ---- Loyalty & Rewards (storefront mode only) ----
|
|
4928
|
+
interface LoyaltyTierSummary {
|
|
4929
|
+
id: string;
|
|
4930
|
+
name: string;
|
|
4931
|
+
level: number; // ordering; higher = better tier
|
|
4932
|
+
pointsMultiplier: number;
|
|
4933
|
+
}
|
|
4934
|
+
|
|
4935
|
+
interface LoyaltyNextTierSummary extends LoyaltyTierSummary {
|
|
4936
|
+
qualificationType: 'SPEND' | 'POINTS';
|
|
4937
|
+
qualificationThreshold: number;
|
|
4938
|
+
}
|
|
4939
|
+
|
|
4910
4940
|
interface LoyaltyStatus {
|
|
4911
4941
|
enrolled: boolean;
|
|
4912
4942
|
pointsBalance: number; // redeemable points (pending earns excluded)
|
|
@@ -4916,6 +4946,10 @@ interface LoyaltyStatus {
|
|
|
4916
4946
|
currencyRatio: number; // points needed to redeem 1 unit of store currency
|
|
4917
4947
|
status: 'DRAFT' | 'ACTIVE' | 'PAUSED';
|
|
4918
4948
|
} | null; // null when the store has no loyalty program
|
|
4949
|
+
tier: LoyaltyTierSummary | null; // null if untiered / no tiers configured
|
|
4950
|
+
nextTier: LoyaltyNextTierSummary | null; // null if at the top tier already
|
|
4951
|
+
progressToNextTier: number; // 0..1
|
|
4952
|
+
pointsToNextTier: number | null;
|
|
4919
4953
|
}
|
|
4920
4954
|
|
|
4921
4955
|
interface LoyaltyReward {
|
|
@@ -4923,16 +4957,19 @@ interface LoyaltyReward {
|
|
|
4923
4957
|
name: string;
|
|
4924
4958
|
description: string | null;
|
|
4925
4959
|
pointsCost: number;
|
|
4926
|
-
|
|
4960
|
+
type: 'FIXED_DISCOUNT' | 'PERCENT_DISCOUNT';
|
|
4961
|
+
discountValue: number; // currency amount (FIXED_DISCOUNT) or 0-100 percent (PERCENT_DISCOUNT)
|
|
4927
4962
|
minOrderAmount: number | null;
|
|
4928
4963
|
maxUsesPerUser: number;
|
|
4929
4964
|
isActive: boolean;
|
|
4965
|
+
minTierLevel: number | null; // minimum tier level required, or null for no restriction
|
|
4930
4966
|
createdAt: string;
|
|
4931
4967
|
updatedAt: string;
|
|
4932
4968
|
}
|
|
4933
4969
|
|
|
4934
4970
|
interface RedeemRewardResult {
|
|
4935
4971
|
couponCode: string; // one-time coupon to apply at checkout
|
|
4972
|
+
discountType: 'FIXED_DISCOUNT' | 'PERCENT_DISCOUNT';
|
|
4936
4973
|
discountValue: number;
|
|
4937
4974
|
pointsSpent: number;
|
|
4938
4975
|
pointsBalance: number; // remaining balance after redemption
|
|
@@ -4942,6 +4979,7 @@ interface RedeemRewardResult {
|
|
|
4942
4979
|
// client.enrollInLoyalty(): Promise<LoyaltyStatus>
|
|
4943
4980
|
// client.getAvailableRewards(): Promise<LoyaltyReward[]>
|
|
4944
4981
|
// client.redeemLoyaltyReward(rewardId: string): Promise<RedeemRewardResult>
|
|
4982
|
+
// client.reportSocialShare(platform?: string): Promise<{ awarded: boolean; points: number }>
|
|
4945
4983
|
`;
|
|
4946
4984
|
var TYPES_BY_DOMAIN = {
|
|
4947
4985
|
products: PRODUCTS_TYPES,
|
|
@@ -6487,7 +6525,7 @@ function formatCapabilities(caps) {
|
|
|
6487
6525
|
}
|
|
6488
6526
|
if (caps.features.hasLoyaltyProgram) {
|
|
6489
6527
|
suggestions.push(
|
|
6490
|
-
"A loyalty program is active. In a storefront-mode client (new BrainerceClient({ storeId })), show the logged-in customer their points balance and redeemable rewards, and let them redeem for a coupon at checkout. Use getLoyaltyStatus(), getAvailableRewards(),
|
|
6528
|
+
"A loyalty program is active. In a storefront-mode client (new BrainerceClient({ storeId })), show the logged-in customer their points balance, tier progress, and redeemable rewards, and let them redeem for a coupon at checkout. Use getLoyaltyStatus() (includes tier/nextTier/progressToNextTier), getAvailableRewards(), redeemLoyaltyReward(id), and optionally reportSocialShare(). Note: loyalty is NOT available in vibe-coded mode."
|
|
6491
6529
|
);
|
|
6492
6530
|
}
|
|
6493
6531
|
if (caps.features.hasCheckoutCustomFields) {
|
package/dist/index.mjs
CHANGED
|
@@ -3315,11 +3315,18 @@ Points are earned automatically by the platform when an order is paid \u2014 the
|
|
|
3315
3315
|
\`\`\`typescript
|
|
3316
3316
|
// requires client.setCustomerToken(auth.token)
|
|
3317
3317
|
const status = await client.getLoyaltyStatus();
|
|
3318
|
-
// {
|
|
3318
|
+
// {
|
|
3319
|
+
// enrolled, pointsBalance, lifetimeEarned,
|
|
3320
|
+
// program: { pointsName, currencyRatio, status } | null,
|
|
3321
|
+
// tier: { id, name, level, pointsMultiplier } | null,
|
|
3322
|
+
// nextTier: { id, name, level, pointsMultiplier, qualificationType, qualificationThreshold } | null,
|
|
3323
|
+
// progressToNextTier, pointsToNextTier,
|
|
3324
|
+
// }
|
|
3319
3325
|
\`\`\`
|
|
3320
3326
|
|
|
3321
3327
|
- \`program === null\` \u2192 the store has no loyalty program; hide the loyalty UI.
|
|
3322
3328
|
- \`program.status !== 'ACTIVE'\` \u2192 program paused/draft; hide the loyalty UI.
|
|
3329
|
+
- \`tier\`/\`nextTier\` are \`null\` when the store hasn't configured tiers, or the customer hasn't qualified for one yet.
|
|
3323
3330
|
|
|
3324
3331
|
## Enroll (only if auto-enroll is off)
|
|
3325
3332
|
|
|
@@ -3327,19 +3334,30 @@ const status = await client.getLoyaltyStatus();
|
|
|
3327
3334
|
await client.enrollInLoyalty(); // same status shape; no-op if already enrolled
|
|
3328
3335
|
\`\`\`
|
|
3329
3336
|
|
|
3337
|
+
May grant a one-time "joined the program" bonus if configured \u2014 distinct from any account-signup bonus (granted automatically on registration, not by this call).
|
|
3338
|
+
|
|
3330
3339
|
## Rewards & redemption
|
|
3331
3340
|
|
|
3332
3341
|
\`\`\`typescript
|
|
3333
3342
|
const rewards = await client.getAvailableRewards();
|
|
3334
|
-
// [{ id, name, description, pointsCost, discountValue, minOrderAmount, maxUsesPerUser, isActive }]
|
|
3343
|
+
// [{ id, name, description, pointsCost, type, discountValue, minOrderAmount, maxUsesPerUser, minTierLevel, isActive }]
|
|
3344
|
+
// Already filtered to rewards the customer's current tier qualifies for.
|
|
3335
3345
|
|
|
3336
|
-
const { couponCode, discountValue, pointsBalance } =
|
|
3346
|
+
const { couponCode, discountType, discountValue, pointsBalance } =
|
|
3347
|
+
await client.redeemLoyaltyReward(rewardId);
|
|
3337
3348
|
await client.applyCoupon(cartId, couponCode); // applies via the normal coupon engine
|
|
3338
3349
|
\`\`\`
|
|
3339
3350
|
|
|
3340
|
-
- \`
|
|
3341
|
-
-
|
|
3351
|
+
- \`reward.type\` is \`'FIXED_DISCOUNT'\` (currency amount) or \`'PERCENT_DISCOUNT'\` (0-100 percent) \u2014 the redeem result's \`discountType\` matches.
|
|
3352
|
+
- \`redeemLoyaltyReward\` mints a one-time coupon (\`usageLimit: 1\`). Apply it with the normal \`applyCoupon\` flow.
|
|
3353
|
+
- Throws if the customer has insufficient points, or their tier is below \`reward.minTierLevel\`. If minting fails, points are refunded automatically.
|
|
3342
3354
|
- Disable a reward's redeem button when \`pointsBalance < reward.pointsCost\`.
|
|
3355
|
+
|
|
3356
|
+
## Social share (optional)
|
|
3357
|
+
|
|
3358
|
+
\`\`\`typescript
|
|
3359
|
+
await client.reportSocialShare('instagram'); // platform optional, self-reported, once per customer
|
|
3360
|
+
\`\`\`
|
|
3343
3361
|
`;
|
|
3344
3362
|
}
|
|
3345
3363
|
function getSectionByTopic(topic, connectionId, currency) {
|
|
@@ -4875,6 +4893,18 @@ interface TaxEstimateResponse {
|
|
|
4875
4893
|
// full shipping address. The country comes from your edge runtime
|
|
4876
4894
|
// (CF-IPCountry / request.geo.country / etc.), NOT the request IP.`;
|
|
4877
4895
|
var LOYALTY_TYPES = `// ---- Loyalty & Rewards (storefront mode only) ----
|
|
4896
|
+
interface LoyaltyTierSummary {
|
|
4897
|
+
id: string;
|
|
4898
|
+
name: string;
|
|
4899
|
+
level: number; // ordering; higher = better tier
|
|
4900
|
+
pointsMultiplier: number;
|
|
4901
|
+
}
|
|
4902
|
+
|
|
4903
|
+
interface LoyaltyNextTierSummary extends LoyaltyTierSummary {
|
|
4904
|
+
qualificationType: 'SPEND' | 'POINTS';
|
|
4905
|
+
qualificationThreshold: number;
|
|
4906
|
+
}
|
|
4907
|
+
|
|
4878
4908
|
interface LoyaltyStatus {
|
|
4879
4909
|
enrolled: boolean;
|
|
4880
4910
|
pointsBalance: number; // redeemable points (pending earns excluded)
|
|
@@ -4884,6 +4914,10 @@ interface LoyaltyStatus {
|
|
|
4884
4914
|
currencyRatio: number; // points needed to redeem 1 unit of store currency
|
|
4885
4915
|
status: 'DRAFT' | 'ACTIVE' | 'PAUSED';
|
|
4886
4916
|
} | null; // null when the store has no loyalty program
|
|
4917
|
+
tier: LoyaltyTierSummary | null; // null if untiered / no tiers configured
|
|
4918
|
+
nextTier: LoyaltyNextTierSummary | null; // null if at the top tier already
|
|
4919
|
+
progressToNextTier: number; // 0..1
|
|
4920
|
+
pointsToNextTier: number | null;
|
|
4887
4921
|
}
|
|
4888
4922
|
|
|
4889
4923
|
interface LoyaltyReward {
|
|
@@ -4891,16 +4925,19 @@ interface LoyaltyReward {
|
|
|
4891
4925
|
name: string;
|
|
4892
4926
|
description: string | null;
|
|
4893
4927
|
pointsCost: number;
|
|
4894
|
-
|
|
4928
|
+
type: 'FIXED_DISCOUNT' | 'PERCENT_DISCOUNT';
|
|
4929
|
+
discountValue: number; // currency amount (FIXED_DISCOUNT) or 0-100 percent (PERCENT_DISCOUNT)
|
|
4895
4930
|
minOrderAmount: number | null;
|
|
4896
4931
|
maxUsesPerUser: number;
|
|
4897
4932
|
isActive: boolean;
|
|
4933
|
+
minTierLevel: number | null; // minimum tier level required, or null for no restriction
|
|
4898
4934
|
createdAt: string;
|
|
4899
4935
|
updatedAt: string;
|
|
4900
4936
|
}
|
|
4901
4937
|
|
|
4902
4938
|
interface RedeemRewardResult {
|
|
4903
4939
|
couponCode: string; // one-time coupon to apply at checkout
|
|
4940
|
+
discountType: 'FIXED_DISCOUNT' | 'PERCENT_DISCOUNT';
|
|
4904
4941
|
discountValue: number;
|
|
4905
4942
|
pointsSpent: number;
|
|
4906
4943
|
pointsBalance: number; // remaining balance after redemption
|
|
@@ -4910,6 +4947,7 @@ interface RedeemRewardResult {
|
|
|
4910
4947
|
// client.enrollInLoyalty(): Promise<LoyaltyStatus>
|
|
4911
4948
|
// client.getAvailableRewards(): Promise<LoyaltyReward[]>
|
|
4912
4949
|
// client.redeemLoyaltyReward(rewardId: string): Promise<RedeemRewardResult>
|
|
4950
|
+
// client.reportSocialShare(platform?: string): Promise<{ awarded: boolean; points: number }>
|
|
4913
4951
|
`;
|
|
4914
4952
|
var TYPES_BY_DOMAIN = {
|
|
4915
4953
|
products: PRODUCTS_TYPES,
|
|
@@ -6455,7 +6493,7 @@ function formatCapabilities(caps) {
|
|
|
6455
6493
|
}
|
|
6456
6494
|
if (caps.features.hasLoyaltyProgram) {
|
|
6457
6495
|
suggestions.push(
|
|
6458
|
-
"A loyalty program is active. In a storefront-mode client (new BrainerceClient({ storeId })), show the logged-in customer their points balance and redeemable rewards, and let them redeem for a coupon at checkout. Use getLoyaltyStatus(), getAvailableRewards(),
|
|
6496
|
+
"A loyalty program is active. In a storefront-mode client (new BrainerceClient({ storeId })), show the logged-in customer their points balance, tier progress, and redeemable rewards, and let them redeem for a coupon at checkout. Use getLoyaltyStatus() (includes tier/nextTier/progressToNextTier), getAvailableRewards(), redeemLoyaltyReward(id), and optionally reportSocialShare(). Note: loyalty is NOT available in vibe-coded mode."
|
|
6459
6497
|
);
|
|
6460
6498
|
}
|
|
6461
6499
|
if (caps.features.hasCheckoutCustomFields) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brainerce/mcp-server",
|
|
3
|
-
"version": "3.12.
|
|
3
|
+
"version": "3.12.3",
|
|
4
4
|
"packageManager": "pnpm@9.0.0",
|
|
5
5
|
"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.",
|
|
6
6
|
"bin": {
|