@open-loyalty/mcp-server 1.0.3 → 1.3.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/README.md +180 -177
- package/dist/auth/provider.js +2 -14
- package/dist/auth/storage.js +22 -0
- package/dist/client/http.d.ts +5 -0
- package/dist/client/http.js +62 -3
- package/dist/config.d.ts +6 -5
- package/dist/config.js +15 -11
- package/dist/http.js +170 -65
- package/dist/instructions.d.ts +5 -0
- package/dist/instructions.js +420 -0
- package/dist/prompts/fan-engagement-setup.d.ts +107 -0
- package/dist/prompts/fan-engagement-setup.js +492 -0
- package/dist/server.d.ts +1 -1
- package/dist/server.js +68 -278
- package/dist/tools/achievement/handlers.d.ts +117 -0
- package/dist/tools/achievement/handlers.js +161 -0
- package/dist/tools/achievement/index.d.ts +479 -0
- package/dist/tools/achievement/index.js +74 -0
- package/dist/tools/achievement/schemas.d.ts +433 -0
- package/dist/tools/achievement/schemas.js +142 -0
- package/dist/tools/achievement.d.ts +155 -121
- package/dist/tools/achievement.js +82 -39
- package/dist/tools/admin.d.ts +18 -6
- package/dist/tools/admin.js +24 -12
- package/dist/tools/analytics.d.ts +29 -11
- package/dist/tools/analytics.js +58 -48
- package/dist/tools/apikey.d.ts +10 -3
- package/dist/tools/apikey.js +13 -6
- package/dist/tools/audit.d.ts +6 -2
- package/dist/tools/audit.js +8 -4
- package/dist/tools/badge.d.ts +14 -6
- package/dist/tools/badge.js +36 -27
- package/dist/tools/campaign/handlers.d.ts +42 -0
- package/dist/tools/campaign/handlers.js +223 -0
- package/dist/tools/campaign/index.d.ts +783 -0
- package/dist/tools/campaign/index.js +112 -0
- package/dist/tools/campaign/member-handlers.d.ts +60 -0
- package/dist/tools/campaign/member-handlers.js +159 -0
- package/dist/tools/campaign/schemas.d.ts +704 -0
- package/dist/tools/campaign/schemas.js +259 -0
- package/dist/tools/campaign/types.d.ts +161 -0
- package/dist/tools/campaign/types.js +2 -0
- package/dist/tools/campaign.d.ts +41 -16
- package/dist/tools/campaign.js +38 -25
- package/dist/tools/custom-event.d.ts +315 -0
- package/dist/tools/custom-event.js +270 -0
- package/dist/tools/export.d.ts +12 -4
- package/dist/tools/export.js +25 -20
- package/dist/tools/import.d.ts +9 -3
- package/dist/tools/import.js +33 -21
- package/dist/tools/index.d.ts +3 -11
- package/dist/tools/index.js +17 -475
- package/dist/tools/member/handlers.d.ts +111 -0
- package/dist/tools/member/handlers.js +206 -0
- package/dist/tools/member/index.d.ts +169 -0
- package/dist/tools/member/index.js +92 -0
- package/dist/tools/member/schemas.d.ts +89 -0
- package/dist/tools/member/schemas.js +65 -0
- package/dist/tools/member.d.ts +21 -0
- package/dist/tools/member.js +56 -62
- package/dist/tools/points.d.ts +19 -6
- package/dist/tools/points.js +51 -49
- package/dist/tools/referral/handlers.d.ts +47 -0
- package/dist/tools/referral/handlers.js +115 -0
- package/dist/tools/referral/index.d.ts +44 -0
- package/dist/tools/referral/index.js +44 -0
- package/dist/tools/referral/schemas.d.ts +34 -0
- package/dist/tools/referral/schemas.js +52 -0
- package/dist/tools/reward/handlers.d.ts +110 -0
- package/dist/tools/reward/handlers.js +289 -0
- package/dist/tools/reward/index.d.ts +177 -0
- package/dist/tools/reward/index.js +90 -0
- package/dist/tools/reward/schemas.d.ts +116 -0
- package/dist/tools/reward/schemas.js +91 -0
- package/dist/tools/reward.d.ts +18 -0
- package/dist/tools/reward.js +56 -66
- package/dist/tools/role.d.ts +26 -7
- package/dist/tools/role.js +25 -12
- package/dist/tools/segment/handlers.d.ts +87 -0
- package/dist/tools/segment/handlers.js +174 -0
- package/dist/tools/segment/index.d.ts +395 -0
- package/dist/tools/segment/index.js +87 -0
- package/dist/tools/segment/schemas.d.ts +337 -0
- package/dist/tools/segment/schemas.js +79 -0
- package/dist/tools/segment.d.ts +29 -10
- package/dist/tools/segment.js +84 -50
- package/dist/tools/store.d.ts +12 -4
- package/dist/tools/store.js +16 -8
- package/dist/tools/tierset.d.ts +19 -7
- package/dist/tools/tierset.js +44 -35
- package/dist/tools/transaction.d.ts +16 -8
- package/dist/tools/transaction.js +25 -21
- package/dist/tools/wallet-type.d.ts +7 -3
- package/dist/tools/wallet-type.js +14 -12
- package/dist/tools/webhook.d.ts +23 -10
- package/dist/tools/webhook.js +135 -33
- package/dist/types/schemas/achievement.d.ts +12 -309
- package/dist/types/schemas/achievement.js +0 -13
- package/dist/types/schemas/admin.d.ts +10 -97
- package/dist/types/schemas/admin.js +0 -38
- package/dist/types/schemas/badge.d.ts +0 -37
- package/dist/types/schemas/badge.js +0 -11
- package/dist/types/schemas/campaign.d.ts +64 -832
- package/dist/types/schemas/campaign.js +2 -25
- package/dist/types/schemas/common.d.ts +5 -0
- package/dist/types/schemas/common.js +5 -0
- package/dist/types/schemas/export.d.ts +0 -17
- package/dist/types/schemas/export.js +0 -7
- package/dist/types/schemas/member.d.ts +37 -176
- package/dist/types/schemas/member.js +0 -27
- package/dist/types/schemas/points.d.ts +0 -63
- package/dist/types/schemas/points.js +0 -22
- package/dist/types/schemas/reward.d.ts +71 -68
- package/dist/types/schemas/reward.js +8 -28
- package/dist/types/schemas/role.d.ts +0 -100
- package/dist/types/schemas/role.js +0 -29
- package/dist/types/schemas/segment.d.ts +0 -58
- package/dist/types/schemas/segment.js +0 -17
- package/dist/types/schemas/tierset.d.ts +0 -176
- package/dist/types/schemas/tierset.js +0 -27
- package/dist/types/schemas/transaction.d.ts +23 -254
- package/dist/types/schemas/transaction.js +0 -7
- package/dist/types/schemas/wallet-type.d.ts +8 -8
- package/dist/types/schemas/wallet-type.js +1 -1
- package/dist/types/schemas/webhook.d.ts +0 -58
- package/dist/types/schemas/webhook.js +0 -12
- package/dist/utils/errors.js +30 -3
- package/dist/utils/payload.d.ts +12 -0
- package/dist/utils/payload.js +14 -0
- package/dist/workflows/app-login-streak.d.ts +39 -0
- package/dist/workflows/app-login-streak.js +298 -0
- package/dist/workflows/early-arrival.d.ts +33 -0
- package/dist/workflows/early-arrival.js +148 -0
- package/dist/workflows/index.d.ts +101 -0
- package/dist/workflows/index.js +208 -0
- package/dist/workflows/match-attendance.d.ts +45 -0
- package/dist/workflows/match-attendance.js +308 -0
- package/dist/workflows/sportsbar-visit.d.ts +41 -0
- package/dist/workflows/sportsbar-visit.js +284 -0
- package/dist/workflows/vod-watching.d.ts +43 -0
- package/dist/workflows/vod-watching.js +326 -0
- package/package.json +10 -2
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { Reward } from "../../types/schemas/reward.js";
|
|
2
|
+
export declare function rewardList(input: {
|
|
3
|
+
storeCode?: string;
|
|
4
|
+
page?: number;
|
|
5
|
+
perPage?: number;
|
|
6
|
+
active?: boolean;
|
|
7
|
+
type?: string;
|
|
8
|
+
categoryId?: string;
|
|
9
|
+
}): Promise<{
|
|
10
|
+
rewards: Array<{
|
|
11
|
+
rewardId: string;
|
|
12
|
+
name: string;
|
|
13
|
+
type: string;
|
|
14
|
+
costInPoints?: number;
|
|
15
|
+
active: boolean;
|
|
16
|
+
}>;
|
|
17
|
+
total: {
|
|
18
|
+
all?: number;
|
|
19
|
+
filtered?: number;
|
|
20
|
+
};
|
|
21
|
+
}>;
|
|
22
|
+
export declare function rewardCreate(input: {
|
|
23
|
+
storeCode?: string;
|
|
24
|
+
translations: {
|
|
25
|
+
en: {
|
|
26
|
+
name: string;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
reward: string;
|
|
30
|
+
activity: {
|
|
31
|
+
from: string;
|
|
32
|
+
to: string;
|
|
33
|
+
};
|
|
34
|
+
visibility: {
|
|
35
|
+
from: string;
|
|
36
|
+
to: string;
|
|
37
|
+
};
|
|
38
|
+
usageLimit: {
|
|
39
|
+
perUser: number;
|
|
40
|
+
general?: number;
|
|
41
|
+
};
|
|
42
|
+
costInPoints?: number;
|
|
43
|
+
usageInstruction?: string;
|
|
44
|
+
active?: boolean;
|
|
45
|
+
categories?: string[];
|
|
46
|
+
levels?: string[];
|
|
47
|
+
segments?: string[];
|
|
48
|
+
target?: string | null;
|
|
49
|
+
couponValue?: number;
|
|
50
|
+
couponValueType?: string;
|
|
51
|
+
daysValid?: number;
|
|
52
|
+
}): Promise<{
|
|
53
|
+
rewardId: string;
|
|
54
|
+
name: string;
|
|
55
|
+
costInPoints?: number;
|
|
56
|
+
}>;
|
|
57
|
+
export declare function rewardGet(input: {
|
|
58
|
+
storeCode?: string;
|
|
59
|
+
rewardId: string;
|
|
60
|
+
}): Promise<Reward>;
|
|
61
|
+
export declare function rewardUpdate(input: {
|
|
62
|
+
storeCode?: string;
|
|
63
|
+
rewardId: string;
|
|
64
|
+
name?: string;
|
|
65
|
+
costInPoints?: number;
|
|
66
|
+
description?: string;
|
|
67
|
+
active?: boolean;
|
|
68
|
+
categories?: string[];
|
|
69
|
+
levels?: string[];
|
|
70
|
+
segments?: string[];
|
|
71
|
+
}): Promise<void>;
|
|
72
|
+
export declare function rewardActivate(input: {
|
|
73
|
+
storeCode?: string;
|
|
74
|
+
rewardId: string;
|
|
75
|
+
}): Promise<void>;
|
|
76
|
+
export declare function rewardDeactivate(input: {
|
|
77
|
+
storeCode?: string;
|
|
78
|
+
rewardId: string;
|
|
79
|
+
}): Promise<void>;
|
|
80
|
+
export declare function rewardBuy(input: {
|
|
81
|
+
storeCode?: string;
|
|
82
|
+
rewardId: string;
|
|
83
|
+
memberId: string;
|
|
84
|
+
quantity?: number;
|
|
85
|
+
couponValue?: number;
|
|
86
|
+
withoutPoints?: boolean;
|
|
87
|
+
}): Promise<{
|
|
88
|
+
issuedRewardId: string;
|
|
89
|
+
couponCode?: string;
|
|
90
|
+
}>;
|
|
91
|
+
export declare function rewardRedeem(input: {
|
|
92
|
+
storeCode?: string;
|
|
93
|
+
memberId: string;
|
|
94
|
+
couponCode: string;
|
|
95
|
+
}): Promise<{
|
|
96
|
+
code: string;
|
|
97
|
+
used: boolean;
|
|
98
|
+
}>;
|
|
99
|
+
export declare function rewardCategoryList(input: {
|
|
100
|
+
storeCode?: string;
|
|
101
|
+
page?: number;
|
|
102
|
+
perPage?: number;
|
|
103
|
+
active?: boolean;
|
|
104
|
+
}): Promise<{
|
|
105
|
+
categories: Array<{
|
|
106
|
+
categoryId: string;
|
|
107
|
+
name: string;
|
|
108
|
+
active: boolean;
|
|
109
|
+
}>;
|
|
110
|
+
}>;
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { apiGet, apiPost, apiPut } from "../../client/http.js";
|
|
2
|
+
import { RewardSchema } from "../../types/schemas/reward.js";
|
|
3
|
+
import { formatApiError, OpenLoyaltyError } from "../../utils/errors.js";
|
|
4
|
+
import { getStoreCode } from "../../config.js";
|
|
5
|
+
import { omitUndefined } from "../../utils/payload.js";
|
|
6
|
+
export async function rewardList(input) {
|
|
7
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
8
|
+
const params = new URLSearchParams();
|
|
9
|
+
if (input.page)
|
|
10
|
+
params.append("_page", String(input.page));
|
|
11
|
+
if (input.perPage)
|
|
12
|
+
params.append("_itemsOnPage", String(input.perPage));
|
|
13
|
+
if (input.active !== undefined)
|
|
14
|
+
params.append("active", String(input.active));
|
|
15
|
+
if (input.type)
|
|
16
|
+
params.append("reward", input.type);
|
|
17
|
+
if (input.categoryId)
|
|
18
|
+
params.append("categoryId", input.categoryId);
|
|
19
|
+
const queryString = params.toString();
|
|
20
|
+
const url = `/${storeCode}/reward${queryString ? `?${queryString}` : ""}`;
|
|
21
|
+
try {
|
|
22
|
+
const response = await apiGet(url);
|
|
23
|
+
const items = response.items || [];
|
|
24
|
+
const rewards = items.map((r) => {
|
|
25
|
+
const reward = r;
|
|
26
|
+
return {
|
|
27
|
+
rewardId: reward.rewardId,
|
|
28
|
+
name: reward.name,
|
|
29
|
+
type: (reward.reward || reward.type),
|
|
30
|
+
costInPoints: reward.costInPoints,
|
|
31
|
+
active: (reward.active ?? false),
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
const total = response.total || {};
|
|
35
|
+
return {
|
|
36
|
+
rewards,
|
|
37
|
+
total: {
|
|
38
|
+
all: typeof total.all === 'number' ? total.all : undefined,
|
|
39
|
+
filtered: typeof total.filtered === 'number' ? total.filtered : undefined,
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
throw formatApiError(error, "ol_reward_list");
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export async function rewardCreate(input) {
|
|
48
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
49
|
+
// API requires: translations (name only), reward (type), activity, visibility, usageLimit.perUser
|
|
50
|
+
// NOTE: description is NOT supported by the API at creation time
|
|
51
|
+
const payload = omitUndefined({
|
|
52
|
+
translations: input.translations,
|
|
53
|
+
reward: input.reward,
|
|
54
|
+
activity: input.activity,
|
|
55
|
+
visibility: input.visibility,
|
|
56
|
+
usageLimit: input.usageLimit,
|
|
57
|
+
costInPoints: input.costInPoints,
|
|
58
|
+
usageInstruction: input.usageInstruction,
|
|
59
|
+
active: input.active,
|
|
60
|
+
categories: input.categories,
|
|
61
|
+
levels: input.levels,
|
|
62
|
+
segments: input.segments,
|
|
63
|
+
target: input.target,
|
|
64
|
+
couponValue: input.couponValue,
|
|
65
|
+
couponValueType: input.couponValueType,
|
|
66
|
+
daysValid: input.daysValid,
|
|
67
|
+
});
|
|
68
|
+
try {
|
|
69
|
+
const response = await apiPost(`/${storeCode}/reward`, { reward: payload });
|
|
70
|
+
return {
|
|
71
|
+
rewardId: response.rewardId,
|
|
72
|
+
name: input.translations.en.name,
|
|
73
|
+
costInPoints: input.costInPoints,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
throw formatApiError(error, "ol_reward_create");
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export async function rewardGet(input) {
|
|
81
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
82
|
+
try {
|
|
83
|
+
const response = await apiGet(`/${storeCode}/reward/${input.rewardId}`);
|
|
84
|
+
return RewardSchema.parse(response);
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
throw formatApiError(error, "ol_reward_get");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
export async function rewardUpdate(input) {
|
|
91
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
92
|
+
// API requires full reward object - fetch existing then merge
|
|
93
|
+
const existing = await apiGet(`/${storeCode}/reward/${input.rewardId}`);
|
|
94
|
+
// Extract only the fields that PUT accepts (API is strict about extra fields)
|
|
95
|
+
// Note: GET returns name at root level, but PUT expects it in translations.en.name
|
|
96
|
+
const existingName = existing.name;
|
|
97
|
+
const existingActivity = existing.activity;
|
|
98
|
+
const existingVisibility = existing.visibility;
|
|
99
|
+
const existingUsageLimit = existing.usageLimit;
|
|
100
|
+
// Build payload with only accepted fields - NEVER include undefined values
|
|
101
|
+
// Only include activity/visibility/usageLimit if they exist in GET response
|
|
102
|
+
const payload = {
|
|
103
|
+
// translations - only include name (GET returns name at root level)
|
|
104
|
+
translations: {
|
|
105
|
+
en: {
|
|
106
|
+
name: existingName || "",
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
// Other fields
|
|
110
|
+
active: existing.active,
|
|
111
|
+
costInPoints: existing.costInPoints,
|
|
112
|
+
};
|
|
113
|
+
// Activity: only include if present in GET response
|
|
114
|
+
if (existingActivity) {
|
|
115
|
+
const activityPayload = {
|
|
116
|
+
allTime: existingActivity.allTime ?? false,
|
|
117
|
+
};
|
|
118
|
+
if (existingActivity.from !== undefined)
|
|
119
|
+
activityPayload.from = existingActivity.from;
|
|
120
|
+
if (existingActivity.to !== undefined)
|
|
121
|
+
activityPayload.to = existingActivity.to;
|
|
122
|
+
payload.activity = activityPayload;
|
|
123
|
+
}
|
|
124
|
+
// Visibility: only include if present in GET response
|
|
125
|
+
if (existingVisibility) {
|
|
126
|
+
const visibilityPayload = {
|
|
127
|
+
allTime: existingVisibility.allTime ?? false,
|
|
128
|
+
};
|
|
129
|
+
if (existingVisibility.from !== undefined)
|
|
130
|
+
visibilityPayload.from = existingVisibility.from;
|
|
131
|
+
if (existingVisibility.to !== undefined)
|
|
132
|
+
visibilityPayload.to = existingVisibility.to;
|
|
133
|
+
payload.visibility = visibilityPayload;
|
|
134
|
+
}
|
|
135
|
+
// usageLimit: Required field, but only include perUser (API rejects extra fields)
|
|
136
|
+
// The GET response may include derived fields that PUT doesn't accept
|
|
137
|
+
payload.usageLimit = {
|
|
138
|
+
perUser: existingUsageLimit?.perUser ?? 1,
|
|
139
|
+
};
|
|
140
|
+
// Coupon-specific fields (required for static_coupon, dynamic_coupon, conversion_coupon)
|
|
141
|
+
if (existing.couponValue !== undefined)
|
|
142
|
+
payload.couponValue = existing.couponValue;
|
|
143
|
+
if (existing.couponValueType !== undefined)
|
|
144
|
+
payload.couponValueType = existing.couponValueType;
|
|
145
|
+
if (existing.daysValid !== undefined)
|
|
146
|
+
payload.daysValid = existing.daysValid;
|
|
147
|
+
// Add optional arrays only if they exist
|
|
148
|
+
if (existing.categories)
|
|
149
|
+
payload.categories = existing.categories;
|
|
150
|
+
if (existing.levels)
|
|
151
|
+
payload.levels = existing.levels;
|
|
152
|
+
if (existing.segments)
|
|
153
|
+
payload.segments = existing.segments;
|
|
154
|
+
if (existing.target)
|
|
155
|
+
payload.target = existing.target;
|
|
156
|
+
// Apply updates
|
|
157
|
+
if (input.name !== undefined) {
|
|
158
|
+
const translations = payload.translations;
|
|
159
|
+
translations.en.name = input.name;
|
|
160
|
+
}
|
|
161
|
+
if (input.costInPoints !== undefined)
|
|
162
|
+
payload.costInPoints = input.costInPoints;
|
|
163
|
+
if (input.active !== undefined)
|
|
164
|
+
payload.active = input.active;
|
|
165
|
+
if (input.categories !== undefined)
|
|
166
|
+
payload.categories = input.categories;
|
|
167
|
+
if (input.levels !== undefined)
|
|
168
|
+
payload.levels = input.levels;
|
|
169
|
+
if (input.segments !== undefined)
|
|
170
|
+
payload.segments = input.segments;
|
|
171
|
+
try {
|
|
172
|
+
await apiPut(`/${storeCode}/reward/${input.rewardId}`, { reward: payload });
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
throw formatApiError(error, "ol_reward_update");
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
export async function rewardActivate(input) {
|
|
179
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
180
|
+
try {
|
|
181
|
+
await apiPost(`/${storeCode}/reward/${input.rewardId}/activate`);
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
throw formatApiError(error, "ol_reward_activate");
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
export async function rewardDeactivate(input) {
|
|
188
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
189
|
+
try {
|
|
190
|
+
await apiPost(`/${storeCode}/reward/${input.rewardId}/deactivate`);
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
throw formatApiError(error, "ol_reward_deactivate");
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
export async function rewardBuy(input) {
|
|
197
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
198
|
+
// API requires quantity - default to 1 if not provided
|
|
199
|
+
const payload = omitUndefined({
|
|
200
|
+
customerId: input.memberId,
|
|
201
|
+
quantity: input.quantity ?? 1,
|
|
202
|
+
couponValue: input.couponValue,
|
|
203
|
+
withoutPoints: input.withoutPoints,
|
|
204
|
+
});
|
|
205
|
+
try {
|
|
206
|
+
const response = await apiPost(`/${storeCode}/reward/${input.rewardId}/buy`, payload);
|
|
207
|
+
// API returns array of issued rewards
|
|
208
|
+
const firstIssued = Array.isArray(response) ? response[0] : response;
|
|
209
|
+
return {
|
|
210
|
+
issuedRewardId: firstIssued?.issuedRewardId || "",
|
|
211
|
+
couponCode: firstIssued?.couponCode,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
216
|
+
if (errorMessage.includes("NotEnoughPoints") || errorMessage.includes("insufficient")) {
|
|
217
|
+
throw new OpenLoyaltyError({
|
|
218
|
+
code: "INSUFFICIENT_BALANCE",
|
|
219
|
+
message: "Member does not have enough points to purchase this reward",
|
|
220
|
+
hint: `Use points_get_balance(memberId: "${input.memberId}") to check available balance. Then use reward_get(rewardId: "${input.rewardId}") to see the costInPoints required.`,
|
|
221
|
+
relatedTool: "ol_reward_buy",
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
throw formatApiError(error, "ol_reward_buy");
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
export async function rewardRedeem(input) {
|
|
228
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
229
|
+
try {
|
|
230
|
+
const response = await apiPost(`/${storeCode}/member/${input.memberId}/reward/redeem`, { couponCode: input.couponCode });
|
|
231
|
+
return { code: response.code || input.couponCode, used: true };
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
235
|
+
if (errorMessage.includes("CouponDoesNotExist")) {
|
|
236
|
+
throw new OpenLoyaltyError({
|
|
237
|
+
code: "COUPON_NOT_FOUND",
|
|
238
|
+
message: `Coupon '${input.couponCode}' does not exist`,
|
|
239
|
+
hint: `Verify the coupon code is correct. Use reward_buy to purchase a reward and obtain a valid coupon code.`,
|
|
240
|
+
relatedTool: "ol_reward_redeem",
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
if (errorMessage.includes("CouponAlreadyUsed")) {
|
|
244
|
+
throw new OpenLoyaltyError({
|
|
245
|
+
code: "COUPON_ALREADY_USED",
|
|
246
|
+
message: `Coupon '${input.couponCode}' has already been redeemed`,
|
|
247
|
+
hint: `Each coupon can only be used once. The member may need to purchase another reward to get a new coupon.`,
|
|
248
|
+
relatedTool: "ol_reward_redeem",
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
if (errorMessage.includes("CouponIsExpired")) {
|
|
252
|
+
throw new OpenLoyaltyError({
|
|
253
|
+
code: "COUPON_EXPIRED",
|
|
254
|
+
message: `Coupon '${input.couponCode}' has expired`,
|
|
255
|
+
hint: `Coupons have a validity period. The member will need to purchase a new reward for a fresh coupon.`,
|
|
256
|
+
relatedTool: "ol_reward_redeem",
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
throw formatApiError(error, "ol_reward_redeem");
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
export async function rewardCategoryList(input) {
|
|
263
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
264
|
+
const params = new URLSearchParams();
|
|
265
|
+
if (input.page)
|
|
266
|
+
params.append("_page", String(input.page));
|
|
267
|
+
if (input.perPage)
|
|
268
|
+
params.append("_itemsOnPage", String(input.perPage));
|
|
269
|
+
if (input.active !== undefined)
|
|
270
|
+
params.append("active", String(input.active));
|
|
271
|
+
const queryString = params.toString();
|
|
272
|
+
const url = `/${storeCode}/rewardCategory${queryString ? `?${queryString}` : ""}`;
|
|
273
|
+
try {
|
|
274
|
+
const response = await apiGet(url);
|
|
275
|
+
const items = response.items || response.categories || [];
|
|
276
|
+
const categories = items.map((c) => {
|
|
277
|
+
const cat = c;
|
|
278
|
+
return {
|
|
279
|
+
categoryId: (cat.rewardCategoryId || cat.categoryId),
|
|
280
|
+
name: cat.name,
|
|
281
|
+
active: (cat.active ?? false),
|
|
282
|
+
};
|
|
283
|
+
});
|
|
284
|
+
return { categories };
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
throw formatApiError(error, "ol_reward_category_list");
|
|
288
|
+
}
|
|
289
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
export { RewardListInputSchema, RewardCreateInputSchema, RewardGetInputSchema, RewardUpdateInputSchema, RewardIdInputSchema, RewardBuyInputSchema, RewardRedeemInputSchema, RewardCategoryListInputSchema, } from "./schemas.js";
|
|
2
|
+
export { rewardList, rewardCreate, rewardGet, rewardUpdate, rewardActivate, rewardDeactivate, rewardBuy, rewardRedeem, rewardCategoryList, } from "./handlers.js";
|
|
3
|
+
import { rewardList, rewardCreate, rewardGet, rewardUpdate, rewardActivate, rewardDeactivate, rewardBuy, rewardRedeem, rewardCategoryList } from "./handlers.js";
|
|
4
|
+
export declare const rewardToolDefinitions: readonly [{
|
|
5
|
+
readonly name: "ol_reward_list";
|
|
6
|
+
readonly title: "Browse Rewards";
|
|
7
|
+
readonly description: string;
|
|
8
|
+
readonly readOnly: true;
|
|
9
|
+
readonly inputSchema: {
|
|
10
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
11
|
+
page: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
12
|
+
perPage: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
13
|
+
active: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
14
|
+
type: import("zod").ZodOptional<import("zod").ZodEnum<["static_coupon", "dynamic_coupon", "conversion_coupon", "material", "fortune_wheel"]>>;
|
|
15
|
+
categoryId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
16
|
+
};
|
|
17
|
+
readonly handler: typeof rewardList;
|
|
18
|
+
}, {
|
|
19
|
+
readonly name: "ol_reward_create";
|
|
20
|
+
readonly title: "Create New Reward";
|
|
21
|
+
readonly description: string;
|
|
22
|
+
readonly readOnly: false;
|
|
23
|
+
readonly inputSchema: {
|
|
24
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
25
|
+
translations: import("zod").ZodObject<{
|
|
26
|
+
en: import("zod").ZodObject<{
|
|
27
|
+
name: import("zod").ZodString;
|
|
28
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
29
|
+
name: string;
|
|
30
|
+
}, {
|
|
31
|
+
name: string;
|
|
32
|
+
}>;
|
|
33
|
+
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
|
|
34
|
+
en: import("zod").ZodObject<{
|
|
35
|
+
name: import("zod").ZodString;
|
|
36
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
37
|
+
name: string;
|
|
38
|
+
}, {
|
|
39
|
+
name: string;
|
|
40
|
+
}>;
|
|
41
|
+
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
|
|
42
|
+
en: import("zod").ZodObject<{
|
|
43
|
+
name: import("zod").ZodString;
|
|
44
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
45
|
+
name: string;
|
|
46
|
+
}, {
|
|
47
|
+
name: string;
|
|
48
|
+
}>;
|
|
49
|
+
}, import("zod").ZodTypeAny, "passthrough">>;
|
|
50
|
+
reward: import("zod").ZodEnum<["static_coupon", "dynamic_coupon", "conversion_coupon", "material", "fortune_wheel"]>;
|
|
51
|
+
activity: import("zod").ZodObject<{
|
|
52
|
+
from: import("zod").ZodString;
|
|
53
|
+
to: import("zod").ZodString;
|
|
54
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
55
|
+
from: string;
|
|
56
|
+
to: string;
|
|
57
|
+
}, {
|
|
58
|
+
from: string;
|
|
59
|
+
to: string;
|
|
60
|
+
}>;
|
|
61
|
+
visibility: import("zod").ZodObject<{
|
|
62
|
+
from: import("zod").ZodString;
|
|
63
|
+
to: import("zod").ZodString;
|
|
64
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
65
|
+
from: string;
|
|
66
|
+
to: string;
|
|
67
|
+
}, {
|
|
68
|
+
from: string;
|
|
69
|
+
to: string;
|
|
70
|
+
}>;
|
|
71
|
+
usageLimit: import("zod").ZodObject<{
|
|
72
|
+
perUser: import("zod").ZodNumber;
|
|
73
|
+
general: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
74
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
75
|
+
perUser: number;
|
|
76
|
+
general?: number | undefined;
|
|
77
|
+
}, {
|
|
78
|
+
perUser: number;
|
|
79
|
+
general?: number | undefined;
|
|
80
|
+
}>;
|
|
81
|
+
costInPoints: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
82
|
+
usageInstruction: import("zod").ZodOptional<import("zod").ZodString>;
|
|
83
|
+
active: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
84
|
+
categories: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
|
|
85
|
+
levels: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
|
|
86
|
+
segments: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
|
|
87
|
+
target: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodEnum<["level", "segment"]>>>;
|
|
88
|
+
couponValue: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
89
|
+
couponValueType: import("zod").ZodOptional<import("zod").ZodEnum<["money", "percentage"]>>;
|
|
90
|
+
daysValid: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
91
|
+
};
|
|
92
|
+
readonly handler: typeof rewardCreate;
|
|
93
|
+
}, {
|
|
94
|
+
readonly name: "ol_reward_get";
|
|
95
|
+
readonly title: "Get Reward Details";
|
|
96
|
+
readonly description: "Get full reward details including configuration, targeting, and coupon settings.";
|
|
97
|
+
readonly readOnly: true;
|
|
98
|
+
readonly inputSchema: {
|
|
99
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
100
|
+
rewardId: import("zod").ZodString;
|
|
101
|
+
};
|
|
102
|
+
readonly handler: typeof rewardGet;
|
|
103
|
+
}, {
|
|
104
|
+
readonly name: "ol_reward_update";
|
|
105
|
+
readonly title: "Update Reward";
|
|
106
|
+
readonly description: "Update reward configuration. Cannot change reward type after creation.";
|
|
107
|
+
readonly readOnly: false;
|
|
108
|
+
readonly inputSchema: {
|
|
109
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
110
|
+
rewardId: import("zod").ZodString;
|
|
111
|
+
name: import("zod").ZodOptional<import("zod").ZodString>;
|
|
112
|
+
costInPoints: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
113
|
+
description: import("zod").ZodOptional<import("zod").ZodString>;
|
|
114
|
+
active: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
115
|
+
categories: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
|
|
116
|
+
levels: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
|
|
117
|
+
segments: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
|
|
118
|
+
};
|
|
119
|
+
readonly handler: typeof rewardUpdate;
|
|
120
|
+
}, {
|
|
121
|
+
readonly name: "ol_reward_activate";
|
|
122
|
+
readonly title: "Activate Reward";
|
|
123
|
+
readonly description: "Activate a reward, making it available for members to redeem.";
|
|
124
|
+
readonly readOnly: false;
|
|
125
|
+
readonly inputSchema: {
|
|
126
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
127
|
+
rewardId: import("zod").ZodString;
|
|
128
|
+
};
|
|
129
|
+
readonly handler: typeof rewardActivate;
|
|
130
|
+
}, {
|
|
131
|
+
readonly name: "ol_reward_deactivate";
|
|
132
|
+
readonly title: "Deactivate Reward";
|
|
133
|
+
readonly description: "Deactivate a reward, hiding it from members. Already purchased rewards remain valid.";
|
|
134
|
+
readonly readOnly: false;
|
|
135
|
+
readonly inputSchema: {
|
|
136
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
137
|
+
rewardId: import("zod").ZodString;
|
|
138
|
+
};
|
|
139
|
+
readonly handler: typeof rewardDeactivate;
|
|
140
|
+
}, {
|
|
141
|
+
readonly name: "ol_reward_buy";
|
|
142
|
+
readonly title: "Redeem Reward for Member";
|
|
143
|
+
readonly description: string;
|
|
144
|
+
readonly readOnly: false;
|
|
145
|
+
readonly inputSchema: {
|
|
146
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
147
|
+
rewardId: import("zod").ZodString;
|
|
148
|
+
memberId: import("zod").ZodString;
|
|
149
|
+
quantity: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
150
|
+
couponValue: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
151
|
+
withoutPoints: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
152
|
+
};
|
|
153
|
+
readonly handler: typeof rewardBuy;
|
|
154
|
+
}, {
|
|
155
|
+
readonly name: "ol_reward_redeem";
|
|
156
|
+
readonly title: "Use Coupon Code";
|
|
157
|
+
readonly description: string;
|
|
158
|
+
readonly readOnly: false;
|
|
159
|
+
readonly inputSchema: {
|
|
160
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
161
|
+
memberId: import("zod").ZodString;
|
|
162
|
+
couponCode: import("zod").ZodString;
|
|
163
|
+
};
|
|
164
|
+
readonly handler: typeof rewardRedeem;
|
|
165
|
+
}, {
|
|
166
|
+
readonly name: "ol_reward_category_list";
|
|
167
|
+
readonly title: "List Reward Categories";
|
|
168
|
+
readonly description: "List reward categories. Use categoryId when creating or filtering rewards.";
|
|
169
|
+
readonly readOnly: true;
|
|
170
|
+
readonly inputSchema: {
|
|
171
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
172
|
+
page: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
173
|
+
perPage: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
174
|
+
active: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
175
|
+
};
|
|
176
|
+
readonly handler: typeof rewardCategoryList;
|
|
177
|
+
}];
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// Re-export schemas
|
|
2
|
+
export { RewardListInputSchema, RewardCreateInputSchema, RewardGetInputSchema, RewardUpdateInputSchema, RewardIdInputSchema, RewardBuyInputSchema, RewardRedeemInputSchema, RewardCategoryListInputSchema, } from "./schemas.js";
|
|
3
|
+
// Re-export handlers
|
|
4
|
+
export { rewardList, rewardCreate, rewardGet, rewardUpdate, rewardActivate, rewardDeactivate, rewardBuy, rewardRedeem, rewardCategoryList, } from "./handlers.js";
|
|
5
|
+
// Imports for tool definitions
|
|
6
|
+
import { RewardListInputSchema, RewardCreateInputSchema, RewardGetInputSchema, RewardUpdateInputSchema, RewardIdInputSchema, RewardBuyInputSchema, RewardRedeemInputSchema, RewardCategoryListInputSchema, } from "./schemas.js";
|
|
7
|
+
import { rewardList, rewardCreate, rewardGet, rewardUpdate, rewardActivate, rewardDeactivate, rewardBuy, rewardRedeem, rewardCategoryList, } from "./handlers.js";
|
|
8
|
+
// Tool definitions
|
|
9
|
+
export const rewardToolDefinitions = [
|
|
10
|
+
{
|
|
11
|
+
name: "ol_reward_list",
|
|
12
|
+
title: "Browse Rewards",
|
|
13
|
+
description: "List available rewards. Use reward_get for full details or reward_buy to redeem. " +
|
|
14
|
+
"Filter by type, active status, or category.",
|
|
15
|
+
readOnly: true,
|
|
16
|
+
inputSchema: RewardListInputSchema,
|
|
17
|
+
handler: rewardList,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: "ol_reward_create",
|
|
21
|
+
title: "Create New Reward",
|
|
22
|
+
description: "Create a new reward that members can redeem with points. " +
|
|
23
|
+
"REQUIRED: translations.en.name, reward (type), activity {from,to}, visibility {from,to}. " +
|
|
24
|
+
"Coupon types should include usageLimit.perUser. " +
|
|
25
|
+
"Types: static_coupon (fixed discount), dynamic_coupon (variable value set at purchase), " +
|
|
26
|
+
"material (physical goods), conversion_coupon (converts points), fortune_wheel (gamified). " +
|
|
27
|
+
"Returns rewardId.",
|
|
28
|
+
readOnly: false,
|
|
29
|
+
inputSchema: RewardCreateInputSchema,
|
|
30
|
+
handler: rewardCreate,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "ol_reward_get",
|
|
34
|
+
title: "Get Reward Details",
|
|
35
|
+
description: "Get full reward details including configuration, targeting, and coupon settings.",
|
|
36
|
+
readOnly: true,
|
|
37
|
+
inputSchema: RewardGetInputSchema,
|
|
38
|
+
handler: rewardGet,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: "ol_reward_update",
|
|
42
|
+
title: "Update Reward",
|
|
43
|
+
description: "Update reward configuration. Cannot change reward type after creation.",
|
|
44
|
+
readOnly: false,
|
|
45
|
+
inputSchema: RewardUpdateInputSchema,
|
|
46
|
+
handler: rewardUpdate,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "ol_reward_activate",
|
|
50
|
+
title: "Activate Reward",
|
|
51
|
+
description: "Activate a reward, making it available for members to redeem.",
|
|
52
|
+
readOnly: false,
|
|
53
|
+
inputSchema: RewardIdInputSchema,
|
|
54
|
+
handler: rewardActivate,
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "ol_reward_deactivate",
|
|
58
|
+
title: "Deactivate Reward",
|
|
59
|
+
description: "Deactivate a reward, hiding it from members. Already purchased rewards remain valid.",
|
|
60
|
+
readOnly: false,
|
|
61
|
+
inputSchema: RewardIdInputSchema,
|
|
62
|
+
handler: rewardDeactivate,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: "ol_reward_buy",
|
|
66
|
+
title: "Redeem Reward for Member",
|
|
67
|
+
description: "Purchase reward for member, deducting points. Returns issuedRewardId and couponCode if applicable. " +
|
|
68
|
+
"Use reward_redeem to mark the coupon as used.",
|
|
69
|
+
readOnly: false,
|
|
70
|
+
inputSchema: RewardBuyInputSchema,
|
|
71
|
+
handler: rewardBuy,
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: "ol_reward_redeem",
|
|
75
|
+
title: "Use Coupon Code",
|
|
76
|
+
description: "Mark coupon as used. Validates coupon exists, belongs to member, and is active. " +
|
|
77
|
+
"Fails if coupon is expired, already used, or doesn't exist.",
|
|
78
|
+
readOnly: false,
|
|
79
|
+
inputSchema: RewardRedeemInputSchema,
|
|
80
|
+
handler: rewardRedeem,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: "ol_reward_category_list",
|
|
84
|
+
title: "List Reward Categories",
|
|
85
|
+
description: "List reward categories. Use categoryId when creating or filtering rewards.",
|
|
86
|
+
readOnly: true,
|
|
87
|
+
inputSchema: RewardCategoryListInputSchema,
|
|
88
|
+
handler: rewardCategoryList,
|
|
89
|
+
},
|
|
90
|
+
];
|