@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
package/dist/tools/points.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { apiGet, apiPost } from "../client/http.js";
|
|
3
|
+
import "../types/schemas/points.js";
|
|
3
4
|
import { formatApiError, OpenLoyaltyError } from "../utils/errors.js";
|
|
4
|
-
import {
|
|
5
|
+
import { getStoreCode } from "../config.js";
|
|
5
6
|
import { buildPaginationParams } from "../utils/pagination.js";
|
|
7
|
+
import { omitUndefined } from "../utils/payload.js";
|
|
6
8
|
// Input Schemas
|
|
7
9
|
export const PointsAddInputSchema = {
|
|
8
|
-
storeCode: z.string().optional().describe("Store code.
|
|
10
|
+
storeCode: z.string().optional().describe("Store code for multi-tenant routing. DO NOT pass this parameter - the configured default will be used automatically. Only provide a value if the user explicitly asks to work with a different store."),
|
|
9
11
|
memberId: z.string().describe("The member ID (UUID) to add points to."),
|
|
10
12
|
points: z.number().describe("Number of points to add (positive number)."),
|
|
11
13
|
walletCode: z.string().optional().describe("Wallet type code (e.g., 'default'). Uses default wallet if not specified."),
|
|
@@ -14,25 +16,25 @@ export const PointsAddInputSchema = {
|
|
|
14
16
|
lockedUntilDays: z.number().optional().describe("Days until points become available (1-9999)."),
|
|
15
17
|
};
|
|
16
18
|
export const PointsSpendInputSchema = {
|
|
17
|
-
storeCode: z.string().optional().describe("Store code.
|
|
19
|
+
storeCode: z.string().optional().describe("Store code for multi-tenant routing. DO NOT pass this parameter - the configured default will be used automatically. Only provide a value if the user explicitly asks to work with a different store."),
|
|
18
20
|
memberId: z.string().describe("The member ID (UUID) to spend points from."),
|
|
19
21
|
points: z.number().describe("Number of points to spend (positive number)."),
|
|
20
22
|
walletCode: z.string().optional().describe("Wallet type code (e.g., 'default'). Uses default wallet if not specified."),
|
|
21
23
|
comment: z.string().optional().describe("Reason for spending points (max 500 chars)."),
|
|
22
24
|
};
|
|
23
25
|
export const PointsTransferInputSchema = {
|
|
24
|
-
storeCode: z.string().optional().describe("Store code.
|
|
26
|
+
storeCode: z.string().optional().describe("Store code for multi-tenant routing. DO NOT pass this parameter - the configured default will be used automatically. Only provide a value if the user explicitly asks to work with a different store."),
|
|
25
27
|
senderId: z.string().describe("The sender member ID (UUID)."),
|
|
26
28
|
receiverId: z.string().describe("The receiver member ID (UUID)."),
|
|
27
29
|
points: z.number().describe("Number of points to transfer."),
|
|
28
30
|
};
|
|
29
31
|
export const PointsBalanceInputSchema = {
|
|
30
|
-
storeCode: z.string().optional().describe("Store code.
|
|
32
|
+
storeCode: z.string().optional().describe("Store code for multi-tenant routing. DO NOT pass this parameter - the configured default will be used automatically. Only provide a value if the user explicitly asks to work with a different store."),
|
|
31
33
|
memberId: z.string().describe("The member ID (UUID) to get balance for."),
|
|
32
34
|
walletCode: z.string().optional().describe("Wallet type code. Returns all wallets if not specified."),
|
|
33
35
|
};
|
|
34
36
|
export const PointsHistoryInputSchema = {
|
|
35
|
-
storeCode: z.string().optional().describe("Store code.
|
|
37
|
+
storeCode: z.string().optional().describe("Store code for multi-tenant routing. DO NOT pass this parameter - the configured default will be used automatically. Only provide a value if the user explicitly asks to work with a different store."),
|
|
36
38
|
memberId: z.string().describe("The member ID (UUID) to get history for."),
|
|
37
39
|
cursor: z.string().optional().describe("Pagination cursor from previous response. If provided, page/perPage are ignored."),
|
|
38
40
|
page: z.number().optional().describe("Page number (default: 1)."),
|
|
@@ -40,7 +42,7 @@ export const PointsHistoryInputSchema = {
|
|
|
40
42
|
type: z.enum(["adding", "spending", "p2p_spending", "p2p_adding", "blocked", "expired"]).optional().describe("Filter by transfer type."),
|
|
41
43
|
};
|
|
42
44
|
export const PointsHistogramInputSchema = {
|
|
43
|
-
storeCode: z.string().optional().describe("Store code.
|
|
45
|
+
storeCode: z.string().optional().describe("Store code for multi-tenant routing. DO NOT pass this parameter - the configured default will be used automatically. Only provide a value if the user explicitly asks to work with a different store."),
|
|
44
46
|
memberId: z.string().describe("The member ID (UUID) to get histogram for."),
|
|
45
47
|
pointType: z.enum(["spent", "earned", "expired", "pending"]).describe("Filter by point type (required). One of: spent, earned, expired, pending."),
|
|
46
48
|
walletCode: z.string().optional().describe("Wallet type code. Uses default if not specified."),
|
|
@@ -50,37 +52,29 @@ export const PointsHistogramInputSchema = {
|
|
|
50
52
|
};
|
|
51
53
|
// Handler functions
|
|
52
54
|
export async function pointsAdd(input) {
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
const payload = {
|
|
55
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
56
|
+
const payload = omitUndefined({
|
|
56
57
|
points: input.points,
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (input.expiresInDays)
|
|
63
|
-
payload.expiresInDays = input.expiresInDays;
|
|
64
|
-
if (input.lockedUntilDays)
|
|
65
|
-
payload.lockedUntilDays = input.lockedUntilDays;
|
|
58
|
+
walletCode: input.walletCode,
|
|
59
|
+
comment: input.comment,
|
|
60
|
+
expiresInDays: input.expiresInDays,
|
|
61
|
+
lockedUntilDays: input.lockedUntilDays,
|
|
62
|
+
});
|
|
66
63
|
try {
|
|
67
64
|
const response = await apiPost(`/${storeCode}/points/add`, { transfer: { customer: input.memberId, ...payload } });
|
|
68
65
|
return { transferId: response.transferId };
|
|
69
66
|
}
|
|
70
67
|
catch (error) {
|
|
71
|
-
throw formatApiError(error, "
|
|
68
|
+
throw formatApiError(error, "ol_points_add");
|
|
72
69
|
}
|
|
73
70
|
}
|
|
74
71
|
export async function pointsSpend(input) {
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
const payload = {
|
|
72
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
73
|
+
const payload = omitUndefined({
|
|
78
74
|
points: input.points,
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (input.comment)
|
|
83
|
-
payload.comment = input.comment;
|
|
75
|
+
walletCode: input.walletCode,
|
|
76
|
+
comment: input.comment,
|
|
77
|
+
});
|
|
84
78
|
try {
|
|
85
79
|
const response = await apiPost(`/${storeCode}/points/spend`, { transfer: { customer: input.memberId, ...payload } });
|
|
86
80
|
return { transferId: response.transferId };
|
|
@@ -93,15 +87,14 @@ export async function pointsSpend(input) {
|
|
|
93
87
|
code: "INSUFFICIENT_BALANCE",
|
|
94
88
|
message: "Member does not have enough points to complete this operation",
|
|
95
89
|
hint: `Use points_get_balance(memberId: "${input.memberId}") to check available balance before spending.`,
|
|
96
|
-
relatedTool: "
|
|
90
|
+
relatedTool: "ol_points_spend",
|
|
97
91
|
});
|
|
98
92
|
}
|
|
99
|
-
throw formatApiError(error, "
|
|
93
|
+
throw formatApiError(error, "ol_points_spend");
|
|
100
94
|
}
|
|
101
95
|
}
|
|
102
96
|
export async function pointsTransfer(input) {
|
|
103
|
-
const
|
|
104
|
-
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
97
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
105
98
|
if (input.senderId === input.receiverId) {
|
|
106
99
|
throw new Error("Cannot transfer points to yourself. senderId and receiverId must be different.");
|
|
107
100
|
}
|
|
@@ -123,15 +116,14 @@ export async function pointsTransfer(input) {
|
|
|
123
116
|
code: "INSUFFICIENT_BALANCE",
|
|
124
117
|
message: "Sender does not have enough points to transfer",
|
|
125
118
|
hint: `Use points_get_balance(memberId: "${input.senderId}") to check sender's available balance before transferring.`,
|
|
126
|
-
relatedTool: "
|
|
119
|
+
relatedTool: "ol_points_transfer",
|
|
127
120
|
});
|
|
128
121
|
}
|
|
129
|
-
throw formatApiError(error, "
|
|
122
|
+
throw formatApiError(error, "ol_points_transfer");
|
|
130
123
|
}
|
|
131
124
|
}
|
|
132
125
|
export async function pointsGetBalance(input) {
|
|
133
|
-
const
|
|
134
|
-
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
126
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
135
127
|
const params = new URLSearchParams();
|
|
136
128
|
if (input.walletCode)
|
|
137
129
|
params.append("walletType:code", input.walletCode);
|
|
@@ -176,12 +168,11 @@ export async function pointsGetBalance(input) {
|
|
|
176
168
|
};
|
|
177
169
|
}
|
|
178
170
|
catch (error) {
|
|
179
|
-
throw formatApiError(error, "
|
|
171
|
+
throw formatApiError(error, "ol_points_get_balance");
|
|
180
172
|
}
|
|
181
173
|
}
|
|
182
174
|
export async function pointsGetHistory(input) {
|
|
183
|
-
const
|
|
184
|
-
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
175
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
185
176
|
const params = new URLSearchParams();
|
|
186
177
|
params.append("member:id", input.memberId);
|
|
187
178
|
// Use buildPaginationParams for cursor/page handling
|
|
@@ -214,12 +205,11 @@ export async function pointsGetHistory(input) {
|
|
|
214
205
|
};
|
|
215
206
|
}
|
|
216
207
|
catch (error) {
|
|
217
|
-
throw formatApiError(error, "
|
|
208
|
+
throw formatApiError(error, "ol_points_get_history");
|
|
218
209
|
}
|
|
219
210
|
}
|
|
220
211
|
export async function pointsGetHistogram(input) {
|
|
221
|
-
const
|
|
222
|
-
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
212
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
223
213
|
const params = new URLSearchParams();
|
|
224
214
|
params.append("member:id", input.memberId);
|
|
225
215
|
// pointType is required by the API: spent|earned|expired|pending
|
|
@@ -255,51 +245,63 @@ export async function pointsGetHistogram(input) {
|
|
|
255
245
|
});
|
|
256
246
|
}
|
|
257
247
|
catch (error) {
|
|
258
|
-
throw formatApiError(error, "
|
|
248
|
+
throw formatApiError(error, "ol_points_get_histogram");
|
|
259
249
|
}
|
|
260
250
|
}
|
|
261
251
|
// Tool definitions
|
|
262
252
|
export const pointsToolDefinitions = [
|
|
263
253
|
{
|
|
264
|
-
name: "
|
|
254
|
+
name: "ol_points_add",
|
|
255
|
+
title: "Add Points to Member",
|
|
265
256
|
description: "Add points to member wallet. Points can have optional expiration and lock period. " +
|
|
266
257
|
"Use for welcome bonuses, manual adjustments, or custom rewards. Returns transferId.",
|
|
258
|
+
readOnly: false,
|
|
267
259
|
inputSchema: PointsAddInputSchema,
|
|
268
260
|
handler: pointsAdd,
|
|
269
261
|
},
|
|
270
262
|
{
|
|
271
|
-
name: "
|
|
263
|
+
name: "ol_points_spend",
|
|
264
|
+
title: "Spend Member Points",
|
|
272
265
|
description: "Deduct points from member wallet. Fails if insufficient balance. " +
|
|
273
266
|
"Use points_get_balance first to verify available points. Returns transferId.",
|
|
267
|
+
readOnly: false,
|
|
274
268
|
inputSchema: PointsSpendInputSchema,
|
|
275
269
|
handler: pointsSpend,
|
|
276
270
|
},
|
|
277
271
|
{
|
|
278
|
-
name: "
|
|
272
|
+
name: "ol_points_transfer",
|
|
273
|
+
title: "Transfer Points Between Members",
|
|
279
274
|
description: "Transfer points from one member to another (P2P transfer). " +
|
|
280
275
|
"Sender must have sufficient balance. Returns transferId.",
|
|
276
|
+
readOnly: false,
|
|
281
277
|
inputSchema: PointsTransferInputSchema,
|
|
282
278
|
handler: pointsTransfer,
|
|
283
279
|
},
|
|
284
280
|
{
|
|
285
|
-
name: "
|
|
281
|
+
name: "ol_points_get_balance",
|
|
282
|
+
title: "Check Points Balance",
|
|
286
283
|
description: "Get member points balance breakdown. activeUnits is available for spending. " +
|
|
287
284
|
"earnedUnits shows lifetime earnings, lockedUnits shows pending points.",
|
|
285
|
+
readOnly: true,
|
|
288
286
|
inputSchema: PointsBalanceInputSchema,
|
|
289
287
|
handler: pointsGetBalance,
|
|
290
288
|
},
|
|
291
289
|
{
|
|
292
|
-
name: "
|
|
290
|
+
name: "ol_points_get_history",
|
|
291
|
+
title: "View Points History",
|
|
293
292
|
description: "Get points transaction history for a member. Filter by type: adding, spending, " +
|
|
294
293
|
"p2p_spending, p2p_adding, blocked, expired. Returns paginated list of transfers. " +
|
|
295
294
|
"Supports cursor pagination: provide 'cursor' from previous response to get next page.",
|
|
295
|
+
readOnly: true,
|
|
296
296
|
inputSchema: PointsHistoryInputSchema,
|
|
297
297
|
handler: pointsGetHistory,
|
|
298
298
|
},
|
|
299
299
|
{
|
|
300
|
-
name: "
|
|
300
|
+
name: "ol_points_get_histogram",
|
|
301
|
+
title: "View Points Trends",
|
|
301
302
|
description: "Get points histogram data for visualization. Shows earning and spending patterns over time. " +
|
|
302
303
|
"Use interval (day/week/month) to aggregate data and dateFrom/dateTo to filter range.",
|
|
304
|
+
readOnly: true,
|
|
303
305
|
inputSchema: PointsHistogramInputSchema,
|
|
304
306
|
handler: pointsGetHistogram,
|
|
305
307
|
},
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a referral relationship between two members
|
|
3
|
+
* POST /api/:storeCode/member/:member/referral
|
|
4
|
+
*/
|
|
5
|
+
export declare function referralCreate(input: {
|
|
6
|
+
storeCode?: string;
|
|
7
|
+
memberId: string;
|
|
8
|
+
referrerId: string;
|
|
9
|
+
}): Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* List referrals with optional filters
|
|
12
|
+
* GET /api/:storeCode/referral
|
|
13
|
+
*/
|
|
14
|
+
export declare function referralList(input: {
|
|
15
|
+
storeCode?: string;
|
|
16
|
+
referralId?: string;
|
|
17
|
+
referrerId?: string;
|
|
18
|
+
referrerName?: string;
|
|
19
|
+
referrerToken?: string;
|
|
20
|
+
refereeId?: string;
|
|
21
|
+
refereeName?: string;
|
|
22
|
+
createdAt?: string;
|
|
23
|
+
page?: number;
|
|
24
|
+
perPage?: number;
|
|
25
|
+
}): Promise<{
|
|
26
|
+
referrals: Array<{
|
|
27
|
+
referralId: string;
|
|
28
|
+
referrerId: string;
|
|
29
|
+
referrerName?: string;
|
|
30
|
+
referrerToken?: string;
|
|
31
|
+
refereeId: string;
|
|
32
|
+
refereeName?: string;
|
|
33
|
+
createdAt: string;
|
|
34
|
+
}>;
|
|
35
|
+
total: {
|
|
36
|
+
all?: number;
|
|
37
|
+
filtered?: number;
|
|
38
|
+
};
|
|
39
|
+
}>;
|
|
40
|
+
/**
|
|
41
|
+
* Delete a referral relationship
|
|
42
|
+
* DELETE /api/:storeCode/member/:member/referral
|
|
43
|
+
*/
|
|
44
|
+
export declare function referralDelete(input: {
|
|
45
|
+
storeCode?: string;
|
|
46
|
+
memberId: string;
|
|
47
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { apiGet, apiPost, apiDelete } from "../../client/http.js";
|
|
2
|
+
import { formatApiError, OpenLoyaltyError } from "../../utils/errors.js";
|
|
3
|
+
import { getStoreCode } from "../../config.js";
|
|
4
|
+
/**
|
|
5
|
+
* Create a referral relationship between two members
|
|
6
|
+
* POST /api/:storeCode/member/:member/referral
|
|
7
|
+
*/
|
|
8
|
+
export async function referralCreate(input) {
|
|
9
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
10
|
+
// Validate that memberId and referrerId are different
|
|
11
|
+
if (input.memberId === input.referrerId) {
|
|
12
|
+
throw new OpenLoyaltyError({
|
|
13
|
+
code: "INVALID_REFERRAL",
|
|
14
|
+
message: "A member cannot refer themselves",
|
|
15
|
+
hint: "The memberId (referee) must be different from the referrerId (referrer). The referee is the new member, the referrer is the existing member who made the referral.",
|
|
16
|
+
relatedTool: "ol_referral_create",
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
await apiPost(`/${storeCode}/member/${input.memberId}/referral`, { referrerId: input.referrerId });
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
24
|
+
if (errorMessage.includes("already has a referrer") || errorMessage.includes("referral already exists")) {
|
|
25
|
+
throw new OpenLoyaltyError({
|
|
26
|
+
code: "REFERRAL_EXISTS",
|
|
27
|
+
message: "This member already has a referral relationship",
|
|
28
|
+
hint: `Member ${input.memberId} has already been referred by someone. Use referral_list(refereeId: "${input.memberId}") to see existing referral.`,
|
|
29
|
+
relatedTool: "ol_referral_create",
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
if (errorMessage.includes("not found") || errorMessage.includes("Not Found")) {
|
|
33
|
+
throw new OpenLoyaltyError({
|
|
34
|
+
code: "MEMBER_NOT_FOUND",
|
|
35
|
+
message: "One or both member IDs do not exist",
|
|
36
|
+
hint: `Verify both members exist: member_get(memberId: "${input.memberId}") for referee and member_get(memberId: "${input.referrerId}") for referrer.`,
|
|
37
|
+
relatedTool: "ol_referral_create",
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
throw formatApiError(error, "ol_referral_create");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* List referrals with optional filters
|
|
45
|
+
* GET /api/:storeCode/referral
|
|
46
|
+
*/
|
|
47
|
+
export async function referralList(input) {
|
|
48
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
49
|
+
const params = new URLSearchParams();
|
|
50
|
+
if (input.referralId)
|
|
51
|
+
params.append("referralId", input.referralId);
|
|
52
|
+
if (input.referrerId)
|
|
53
|
+
params.append("referrerId", input.referrerId);
|
|
54
|
+
if (input.referrerName)
|
|
55
|
+
params.append("referrerName", input.referrerName);
|
|
56
|
+
if (input.referrerToken)
|
|
57
|
+
params.append("referrerToken", input.referrerToken);
|
|
58
|
+
if (input.refereeId)
|
|
59
|
+
params.append("refereeId", input.refereeId);
|
|
60
|
+
if (input.refereeName)
|
|
61
|
+
params.append("refereeName", input.refereeName);
|
|
62
|
+
if (input.createdAt)
|
|
63
|
+
params.append("createdAt", input.createdAt);
|
|
64
|
+
if (input.page)
|
|
65
|
+
params.append("_page", String(input.page));
|
|
66
|
+
if (input.perPage)
|
|
67
|
+
params.append("_itemsOnPage", String(input.perPage));
|
|
68
|
+
const queryString = params.toString();
|
|
69
|
+
const url = `/${storeCode}/referral${queryString ? `?${queryString}` : ""}`;
|
|
70
|
+
try {
|
|
71
|
+
const response = await apiGet(url);
|
|
72
|
+
const referrals = (response.items || []).map((item) => ({
|
|
73
|
+
referralId: item.referralId,
|
|
74
|
+
referrerId: item.referrerId,
|
|
75
|
+
referrerName: item.referrerName,
|
|
76
|
+
referrerToken: item.referrerToken,
|
|
77
|
+
refereeId: item.refereeId,
|
|
78
|
+
refereeName: item.refereeName,
|
|
79
|
+
createdAt: item.createdAt,
|
|
80
|
+
}));
|
|
81
|
+
const total = response.total || {};
|
|
82
|
+
return {
|
|
83
|
+
referrals,
|
|
84
|
+
total: {
|
|
85
|
+
all: typeof total.all === "number" ? total.all : undefined,
|
|
86
|
+
filtered: typeof total.filtered === "number" ? total.filtered : undefined,
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
throw formatApiError(error, "ol_referral_list");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Delete a referral relationship
|
|
96
|
+
* DELETE /api/:storeCode/member/:member/referral
|
|
97
|
+
*/
|
|
98
|
+
export async function referralDelete(input) {
|
|
99
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
100
|
+
try {
|
|
101
|
+
await apiDelete(`/${storeCode}/member/${input.memberId}/referral`);
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
105
|
+
if (errorMessage.includes("not found") || errorMessage.includes("Not Found")) {
|
|
106
|
+
throw new OpenLoyaltyError({
|
|
107
|
+
code: "REFERRAL_NOT_FOUND",
|
|
108
|
+
message: "No referral relationship found for this member",
|
|
109
|
+
hint: `Member ${input.memberId} does not have a referral relationship. Use referral_list(refereeId: "${input.memberId}") to verify.`,
|
|
110
|
+
relatedTool: "ol_referral_delete",
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
throw formatApiError(error, "ol_referral_delete");
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export { ReferralCreateInputSchema, ReferralListInputSchema, ReferralDeleteInputSchema, } from "./schemas.js";
|
|
2
|
+
export { referralCreate, referralList, referralDelete } from "./handlers.js";
|
|
3
|
+
import { referralCreate, referralList, referralDelete } from "./handlers.js";
|
|
4
|
+
export declare const referralToolDefinitions: readonly [{
|
|
5
|
+
readonly name: "ol_referral_create";
|
|
6
|
+
readonly title: "Create Referral Relationship";
|
|
7
|
+
readonly description: string;
|
|
8
|
+
readonly readOnly: false;
|
|
9
|
+
readonly inputSchema: {
|
|
10
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
11
|
+
memberId: import("zod").ZodString;
|
|
12
|
+
referrerId: import("zod").ZodString;
|
|
13
|
+
};
|
|
14
|
+
readonly handler: typeof referralCreate;
|
|
15
|
+
}, {
|
|
16
|
+
readonly name: "ol_referral_list";
|
|
17
|
+
readonly title: "List Referrals";
|
|
18
|
+
readonly description: string;
|
|
19
|
+
readonly readOnly: true;
|
|
20
|
+
readonly inputSchema: {
|
|
21
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
22
|
+
referralId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
23
|
+
referrerId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
24
|
+
referrerName: import("zod").ZodOptional<import("zod").ZodString>;
|
|
25
|
+
referrerToken: import("zod").ZodOptional<import("zod").ZodString>;
|
|
26
|
+
refereeId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
27
|
+
refereeName: import("zod").ZodOptional<import("zod").ZodString>;
|
|
28
|
+
createdAt: import("zod").ZodOptional<import("zod").ZodString>;
|
|
29
|
+
page: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
30
|
+
perPage: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
31
|
+
};
|
|
32
|
+
readonly handler: typeof referralList;
|
|
33
|
+
}, {
|
|
34
|
+
readonly name: "ol_referral_delete";
|
|
35
|
+
readonly title: "Delete Referral Relationship";
|
|
36
|
+
readonly description: string;
|
|
37
|
+
readonly readOnly: false;
|
|
38
|
+
readonly destructive: true;
|
|
39
|
+
readonly inputSchema: {
|
|
40
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
41
|
+
memberId: import("zod").ZodString;
|
|
42
|
+
};
|
|
43
|
+
readonly handler: typeof referralDelete;
|
|
44
|
+
}];
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Re-export schemas
|
|
2
|
+
export { ReferralCreateInputSchema, ReferralListInputSchema, ReferralDeleteInputSchema, } from "./schemas.js";
|
|
3
|
+
// Re-export handlers
|
|
4
|
+
export { referralCreate, referralList, referralDelete } from "./handlers.js";
|
|
5
|
+
// Imports for tool definitions
|
|
6
|
+
import { ReferralCreateInputSchema, ReferralListInputSchema, ReferralDeleteInputSchema, } from "./schemas.js";
|
|
7
|
+
import { referralCreate, referralList, referralDelete } from "./handlers.js";
|
|
8
|
+
// Tool definitions
|
|
9
|
+
export const referralToolDefinitions = [
|
|
10
|
+
{
|
|
11
|
+
name: "ol_referral_create",
|
|
12
|
+
title: "Create Referral Relationship",
|
|
13
|
+
description: "Create a referral relationship between an existing member (referrer) and a new member (referee). " +
|
|
14
|
+
"The referrer is the member who made the referral and will receive referral rewards. " +
|
|
15
|
+
"The referee (memberId) is the new member who was referred. " +
|
|
16
|
+
"Use this after creating a new member who was referred by an existing member. " +
|
|
17
|
+
"Both members must exist. A member can only have one referrer.",
|
|
18
|
+
readOnly: false,
|
|
19
|
+
inputSchema: ReferralCreateInputSchema,
|
|
20
|
+
handler: referralCreate,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: "ol_referral_list",
|
|
24
|
+
title: "List Referrals",
|
|
25
|
+
description: "List referral relationships with optional filters. " +
|
|
26
|
+
"Filter by referrerId to see all members a specific person has referred. " +
|
|
27
|
+
"Filter by refereeId to find who referred a specific member. " +
|
|
28
|
+
"Returns referralId, referrerId, referrerName, refereeId, refereeName, and createdAt.",
|
|
29
|
+
readOnly: true,
|
|
30
|
+
inputSchema: ReferralListInputSchema,
|
|
31
|
+
handler: referralList,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: "ol_referral_delete",
|
|
35
|
+
title: "Delete Referral Relationship",
|
|
36
|
+
description: "Delete a referral relationship for a member. " +
|
|
37
|
+
"Use with caution - this removes the referral tracking but may not reverse any rewards already given. " +
|
|
38
|
+
"The memberId is the referee (the member who was referred).",
|
|
39
|
+
readOnly: false,
|
|
40
|
+
destructive: true,
|
|
41
|
+
inputSchema: ReferralDeleteInputSchema,
|
|
42
|
+
handler: referralDelete,
|
|
43
|
+
},
|
|
44
|
+
];
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Schema for creating a referral relationship
|
|
4
|
+
* POST /api/:storeCode/member/:member/referral
|
|
5
|
+
*/
|
|
6
|
+
export declare const ReferralCreateInputSchema: {
|
|
7
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
8
|
+
memberId: z.ZodString;
|
|
9
|
+
referrerId: z.ZodString;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Schema for listing referrals
|
|
13
|
+
* GET /api/:storeCode/referral
|
|
14
|
+
*/
|
|
15
|
+
export declare const ReferralListInputSchema: {
|
|
16
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
17
|
+
referralId: z.ZodOptional<z.ZodString>;
|
|
18
|
+
referrerId: z.ZodOptional<z.ZodString>;
|
|
19
|
+
referrerName: z.ZodOptional<z.ZodString>;
|
|
20
|
+
referrerToken: z.ZodOptional<z.ZodString>;
|
|
21
|
+
refereeId: z.ZodOptional<z.ZodString>;
|
|
22
|
+
refereeName: z.ZodOptional<z.ZodString>;
|
|
23
|
+
createdAt: z.ZodOptional<z.ZodString>;
|
|
24
|
+
page: z.ZodOptional<z.ZodNumber>;
|
|
25
|
+
perPage: z.ZodOptional<z.ZodNumber>;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Schema for deleting a referral relationship
|
|
29
|
+
* DELETE /api/:storeCode/member/:member/referral
|
|
30
|
+
*/
|
|
31
|
+
export declare const ReferralDeleteInputSchema: {
|
|
32
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
33
|
+
memberId: z.ZodString;
|
|
34
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Schema for creating a referral relationship
|
|
4
|
+
* POST /api/:storeCode/member/:member/referral
|
|
5
|
+
*/
|
|
6
|
+
export const ReferralCreateInputSchema = {
|
|
7
|
+
storeCode: z
|
|
8
|
+
.string()
|
|
9
|
+
.optional()
|
|
10
|
+
.describe("Store code for multi-tenant routing. DO NOT pass this parameter - the configured default will be used automatically. Only provide a value if the user explicitly asks to work with a different store."),
|
|
11
|
+
memberId: z
|
|
12
|
+
.string()
|
|
13
|
+
.uuid()
|
|
14
|
+
.describe("The member ID (UUID) of the referee (the new member being referred). This is the member who was referred by someone else."),
|
|
15
|
+
referrerId: z
|
|
16
|
+
.string()
|
|
17
|
+
.uuid()
|
|
18
|
+
.describe("The member ID (UUID) of the referrer (the existing member who made the referral). This member will receive referral rewards."),
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Schema for listing referrals
|
|
22
|
+
* GET /api/:storeCode/referral
|
|
23
|
+
*/
|
|
24
|
+
export const ReferralListInputSchema = {
|
|
25
|
+
storeCode: z
|
|
26
|
+
.string()
|
|
27
|
+
.optional()
|
|
28
|
+
.describe("Store code for multi-tenant routing. DO NOT pass this parameter - the configured default will be used automatically. Only provide a value if the user explicitly asks to work with a different store."),
|
|
29
|
+
referralId: z.string().uuid().optional().describe("Filter by specific referral ID"),
|
|
30
|
+
referrerId: z.string().uuid().optional().describe("Filter by referrer member ID"),
|
|
31
|
+
referrerName: z.string().max(255).optional().describe("Filter by referrer name"),
|
|
32
|
+
referrerToken: z.string().max(255).optional().describe("Filter by referrer token"),
|
|
33
|
+
refereeId: z.string().uuid().optional().describe("Filter by referee member ID"),
|
|
34
|
+
refereeName: z.string().max(255).optional().describe("Filter by referee name"),
|
|
35
|
+
createdAt: z.string().optional().describe("Filter by creation date (ISO 8601)"),
|
|
36
|
+
page: z.number().int().min(1).optional().describe("Page number (starts from 1)"),
|
|
37
|
+
perPage: z.number().int().min(1).max(100).optional().describe("Items per page (default 25, max 100)"),
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Schema for deleting a referral relationship
|
|
41
|
+
* DELETE /api/:storeCode/member/:member/referral
|
|
42
|
+
*/
|
|
43
|
+
export const ReferralDeleteInputSchema = {
|
|
44
|
+
storeCode: z
|
|
45
|
+
.string()
|
|
46
|
+
.optional()
|
|
47
|
+
.describe("Store code for multi-tenant routing. DO NOT pass this parameter - the configured default will be used automatically. Only provide a value if the user explicitly asks to work with a different store."),
|
|
48
|
+
memberId: z
|
|
49
|
+
.string()
|
|
50
|
+
.uuid()
|
|
51
|
+
.describe("The member ID (UUID) of the referee whose referral relationship should be deleted."),
|
|
52
|
+
};
|