@open-loyalty/mcp-server 1.5.3 → 1.7.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.
Files changed (132) hide show
  1. package/dist/config.d.ts +4 -0
  2. package/dist/config.js +11 -0
  3. package/dist/index.js +0 -8
  4. package/dist/server.js +13 -0
  5. package/dist/tools/achievement/handlers.js +47 -0
  6. package/dist/tools/achievement/index.d.ts +11 -4
  7. package/dist/tools/achievement/index.js +12 -1
  8. package/dist/tools/achievement/schemas.d.ts +4 -4
  9. package/dist/tools/achievement/schemas.js +13 -12
  10. package/dist/tools/admin/handlers.d.ts +48 -0
  11. package/dist/tools/admin/handlers.js +159 -0
  12. package/dist/tools/admin/index.d.ts +86 -0
  13. package/dist/tools/admin/index.js +64 -0
  14. package/dist/tools/admin/schemas.d.ts +40 -0
  15. package/dist/tools/admin/schemas.js +40 -0
  16. package/dist/tools/analytics/handlers.d.ts +42 -0
  17. package/dist/tools/analytics/handlers.js +282 -0
  18. package/dist/tools/analytics/index.d.ts +108 -0
  19. package/dist/tools/analytics/index.js +91 -0
  20. package/dist/tools/analytics/schemas.d.ts +42 -0
  21. package/dist/tools/analytics/schemas.js +47 -0
  22. package/dist/tools/apikey/handlers.d.ts +15 -0
  23. package/dist/tools/apikey/handlers.js +53 -0
  24. package/dist/tools/apikey/index.d.ts +41 -0
  25. package/dist/tools/apikey/index.js +38 -0
  26. package/dist/tools/apikey/schemas.d.ts +31 -0
  27. package/dist/tools/apikey/schemas.js +15 -0
  28. package/dist/tools/audit/handlers.d.ts +20 -0
  29. package/dist/tools/audit/handlers.js +82 -0
  30. package/dist/tools/audit/index.d.ts +36 -0
  31. package/dist/tools/audit/index.js +28 -0
  32. package/dist/tools/audit/schemas.d.ts +62 -0
  33. package/dist/tools/audit/schemas.js +18 -0
  34. package/dist/tools/badge/handlers.d.ts +45 -0
  35. package/dist/tools/badge/handlers.js +135 -0
  36. package/dist/tools/badge/index.d.ts +68 -0
  37. package/dist/tools/badge/index.js +47 -0
  38. package/dist/tools/badge/schemas.d.ts +37 -0
  39. package/dist/tools/badge/schemas.js +31 -0
  40. package/dist/tools/campaign/handlers.js +61 -0
  41. package/dist/tools/campaign/index.d.ts +12 -0
  42. package/dist/tools/campaign/index.js +20 -1
  43. package/dist/tools/campaign/member-handlers.js +37 -1
  44. package/dist/tools/campaign/schemas.js +16 -14
  45. package/dist/tools/custom-event/handlers.d.ts +98 -0
  46. package/dist/tools/custom-event/handlers.js +238 -0
  47. package/dist/tools/custom-event/index.d.ts +139 -0
  48. package/dist/tools/custom-event/index.js +78 -0
  49. package/dist/tools/custom-event/schemas.d.ts +87 -0
  50. package/dist/tools/custom-event/schemas.js +59 -0
  51. package/dist/tools/export/handlers.d.ts +29 -0
  52. package/dist/tools/export/handlers.js +128 -0
  53. package/dist/tools/export/index.d.ts +56 -0
  54. package/dist/tools/export/index.js +46 -0
  55. package/dist/tools/export/schemas.d.ts +42 -0
  56. package/dist/tools/export/schemas.js +41 -0
  57. package/dist/tools/import/handlers.d.ts +22 -0
  58. package/dist/tools/import/handlers.js +123 -0
  59. package/dist/tools/import/index.d.ts +45 -0
  60. package/dist/tools/import/index.js +41 -0
  61. package/dist/tools/import/schemas.d.ts +57 -0
  62. package/dist/tools/import/schemas.js +39 -0
  63. package/dist/tools/index.d.ts +1 -0
  64. package/dist/tools/index.js +11 -11
  65. package/dist/tools/member/handlers.js +30 -0
  66. package/dist/tools/member/index.d.ts +10 -0
  67. package/dist/tools/member/index.js +10 -0
  68. package/dist/tools/member/schemas.js +13 -13
  69. package/dist/tools/points/handlers.js +73 -0
  70. package/dist/tools/points/index.d.ts +6 -0
  71. package/dist/tools/points/index.js +6 -0
  72. package/dist/tools/points/schemas.js +1 -1
  73. package/dist/tools/referral/index.d.ts +3 -0
  74. package/dist/tools/referral/index.js +3 -0
  75. package/dist/tools/reward/handlers.js +21 -13
  76. package/dist/tools/reward/index.d.ts +9 -0
  77. package/dist/tools/reward/index.js +12 -1
  78. package/dist/tools/reward/schemas.js +2 -2
  79. package/dist/tools/role/handlers.d.ts +35 -0
  80. package/dist/tools/role/handlers.js +127 -0
  81. package/dist/tools/role/index.d.ts +99 -0
  82. package/dist/tools/role/index.js +65 -0
  83. package/dist/tools/role/schemas.d.ts +56 -0
  84. package/dist/tools/role/schemas.js +35 -0
  85. package/dist/tools/segment/handlers.js +68 -1
  86. package/dist/tools/segment/index.d.ts +9 -0
  87. package/dist/tools/segment/index.js +13 -0
  88. package/dist/tools/segment/schemas.js +8 -5
  89. package/dist/tools/store/handlers.d.ts +25 -0
  90. package/dist/tools/store/handlers.js +89 -0
  91. package/dist/tools/store/index.d.ts +55 -0
  92. package/dist/tools/store/index.js +46 -0
  93. package/dist/tools/store/schemas.d.ts +38 -0
  94. package/dist/tools/store/schemas.js +23 -0
  95. package/dist/tools/tierset/handlers.js +92 -1
  96. package/dist/tools/tierset/index.d.ts +6 -0
  97. package/dist/tools/tierset/index.js +8 -1
  98. package/dist/tools/transaction/handlers.js +40 -0
  99. package/dist/tools/transaction/index.d.ts +4 -0
  100. package/dist/tools/transaction/index.js +4 -0
  101. package/dist/tools/transaction/schemas.js +3 -3
  102. package/dist/tools/wallet-type/index.d.ts +4 -0
  103. package/dist/tools/wallet-type/index.js +5 -1
  104. package/dist/tools/webhook/handlers.d.ts +34 -0
  105. package/dist/tools/webhook/handlers.js +147 -0
  106. package/dist/tools/webhook/index.d.ts +97 -0
  107. package/dist/tools/webhook/index.js +65 -0
  108. package/dist/tools/webhook/schemas.d.ts +72 -0
  109. package/dist/tools/{webhook.js → webhook/schemas.js} +0 -140
  110. package/dist/types/schemas/tierset.js +3 -1
  111. package/package.json +1 -1
  112. package/dist/tools/admin.d.ts +0 -165
  113. package/dist/tools/admin.js +0 -205
  114. package/dist/tools/analytics.d.ts +0 -180
  115. package/dist/tools/analytics.js +0 -255
  116. package/dist/tools/apikey.d.ts +0 -79
  117. package/dist/tools/apikey.js +0 -85
  118. package/dist/tools/audit.d.ts +0 -111
  119. package/dist/tools/audit.js +0 -94
  120. package/dist/tools/badge.d.ts +0 -143
  121. package/dist/tools/badge.js +0 -174
  122. package/dist/tools/custom-event.d.ts +0 -315
  123. package/dist/tools/custom-event.js +0 -271
  124. package/dist/tools/export.d.ts +0 -118
  125. package/dist/tools/export.js +0 -152
  126. package/dist/tools/import.d.ts +0 -116
  127. package/dist/tools/import.js +0 -143
  128. package/dist/tools/role.d.ts +0 -180
  129. package/dist/tools/role.js +0 -173
  130. package/dist/tools/store.d.ts +0 -109
  131. package/dist/tools/store.js +0 -125
  132. package/dist/tools/webhook.d.ts +0 -192
