@open-loyalty/mcp-server 1.3.7 → 1.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts +4 -3
- package/dist/config.js +9 -7
- package/dist/instructions.d.ts +1 -1
- package/dist/instructions.js +26 -8
- package/dist/tools/achievement/handlers.js +60 -1
- package/dist/tools/achievement/index.d.ts +8 -8
- package/dist/tools/achievement/index.js +10 -11
- package/dist/tools/achievement/schemas.d.ts +8 -8
- package/dist/tools/achievement/schemas.js +36 -32
- package/dist/tools/analytics.js +9 -9
- package/dist/tools/badge.js +4 -4
- package/dist/tools/campaign/handlers.js +35 -1
- package/dist/tools/campaign/index.d.ts +97 -34
- package/dist/tools/campaign/index.js +14 -12
- package/dist/tools/campaign/schemas.d.ts +96 -33
- package/dist/tools/campaign/schemas.js +89 -55
- package/dist/tools/custom-event.js +10 -9
- package/dist/tools/export.js +4 -4
- package/dist/tools/import.d.ts +1 -1
- package/dist/tools/import.js +11 -6
- package/dist/tools/index.js +4 -4
- package/dist/tools/member/handlers.js +48 -1
- package/dist/tools/member/index.d.ts +1 -1
- package/dist/tools/member/index.js +3 -1
- package/dist/tools/member/schemas.js +12 -12
- package/dist/tools/points/handlers.d.ts +75 -0
- package/dist/tools/{points.js → points/handlers.js} +21 -112
- package/dist/tools/points/index.d.ts +84 -0
- package/dist/tools/points/index.js +63 -0
- package/dist/tools/points/schemas.d.ts +45 -0
- package/dist/tools/points/schemas.js +47 -0
- package/dist/tools/referral/schemas.js +3 -3
- package/dist/tools/reward/handlers.d.ts +2 -0
- package/dist/tools/reward/handlers.js +79 -6
- package/dist/tools/reward/index.d.ts +2 -0
- package/dist/tools/reward/index.js +10 -10
- package/dist/tools/reward/schemas.d.ts +2 -0
- package/dist/tools/reward/schemas.js +42 -23
- package/dist/tools/segment/index.js +7 -5
- package/dist/tools/segment/schemas.js +11 -11
- package/dist/tools/tierset/handlers.d.ts +26 -0
- package/dist/tools/tierset/handlers.js +196 -0
- package/dist/tools/tierset/index.d.ts +124 -0
- package/dist/tools/tierset/index.js +88 -0
- package/dist/tools/tierset/schemas.d.ts +127 -0
- package/dist/tools/tierset/schemas.js +62 -0
- package/dist/tools/transaction/handlers.d.ts +89 -0
- package/dist/tools/transaction/handlers.js +159 -0
- package/dist/tools/transaction/index.d.ts +153 -0
- package/dist/tools/transaction/index.js +54 -0
- package/dist/tools/transaction/schemas.d.ts +126 -0
- package/dist/tools/transaction/schemas.js +60 -0
- package/dist/tools/wallet-type/handlers.d.ts +63 -0
- package/dist/tools/{wallet-type.js → wallet-type/handlers.js} +15 -78
- package/dist/tools/{wallet-type.d.ts → wallet-type/index.d.ts} +3 -64
- package/dist/tools/wallet-type/index.js +65 -0
- package/dist/tools/wallet-type/schemas.d.ts +1 -0
- package/dist/tools/wallet-type/schemas.js +1 -0
- package/dist/tools/webhook.js +6 -6
- package/dist/types/schemas/achievement.d.ts +48 -48
- package/dist/types/schemas/admin.d.ts +10 -10
- package/dist/types/schemas/campaign.d.ts +12 -12
- package/dist/types/schemas/common.js +1 -1
- package/dist/types/schemas/member.d.ts +18 -18
- package/dist/types/schemas/role.d.ts +4 -4
- package/dist/types/schemas/tierset.js +2 -1
- package/dist/types/schemas/transaction.d.ts +12 -12
- package/dist/types/schemas/wallet-type.js +12 -10
- package/dist/types/schemas/webhook.d.ts +6 -6
- package/dist/utils/errors.js +40 -0
- package/package.json +3 -2
- package/dist/prompts/fan-engagement-setup.d.ts +0 -107
- package/dist/prompts/fan-engagement-setup.js +0 -492
- package/dist/tools/achievement.d.ts +0 -1017
- package/dist/tools/achievement.js +0 -354
- package/dist/tools/campaign.d.ts +0 -1800
- package/dist/tools/campaign.js +0 -737
- package/dist/tools/member.d.ts +0 -366
- package/dist/tools/member.js +0 -352
- package/dist/tools/points.d.ts +0 -201
- package/dist/tools/reward.d.ts +0 -279
- package/dist/tools/reward.js +0 -361
- package/dist/tools/segment.d.ts +0 -816
- package/dist/tools/segment.js +0 -333
- package/dist/tools/tierset.d.ts +0 -273
- package/dist/tools/tierset.js +0 -289
- package/dist/tools/transaction.d.ts +0 -365
- package/dist/tools/transaction.js +0 -259
- package/dist/workflows/app-login-streak.d.ts +0 -39
- package/dist/workflows/app-login-streak.js +0 -298
- package/dist/workflows/early-arrival.d.ts +0 -33
- package/dist/workflows/early-arrival.js +0 -148
- package/dist/workflows/index.d.ts +0 -101
- package/dist/workflows/index.js +0 -208
- package/dist/workflows/match-attendance.d.ts +0 -45
- package/dist/workflows/match-attendance.js +0 -308
- package/dist/workflows/sportsbar-visit.d.ts +0 -41
- package/dist/workflows/sportsbar-visit.js +0 -284
- package/dist/workflows/vod-watching.d.ts +0 -43
- package/dist/workflows/vod-watching.js +0 -326
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { TierSet, TierSetListItem, Tier } from "../../types/schemas/tierset.js";
|
|
2
|
+
import type { TierSetListInput, TierSetCreateInput, TierSetGetInput, TierSetUpdateInput, TierSetUpdateTiersInput } from "./schemas.js";
|
|
3
|
+
export declare function tiersetList(input: TierSetListInput): Promise<{
|
|
4
|
+
items: TierSetListItem[];
|
|
5
|
+
total: {
|
|
6
|
+
all?: number;
|
|
7
|
+
filtered?: number;
|
|
8
|
+
};
|
|
9
|
+
}>;
|
|
10
|
+
export declare function tiersetCreate(input: TierSetCreateInput): Promise<{
|
|
11
|
+
tierSetId: string;
|
|
12
|
+
conditions: {
|
|
13
|
+
conditionId: string;
|
|
14
|
+
attribute: string;
|
|
15
|
+
}[];
|
|
16
|
+
}>;
|
|
17
|
+
export declare function tiersetGet(input: TierSetGetInput): Promise<TierSet>;
|
|
18
|
+
export declare function tiersetUpdate(input: TierSetUpdateInput): Promise<void>;
|
|
19
|
+
export declare function tiersetUpdateTiers(input: TierSetUpdateTiersInput): Promise<void>;
|
|
20
|
+
export declare function tiersetGetTiers(input: TierSetGetInput): Promise<{
|
|
21
|
+
items: Tier[];
|
|
22
|
+
total: {
|
|
23
|
+
all?: number;
|
|
24
|
+
filtered?: number;
|
|
25
|
+
};
|
|
26
|
+
}>;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { apiGet, apiPost, apiPut } from "../../client/http.js";
|
|
2
|
+
import { TierSetSchema, TierSetListResponseSchema, TierListResponseSchema, } from "../../types/schemas/tierset.js";
|
|
3
|
+
import { formatApiError, OpenLoyaltyError } from "../../utils/errors.js";
|
|
4
|
+
import { getStoreCode } from "../../config.js";
|
|
5
|
+
import { buildPaginationQuery } from "../../utils/pagination.js";
|
|
6
|
+
export async function tiersetList(input) {
|
|
7
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
8
|
+
const query = buildPaginationQuery({
|
|
9
|
+
page: input.page,
|
|
10
|
+
perPage: input.perPage,
|
|
11
|
+
});
|
|
12
|
+
try {
|
|
13
|
+
const response = await apiGet(`/${storeCode}/tierSet${query}`);
|
|
14
|
+
const validated = TierSetListResponseSchema.parse(response);
|
|
15
|
+
return {
|
|
16
|
+
items: validated.items.map((ts) => ({
|
|
17
|
+
tierSetId: ts.tierSetId,
|
|
18
|
+
name: ts.name,
|
|
19
|
+
active: ts.active,
|
|
20
|
+
tiersCount: ts.tiersCount,
|
|
21
|
+
})),
|
|
22
|
+
total: {
|
|
23
|
+
all: typeof validated.total.all === 'number' ? validated.total.all : undefined,
|
|
24
|
+
filtered: typeof validated.total.filtered === 'number' ? validated.total.filtered : undefined,
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
throw formatApiError(error, "ol_tierset_list");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export async function tiersetCreate(input) {
|
|
33
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
34
|
+
// API QUIRK: Only accepts specific fields at creation time.
|
|
35
|
+
// Fields NOT supported at creation: tiers, active, downgrade
|
|
36
|
+
// These must be set via tierset_update or tierset_update_tiers after creation.
|
|
37
|
+
//
|
|
38
|
+
// REQUIRED fields:
|
|
39
|
+
// - translations.en.name (string)
|
|
40
|
+
// - conditions (array with attribute, optionally walletType)
|
|
41
|
+
//
|
|
42
|
+
// IMPORTANT: Only include description if actually provided - API rejects empty string as "extra field"
|
|
43
|
+
const enTranslation = {
|
|
44
|
+
name: input.name,
|
|
45
|
+
};
|
|
46
|
+
if (input.description) {
|
|
47
|
+
enTranslation.description = input.description;
|
|
48
|
+
}
|
|
49
|
+
// Explicitly map conditions to only include known fields (attribute + walletType)
|
|
50
|
+
// This strips any extra fields that might slip through Zod validation
|
|
51
|
+
const mappedConditions = input.conditions.map((c) => {
|
|
52
|
+
const condition = {
|
|
53
|
+
attribute: c.attribute,
|
|
54
|
+
};
|
|
55
|
+
if (c.walletType) {
|
|
56
|
+
condition.walletType = c.walletType;
|
|
57
|
+
}
|
|
58
|
+
return condition;
|
|
59
|
+
});
|
|
60
|
+
const tierSetPayload = {
|
|
61
|
+
translations: {
|
|
62
|
+
en: enTranslation,
|
|
63
|
+
},
|
|
64
|
+
conditions: mappedConditions,
|
|
65
|
+
};
|
|
66
|
+
const payload = { tierSet: tierSetPayload };
|
|
67
|
+
try {
|
|
68
|
+
const response = await apiPost(`/${storeCode}/tierSet`, payload);
|
|
69
|
+
// API QUIRK: Create endpoint only returns { tierSetId: string }
|
|
70
|
+
// We need to fetch the full tier set to get the conditionId values
|
|
71
|
+
const createResponse = response;
|
|
72
|
+
if (!createResponse.tierSetId) {
|
|
73
|
+
throw new Error(`Unexpected response format: ${JSON.stringify(response)}`);
|
|
74
|
+
}
|
|
75
|
+
// Fetch the created tier set to get condition IDs
|
|
76
|
+
const tierSetResponse = await apiGet(`/${storeCode}/tierSet/${createResponse.tierSetId}`);
|
|
77
|
+
const validated = TierSetSchema.parse(tierSetResponse);
|
|
78
|
+
return {
|
|
79
|
+
tierSetId: validated.tierSetId,
|
|
80
|
+
conditions: validated.conditions.map((c) => ({
|
|
81
|
+
conditionId: c.id,
|
|
82
|
+
attribute: c.attribute,
|
|
83
|
+
})),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
// Detect "maximum 3 active tier sets" limit error
|
|
88
|
+
const axiosError = error;
|
|
89
|
+
const allMessages = [
|
|
90
|
+
axiosError.response?.data?.message || "",
|
|
91
|
+
...(axiosError.response?.data?.errors || []).map(e => e.message)
|
|
92
|
+
].join(" ").toLowerCase();
|
|
93
|
+
if (allMessages.includes("maximum") || allMessages.includes("limit") || (allMessages.includes("tier") && allMessages.includes("3"))) {
|
|
94
|
+
throw new OpenLoyaltyError({
|
|
95
|
+
code: "TIER_SET_LIMIT",
|
|
96
|
+
message: "Maximum 3 active tier sets per store",
|
|
97
|
+
hint: "Use ol_tierset_list() to see existing tier sets. Reuse an existing tier set or deactivate one before creating a new one.",
|
|
98
|
+
relatedTool: "ol_tierset_create",
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
throw formatApiError(error, "ol_tierset_create");
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
export async function tiersetGet(input) {
|
|
105
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
106
|
+
try {
|
|
107
|
+
const response = await apiGet(`/${storeCode}/tierSet/${input.tierSetId}`);
|
|
108
|
+
const validated = TierSetSchema.parse(response);
|
|
109
|
+
return validated;
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
throw formatApiError(error, "ol_tierset_get");
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export async function tiersetUpdate(input) {
|
|
116
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
117
|
+
// API requires conditions to be present in PUT requests, even for metadata-only updates.
|
|
118
|
+
// Fetch existing tier set to preserve conditions.
|
|
119
|
+
let existingTierSet;
|
|
120
|
+
try {
|
|
121
|
+
const response = await apiGet(`/${storeCode}/tierSet/${input.tierSetId}`);
|
|
122
|
+
existingTierSet = TierSetSchema.parse(response);
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
throw formatApiError(error, "ol_tierset_update");
|
|
126
|
+
}
|
|
127
|
+
// Build payload using existing values as defaults
|
|
128
|
+
const tierSetPayload = {
|
|
129
|
+
// Always include conditions - API requires this even for metadata updates
|
|
130
|
+
conditions: existingTierSet.conditions.map((c) => ({
|
|
131
|
+
attribute: c.attribute,
|
|
132
|
+
walletType: c.walletType,
|
|
133
|
+
})),
|
|
134
|
+
// Always include translations
|
|
135
|
+
translations: {
|
|
136
|
+
en: {
|
|
137
|
+
name: input.name ?? existingTierSet.name,
|
|
138
|
+
description: input.description ?? existingTierSet.description ?? "",
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
// Preserve active status unless explicitly changed
|
|
142
|
+
active: input.active ?? existingTierSet.active,
|
|
143
|
+
};
|
|
144
|
+
if (input.downgrade !== undefined) {
|
|
145
|
+
tierSetPayload.downgrade = input.downgrade;
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
await apiPut(`/${storeCode}/tierSet/${input.tierSetId}`, { tierSet: tierSetPayload });
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
throw formatApiError(error, "ol_tierset_update");
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
export async function tiersetUpdateTiers(input) {
|
|
155
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
156
|
+
// API requires translations (at least en is required)
|
|
157
|
+
const payload = {
|
|
158
|
+
tiers: input.tiers.map((tier) => ({
|
|
159
|
+
levelId: tier.levelId,
|
|
160
|
+
active: tier.active ?? true,
|
|
161
|
+
conditions: tier.conditions.map((c) => ({
|
|
162
|
+
conditionId: c.conditionId,
|
|
163
|
+
value: c.value,
|
|
164
|
+
})),
|
|
165
|
+
translations: {
|
|
166
|
+
en: {
|
|
167
|
+
name: tier.name,
|
|
168
|
+
description: tier.description || "",
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
})),
|
|
172
|
+
};
|
|
173
|
+
try {
|
|
174
|
+
await apiPut(`/${storeCode}/tierSet/${input.tierSetId}/tiers`, payload);
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
throw formatApiError(error, "ol_tierset_update_tiers");
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
export async function tiersetGetTiers(input) {
|
|
181
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
182
|
+
try {
|
|
183
|
+
const response = await apiGet(`/${storeCode}/tierSet/${input.tierSetId}/tiers`);
|
|
184
|
+
const validated = TierListResponseSchema.parse(response);
|
|
185
|
+
return {
|
|
186
|
+
items: validated.items,
|
|
187
|
+
total: {
|
|
188
|
+
all: typeof validated.total.all === 'number' ? validated.total.all : undefined,
|
|
189
|
+
filtered: typeof validated.total.filtered === 'number' ? validated.total.filtered : undefined,
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
throw formatApiError(error, "ol_tierset_get_tiers");
|
|
195
|
+
}
|
|
196
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
export { TierSetListInputSchema, TierSetCreateInputSchema, TierSetGetInputSchema, TierSetUpdateInputSchema, TierSetUpdateTiersInputSchema, TierSetGetTiersInputSchema, } from "./schemas.js";
|
|
2
|
+
export type { TierSetListInput, TierSetCreateInput, TierSetGetInput, TierSetUpdateInput, TierSetUpdateTiersInput, } from "./schemas.js";
|
|
3
|
+
export { tiersetList, tiersetCreate, tiersetGet, tiersetUpdate, tiersetUpdateTiers, tiersetGetTiers, } from "./handlers.js";
|
|
4
|
+
import { tiersetList, tiersetCreate, tiersetGet, tiersetUpdate, tiersetUpdateTiers, tiersetGetTiers } from "./handlers.js";
|
|
5
|
+
export declare const tiersetToolDefinitions: readonly [{
|
|
6
|
+
readonly name: "ol_tierset_list";
|
|
7
|
+
readonly title: "List Loyalty Programs";
|
|
8
|
+
readonly description: string;
|
|
9
|
+
readonly readOnly: true;
|
|
10
|
+
readonly inputSchema: {
|
|
11
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
12
|
+
page: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
13
|
+
perPage: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
14
|
+
};
|
|
15
|
+
readonly handler: typeof tiersetList;
|
|
16
|
+
}, {
|
|
17
|
+
readonly name: "ol_tierset_create";
|
|
18
|
+
readonly title: "Create Loyalty Program";
|
|
19
|
+
readonly description: string;
|
|
20
|
+
readonly readOnly: false;
|
|
21
|
+
readonly inputSchema: {
|
|
22
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
23
|
+
name: import("zod").ZodString;
|
|
24
|
+
description: import("zod").ZodOptional<import("zod").ZodString>;
|
|
25
|
+
conditions: import("zod").ZodArray<import("zod").ZodObject<{
|
|
26
|
+
attribute: import("zod").ZodEnum<["activeUnits", "totalEarnedUnits", "totalSpending", "monthsSinceJoiningProgram", "cumulatedEarnedUnits"]>;
|
|
27
|
+
walletType: import("zod").ZodOptional<import("zod").ZodString>;
|
|
28
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
29
|
+
attribute: "activeUnits" | "totalEarnedUnits" | "totalSpending" | "monthsSinceJoiningProgram" | "cumulatedEarnedUnits";
|
|
30
|
+
walletType?: string | undefined;
|
|
31
|
+
}, {
|
|
32
|
+
attribute: "activeUnits" | "totalEarnedUnits" | "totalSpending" | "monthsSinceJoiningProgram" | "cumulatedEarnedUnits";
|
|
33
|
+
walletType?: string | undefined;
|
|
34
|
+
}>, "many">;
|
|
35
|
+
};
|
|
36
|
+
readonly handler: typeof tiersetCreate;
|
|
37
|
+
}, {
|
|
38
|
+
readonly name: "ol_tierset_get";
|
|
39
|
+
readonly title: "Get Loyalty Program Details";
|
|
40
|
+
readonly description: string;
|
|
41
|
+
readonly readOnly: true;
|
|
42
|
+
readonly inputSchema: {
|
|
43
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
44
|
+
tierSetId: import("zod").ZodString;
|
|
45
|
+
};
|
|
46
|
+
readonly handler: typeof tiersetGet;
|
|
47
|
+
}, {
|
|
48
|
+
readonly name: "ol_tierset_update";
|
|
49
|
+
readonly title: "Update Loyalty Program";
|
|
50
|
+
readonly description: string;
|
|
51
|
+
readonly readOnly: false;
|
|
52
|
+
readonly inputSchema: {
|
|
53
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
54
|
+
tierSetId: import("zod").ZodString;
|
|
55
|
+
name: import("zod").ZodOptional<import("zod").ZodString>;
|
|
56
|
+
description: import("zod").ZodOptional<import("zod").ZodString>;
|
|
57
|
+
active: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
58
|
+
downgrade: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
59
|
+
mode: import("zod").ZodEnum<["none", "automatic", "x_days"]>;
|
|
60
|
+
days: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
61
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
62
|
+
mode: "none" | "automatic" | "x_days";
|
|
63
|
+
days?: number | undefined;
|
|
64
|
+
}, {
|
|
65
|
+
mode: "none" | "automatic" | "x_days";
|
|
66
|
+
days?: number | undefined;
|
|
67
|
+
}>>;
|
|
68
|
+
};
|
|
69
|
+
readonly handler: typeof tiersetUpdate;
|
|
70
|
+
}, {
|
|
71
|
+
readonly name: "ol_tierset_update_tiers";
|
|
72
|
+
readonly title: "Configure Tier Thresholds";
|
|
73
|
+
readonly description: "Add ALL tiers to a tier set in ONE call. A tier set is a CONTAINER - add all tiers (Bronze, Silver, Gold, etc.) to it together.\n\n⚠️ CRITICAL: Pass ALL tiers in a SINGLE call to this endpoint. DO NOT call this multiple times with one tier each.\n\n⚠️ INPUT FORMAT: Pass 'name' and 'description' as TOP-LEVEL fields on each tier object.\n❌ WRONG: { translations: { en: { name: \"Bronze\" } } }\n✅ CORRECT: { name: \"Bronze\", description: \"Entry tier\" }\n\nExample - Creating 4 tiers in ONE call:\ntiers: [\n { name: \"Bronze\", description: \"Entry tier\", conditions: [{ conditionId: \"xxx\", value: 0 }] },\n { name: \"Silver\", description: \"500+ points\", conditions: [{ conditionId: \"xxx\", value: 500 }] },\n { name: \"Gold\", description: \"1000+ points\", conditions: [{ conditionId: \"xxx\", value: 1000 }] },\n { name: \"Platinum\", description: \"Top tier\", conditions: [{ conditionId: \"xxx\", value: 2000 }] }\n]\n\nThe conditionId must match the one from tierset_get response - use the SAME conditionId for all tiers.";
|
|
74
|
+
readonly readOnly: false;
|
|
75
|
+
readonly inputSchema: {
|
|
76
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
77
|
+
tierSetId: import("zod").ZodString;
|
|
78
|
+
tiers: import("zod").ZodArray<import("zod").ZodObject<{
|
|
79
|
+
levelId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
80
|
+
name: import("zod").ZodString;
|
|
81
|
+
description: import("zod").ZodOptional<import("zod").ZodString>;
|
|
82
|
+
active: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
83
|
+
conditions: import("zod").ZodArray<import("zod").ZodObject<{
|
|
84
|
+
conditionId: import("zod").ZodString;
|
|
85
|
+
value: import("zod").ZodNumber;
|
|
86
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
87
|
+
value: number;
|
|
88
|
+
conditionId: string;
|
|
89
|
+
}, {
|
|
90
|
+
value: number;
|
|
91
|
+
conditionId: string;
|
|
92
|
+
}>, "many">;
|
|
93
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
94
|
+
name: string;
|
|
95
|
+
conditions: {
|
|
96
|
+
value: number;
|
|
97
|
+
conditionId: string;
|
|
98
|
+
}[];
|
|
99
|
+
active?: boolean | undefined;
|
|
100
|
+
description?: string | undefined;
|
|
101
|
+
levelId?: string | undefined;
|
|
102
|
+
}, {
|
|
103
|
+
name: string;
|
|
104
|
+
conditions: {
|
|
105
|
+
value: number;
|
|
106
|
+
conditionId: string;
|
|
107
|
+
}[];
|
|
108
|
+
active?: boolean | undefined;
|
|
109
|
+
description?: string | undefined;
|
|
110
|
+
levelId?: string | undefined;
|
|
111
|
+
}>, "many">;
|
|
112
|
+
};
|
|
113
|
+
readonly handler: typeof tiersetUpdateTiers;
|
|
114
|
+
}, {
|
|
115
|
+
readonly name: "ol_tierset_get_tiers";
|
|
116
|
+
readonly title: "Get Tier Configuration";
|
|
117
|
+
readonly description: "Get all tiers in a tier set. Returns levelId values that can be used for campaign targeting. Includes each tier's name and condition thresholds.";
|
|
118
|
+
readonly readOnly: true;
|
|
119
|
+
readonly inputSchema: {
|
|
120
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
121
|
+
tierSetId: import("zod").ZodString;
|
|
122
|
+
};
|
|
123
|
+
readonly handler: typeof tiersetGetTiers;
|
|
124
|
+
}];
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Re-export schemas
|
|
2
|
+
export { TierSetListInputSchema, TierSetCreateInputSchema, TierSetGetInputSchema, TierSetUpdateInputSchema, TierSetUpdateTiersInputSchema, TierSetGetTiersInputSchema, } from "./schemas.js";
|
|
3
|
+
// Re-export handlers
|
|
4
|
+
export { tiersetList, tiersetCreate, tiersetGet, tiersetUpdate, tiersetUpdateTiers, tiersetGetTiers, } from "./handlers.js";
|
|
5
|
+
// Imports for tool definitions
|
|
6
|
+
import { TierSetListInputSchema, TierSetCreateInputSchema, TierSetGetInputSchema, TierSetUpdateInputSchema, TierSetUpdateTiersInputSchema, TierSetGetTiersInputSchema, } from "./schemas.js";
|
|
7
|
+
import { tiersetList, tiersetCreate, tiersetGet, tiersetUpdate, tiersetUpdateTiers, tiersetGetTiers, } from "./handlers.js";
|
|
8
|
+
// Tool definitions
|
|
9
|
+
export const tiersetToolDefinitions = [
|
|
10
|
+
{
|
|
11
|
+
name: "ol_tierset_list",
|
|
12
|
+
title: "List Loyalty Programs",
|
|
13
|
+
description: "List all tier sets. A tier set is a CONTAINER that holds MULTIPLE tiers (e.g., Bronze/Silver/Gold). " +
|
|
14
|
+
"⚠️ ALWAYS check existing tier sets FIRST before creating - reuse if one exists. " +
|
|
15
|
+
"Returns tierSetId, name, active status, and tier count for each tier set.",
|
|
16
|
+
readOnly: true,
|
|
17
|
+
inputSchema: TierSetListInputSchema,
|
|
18
|
+
handler: tiersetList,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: "ol_tierset_create",
|
|
22
|
+
title: "Create Loyalty Program",
|
|
23
|
+
description: "Create a tier set -- a container for all tiers (e.g., Bronze/Silver/Gold/Platinum). " +
|
|
24
|
+
"KEY DECISIONS (confirm with user if not specified): " +
|
|
25
|
+
"1. Progression metric -- what drives tier advancement? totalEarnedUnits (lifetime loyalty), totalSpending (revenue-focused), activeUnits (balance-based, penalizes redemptions) " +
|
|
26
|
+
"2. Tier structure -- how many tiers and what names? (design tiers before creating) " +
|
|
27
|
+
"WORKFLOW: tierset_list (check existing, max 3 active) -> tierset_create (ONE set) -> tierset_get (get conditionId) -> tierset_update_tiers (add ALL tiers). " +
|
|
28
|
+
"REQUIRED: name, conditions array. Only name/description/conditions accepted at creation. " +
|
|
29
|
+
"NOTE: Use 'attribute' NOT 'type' in conditions. For unit-based attributes, set walletType to 'default'.",
|
|
30
|
+
readOnly: false,
|
|
31
|
+
inputSchema: TierSetCreateInputSchema,
|
|
32
|
+
handler: tiersetCreate,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: "ol_tierset_get",
|
|
36
|
+
title: "Get Loyalty Program Details",
|
|
37
|
+
description: "Get tier set details including conditionId values needed for tierset_update_tiers. " +
|
|
38
|
+
"CRITICAL: After tierset_create, call this to get the conditionId from conditions[].id. " +
|
|
39
|
+
"Use this SAME conditionId for ALL tiers when calling tierset_update_tiers.",
|
|
40
|
+
readOnly: true,
|
|
41
|
+
inputSchema: TierSetGetInputSchema,
|
|
42
|
+
handler: tiersetGet,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: "ol_tierset_update",
|
|
46
|
+
title: "Update Loyalty Program",
|
|
47
|
+
description: "Update tier set metadata (name, description, active status, downgrade settings). " +
|
|
48
|
+
"KEY DECISIONS (confirm with user if not specified): " +
|
|
49
|
+
"1. Downgrade policy -- 'none' (members never lose tier), 'automatic' (instant downgrade), 'x_days' (grace period) " +
|
|
50
|
+
"2. Active toggle -- activating affects ALL members' tier placement immediately " +
|
|
51
|
+
"Automatically preserves existing conditions. Does not modify tiers -- use tierset_update_tiers for that.",
|
|
52
|
+
readOnly: false,
|
|
53
|
+
inputSchema: TierSetUpdateInputSchema,
|
|
54
|
+
handler: tiersetUpdate,
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "ol_tierset_update_tiers",
|
|
58
|
+
title: "Configure Tier Thresholds",
|
|
59
|
+
description: `Add ALL tiers to a tier set in ONE call. A tier set is a CONTAINER - add all tiers (Bronze, Silver, Gold, etc.) to it together.
|
|
60
|
+
|
|
61
|
+
⚠️ CRITICAL: Pass ALL tiers in a SINGLE call to this endpoint. DO NOT call this multiple times with one tier each.
|
|
62
|
+
|
|
63
|
+
⚠️ INPUT FORMAT: Pass 'name' and 'description' as TOP-LEVEL fields on each tier object.
|
|
64
|
+
❌ WRONG: { translations: { en: { name: "Bronze" } } }
|
|
65
|
+
✅ CORRECT: { name: "Bronze", description: "Entry tier" }
|
|
66
|
+
|
|
67
|
+
Example - Creating 4 tiers in ONE call:
|
|
68
|
+
tiers: [
|
|
69
|
+
{ name: "Bronze", description: "Entry tier", conditions: [{ conditionId: "xxx", value: 0 }] },
|
|
70
|
+
{ name: "Silver", description: "500+ points", conditions: [{ conditionId: "xxx", value: 500 }] },
|
|
71
|
+
{ name: "Gold", description: "1000+ points", conditions: [{ conditionId: "xxx", value: 1000 }] },
|
|
72
|
+
{ name: "Platinum", description: "Top tier", conditions: [{ conditionId: "xxx", value: 2000 }] }
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
The conditionId must match the one from tierset_get response - use the SAME conditionId for all tiers.`,
|
|
76
|
+
readOnly: false,
|
|
77
|
+
inputSchema: TierSetUpdateTiersInputSchema,
|
|
78
|
+
handler: tiersetUpdateTiers,
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: "ol_tierset_get_tiers",
|
|
82
|
+
title: "Get Tier Configuration",
|
|
83
|
+
description: "Get all tiers in a tier set. Returns levelId values that can be used for campaign targeting. Includes each tier's name and condition thresholds.",
|
|
84
|
+
readOnly: true,
|
|
85
|
+
inputSchema: TierSetGetTiersInputSchema,
|
|
86
|
+
handler: tiersetGetTiers,
|
|
87
|
+
},
|
|
88
|
+
];
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const TierSetListInputSchema: {
|
|
3
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
4
|
+
page: z.ZodOptional<z.ZodNumber>;
|
|
5
|
+
perPage: z.ZodOptional<z.ZodNumber>;
|
|
6
|
+
};
|
|
7
|
+
export declare const TierSetCreateInputSchema: {
|
|
8
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
9
|
+
name: z.ZodString;
|
|
10
|
+
description: z.ZodOptional<z.ZodString>;
|
|
11
|
+
conditions: z.ZodArray<z.ZodObject<{
|
|
12
|
+
attribute: z.ZodEnum<["activeUnits", "totalEarnedUnits", "totalSpending", "monthsSinceJoiningProgram", "cumulatedEarnedUnits"]>;
|
|
13
|
+
walletType: z.ZodOptional<z.ZodString>;
|
|
14
|
+
}, "strip", z.ZodTypeAny, {
|
|
15
|
+
attribute: "activeUnits" | "totalEarnedUnits" | "totalSpending" | "monthsSinceJoiningProgram" | "cumulatedEarnedUnits";
|
|
16
|
+
walletType?: string | undefined;
|
|
17
|
+
}, {
|
|
18
|
+
attribute: "activeUnits" | "totalEarnedUnits" | "totalSpending" | "monthsSinceJoiningProgram" | "cumulatedEarnedUnits";
|
|
19
|
+
walletType?: string | undefined;
|
|
20
|
+
}>, "many">;
|
|
21
|
+
};
|
|
22
|
+
export declare const TierSetGetInputSchema: {
|
|
23
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
24
|
+
tierSetId: z.ZodString;
|
|
25
|
+
};
|
|
26
|
+
export declare const TierSetUpdateInputSchema: {
|
|
27
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
28
|
+
tierSetId: z.ZodString;
|
|
29
|
+
name: z.ZodOptional<z.ZodString>;
|
|
30
|
+
description: z.ZodOptional<z.ZodString>;
|
|
31
|
+
active: z.ZodOptional<z.ZodBoolean>;
|
|
32
|
+
downgrade: z.ZodOptional<z.ZodObject<{
|
|
33
|
+
mode: z.ZodEnum<["none", "automatic", "x_days"]>;
|
|
34
|
+
days: z.ZodOptional<z.ZodNumber>;
|
|
35
|
+
}, "strip", z.ZodTypeAny, {
|
|
36
|
+
mode: "none" | "automatic" | "x_days";
|
|
37
|
+
days?: number | undefined;
|
|
38
|
+
}, {
|
|
39
|
+
mode: "none" | "automatic" | "x_days";
|
|
40
|
+
days?: number | undefined;
|
|
41
|
+
}>>;
|
|
42
|
+
};
|
|
43
|
+
export declare const TierSetUpdateTiersInputSchema: {
|
|
44
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
45
|
+
tierSetId: z.ZodString;
|
|
46
|
+
tiers: z.ZodArray<z.ZodObject<{
|
|
47
|
+
levelId: z.ZodOptional<z.ZodString>;
|
|
48
|
+
name: z.ZodString;
|
|
49
|
+
description: z.ZodOptional<z.ZodString>;
|
|
50
|
+
active: z.ZodOptional<z.ZodBoolean>;
|
|
51
|
+
conditions: z.ZodArray<z.ZodObject<{
|
|
52
|
+
conditionId: z.ZodString;
|
|
53
|
+
value: z.ZodNumber;
|
|
54
|
+
}, "strip", z.ZodTypeAny, {
|
|
55
|
+
value: number;
|
|
56
|
+
conditionId: string;
|
|
57
|
+
}, {
|
|
58
|
+
value: number;
|
|
59
|
+
conditionId: string;
|
|
60
|
+
}>, "many">;
|
|
61
|
+
}, "strip", z.ZodTypeAny, {
|
|
62
|
+
name: string;
|
|
63
|
+
conditions: {
|
|
64
|
+
value: number;
|
|
65
|
+
conditionId: string;
|
|
66
|
+
}[];
|
|
67
|
+
active?: boolean | undefined;
|
|
68
|
+
description?: string | undefined;
|
|
69
|
+
levelId?: string | undefined;
|
|
70
|
+
}, {
|
|
71
|
+
name: string;
|
|
72
|
+
conditions: {
|
|
73
|
+
value: number;
|
|
74
|
+
conditionId: string;
|
|
75
|
+
}[];
|
|
76
|
+
active?: boolean | undefined;
|
|
77
|
+
description?: string | undefined;
|
|
78
|
+
levelId?: string | undefined;
|
|
79
|
+
}>, "many">;
|
|
80
|
+
};
|
|
81
|
+
export declare const TierSetGetTiersInputSchema: {
|
|
82
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
83
|
+
tierSetId: z.ZodString;
|
|
84
|
+
};
|
|
85
|
+
export type TierSetListInput = {
|
|
86
|
+
storeCode?: string;
|
|
87
|
+
page?: number;
|
|
88
|
+
perPage?: number;
|
|
89
|
+
};
|
|
90
|
+
export type TierSetCreateInput = {
|
|
91
|
+
storeCode?: string;
|
|
92
|
+
name: string;
|
|
93
|
+
description?: string;
|
|
94
|
+
conditions: {
|
|
95
|
+
attribute: string;
|
|
96
|
+
walletType?: string;
|
|
97
|
+
}[];
|
|
98
|
+
};
|
|
99
|
+
export type TierSetGetInput = {
|
|
100
|
+
storeCode?: string;
|
|
101
|
+
tierSetId: string;
|
|
102
|
+
};
|
|
103
|
+
export type TierSetUpdateInput = {
|
|
104
|
+
storeCode?: string;
|
|
105
|
+
tierSetId: string;
|
|
106
|
+
name?: string;
|
|
107
|
+
description?: string;
|
|
108
|
+
active?: boolean;
|
|
109
|
+
downgrade?: {
|
|
110
|
+
mode: string;
|
|
111
|
+
days?: number;
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
export type TierSetUpdateTiersInput = {
|
|
115
|
+
storeCode?: string;
|
|
116
|
+
tierSetId: string;
|
|
117
|
+
tiers: {
|
|
118
|
+
levelId?: string;
|
|
119
|
+
name: string;
|
|
120
|
+
description?: string;
|
|
121
|
+
active?: boolean;
|
|
122
|
+
conditions: {
|
|
123
|
+
conditionId: string;
|
|
124
|
+
value: number;
|
|
125
|
+
}[];
|
|
126
|
+
}[];
|
|
127
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { TierSetAttributeEnum, DowngradeModeEnum, } from "../../types/schemas/tierset.js";
|
|
3
|
+
export const TierSetListInputSchema = {
|
|
4
|
+
storeCode: z.string().optional().describe("INTERNAL: Auto-configured from server settings. NEVER ask the user for this value. Only set if the user explicitly requests a different store."),
|
|
5
|
+
page: z.number().optional().describe("Page number for pagination (starts at 1)."),
|
|
6
|
+
perPage: z.number().optional().describe("Number of items per page."),
|
|
7
|
+
};
|
|
8
|
+
export const TierSetCreateInputSchema = {
|
|
9
|
+
storeCode: z.string().optional().describe("INTERNAL: Auto-configured from server settings. NEVER ask the user for this value. Only set if the user explicitly requests a different store."),
|
|
10
|
+
name: z.string().describe("Name of the tier set."),
|
|
11
|
+
description: z.string().optional().describe("Description of the tier set."),
|
|
12
|
+
conditions: z.array(z.object({
|
|
13
|
+
attribute: TierSetAttributeEnum.describe("The condition field name. IMPORTANT: Use 'attribute' NOT 'type'. " +
|
|
14
|
+
"BUSINESS DECISION: Determines what drives tier progression. " +
|
|
15
|
+
"totalEarnedUnits = lifetime loyalty rewards engagement. totalSpending = revenue-focused. " +
|
|
16
|
+
"activeUnits = balance-based (penalizes redemptions). " +
|
|
17
|
+
"NOTE: 'earnedUnits' is NOT valid -- use 'totalEarnedUnits'."),
|
|
18
|
+
walletType: z.string().optional().describe("Wallet type CODE (not UUID). Required for unit-based attributes (activeUnits, totalEarnedUnits, cumulatedEarnedUnits). " +
|
|
19
|
+
"Use wallet_type_list to find walletType.code (e.g., 'default')."),
|
|
20
|
+
})).describe("Array of conditions that define tier progression criteria. " +
|
|
21
|
+
"EXACT FORMAT: [{ \"attribute\": \"totalEarnedUnits\", \"walletType\": \"default\" }]. " +
|
|
22
|
+
"Use 'attribute' NOT 'type' for the condition field name."),
|
|
23
|
+
// NOTE: downgrade and active are NOT supported at creation time - use tierset_update after creation
|
|
24
|
+
};
|
|
25
|
+
export const TierSetGetInputSchema = {
|
|
26
|
+
storeCode: z.string().optional().describe("INTERNAL: Auto-configured from server settings. NEVER ask the user for this value. Only set if the user explicitly requests a different store."),
|
|
27
|
+
tierSetId: z.string().describe("The tier set ID to retrieve."),
|
|
28
|
+
};
|
|
29
|
+
export const TierSetUpdateInputSchema = {
|
|
30
|
+
storeCode: z.string().optional().describe("INTERNAL: Auto-configured from server settings. NEVER ask the user for this value. Only set if the user explicitly requests a different store."),
|
|
31
|
+
tierSetId: z.string().describe("The tier set ID to update."),
|
|
32
|
+
name: z.string().optional().describe("New name for the tier set."),
|
|
33
|
+
description: z.string().optional().describe("New description for the tier set."),
|
|
34
|
+
active: z.boolean().optional().describe("Whether the tier set is active. " +
|
|
35
|
+
"BUSINESS IMPACT: Activating affects ALL members' tier placement immediately."),
|
|
36
|
+
downgrade: z.object({
|
|
37
|
+
mode: DowngradeModeEnum.describe("BUSINESS DECISION: 'none' = members never lose tier (generous but expensive). " +
|
|
38
|
+
"'automatic' = instant downgrade when conditions not met (strict, controls costs). " +
|
|
39
|
+
"'x_days' = grace period before downgrade (balanced approach)."),
|
|
40
|
+
days: z.number().optional().describe("Grace period in days (required when mode='x_days'). Typical values: 30-90 days."),
|
|
41
|
+
}).optional().describe("Downgrade configuration. Determines if and when members lose tier status."),
|
|
42
|
+
};
|
|
43
|
+
export const TierSetUpdateTiersInputSchema = {
|
|
44
|
+
storeCode: z.string().optional().describe("INTERNAL: Auto-configured from server settings. NEVER ask the user for this value. Only set if the user explicitly requests a different store."),
|
|
45
|
+
tierSetId: z.string().describe("The tier set ID to update tiers for."),
|
|
46
|
+
tiers: z.array(z.object({
|
|
47
|
+
levelId: z.string().optional().describe("Existing level ID (for updates). Omit for new tiers."),
|
|
48
|
+
name: z.string().describe("Tier name as a TOP-LEVEL string (e.g., 'Bronze'). NOT in translations wrapper."),
|
|
49
|
+
description: z.string().optional().describe("Tier description as a TOP-LEVEL string. NOT in translations wrapper."),
|
|
50
|
+
active: z.boolean().optional().describe("Whether the tier is active. Defaults to true."),
|
|
51
|
+
conditions: z.array(z.object({
|
|
52
|
+
conditionId: z.string().describe("Condition ID from tierset_get response."),
|
|
53
|
+
value: z.number().describe("Threshold value for this tier. " +
|
|
54
|
+
"BUSINESS IMPACT: Tier thresholds define program difficulty. Too low = everyone at top tier (budget bloat). " +
|
|
55
|
+
"Too high = empty tiers (member frustration). Industry guideline: ~50% at base, ~5% at top."),
|
|
56
|
+
})).describe("Array of condition thresholds. Each uses conditionId from tierset_get."),
|
|
57
|
+
})).describe("Array of tier definitions. Each tier needs 'name' as a direct string field, NOT wrapped in translations."),
|
|
58
|
+
};
|
|
59
|
+
export const TierSetGetTiersInputSchema = {
|
|
60
|
+
storeCode: z.string().optional().describe("INTERNAL: Auto-configured from server settings. NEVER ask the user for this value. Only set if the user explicitly requests a different store."),
|
|
61
|
+
tierSetId: z.string().describe("The tier set ID to get tiers for."),
|
|
62
|
+
};
|