@open-loyalty/mcp-server 1.0.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/LICENSE +21 -0
- package/README.md +654 -0
- package/dist/client/http.d.ts +8 -0
- package/dist/client/http.js +69 -0
- package/dist/config.d.ts +17 -0
- package/dist/config.js +40 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +20 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.js +334 -0
- package/dist/tools/achievement.d.ts +983 -0
- package/dist/tools/achievement.js +311 -0
- package/dist/tools/admin.d.ts +153 -0
- package/dist/tools/admin.js +193 -0
- package/dist/tools/analytics.d.ts +162 -0
- package/dist/tools/analytics.js +245 -0
- package/dist/tools/apikey.d.ts +72 -0
- package/dist/tools/apikey.js +78 -0
- package/dist/tools/audit.d.ts +107 -0
- package/dist/tools/audit.js +90 -0
- package/dist/tools/badge.d.ts +135 -0
- package/dist/tools/badge.js +165 -0
- package/dist/tools/campaign.d.ts +1775 -0
- package/dist/tools/campaign.js +724 -0
- package/dist/tools/export.d.ts +110 -0
- package/dist/tools/export.js +147 -0
- package/dist/tools/import.d.ts +110 -0
- package/dist/tools/import.js +126 -0
- package/dist/tools/index.d.ts +22 -0
- package/dist/tools/index.js +527 -0
- package/dist/tools/member.d.ts +345 -0
- package/dist/tools/member.js +358 -0
- package/dist/tools/member.test.d.ts +1 -0
- package/dist/tools/member.test.js +213 -0
- package/dist/tools/points.d.ts +188 -0
- package/dist/tools/points.js +306 -0
- package/dist/tools/points.test.d.ts +1 -0
- package/dist/tools/points.test.js +292 -0
- package/dist/tools/reward.d.ts +261 -0
- package/dist/tools/reward.js +371 -0
- package/dist/tools/reward.test.d.ts +1 -0
- package/dist/tools/reward.test.js +240 -0
- package/dist/tools/role.d.ts +161 -0
- package/dist/tools/role.js +160 -0
- package/dist/tools/segment.d.ts +797 -0
- package/dist/tools/segment.js +299 -0
- package/dist/tools/store.d.ts +101 -0
- package/dist/tools/store.js +117 -0
- package/dist/tools/tierset.d.ts +288 -0
- package/dist/tools/tierset.js +244 -0
- package/dist/tools/transaction.d.ts +357 -0
- package/dist/tools/transaction.js +242 -0
- package/dist/tools/transaction.test.d.ts +1 -0
- package/dist/tools/transaction.test.js +235 -0
- package/dist/tools/wallet-type.d.ts +32 -0
- package/dist/tools/wallet-type.js +58 -0
- package/dist/tools/webhook.d.ts +179 -0
- package/dist/tools/webhook.js +171 -0
- package/dist/types/schemas/achievement.d.ts +1116 -0
- package/dist/types/schemas/achievement.js +172 -0
- package/dist/types/schemas/admin.d.ts +263 -0
- package/dist/types/schemas/admin.js +99 -0
- package/dist/types/schemas/analytics.d.ts +542 -0
- package/dist/types/schemas/analytics.js +130 -0
- package/dist/types/schemas/badge.d.ts +131 -0
- package/dist/types/schemas/badge.js +48 -0
- package/dist/types/schemas/campaign.d.ts +2005 -0
- package/dist/types/schemas/campaign.js +189 -0
- package/dist/types/schemas/common.d.ts +52 -0
- package/dist/types/schemas/common.js +26 -0
- package/dist/types/schemas/export.d.ts +127 -0
- package/dist/types/schemas/export.js +43 -0
- package/dist/types/schemas/import.d.ts +344 -0
- package/dist/types/schemas/import.js +68 -0
- package/dist/types/schemas/member.d.ts +443 -0
- package/dist/types/schemas/member.js +92 -0
- package/dist/types/schemas/points.d.ts +188 -0
- package/dist/types/schemas/points.js +54 -0
- package/dist/types/schemas/reward.d.ts +278 -0
- package/dist/types/schemas/reward.js +69 -0
- package/dist/types/schemas/role.d.ts +260 -0
- package/dist/types/schemas/role.js +75 -0
- package/dist/types/schemas/segment.d.ts +592 -0
- package/dist/types/schemas/segment.js +114 -0
- package/dist/types/schemas/tierset.d.ts +552 -0
- package/dist/types/schemas/tierset.js +87 -0
- package/dist/types/schemas/transaction.d.ts +1022 -0
- package/dist/types/schemas/transaction.js +63 -0
- package/dist/types/schemas/wallet-type.d.ts +99 -0
- package/dist/types/schemas/wallet-type.js +17 -0
- package/dist/types/schemas/webhook.d.ts +195 -0
- package/dist/types/schemas/webhook.js +39 -0
- package/dist/utils/cursor.d.ts +84 -0
- package/dist/utils/cursor.js +117 -0
- package/dist/utils/errors.d.ts +12 -0
- package/dist/utils/errors.js +69 -0
- package/dist/utils/pagination.d.ts +39 -0
- package/dist/utils/pagination.js +77 -0
- package/package.json +65 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { Reward } from "../types/schemas/reward.js";
|
|
3
|
+
export declare const RewardListInputSchema: {
|
|
4
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
5
|
+
page: z.ZodOptional<z.ZodNumber>;
|
|
6
|
+
perPage: z.ZodOptional<z.ZodNumber>;
|
|
7
|
+
active: z.ZodOptional<z.ZodBoolean>;
|
|
8
|
+
type: z.ZodOptional<z.ZodEnum<["static_coupon", "dynamic_coupon", "conversion_coupon", "material", "fortune_wheel"]>>;
|
|
9
|
+
categoryId: z.ZodOptional<z.ZodString>;
|
|
10
|
+
};
|
|
11
|
+
export declare const RewardCreateInputSchema: {
|
|
12
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
13
|
+
name: z.ZodString;
|
|
14
|
+
type: z.ZodEnum<["static_coupon", "dynamic_coupon", "conversion_coupon", "material", "fortune_wheel"]>;
|
|
15
|
+
costInPoints: z.ZodOptional<z.ZodNumber>;
|
|
16
|
+
description: z.ZodOptional<z.ZodString>;
|
|
17
|
+
usageInstruction: z.ZodOptional<z.ZodString>;
|
|
18
|
+
active: z.ZodOptional<z.ZodBoolean>;
|
|
19
|
+
categories: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
20
|
+
levels: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
21
|
+
segments: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
22
|
+
target: z.ZodOptional<z.ZodNullable<z.ZodEnum<["level", "segment"]>>>;
|
|
23
|
+
couponValue: z.ZodOptional<z.ZodNumber>;
|
|
24
|
+
couponValueType: z.ZodOptional<z.ZodEnum<["Money", "Percentage"]>>;
|
|
25
|
+
daysValid: z.ZodOptional<z.ZodNumber>;
|
|
26
|
+
};
|
|
27
|
+
export declare const RewardGetInputSchema: {
|
|
28
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
29
|
+
rewardId: z.ZodString;
|
|
30
|
+
};
|
|
31
|
+
export declare const RewardUpdateInputSchema: {
|
|
32
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
33
|
+
rewardId: z.ZodString;
|
|
34
|
+
name: z.ZodOptional<z.ZodString>;
|
|
35
|
+
costInPoints: z.ZodOptional<z.ZodNumber>;
|
|
36
|
+
description: z.ZodOptional<z.ZodString>;
|
|
37
|
+
active: z.ZodOptional<z.ZodBoolean>;
|
|
38
|
+
categories: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
39
|
+
levels: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
40
|
+
segments: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
41
|
+
};
|
|
42
|
+
export declare const RewardIdInputSchema: {
|
|
43
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
44
|
+
rewardId: z.ZodString;
|
|
45
|
+
};
|
|
46
|
+
export declare const RewardBuyInputSchema: {
|
|
47
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
48
|
+
rewardId: z.ZodString;
|
|
49
|
+
memberId: z.ZodString;
|
|
50
|
+
quantity: z.ZodOptional<z.ZodNumber>;
|
|
51
|
+
couponValue: z.ZodOptional<z.ZodNumber>;
|
|
52
|
+
withoutPoints: z.ZodOptional<z.ZodBoolean>;
|
|
53
|
+
};
|
|
54
|
+
export declare const RewardRedeemInputSchema: {
|
|
55
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
56
|
+
memberId: z.ZodString;
|
|
57
|
+
couponCode: z.ZodString;
|
|
58
|
+
};
|
|
59
|
+
export declare const RewardCategoryListInputSchema: {
|
|
60
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
61
|
+
page: z.ZodOptional<z.ZodNumber>;
|
|
62
|
+
perPage: z.ZodOptional<z.ZodNumber>;
|
|
63
|
+
active: z.ZodOptional<z.ZodBoolean>;
|
|
64
|
+
};
|
|
65
|
+
export declare function rewardList(input: {
|
|
66
|
+
storeCode?: string;
|
|
67
|
+
page?: number;
|
|
68
|
+
perPage?: number;
|
|
69
|
+
active?: boolean;
|
|
70
|
+
type?: string;
|
|
71
|
+
categoryId?: string;
|
|
72
|
+
}): Promise<{
|
|
73
|
+
rewards: Array<{
|
|
74
|
+
rewardId: string;
|
|
75
|
+
name: string;
|
|
76
|
+
type: string;
|
|
77
|
+
costInPoints?: number;
|
|
78
|
+
active: boolean;
|
|
79
|
+
}>;
|
|
80
|
+
total: {
|
|
81
|
+
all?: number;
|
|
82
|
+
filtered?: number;
|
|
83
|
+
};
|
|
84
|
+
}>;
|
|
85
|
+
export declare function rewardCreate(input: {
|
|
86
|
+
storeCode?: string;
|
|
87
|
+
name: string;
|
|
88
|
+
type: string;
|
|
89
|
+
costInPoints?: number;
|
|
90
|
+
description?: string;
|
|
91
|
+
usageInstruction?: string;
|
|
92
|
+
active?: boolean;
|
|
93
|
+
categories?: string[];
|
|
94
|
+
levels?: string[];
|
|
95
|
+
segments?: string[];
|
|
96
|
+
target?: string | null;
|
|
97
|
+
couponValue?: number;
|
|
98
|
+
couponValueType?: string;
|
|
99
|
+
daysValid?: number;
|
|
100
|
+
}): Promise<{
|
|
101
|
+
rewardId: string;
|
|
102
|
+
name: string;
|
|
103
|
+
costInPoints?: number;
|
|
104
|
+
}>;
|
|
105
|
+
export declare function rewardGet(input: {
|
|
106
|
+
storeCode?: string;
|
|
107
|
+
rewardId: string;
|
|
108
|
+
}): Promise<Reward>;
|
|
109
|
+
export declare function rewardUpdate(input: {
|
|
110
|
+
storeCode?: string;
|
|
111
|
+
rewardId: string;
|
|
112
|
+
name?: string;
|
|
113
|
+
costInPoints?: number;
|
|
114
|
+
description?: string;
|
|
115
|
+
active?: boolean;
|
|
116
|
+
categories?: string[];
|
|
117
|
+
levels?: string[];
|
|
118
|
+
segments?: string[];
|
|
119
|
+
}): Promise<void>;
|
|
120
|
+
export declare function rewardActivate(input: {
|
|
121
|
+
storeCode?: string;
|
|
122
|
+
rewardId: string;
|
|
123
|
+
}): Promise<void>;
|
|
124
|
+
export declare function rewardDeactivate(input: {
|
|
125
|
+
storeCode?: string;
|
|
126
|
+
rewardId: string;
|
|
127
|
+
}): Promise<void>;
|
|
128
|
+
export declare function rewardBuy(input: {
|
|
129
|
+
storeCode?: string;
|
|
130
|
+
rewardId: string;
|
|
131
|
+
memberId: string;
|
|
132
|
+
quantity?: number;
|
|
133
|
+
couponValue?: number;
|
|
134
|
+
withoutPoints?: boolean;
|
|
135
|
+
}): Promise<{
|
|
136
|
+
issuedRewardId: string;
|
|
137
|
+
couponCode?: string;
|
|
138
|
+
}>;
|
|
139
|
+
export declare function rewardRedeem(input: {
|
|
140
|
+
storeCode?: string;
|
|
141
|
+
memberId: string;
|
|
142
|
+
couponCode: string;
|
|
143
|
+
}): Promise<{
|
|
144
|
+
code: string;
|
|
145
|
+
used: boolean;
|
|
146
|
+
}>;
|
|
147
|
+
export declare function rewardCategoryList(input: {
|
|
148
|
+
storeCode?: string;
|
|
149
|
+
page?: number;
|
|
150
|
+
perPage?: number;
|
|
151
|
+
active?: boolean;
|
|
152
|
+
}): Promise<{
|
|
153
|
+
categories: Array<{
|
|
154
|
+
categoryId: string;
|
|
155
|
+
name: string;
|
|
156
|
+
active: boolean;
|
|
157
|
+
}>;
|
|
158
|
+
}>;
|
|
159
|
+
export declare const rewardToolDefinitions: readonly [{
|
|
160
|
+
readonly name: "openloyalty_reward_list";
|
|
161
|
+
readonly description: string;
|
|
162
|
+
readonly inputSchema: {
|
|
163
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
164
|
+
page: z.ZodOptional<z.ZodNumber>;
|
|
165
|
+
perPage: z.ZodOptional<z.ZodNumber>;
|
|
166
|
+
active: z.ZodOptional<z.ZodBoolean>;
|
|
167
|
+
type: z.ZodOptional<z.ZodEnum<["static_coupon", "dynamic_coupon", "conversion_coupon", "material", "fortune_wheel"]>>;
|
|
168
|
+
categoryId: z.ZodOptional<z.ZodString>;
|
|
169
|
+
};
|
|
170
|
+
readonly handler: typeof rewardList;
|
|
171
|
+
}, {
|
|
172
|
+
readonly name: "openloyalty_reward_create";
|
|
173
|
+
readonly description: string;
|
|
174
|
+
readonly inputSchema: {
|
|
175
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
176
|
+
name: z.ZodString;
|
|
177
|
+
type: z.ZodEnum<["static_coupon", "dynamic_coupon", "conversion_coupon", "material", "fortune_wheel"]>;
|
|
178
|
+
costInPoints: z.ZodOptional<z.ZodNumber>;
|
|
179
|
+
description: z.ZodOptional<z.ZodString>;
|
|
180
|
+
usageInstruction: z.ZodOptional<z.ZodString>;
|
|
181
|
+
active: z.ZodOptional<z.ZodBoolean>;
|
|
182
|
+
categories: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
183
|
+
levels: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
184
|
+
segments: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
185
|
+
target: z.ZodOptional<z.ZodNullable<z.ZodEnum<["level", "segment"]>>>;
|
|
186
|
+
couponValue: z.ZodOptional<z.ZodNumber>;
|
|
187
|
+
couponValueType: z.ZodOptional<z.ZodEnum<["Money", "Percentage"]>>;
|
|
188
|
+
daysValid: z.ZodOptional<z.ZodNumber>;
|
|
189
|
+
};
|
|
190
|
+
readonly handler: typeof rewardCreate;
|
|
191
|
+
}, {
|
|
192
|
+
readonly name: "openloyalty_reward_get";
|
|
193
|
+
readonly description: "Get full reward details including configuration, targeting, and coupon settings.";
|
|
194
|
+
readonly inputSchema: {
|
|
195
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
196
|
+
rewardId: z.ZodString;
|
|
197
|
+
};
|
|
198
|
+
readonly handler: typeof rewardGet;
|
|
199
|
+
}, {
|
|
200
|
+
readonly name: "openloyalty_reward_update";
|
|
201
|
+
readonly description: "Update reward configuration. Cannot change reward type after creation.";
|
|
202
|
+
readonly inputSchema: {
|
|
203
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
204
|
+
rewardId: z.ZodString;
|
|
205
|
+
name: z.ZodOptional<z.ZodString>;
|
|
206
|
+
costInPoints: z.ZodOptional<z.ZodNumber>;
|
|
207
|
+
description: z.ZodOptional<z.ZodString>;
|
|
208
|
+
active: z.ZodOptional<z.ZodBoolean>;
|
|
209
|
+
categories: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
210
|
+
levels: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
211
|
+
segments: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
212
|
+
};
|
|
213
|
+
readonly handler: typeof rewardUpdate;
|
|
214
|
+
}, {
|
|
215
|
+
readonly name: "openloyalty_reward_activate";
|
|
216
|
+
readonly description: "Activate a reward, making it available for members to redeem.";
|
|
217
|
+
readonly inputSchema: {
|
|
218
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
219
|
+
rewardId: z.ZodString;
|
|
220
|
+
};
|
|
221
|
+
readonly handler: typeof rewardActivate;
|
|
222
|
+
}, {
|
|
223
|
+
readonly name: "openloyalty_reward_deactivate";
|
|
224
|
+
readonly description: "Deactivate a reward, hiding it from members. Already purchased rewards remain valid.";
|
|
225
|
+
readonly inputSchema: {
|
|
226
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
227
|
+
rewardId: z.ZodString;
|
|
228
|
+
};
|
|
229
|
+
readonly handler: typeof rewardDeactivate;
|
|
230
|
+
}, {
|
|
231
|
+
readonly name: "openloyalty_reward_buy";
|
|
232
|
+
readonly description: string;
|
|
233
|
+
readonly inputSchema: {
|
|
234
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
235
|
+
rewardId: z.ZodString;
|
|
236
|
+
memberId: z.ZodString;
|
|
237
|
+
quantity: z.ZodOptional<z.ZodNumber>;
|
|
238
|
+
couponValue: z.ZodOptional<z.ZodNumber>;
|
|
239
|
+
withoutPoints: z.ZodOptional<z.ZodBoolean>;
|
|
240
|
+
};
|
|
241
|
+
readonly handler: typeof rewardBuy;
|
|
242
|
+
}, {
|
|
243
|
+
readonly name: "openloyalty_reward_redeem";
|
|
244
|
+
readonly description: string;
|
|
245
|
+
readonly inputSchema: {
|
|
246
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
247
|
+
memberId: z.ZodString;
|
|
248
|
+
couponCode: z.ZodString;
|
|
249
|
+
};
|
|
250
|
+
readonly handler: typeof rewardRedeem;
|
|
251
|
+
}, {
|
|
252
|
+
readonly name: "openloyalty_reward_category_list";
|
|
253
|
+
readonly description: "List reward categories. Use categoryId when creating or filtering rewards.";
|
|
254
|
+
readonly inputSchema: {
|
|
255
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
256
|
+
page: z.ZodOptional<z.ZodNumber>;
|
|
257
|
+
perPage: z.ZodOptional<z.ZodNumber>;
|
|
258
|
+
active: z.ZodOptional<z.ZodBoolean>;
|
|
259
|
+
};
|
|
260
|
+
readonly handler: typeof rewardCategoryList;
|
|
261
|
+
}];
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { apiGet, apiPost, apiPut } from "../client/http.js";
|
|
3
|
+
import { RewardSchema, } from "../types/schemas/reward.js";
|
|
4
|
+
import { formatApiError, OpenLoyaltyError } from "../utils/errors.js";
|
|
5
|
+
import { getConfig } from "../config.js";
|
|
6
|
+
// Input Schemas
|
|
7
|
+
export const RewardListInputSchema = {
|
|
8
|
+
storeCode: z.string().optional().describe("Store code. If not provided, uses the default store code from configuration."),
|
|
9
|
+
page: z.number().optional().describe("Page number (default: 1)."),
|
|
10
|
+
perPage: z.number().optional().describe("Items per page (default: 10)."),
|
|
11
|
+
active: z.boolean().optional().describe("Filter by active status."),
|
|
12
|
+
type: z.enum(["static_coupon", "dynamic_coupon", "conversion_coupon", "material", "fortune_wheel"]).optional().describe("Filter by reward type."),
|
|
13
|
+
categoryId: z.string().optional().describe("Filter by category ID."),
|
|
14
|
+
};
|
|
15
|
+
export const RewardCreateInputSchema = {
|
|
16
|
+
storeCode: z.string().optional().describe("Store code. If not provided, uses the default store code from configuration."),
|
|
17
|
+
name: z.string().describe("Reward name (required, max 255 chars)."),
|
|
18
|
+
type: z.enum(["static_coupon", "dynamic_coupon", "conversion_coupon", "material", "fortune_wheel"]).describe("Reward type: static_coupon (fixed discount), dynamic_coupon (variable value), " +
|
|
19
|
+
"conversion_coupon (converts points to coupon), material (physical goods), fortune_wheel (gamified)."),
|
|
20
|
+
costInPoints: z.number().optional().describe("Points required to redeem this reward."),
|
|
21
|
+
description: z.string().optional().describe("Reward description."),
|
|
22
|
+
usageInstruction: z.string().optional().describe("Instructions for using the reward."),
|
|
23
|
+
active: z.boolean().optional().describe("Whether reward is active (default: false)."),
|
|
24
|
+
categories: z.array(z.string()).optional().describe("Array of category UUIDs."),
|
|
25
|
+
levels: z.array(z.string()).optional().describe("Array of tier level UUIDs that can see/redeem."),
|
|
26
|
+
segments: z.array(z.string()).optional().describe("Array of segment UUIDs that can see/redeem."),
|
|
27
|
+
target: z.enum(["level", "segment"]).nullable().optional().describe("Target type for visibility: level (tier-based), segment (segment-based), or null (all)."),
|
|
28
|
+
couponValue: z.number().optional().describe("Coupon value (required for static_coupon)."),
|
|
29
|
+
couponValueType: z.enum(["Money", "Percentage"]).optional().describe("Coupon value type."),
|
|
30
|
+
daysValid: z.number().optional().describe("Days the coupon remains valid after purchase."),
|
|
31
|
+
};
|
|
32
|
+
export const RewardGetInputSchema = {
|
|
33
|
+
storeCode: z.string().optional().describe("Store code. If not provided, uses the default store code from configuration."),
|
|
34
|
+
rewardId: z.string().describe("The reward ID (UUID) to retrieve."),
|
|
35
|
+
};
|
|
36
|
+
export const RewardUpdateInputSchema = {
|
|
37
|
+
storeCode: z.string().optional().describe("Store code. If not provided, uses the default store code from configuration."),
|
|
38
|
+
rewardId: z.string().describe("The reward ID (UUID) to update."),
|
|
39
|
+
name: z.string().optional().describe("Reward name."),
|
|
40
|
+
costInPoints: z.number().optional().describe("Points required to redeem."),
|
|
41
|
+
description: z.string().optional().describe("Reward description."),
|
|
42
|
+
active: z.boolean().optional().describe("Whether reward is active."),
|
|
43
|
+
categories: z.array(z.string()).optional().describe("Array of category UUIDs."),
|
|
44
|
+
levels: z.array(z.string()).optional().describe("Array of tier level UUIDs."),
|
|
45
|
+
segments: z.array(z.string()).optional().describe("Array of segment UUIDs."),
|
|
46
|
+
};
|
|
47
|
+
export const RewardIdInputSchema = {
|
|
48
|
+
storeCode: z.string().optional().describe("Store code. If not provided, uses the default store code from configuration."),
|
|
49
|
+
rewardId: z.string().describe("The reward ID (UUID)."),
|
|
50
|
+
};
|
|
51
|
+
export const RewardBuyInputSchema = {
|
|
52
|
+
storeCode: z.string().optional().describe("Store code. If not provided, uses the default store code from configuration."),
|
|
53
|
+
rewardId: z.string().describe("The reward ID (UUID) to purchase."),
|
|
54
|
+
memberId: z.string().describe("The member ID (UUID) purchasing the reward."),
|
|
55
|
+
quantity: z.number().optional().describe("Number of rewards to purchase (1-32, default: 1)."),
|
|
56
|
+
couponValue: z.number().optional().describe("Coupon value (for dynamic coupons)."),
|
|
57
|
+
withoutPoints: z.boolean().optional().describe("Admin only: skip points deduction."),
|
|
58
|
+
};
|
|
59
|
+
export const RewardRedeemInputSchema = {
|
|
60
|
+
storeCode: z.string().optional().describe("Store code. If not provided, uses the default store code from configuration."),
|
|
61
|
+
memberId: z.string().describe("The member ID (UUID) redeeming the coupon."),
|
|
62
|
+
couponCode: z.string().describe("The coupon code to redeem."),
|
|
63
|
+
};
|
|
64
|
+
export const RewardCategoryListInputSchema = {
|
|
65
|
+
storeCode: z.string().optional().describe("Store code. If not provided, uses the default store code from configuration."),
|
|
66
|
+
page: z.number().optional().describe("Page number (default: 1)."),
|
|
67
|
+
perPage: z.number().optional().describe("Items per page (default: 10)."),
|
|
68
|
+
active: z.boolean().optional().describe("Filter by active status."),
|
|
69
|
+
};
|
|
70
|
+
// Handler functions
|
|
71
|
+
export async function rewardList(input) {
|
|
72
|
+
const config = getConfig();
|
|
73
|
+
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
74
|
+
const params = new URLSearchParams();
|
|
75
|
+
if (input.page)
|
|
76
|
+
params.append("_page", String(input.page));
|
|
77
|
+
if (input.perPage)
|
|
78
|
+
params.append("_itemsOnPage", String(input.perPage));
|
|
79
|
+
if (input.active !== undefined)
|
|
80
|
+
params.append("active", String(input.active));
|
|
81
|
+
if (input.type)
|
|
82
|
+
params.append("reward", input.type);
|
|
83
|
+
if (input.categoryId)
|
|
84
|
+
params.append("categoryId", input.categoryId);
|
|
85
|
+
const queryString = params.toString();
|
|
86
|
+
const url = `/${storeCode}/reward${queryString ? `?${queryString}` : ""}`;
|
|
87
|
+
try {
|
|
88
|
+
const response = await apiGet(url);
|
|
89
|
+
const items = response.items || [];
|
|
90
|
+
const rewards = items.map((r) => {
|
|
91
|
+
const reward = r;
|
|
92
|
+
return {
|
|
93
|
+
rewardId: reward.rewardId,
|
|
94
|
+
name: reward.name,
|
|
95
|
+
type: (reward.reward || reward.type),
|
|
96
|
+
costInPoints: reward.costInPoints,
|
|
97
|
+
active: (reward.active ?? false),
|
|
98
|
+
};
|
|
99
|
+
});
|
|
100
|
+
const total = response.total || {};
|
|
101
|
+
return {
|
|
102
|
+
rewards,
|
|
103
|
+
total: {
|
|
104
|
+
all: typeof total.all === 'number' ? total.all : undefined,
|
|
105
|
+
filtered: typeof total.filtered === 'number' ? total.filtered : undefined,
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
throw formatApiError(error, "openloyalty_reward_list");
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
export async function rewardCreate(input) {
|
|
114
|
+
const config = getConfig();
|
|
115
|
+
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
116
|
+
const payload = {
|
|
117
|
+
name: input.name,
|
|
118
|
+
type: input.type,
|
|
119
|
+
};
|
|
120
|
+
if (input.costInPoints !== undefined)
|
|
121
|
+
payload.costInPoints = input.costInPoints;
|
|
122
|
+
if (input.description)
|
|
123
|
+
payload.description = input.description;
|
|
124
|
+
if (input.usageInstruction)
|
|
125
|
+
payload.usageInstruction = input.usageInstruction;
|
|
126
|
+
if (input.active !== undefined)
|
|
127
|
+
payload.active = input.active;
|
|
128
|
+
if (input.categories)
|
|
129
|
+
payload.categories = input.categories;
|
|
130
|
+
if (input.levels)
|
|
131
|
+
payload.levels = input.levels;
|
|
132
|
+
if (input.segments)
|
|
133
|
+
payload.segments = input.segments;
|
|
134
|
+
if (input.target !== undefined)
|
|
135
|
+
payload.target = input.target;
|
|
136
|
+
if (input.couponValue !== undefined)
|
|
137
|
+
payload.couponValue = input.couponValue;
|
|
138
|
+
if (input.couponValueType)
|
|
139
|
+
payload.couponValueType = input.couponValueType;
|
|
140
|
+
if (input.daysValid !== undefined)
|
|
141
|
+
payload.daysValid = input.daysValid;
|
|
142
|
+
try {
|
|
143
|
+
const response = await apiPost(`/${storeCode}/reward`, { reward: payload });
|
|
144
|
+
return {
|
|
145
|
+
rewardId: response.rewardId,
|
|
146
|
+
name: input.name,
|
|
147
|
+
costInPoints: input.costInPoints,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
throw formatApiError(error, "openloyalty_reward_create");
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
export async function rewardGet(input) {
|
|
155
|
+
const config = getConfig();
|
|
156
|
+
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
157
|
+
try {
|
|
158
|
+
const response = await apiGet(`/${storeCode}/reward/${input.rewardId}`);
|
|
159
|
+
return RewardSchema.parse(response);
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
throw formatApiError(error, "openloyalty_reward_get");
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
export async function rewardUpdate(input) {
|
|
166
|
+
const config = getConfig();
|
|
167
|
+
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
168
|
+
const payload = {};
|
|
169
|
+
if (input.name)
|
|
170
|
+
payload.name = input.name;
|
|
171
|
+
if (input.costInPoints !== undefined)
|
|
172
|
+
payload.costInPoints = input.costInPoints;
|
|
173
|
+
if (input.description)
|
|
174
|
+
payload.description = input.description;
|
|
175
|
+
if (input.active !== undefined)
|
|
176
|
+
payload.active = input.active;
|
|
177
|
+
if (input.categories)
|
|
178
|
+
payload.categories = input.categories;
|
|
179
|
+
if (input.levels)
|
|
180
|
+
payload.levels = input.levels;
|
|
181
|
+
if (input.segments)
|
|
182
|
+
payload.segments = input.segments;
|
|
183
|
+
try {
|
|
184
|
+
await apiPut(`/${storeCode}/reward/${input.rewardId}`, { reward: payload });
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
throw formatApiError(error, "openloyalty_reward_update");
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
export async function rewardActivate(input) {
|
|
191
|
+
const config = getConfig();
|
|
192
|
+
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
193
|
+
try {
|
|
194
|
+
await apiPost(`/${storeCode}/reward/${input.rewardId}/activate`);
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
throw formatApiError(error, "openloyalty_reward_activate");
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
export async function rewardDeactivate(input) {
|
|
201
|
+
const config = getConfig();
|
|
202
|
+
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
203
|
+
try {
|
|
204
|
+
await apiPost(`/${storeCode}/reward/${input.rewardId}/deactivate`);
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
throw formatApiError(error, "openloyalty_reward_deactivate");
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
export async function rewardBuy(input) {
|
|
211
|
+
const config = getConfig();
|
|
212
|
+
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
213
|
+
const payload = {
|
|
214
|
+
customerId: input.memberId,
|
|
215
|
+
};
|
|
216
|
+
if (input.quantity)
|
|
217
|
+
payload.quantity = input.quantity;
|
|
218
|
+
if (input.couponValue !== undefined)
|
|
219
|
+
payload.couponValue = input.couponValue;
|
|
220
|
+
if (input.withoutPoints !== undefined)
|
|
221
|
+
payload.withoutPoints = input.withoutPoints;
|
|
222
|
+
try {
|
|
223
|
+
const response = await apiPost(`/${storeCode}/reward/${input.rewardId}/buy`, payload);
|
|
224
|
+
// API returns array of issued rewards
|
|
225
|
+
const firstIssued = Array.isArray(response) ? response[0] : response;
|
|
226
|
+
return {
|
|
227
|
+
issuedRewardId: firstIssued?.issuedRewardId || "",
|
|
228
|
+
couponCode: firstIssued?.couponCode,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
233
|
+
if (errorMessage.includes("NotEnoughPoints") || errorMessage.includes("insufficient")) {
|
|
234
|
+
throw new OpenLoyaltyError({
|
|
235
|
+
code: "INSUFFICIENT_BALANCE",
|
|
236
|
+
message: "Member does not have enough points to purchase this reward",
|
|
237
|
+
hint: `Use points_get_balance(memberId: "${input.memberId}") to check available balance. Then use reward_get(rewardId: "${input.rewardId}") to see the costInPoints required.`,
|
|
238
|
+
relatedTool: "openloyalty_reward_buy",
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
throw formatApiError(error, "openloyalty_reward_buy");
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
export async function rewardRedeem(input) {
|
|
245
|
+
const config = getConfig();
|
|
246
|
+
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
247
|
+
try {
|
|
248
|
+
const response = await apiPost(`/${storeCode}/member/${input.memberId}/reward/redeem`, { couponCode: input.couponCode });
|
|
249
|
+
return { code: response.code || input.couponCode, used: true };
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
253
|
+
if (errorMessage.includes("CouponDoesNotExist")) {
|
|
254
|
+
throw new OpenLoyaltyError({
|
|
255
|
+
code: "COUPON_NOT_FOUND",
|
|
256
|
+
message: `Coupon '${input.couponCode}' does not exist`,
|
|
257
|
+
hint: `Verify the coupon code is correct. Use reward_buy to purchase a reward and obtain a valid coupon code.`,
|
|
258
|
+
relatedTool: "openloyalty_reward_redeem",
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
if (errorMessage.includes("CouponAlreadyUsed")) {
|
|
262
|
+
throw new OpenLoyaltyError({
|
|
263
|
+
code: "COUPON_ALREADY_USED",
|
|
264
|
+
message: `Coupon '${input.couponCode}' has already been redeemed`,
|
|
265
|
+
hint: `Each coupon can only be used once. The member may need to purchase another reward to get a new coupon.`,
|
|
266
|
+
relatedTool: "openloyalty_reward_redeem",
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
if (errorMessage.includes("CouponIsExpired")) {
|
|
270
|
+
throw new OpenLoyaltyError({
|
|
271
|
+
code: "COUPON_EXPIRED",
|
|
272
|
+
message: `Coupon '${input.couponCode}' has expired`,
|
|
273
|
+
hint: `Coupons have a validity period. The member will need to purchase a new reward for a fresh coupon.`,
|
|
274
|
+
relatedTool: "openloyalty_reward_redeem",
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
throw formatApiError(error, "openloyalty_reward_redeem");
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
export async function rewardCategoryList(input) {
|
|
281
|
+
const config = getConfig();
|
|
282
|
+
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
283
|
+
const params = new URLSearchParams();
|
|
284
|
+
if (input.page)
|
|
285
|
+
params.append("_page", String(input.page));
|
|
286
|
+
if (input.perPage)
|
|
287
|
+
params.append("_itemsOnPage", String(input.perPage));
|
|
288
|
+
if (input.active !== undefined)
|
|
289
|
+
params.append("active", String(input.active));
|
|
290
|
+
const queryString = params.toString();
|
|
291
|
+
const url = `/${storeCode}/rewardCategory${queryString ? `?${queryString}` : ""}`;
|
|
292
|
+
try {
|
|
293
|
+
const response = await apiGet(url);
|
|
294
|
+
const items = response.items || response.categories || [];
|
|
295
|
+
const categories = items.map((c) => {
|
|
296
|
+
const cat = c;
|
|
297
|
+
return {
|
|
298
|
+
categoryId: (cat.rewardCategoryId || cat.categoryId),
|
|
299
|
+
name: cat.name,
|
|
300
|
+
active: (cat.active ?? false),
|
|
301
|
+
};
|
|
302
|
+
});
|
|
303
|
+
return { categories };
|
|
304
|
+
}
|
|
305
|
+
catch (error) {
|
|
306
|
+
throw formatApiError(error, "openloyalty_reward_category_list");
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
// Tool definitions
|
|
310
|
+
export const rewardToolDefinitions = [
|
|
311
|
+
{
|
|
312
|
+
name: "openloyalty_reward_list",
|
|
313
|
+
description: "List available rewards. Use reward_get for full details or reward_buy to redeem. " +
|
|
314
|
+
"Filter by type, active status, or category.",
|
|
315
|
+
inputSchema: RewardListInputSchema,
|
|
316
|
+
handler: rewardList,
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
name: "openloyalty_reward_create",
|
|
320
|
+
description: "Create a new reward that members can redeem with points. " +
|
|
321
|
+
"Types: static_coupon (fixed discount), dynamic_coupon (variable value set at purchase), " +
|
|
322
|
+
"material (physical goods), conversion_coupon (converts points), fortune_wheel (gamified). " +
|
|
323
|
+
"Returns rewardId.",
|
|
324
|
+
inputSchema: RewardCreateInputSchema,
|
|
325
|
+
handler: rewardCreate,
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
name: "openloyalty_reward_get",
|
|
329
|
+
description: "Get full reward details including configuration, targeting, and coupon settings.",
|
|
330
|
+
inputSchema: RewardGetInputSchema,
|
|
331
|
+
handler: rewardGet,
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
name: "openloyalty_reward_update",
|
|
335
|
+
description: "Update reward configuration. Cannot change reward type after creation.",
|
|
336
|
+
inputSchema: RewardUpdateInputSchema,
|
|
337
|
+
handler: rewardUpdate,
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
name: "openloyalty_reward_activate",
|
|
341
|
+
description: "Activate a reward, making it available for members to redeem.",
|
|
342
|
+
inputSchema: RewardIdInputSchema,
|
|
343
|
+
handler: rewardActivate,
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
name: "openloyalty_reward_deactivate",
|
|
347
|
+
description: "Deactivate a reward, hiding it from members. Already purchased rewards remain valid.",
|
|
348
|
+
inputSchema: RewardIdInputSchema,
|
|
349
|
+
handler: rewardDeactivate,
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
name: "openloyalty_reward_buy",
|
|
353
|
+
description: "Purchase reward for member, deducting points. Returns issuedRewardId and couponCode if applicable. " +
|
|
354
|
+
"Use reward_redeem to mark the coupon as used.",
|
|
355
|
+
inputSchema: RewardBuyInputSchema,
|
|
356
|
+
handler: rewardBuy,
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
name: "openloyalty_reward_redeem",
|
|
360
|
+
description: "Mark coupon as used. Validates coupon exists, belongs to member, and is active. " +
|
|
361
|
+
"Fails if coupon is expired, already used, or doesn't exist.",
|
|
362
|
+
inputSchema: RewardRedeemInputSchema,
|
|
363
|
+
handler: rewardRedeem,
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
name: "openloyalty_reward_category_list",
|
|
367
|
+
description: "List reward categories. Use categoryId when creating or filtering rewards.",
|
|
368
|
+
inputSchema: RewardCategoryListInputSchema,
|
|
369
|
+
handler: rewardCategoryList,
|
|
370
|
+
},
|
|
371
|
+
];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|