@@ -1,5 +1,5 @@
1
1
  import { apiGet, apiPost } from "../../client/http.js";
2
- import { formatApiError } from "../../utils/errors.js";
2
+ import { formatApiError, OpenLoyaltyError } from "../../utils/errors.js";
3
3
  import { getStoreCode } from "../../config.js";
4
4
  // Code management handlers
5
5
  export async function campaignGenerateCodes(input) {
@@ -9,6 +9,15 @@ export async function campaignGenerateCodes(input) {
9
9
  return { codesGenerated: input.quantity };
10
10
  }
11
11
  catch (error) {
12
+ const axiosError = error;
13
+ if (axiosError.response?.status === 404) {
14
+ throw new OpenLoyaltyError({
15
+ code: "NOT_FOUND",
16
+ message: `Campaign '${input.campaignId}' not found`,
17
+ hint: "Use ol_campaign_list() to find existing campaigns and their IDs. The campaignId may be incorrect or the campaign may have been deleted.",
18
+ relatedTool: "ol_campaign_generate_codes",
19
+ });
20
+ }
12
21
  throw formatApiError(error, "ol_campaign_generate_codes");
13
22
  }
14
23
  }
@@ -83,6 +92,15 @@ export async function campaignGetAvailable(input) {
83
92
  };
84
93
  }
85
94
  catch (error) {
95
+ const axiosError = error;
96
+ if (axiosError.response?.status === 404) {
97
+ throw new OpenLoyaltyError({
98
+ code: "NOT_FOUND",
99
+ message: `Member '${input.memberId}' not found`,
100
+ hint: "Use ol_member_list() to search for the member by email, name, or phone. The member ID may be incorrect.",
101
+ relatedTool: "ol_campaign_get_available",
102
+ });
103
+ }
86
104
  throw formatApiError(error, "ol_campaign_get_available");
87
105
  }
88
106
  }
@@ -117,6 +135,15 @@ export async function campaignGetVisible(input) {
117
135
  };
118
136
  }
119
137
  catch (error) {
138
+ const axiosError = error;
139
+ if (axiosError.response?.status === 404) {
140
+ throw new OpenLoyaltyError({
141
+ code: "NOT_FOUND",
142
+ message: `Member '${input.memberId}' not found`,
143
+ hint: "Use ol_member_list() to search for the member by email, name, or phone. The member ID may be incorrect.",
144
+ relatedTool: "ol_campaign_get_visible",
145
+ });
146
+ }
120
147
  throw formatApiError(error, "ol_campaign_get_visible");
121
148
  }
122
149
  }
@@ -154,6 +181,15 @@ export async function campaignGetLeaderboard(input) {
154
181
  };
155
182
  }
156
183
  catch (error) {
184
+ const axiosError = error;
185
+ if (axiosError.response?.status === 404) {
186
+ throw new OpenLoyaltyError({
187
+ code: "NOT_FOUND",
188
+ message: `Campaign '${input.campaignId}' not found`,
189
+ hint: "Use ol_campaign_list() to find existing campaigns and their IDs.",
190
+ relatedTool: "ol_campaign_get_leaderboard",
191
+ });
192
+ }
157
193
  throw formatApiError(error, "ol_campaign_get_leaderboard");
158
194
  }
159
195
  }
@@ -18,8 +18,8 @@ const CampaignEffectInputSchema = z.object({
18
18
  "Conditional: 'event.body.minutes_before >= 60 ? 25 : 0'. " +
19
19
  "BUSINESS IMPACT: 'transaction.grossValue * 10' on $500 avg transaction = 5,000 points/purchase. " +
20
20
  "At $0.01/point, that is a 10% return rate. Confirm the formula and earn rate with the user."),
21
- walletCode: z.string().optional().describe("Wallet code for points (default wallet if not specified)."),
22
- rewardId: z.string().optional().describe("Reward ID (required for give_reward effect)."),
21
+ walletCode: z.string().optional().describe("Wallet code for points (default wallet if not specified). Use ol_wallet_type_list to find valid codes."),
22
+ rewardId: z.string().optional().describe("Reward ID (required for give_reward effect). Use ol_reward_list to find valid rewardId values."),
23
23
  customAttributeKey: z.string().optional().describe("Custom attribute key (for assign/remove member custom attribute effects)."),
24
24
  customAttributeValueRule: z.string().optional().describe("Custom attribute value rule."),
25
25
  });
@@ -52,8 +52,8 @@ const CampaignRuleInputSchema = z.object({
52
52
  });
53
53
  // Activity input schema
54
54
  const CampaignActivityInputSchema = z.object({
55
- startsAt: z.string().describe("Campaign start date/time (ISO format: YYYY-MM-DD HH:mm+TZ). REQUIRED."),
56
- endsAt: z.string().optional().describe("Campaign end date/time (ISO format). " +
55
+ startsAt: z.string().describe("Campaign start date/time (format: 'YYYY-MM-DD HH:mm+TZ', e.g., '2026-01-01 00:00+00:00'). REQUIRED."),
56
+ endsAt: z.string().optional().describe("Campaign end date/time (format: 'YYYY-MM-DD HH:mm+TZ', e.g., '2026-12-31 23:59+00:00'). " +
57
57
  "BUSINESS IMPACT: If not specified, campaign runs indefinitely -- this is an open-ended budget commitment. " +
58
58
  "Confirm with user whether the campaign should have an end date."),
59
59
  });
@@ -89,15 +89,15 @@ const CampaignLimitsInputSchema = z.object({
89
89
  }).optional();
90
90
  // Label input schema
91
91
  const CampaignLabelInputSchema = z.object({
92
- key: z.string().describe("Label key."),
93
- value: z.string().describe("Label value."),
92
+ key: z.string().describe("Label key (e.g., 'category', 'channel', 'season')."),
93
+ value: z.string().describe("Label value (e.g., 'electronics', 'online', 'summer')."),
94
94
  });
95
95
  // Transaction item for simulation
96
96
  const SimulateTransactionItemSchema = z.object({
97
97
  sku: z.string().describe("Product SKU."),
98
98
  name: z.string().describe("Product name."),
99
- qty: z.union([z.string(), z.number()]).optional().describe("Item quantity."),
100
- grossValue: z.union([z.string(), z.number()]).describe("Item gross value."),
99
+ qty: z.union([z.string(), z.number()]).optional().describe("Item quantity. Accepts string or number (API is flexible on type)."),
100
+ grossValue: z.union([z.string(), z.number()]).describe("Item gross value. Accepts string or number (API is flexible on type)."),
101
101
  category: z.string().optional().describe("Product category."),
102
102
  maker: z.string().optional().describe("Product maker/brand."),
103
103
  labels: z.array(z.object({
@@ -120,7 +120,7 @@ const SimulateTransactionSchema = z.object({
120
120
  }).optional();
121
121
  // Custom event for simulation
122
122
  const SimulateCustomEventSchema = z.object({
123
- eventCode: z.string().describe("Custom event code (must match campaign trigger event)."),
123
+ eventCode: z.string().describe("Custom event code (must match campaign trigger event). Use ol_custom_event_schema_list to find valid event codes."),
124
124
  attributes: z.record(z.unknown()).optional().describe("Custom event attributes."),
125
125
  }).optional();
126
126
  // Customer for simulation
@@ -156,7 +156,8 @@ export const CampaignUpdateInputSchema = {
156
156
  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."),
157
157
  campaignId: z.string().describe("The campaign ID (UUID) to update."),
158
158
  type: CampaignTypeEnum.describe("Campaign type: direct or referral."),
159
- trigger: CampaignTriggerEnum.describe("What triggers the campaign: transaction, custom_event, time, achievement, geolocation, etc."),
159
+ trigger: CampaignTriggerEnum.describe("What triggers the campaign. Valid values: transaction, custom_event, time, achievement, " +
160
+ "custom_event_unique_code, leaderboard, internal_event, return_transaction, challenge, fortune_wheel."),
160
161
  translations: z.object({
161
162
  en: z.object({
162
163
  name: z.string().describe("Campaign name in English (REQUIRED)."),
@@ -164,8 +165,8 @@ export const CampaignUpdateInputSchema = {
164
165
  }),
165
166
  }).passthrough().describe("Translations object with at least 'en' key."),
166
167
  activity: z.object({
167
- startsAt: z.string().describe("Campaign start date/time (ISO format: YYYY-MM-DD HH:mm+TZ). REQUIRED."),
168
- endsAt: z.string().optional().describe("Campaign end date/time (ISO format). If not specified, campaign runs indefinitely."),
168
+ startsAt: z.string().describe("Campaign start date/time (format: 'YYYY-MM-DD HH:mm+TZ', e.g., '2026-01-01 00:00+00:00'). REQUIRED."),
169
+ endsAt: z.string().optional().describe("Campaign end date/time (format: 'YYYY-MM-DD HH:mm+TZ', e.g., '2026-12-31 23:59+00:00'). If not specified, campaign runs indefinitely."),
169
170
  }).describe("Campaign active period with required startsAt."),
170
171
  rules: z.array(z.object({
171
172
  name: z.string().describe("Rule name (required)."),
@@ -285,7 +286,8 @@ export const CampaignGetLeaderboardInputSchema = {
285
286
  export const CampaignCreateInputSchema = {
286
287
  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."),
287
288
  type: CampaignTypeEnum.describe("Campaign type: direct (standard) or referral (for referral programs)."),
288
- trigger: CampaignTriggerEnum.describe("What triggers the campaign: transaction, custom_event, time, achievement, etc."),
289
+ trigger: CampaignTriggerEnum.describe("What triggers the campaign. Valid values: transaction, custom_event, time, achievement, " +
290
+ "custom_event_unique_code, leaderboard, internal_event, return_transaction, challenge, fortune_wheel."),
289
291
  translations: TranslationsInputSchema,
290
292
  activity: CampaignActivityInputSchema.describe("Campaign active period with required startsAt and optional endsAt."),
291
293
  rules: z.array(CampaignRuleInputSchema).describe("Array of rules defining when and what effects to apply. Each rule requires a name."),
@@ -300,7 +302,7 @@ export const CampaignCreateInputSchema = {
300
302
  active: z.boolean().optional().describe("Whether campaign is active (default: false)."),
301
303
  displayOrder: z.number().optional().describe("Display order for sorting campaigns."),
302
304
  labels: z.array(CampaignLabelInputSchema).optional().describe("Custom labels/tags for the campaign."),
303
- event: z.string().optional().describe("Custom event name (required for custom_event trigger). Must match an existing custom event schema."),
305
+ event: z.string().optional().describe("Custom event name (required for custom_event trigger). Must match an existing custom event schema. Use ol_custom_event_schema_list to find valid event codes."),
304
306
  achievementId: z.string().optional().describe("Achievement ID (required for trigger='achievement'). " +
305
307
  "Use achievement_create first, then pass the returned achievementId here to award points/rewards when members complete that achievement."),
306
308
  };
@@ -0,0 +1,98 @@
1
+ interface CustomEventSchemaItem {
2
+ eventType: string;
3
+ name: string;
4
+ schema?: {
5
+ fields?: Array<{
6
+ name: string;
7
+ type: string;
8
+ description?: string;
9
+ }>;
10
+ };
11
+ active: boolean;
12
+ createdAt?: string;
13
+ }
14
+ export declare function customEventSchemaList(input: {
15
+ storeCode?: string;
16
+ page?: number;
17
+ perPage?: number;
18
+ eventType?: string;
19
+ name?: string;
20
+ active?: boolean;
21
+ }): Promise<{
22
+ schemas: CustomEventSchemaItem[];
23
+ total: {
24
+ all?: number;
25
+ filtered?: number;
26
+ };
27
+ }>;
28
+ export declare function customEventSchemaGet(input: {
29
+ storeCode?: string;
30
+ eventType: string;
31
+ }): Promise<CustomEventSchemaItem>;
32
+ export declare function customEventSchemaCreate(input: {
33
+ storeCode?: string;
34
+ eventType: string;
35
+ name: string;
36
+ fields: Array<{
37
+ name: string;
38
+ type: string;
39
+ description?: string;
40
+ }>;
41
+ active?: boolean;
42
+ }): Promise<void>;
43
+ interface CustomEventSchemaUpdateInput {
44
+ storeCode?: string;
45
+ eventType: string;
46
+ name: string;
47
+ fields: Array<{
48
+ name: string;
49
+ type: string;
50
+ description?: string;
51
+ }>;
52
+ active?: boolean;
53
+ }
54
+ export declare function customEventSchemaUpdate(input: CustomEventSchemaUpdateInput): Promise<void>;
55
+ export declare function customEventSchemaActivate(input: {
56
+ storeCode?: string;
57
+ eventType: string;
58
+ active: boolean;
59
+ }): Promise<void>;
60
+ interface CustomEventSendInput {
61
+ storeCode?: string;
62
+ eventType: string;
63
+ customerData: {
64
+ customerId?: string;
65
+ email?: string;
66
+ phone?: string;
67
+ loyaltyCardNumber?: string;
68
+ };
69
+ eventDate: string;
70
+ body?: Record<string, unknown>;
71
+ eventId?: string;
72
+ }
73
+ export declare function customEventSend(input: CustomEventSendInput): Promise<{
74
+ customEventId?: string;
75
+ }>;
76
+ interface CustomEventItem {
77
+ customEventId: string;
78
+ type: string;
79
+ customerId?: string;
80
+ eventDate?: string;
81
+ body?: Record<string, unknown>;
82
+ createdAt?: string;
83
+ }
84
+ export declare function customEventList(input: {
85
+ storeCode?: string;
86
+ page?: number;
87
+ perPage?: number;
88
+ type?: string;
89
+ customerId?: string;
90
+ email?: string;
91
+ }): Promise<{
92
+ events: CustomEventItem[];
93
+ total: {
94
+ all?: number;
95
+ filtered?: number;
96
+ };
97
+ }>;
98
+ export {};
@@ -0,0 +1,238 @@
1
+ import { apiGet, apiPost, apiPut } from "../../client/http.js";
2
+ import { formatApiError, OpenLoyaltyError } from "../../utils/errors.js";
3
+ import axios from "axios";
4
+ import { getStoreCode } from "../../config.js";
5
+ export async function customEventSchemaList(input) {
6
+ const storeCode = getStoreCode(input.storeCode);
7
+ const params = new URLSearchParams();
8
+ if (input.page)
9
+ params.append("_page", String(input.page));
10
+ if (input.perPage)
11
+ params.append("_itemsOnPage", String(input.perPage));
12
+ if (input.eventType)
13
+ params.append("eventType", input.eventType);
14
+ if (input.name)
15
+ params.append("name", input.name);
16
+ if (input.active !== undefined)
17
+ params.append("active", String(input.active));
18
+ const queryString = params.toString();
19
+ const url = `/${storeCode}/customEvent/schema${queryString ? `?${queryString}` : ""}`;
20
+ try {
21
+ const response = await apiGet(url);
22
+ const total = response.total || {};
23
+ return {
24
+ schemas: response.items || [],
25
+ total: {
26
+ all: typeof total.all === "number" ? total.all : undefined,
27
+ filtered: typeof total.filtered === "number" ? total.filtered : undefined,
28
+ },
29
+ };
30
+ }
31
+ catch (error) {
32
+ if (axios.isAxiosError(error) && error.response?.status === 404) {
33
+ throw new OpenLoyaltyError({
34
+ code: "STORE_NOT_FOUND",
35
+ message: "Cannot list custom event schemas - store not found",
36
+ hint: "Use ol_store_list() to verify the store code is correct.",
37
+ relatedTool: "ol_custom_event_schema_list",
38
+ });
39
+ }
40
+ if (axios.isAxiosError(error) && error.response?.status === 403) {
41
+ throw new OpenLoyaltyError({
42
+ code: "CUSTOM_EVENT_PERMISSION_DENIED",
43
+ message: "You don't have permission to view custom event schemas",
44
+ hint: "Custom event management requires the EVENTS:VIEW permission. Use ol_admin_get_permissions() to check your access.",
45
+ relatedTool: "ol_custom_event_schema_list",
46
+ });
47
+ }
48
+ throw formatApiError(error, "ol_custom_event_schema_list");
49
+ }
50
+ }
51
+ export async function customEventSchemaGet(input) {
52
+ const storeCode = getStoreCode(input.storeCode);
53
+ try {
54
+ const response = await apiGet(`/${storeCode}/customEvent/schema/${input.eventType}`);
55
+ return response;
56
+ }
57
+ catch (error) {
58
+ if (error.response?.status === 404) {
59
+ throw new OpenLoyaltyError({ code: "NOT_FOUND", message: `Custom event schema '${input.eventType}' not found`,
60
+ hint: "Use ol_custom_event_schema_list() to find existing event schemas.", relatedTool: "ol_custom_event_schema_get" });
61
+ }
62
+ throw formatApiError(error, "ol_custom_event_schema_get");
63
+ }
64
+ }
65
+ export async function customEventSchemaCreate(input) {
66
+ const storeCode = getStoreCode(input.storeCode);
67
+ const schemaPayload = {
68
+ customEventSchema: {
69
+ eventType: input.eventType,
70
+ name: input.name,
71
+ schema: {
72
+ fields: input.fields,
73
+ },
74
+ active: {
75
+ isActive: input.active ?? true,
76
+ },
77
+ },
78
+ };
79
+ try {
80
+ await apiPost(`/${storeCode}/customEvent/schema`, schemaPayload);
81
+ }
82
+ catch (error) {
83
+ const axiosError = error;
84
+ const apiErrors = axiosError.response?.data?.errors || [];
85
+ const allMessages = [
86
+ axiosError.response?.data?.message || "",
87
+ ...apiErrors.map(e => e.message)
88
+ ].join(" ").toLowerCase();
89
+ if (allMessages.includes("already") || allMessages.includes("duplicate") || allMessages.includes("unique")) {
90
+ throw new OpenLoyaltyError({
91
+ code: "DUPLICATE_EVENT_TYPE",
92
+ message: `Custom event schema '${input.eventType}' already exists`,
93
+ hint: `Use ol_custom_event_schema_list(eventType: "${input.eventType}") to find the existing schema. Use ol_custom_event_schema_update() to modify it, or choose a different eventType code.`,
94
+ relatedTool: "ol_custom_event_schema_create",
95
+ });
96
+ }
97
+ throw formatApiError(error, "ol_custom_event_schema_create");
98
+ }
99
+ }
100
+ export async function customEventSchemaUpdate(input) {
101
+ const storeCode = getStoreCode(input.storeCode);
102
+ const schemaPayload = {
103
+ customEventSchema: {
104
+ name: input.name,
105
+ schema: {
106
+ fields: input.fields,
107
+ },
108
+ active: {
109
+ isActive: input.active ?? true,
110
+ },
111
+ },
112
+ };
113
+ try {
114
+ await apiPut(`/${storeCode}/customEvent/schema/${input.eventType}`, schemaPayload);
115
+ }
116
+ catch (error) {
117
+ if (error.response?.status === 404) {
118
+ throw new OpenLoyaltyError({ code: "NOT_FOUND", message: `Custom event schema '${input.eventType}' not found`,
119
+ hint: "Use ol_custom_event_schema_list() to find existing schemas, or create with ol_custom_event_schema_create().",
120
+ relatedTool: "ol_custom_event_schema_update" });
121
+ }
122
+ throw formatApiError(error, "ol_custom_event_schema_update");
123
+ }
124
+ }
125
+ export async function customEventSchemaActivate(input) {
126
+ const storeCode = getStoreCode(input.storeCode);
127
+ try {
128
+ await apiPost(`/${storeCode}/customEvent/schema/${input.eventType}/active`, {
129
+ active: input.active,
130
+ });
131
+ }
132
+ catch (error) {
133
+ if (error.response?.status === 404) {
134
+ throw new OpenLoyaltyError({ code: "NOT_FOUND", message: `Custom event schema '${input.eventType}' not found`,
135
+ hint: "Use ol_custom_event_schema_list() to find existing event schemas.", relatedTool: "ol_custom_event_schema_activate" });
136
+ }
137
+ throw formatApiError(error, "ol_custom_event_schema_activate");
138
+ }
139
+ }
140
+ export async function customEventSend(input) {
141
+ const storeCode = getStoreCode(input.storeCode);
142
+ const eventPayload = {
143
+ event: {
144
+ type: input.eventType,
145
+ customerData: input.customerData,
146
+ eventDate: input.eventDate,
147
+ },
148
+ };
149
+ const eventObj = eventPayload.event;
150
+ if (input.body)
151
+ eventObj.body = input.body;
152
+ if (input.eventId)
153
+ eventObj.eventId = input.eventId;
154
+ try {
155
+ const response = await apiPost(`/${storeCode}/customEvent`, eventPayload);
156
+ return { customEventId: response.customEventId };
157
+ }
158
+ catch (error) {
159
+ const axiosError = error;
160
+ const apiErrors = axiosError.response?.data?.errors || [];
161
+ const allMessages = [
162
+ error instanceof Error ? error.message : "",
163
+ axiosError.response?.data?.message || "",
164
+ ...apiErrors.map(e => e.message)
165
+ ].join(" ").toLowerCase();
166
+ if (allMessages.includes("schema") && (allMessages.includes("not found") || allMessages.includes("not exist") || allMessages.includes("invalid"))) {
167
+ throw new OpenLoyaltyError({
168
+ code: "SCHEMA_NOT_FOUND",
169
+ message: `Custom event schema '${input.eventType}' not found`,
170
+ hint: `Use ol_custom_event_schema_list() to find valid event type codes. The eventType must match an existing active schema. You may need to create one with ol_custom_event_schema_create().`,
171
+ relatedTool: "ol_custom_event_send",
172
+ });
173
+ }
174
+ if (axiosError.response?.status === 404 || (allMessages.includes("event") && allMessages.includes("not found"))) {
175
+ throw new OpenLoyaltyError({
176
+ code: "SCHEMA_NOT_FOUND",
177
+ message: `Custom event type '${input.eventType}' not found or member not found`,
178
+ hint: `Verify: 1) The eventType '${input.eventType}' exists (use ol_custom_event_schema_list()). 2) The member exists (use ol_member_list() to search).`,
179
+ relatedTool: "ol_custom_event_send",
180
+ });
181
+ }
182
+ if (allMessages.includes("customer") && (allMessages.includes("not found") || allMessages.includes("not exist"))) {
183
+ throw new OpenLoyaltyError({
184
+ code: "MEMBER_NOT_FOUND",
185
+ message: "The specified member was not found",
186
+ hint: "Use ol_member_list() to search for the member by email, name, or phone. Verify the customerId, email, phone, or loyaltyCardNumber is correct.",
187
+ relatedTool: "ol_custom_event_send",
188
+ });
189
+ }
190
+ throw formatApiError(error, "ol_custom_event_send");
191
+ }
192
+ }
193
+ export async function customEventList(input) {
194
+ const storeCode = getStoreCode(input.storeCode);
195
+ const params = new URLSearchParams();
196
+ if (input.page)
197
+ params.append("_page", String(input.page));
198
+ if (input.perPage)
199
+ params.append("_itemsOnPage", String(input.perPage));
200
+ if (input.type)
201
+ params.append("type", input.type);
202
+ if (input.customerId)
203
+ params.append("customerId", input.customerId);
204
+ if (input.email)
205
+ params.append("customerData:email", input.email);
206
+ const queryString = params.toString();
207
+ const url = `/${storeCode}/customEvent${queryString ? `?${queryString}` : ""}`;
208
+ try {
209
+ const response = await apiGet(url);
210
+ const total = response.total || {};
211
+ return {
212
+ events: response.items || [],
213
+ total: {
214
+ all: typeof total.all === "number" ? total.all : undefined,
215
+ filtered: typeof total.filtered === "number" ? total.filtered : undefined,
216
+ },
217
+ };
218
+ }
219
+ catch (error) {
220
+ if (axios.isAxiosError(error) && error.response?.status === 404) {
221
+ throw new OpenLoyaltyError({
222
+ code: "STORE_NOT_FOUND",
223
+ message: "Cannot list custom events - store not found",
224
+ hint: "Use ol_store_list() to verify the store code is correct.",
225
+ relatedTool: "ol_custom_event_list",
226
+ });
227
+ }
228
+ if (axios.isAxiosError(error) && error.response?.status === 403) {
229
+ throw new OpenLoyaltyError({
230
+ code: "CUSTOM_EVENT_PERMISSION_DENIED",
231
+ message: "You don't have permission to view custom events",
232
+ hint: "Custom event access requires the EVENTS:VIEW permission. Use ol_admin_get_permissions() to check your access.",
233
+ relatedTool: "ol_custom_event_list",
234
+ });
235
+ }
236
+ throw formatApiError(error, "ol_custom_event_list");
237
+ }
238
+ }
@@ -0,0 +1,139 @@
1
+ export { CustomEventSchemaListInputSchema, CustomEventSchemaGetInputSchema, CustomEventSchemaCreateInputSchema, CustomEventSchemaUpdateInputSchema, CustomEventSchemaActivateInputSchema, CustomEventSendInputSchema, CustomEventListInputSchema, } from "./schemas.js";
2
+ export { customEventSchemaList, customEventSchemaGet, customEventSchemaCreate, customEventSchemaUpdate, customEventSchemaActivate, customEventSend, customEventList, } from "./handlers.js";
3
+ import { customEventSchemaList, customEventSchemaGet, customEventSchemaCreate, customEventSchemaUpdate, customEventSchemaActivate, customEventSend, customEventList } from "./handlers.js";
4
+ export declare const customEventToolDefinitions: readonly [{
5
+ readonly name: "ol_custom_event_schema_list";
6
+ readonly title: "List Custom Event Schemas";
7
+ readonly description: string;
8
+ readonly readOnly: true;
9
+ readonly idempotent: 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
+ eventType: import("zod").ZodOptional<import("zod").ZodString>;
15
+ name: import("zod").ZodOptional<import("zod").ZodString>;
16
+ active: import("zod").ZodOptional<import("zod").ZodBoolean>;
17
+ };
18
+ readonly handler: typeof customEventSchemaList;
19
+ }, {
20
+ readonly name: "ol_custom_event_schema_get";
21
+ readonly title: "Get Custom Event Schema";
22
+ readonly description: "Get details of a specific custom event schema including its fields.";
23
+ readonly readOnly: true;
24
+ readonly idempotent: true;
25
+ readonly inputSchema: {
26
+ storeCode: import("zod").ZodOptional<import("zod").ZodString>;
27
+ eventType: import("zod").ZodString;
28
+ };
29
+ readonly handler: typeof customEventSchemaGet;
30
+ }, {
31
+ readonly name: "ol_custom_event_schema_create";
32
+ readonly title: "Create Custom Event Schema";
33
+ readonly description: string;
34
+ readonly readOnly: false;
35
+ readonly idempotent: false;
36
+ readonly inputSchema: {
37
+ storeCode: import("zod").ZodOptional<import("zod").ZodString>;
38
+ eventType: import("zod").ZodString;
39
+ name: import("zod").ZodString;
40
+ fields: import("zod").ZodArray<import("zod").ZodObject<{
41
+ name: import("zod").ZodString;
42
+ type: import("zod").ZodEnum<["text", "number", "boolean", "datetime"]>;
43
+ description: import("zod").ZodOptional<import("zod").ZodString>;
44
+ }, "strip", import("zod").ZodTypeAny, {
45
+ type: "number" | "boolean" | "text" | "datetime";
46
+ name: string;
47
+ description?: string | undefined;
48
+ }, {
49
+ type: "number" | "boolean" | "text" | "datetime";
50
+ name: string;
51
+ description?: string | undefined;
52
+ }>, "many">;
53
+ active: import("zod").ZodOptional<import("zod").ZodBoolean>;
54
+ };
55
+ readonly handler: typeof customEventSchemaCreate;
56
+ }, {
57
+ readonly name: "ol_custom_event_schema_update";
58
+ readonly title: "Update Custom Event Schema";
59
+ readonly description: "Update an existing custom event schema (name, fields, active status).";
60
+ readonly readOnly: false;
61
+ readonly idempotent: true;
62
+ readonly inputSchema: {
63
+ storeCode: import("zod").ZodOptional<import("zod").ZodString>;
64
+ eventType: import("zod").ZodString;
65
+ name: import("zod").ZodString;
66
+ fields: import("zod").ZodArray<import("zod").ZodObject<{
67
+ name: import("zod").ZodString;
68
+ type: import("zod").ZodEnum<["text", "number", "boolean", "datetime"]>;
69
+ description: import("zod").ZodOptional<import("zod").ZodString>;
70
+ }, "strip", import("zod").ZodTypeAny, {
71
+ type: "number" | "boolean" | "text" | "datetime";
72
+ name: string;
73
+ description?: string | undefined;
74
+ }, {
75
+ type: "number" | "boolean" | "text" | "datetime";
76
+ name: string;
77
+ description?: string | undefined;
78
+ }>, "many">;
79
+ active: import("zod").ZodOptional<import("zod").ZodBoolean>;
80
+ };
81
+ readonly handler: typeof customEventSchemaUpdate;
82
+ }, {
83
+ readonly name: "ol_custom_event_schema_activate";
84
+ readonly title: "Activate/Deactivate Custom Event Schema";
85
+ readonly description: "Activate or deactivate a custom event schema. Inactive schemas won't trigger campaigns/achievements.";
86
+ readonly readOnly: false;
87
+ readonly idempotent: true;
88
+ readonly inputSchema: {
89
+ storeCode: import("zod").ZodOptional<import("zod").ZodString>;
90
+ eventType: import("zod").ZodString;
91
+ active: import("zod").ZodBoolean;
92
+ };
93
+ readonly handler: typeof customEventSchemaActivate;
94
+ }, {
95
+ readonly name: "ol_custom_event_send";
96
+ readonly title: "Send Custom Event";
97
+ readonly description: string;
98
+ readonly readOnly: false;
99
+ readonly idempotent: false;
100
+ readonly inputSchema: {
101
+ storeCode: import("zod").ZodOptional<import("zod").ZodString>;
102
+ eventType: import("zod").ZodString;
103
+ customerData: import("zod").ZodObject<{
104
+ customerId: import("zod").ZodOptional<import("zod").ZodString>;
105
+ email: import("zod").ZodOptional<import("zod").ZodString>;
106
+ phone: import("zod").ZodOptional<import("zod").ZodString>;
107
+ loyaltyCardNumber: import("zod").ZodOptional<import("zod").ZodString>;
108
+ }, "strip", import("zod").ZodTypeAny, {
109
+ email?: string | undefined;
110
+ phone?: string | undefined;
111
+ loyaltyCardNumber?: string | undefined;
112
+ customerId?: string | undefined;
113
+ }, {
114
+ email?: string | undefined;
115
+ phone?: string | undefined;
116
+ loyaltyCardNumber?: string | undefined;
117
+ customerId?: string | undefined;
118
+ }>;
119
+ eventDate: import("zod").ZodString;
120
+ body: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodUnknown>>;
121
+ eventId: import("zod").ZodOptional<import("zod").ZodString>;
122
+ };
123
+ readonly handler: typeof customEventSend;
124
+ }, {
125
+ readonly name: "ol_custom_event_list";
126
+ readonly title: "List Custom Events";
127
+ readonly description: "List custom events that have been sent. Filter by event type or member to see event history.";
128
+ readonly readOnly: true;
129
+ readonly idempotent: true;
130
+ readonly inputSchema: {
131
+ storeCode: import("zod").ZodOptional<import("zod").ZodString>;
132
+ page: import("zod").ZodOptional<import("zod").ZodNumber>;
133
+ perPage: import("zod").ZodOptional<import("zod").ZodNumber>;
134
+ type: import("zod").ZodOptional<import("zod").ZodString>;
135
+ customerId: import("zod").ZodOptional<import("zod").ZodString>;
136
+ email: import("zod").ZodOptional<import("zod").ZodString>;
137
+ };
138
+ readonly handler: typeof customEventList;
139
+ }];