@open-loyalty/mcp-server 1.1.0 → 1.3.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.
Files changed (112) hide show
  1. package/README.md +180 -177
  2. package/dist/auth/provider.js +2 -14
  3. package/dist/auth/storage.js +22 -0
  4. package/dist/client/http.js +10 -0
  5. package/dist/config.d.ts +0 -13
  6. package/dist/config.js +0 -14
  7. package/dist/http.js +35 -3
  8. package/dist/instructions.d.ts +5 -0
  9. package/dist/instructions.js +440 -0
  10. package/dist/prompts/fan-engagement-setup.d.ts +107 -0
  11. package/dist/prompts/fan-engagement-setup.js +492 -0
  12. package/dist/server.d.ts +1 -1
  13. package/dist/server.js +60 -273
  14. package/dist/tools/achievement/handlers.d.ts +117 -0
  15. package/dist/tools/achievement/handlers.js +161 -0
  16. package/dist/tools/achievement/index.d.ts +479 -0
  17. package/dist/tools/achievement/index.js +74 -0
  18. package/dist/tools/achievement/schemas.d.ts +433 -0
  19. package/dist/tools/achievement/schemas.js +142 -0
  20. package/dist/tools/achievement.d.ts +141 -121
  21. package/dist/tools/achievement.js +60 -24
  22. package/dist/tools/admin.d.ts +6 -6
  23. package/dist/tools/admin.js +12 -12
  24. package/dist/tools/analytics.d.ts +11 -11
  25. package/dist/tools/analytics.js +30 -29
  26. package/dist/tools/apikey.d.ts +3 -3
  27. package/dist/tools/apikey.js +6 -6
  28. package/dist/tools/audit.d.ts +2 -2
  29. package/dist/tools/audit.js +4 -4
  30. package/dist/tools/badge.d.ts +6 -6
  31. package/dist/tools/badge.js +23 -18
  32. package/dist/tools/campaign/handlers.d.ts +42 -0
  33. package/dist/tools/campaign/handlers.js +223 -0
  34. package/dist/tools/campaign/index.d.ts +783 -0
  35. package/dist/tools/campaign/index.js +117 -0
  36. package/dist/tools/campaign/member-handlers.d.ts +60 -0
  37. package/dist/tools/campaign/member-handlers.js +159 -0
  38. package/dist/tools/campaign/schemas.d.ts +704 -0
  39. package/dist/tools/campaign/schemas.js +259 -0
  40. package/dist/tools/campaign/types.d.ts +161 -0
  41. package/dist/tools/campaign/types.js +2 -0
  42. package/dist/tools/custom-event.d.ts +315 -0
  43. package/dist/tools/custom-event.js +270 -0
  44. package/dist/tools/export.d.ts +4 -4
  45. package/dist/tools/export.js +12 -12
  46. package/dist/tools/import.d.ts +3 -3
  47. package/dist/tools/import.js +23 -15
  48. package/dist/tools/index.js +13 -5
  49. package/dist/tools/member/handlers.d.ts +111 -0
  50. package/dist/tools/member/handlers.js +206 -0
  51. package/dist/tools/member/index.d.ts +169 -0
  52. package/dist/tools/member/index.js +92 -0
  53. package/dist/tools/member/schemas.d.ts +89 -0
  54. package/dist/tools/member/schemas.js +65 -0
  55. package/dist/tools/points.d.ts +7 -6
  56. package/dist/tools/points.js +21 -20
  57. package/dist/tools/referral/handlers.d.ts +47 -0
  58. package/dist/tools/referral/handlers.js +115 -0
  59. package/dist/tools/referral/index.d.ts +44 -0
  60. package/dist/tools/referral/index.js +44 -0
  61. package/dist/tools/referral/schemas.d.ts +34 -0
  62. package/dist/tools/referral/schemas.js +52 -0
  63. package/dist/tools/reward/handlers.d.ts +110 -0
  64. package/dist/tools/reward/handlers.js +289 -0
  65. package/dist/tools/reward/index.d.ts +177 -0
  66. package/dist/tools/reward/index.js +93 -0
  67. package/dist/tools/reward/schemas.d.ts +116 -0
  68. package/dist/tools/reward/schemas.js +92 -0
  69. package/dist/tools/role.d.ts +6 -6
  70. package/dist/tools/role.js +12 -12
  71. package/dist/tools/segment/handlers.d.ts +87 -0
  72. package/dist/tools/segment/handlers.js +174 -0
  73. package/dist/tools/segment/index.d.ts +395 -0
  74. package/dist/tools/segment/index.js +88 -0
  75. package/dist/tools/segment/schemas.d.ts +337 -0
  76. package/dist/tools/segment/schemas.js +79 -0
  77. package/dist/tools/segment.d.ts +10 -10
  78. package/dist/tools/segment.js +55 -31
  79. package/dist/tools/store.d.ts +4 -4
  80. package/dist/tools/store.js +8 -8
  81. package/dist/tools/tierset.d.ts +10 -10
  82. package/dist/tools/tierset.js +69 -37
  83. package/dist/tools/transaction.d.ts +4 -4
  84. package/dist/tools/transaction.js +12 -12
  85. package/dist/tools/wallet-type.d.ts +221 -16
  86. package/dist/tools/wallet-type.js +248 -17
  87. package/dist/tools/webhook.d.ts +6 -6
  88. package/dist/tools/webhook.js +90 -31
  89. package/dist/types/schemas/achievement.d.ts +18 -18
  90. package/dist/types/schemas/campaign.d.ts +64 -184
  91. package/dist/types/schemas/campaign.js +2 -7
  92. package/dist/types/schemas/common.d.ts +5 -0
  93. package/dist/types/schemas/common.js +5 -0
  94. package/dist/types/schemas/member.d.ts +2 -2
  95. package/dist/types/schemas/reward.d.ts +94 -18
  96. package/dist/types/schemas/reward.js +8 -3
  97. package/dist/types/schemas/wallet-type.d.ts +306 -8
  98. package/dist/types/schemas/wallet-type.js +82 -1
  99. package/dist/utils/errors.js +32 -5
  100. package/dist/workflows/app-login-streak.d.ts +39 -0
  101. package/dist/workflows/app-login-streak.js +298 -0
  102. package/dist/workflows/early-arrival.d.ts +33 -0
  103. package/dist/workflows/early-arrival.js +148 -0
  104. package/dist/workflows/index.d.ts +101 -0
  105. package/dist/workflows/index.js +208 -0
  106. package/dist/workflows/match-attendance.d.ts +45 -0
  107. package/dist/workflows/match-attendance.js +308 -0
  108. package/dist/workflows/sportsbar-visit.d.ts +41 -0
  109. package/dist/workflows/sportsbar-visit.js +284 -0
  110. package/dist/workflows/vod-watching.d.ts +43 -0
  111. package/dist/workflows/vod-watching.js +326 -0
  112. package/package.json +8 -2
@@ -0,0 +1,92 @@
1
+ import { z } from "zod";
2
+ export const RewardListInputSchema = {
3
+ 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."),
4
+ page: z.number().optional().describe("Page number (default: 1)."),
5
+ perPage: z.number().optional().describe("Items per page (default: 10)."),
6
+ active: z.boolean().optional().describe("Filter by active status."),
7
+ type: z.enum(["static_coupon", "dynamic_coupon", "conversion_coupon", "material", "fortune_wheel"]).optional().describe("Filter by reward type."),
8
+ categoryId: z.string().optional().describe("Filter by category ID."),
9
+ };
10
+ // Translations schema for rewards (API requires translations.en at minimum)
11
+ // Note: translations.en must ONLY contain name, description is a separate field at top level
12
+ const RewardTranslationsInputSchema = z.object({
13
+ en: z.object({
14
+ name: z.string().describe("Reward name in English (required)."),
15
+ }),
16
+ }).passthrough().describe("Translations object with at least 'en' key containing { name }. Description goes at top level.");
17
+ // Activity period schema (REQUIRED by API)
18
+ // API requires datetime format: YYYY-MM-DD HH:mm (NOT just YYYY-MM-DD)
19
+ const RewardActivityInputSchema = z.object({
20
+ from: z.string().describe("Start datetime (format: 'YYYY-MM-DD HH:mm', e.g., '2026-01-01 00:00'). REQUIRED."),
21
+ to: z.string().describe("End datetime (format: 'YYYY-MM-DD HH:mm', e.g., '2026-12-31 23:59'). REQUIRED."),
22
+ });
23
+ // Visibility period schema (REQUIRED by API)
24
+ // API requires datetime format: YYYY-MM-DD HH:mm (NOT just YYYY-MM-DD)
25
+ const RewardVisibilityInputSchema = z.object({
26
+ from: z.string().describe("Visibility start datetime (format: 'YYYY-MM-DD HH:mm'). REQUIRED."),
27
+ to: z.string().describe("Visibility end datetime (format: 'YYYY-MM-DD HH:mm'). REQUIRED."),
28
+ });
29
+ // Usage limit schema (REQUIRED by API)
30
+ // NOTE: API uses 'general' (not 'total') for total redemptions limit
31
+ // BOTH perUser and general are REQUIRED by the API
32
+ const RewardUsageLimitInputSchema = z.object({
33
+ perUser: z.number().describe("Maximum redemptions per member. REQUIRED."),
34
+ general: z.number().describe("Total redemptions across all members. REQUIRED. Use a large number (e.g., 10000) if unlimited."),
35
+ });
36
+ export const RewardCreateInputSchema = {
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."),
38
+ translations: RewardTranslationsInputSchema.describe("Reward name translations. At least 'en' key with { name } is REQUIRED."),
39
+ reward: z.enum(["static_coupon", "dynamic_coupon", "conversion_coupon", "material", "fortune_wheel"]).describe("Reward type: static_coupon (fixed discount), dynamic_coupon (variable value), " +
40
+ "conversion_coupon (converts points to coupon), material (physical goods), fortune_wheel (gamified)."),
41
+ activity: RewardActivityInputSchema.describe("Activity period when reward can be purchased. Use datetime format 'YYYY-MM-DD HH:mm'. REQUIRED."),
42
+ visibility: RewardVisibilityInputSchema.describe("Visibility period when reward is shown. Use datetime format 'YYYY-MM-DD HH:mm'. REQUIRED."),
43
+ usageLimit: RewardUsageLimitInputSchema.describe("Usage limits. ⚠️ BOTH perUser AND general are REQUIRED by the API."),
44
+ costInPoints: z.number().optional().describe("Points required to redeem this reward."),
45
+ usageInstruction: z.string().optional().describe("Instructions for using the reward."),
46
+ active: z.boolean().optional().describe("Whether reward is active (default: false)."),
47
+ categories: z.array(z.string()).optional().describe("Array of category UUIDs."),
48
+ levels: z.array(z.string()).optional().describe("Array of tier level UUIDs that can see/redeem."),
49
+ segments: z.array(z.string()).optional().describe("Array of segment UUIDs that can see/redeem."),
50
+ target: z.enum(["level", "segment"]).nullable().optional().describe("Target type for visibility: level (tier-based), segment (segment-based), or null (all)."),
51
+ couponValue: z.number().optional().describe("Coupon value (required for static_coupon)."),
52
+ couponValueType: z.enum(["money", "percentage"]).optional().describe("Coupon value type: 'money' or 'percentage' (lowercase)."),
53
+ daysValid: z.number().optional().describe("Days the coupon remains valid after purchase."),
54
+ };
55
+ export const RewardGetInputSchema = {
56
+ 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."),
57
+ rewardId: z.string().describe("The reward ID (UUID) to retrieve."),
58
+ };
59
+ export const RewardUpdateInputSchema = {
60
+ 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."),
61
+ rewardId: z.string().describe("The reward ID (UUID) to update."),
62
+ name: z.string().optional().describe("Reward name."),
63
+ costInPoints: z.number().optional().describe("Points required to redeem."),
64
+ description: z.string().optional().describe("Reward description."),
65
+ active: z.boolean().optional().describe("Whether reward is active."),
66
+ categories: z.array(z.string()).optional().describe("Array of category UUIDs."),
67
+ levels: z.array(z.string()).optional().describe("Array of tier level UUIDs."),
68
+ segments: z.array(z.string()).optional().describe("Array of segment UUIDs."),
69
+ };
70
+ export const RewardIdInputSchema = {
71
+ 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."),
72
+ rewardId: z.string().describe("The reward ID (UUID)."),
73
+ };
74
+ export const RewardBuyInputSchema = {
75
+ 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."),
76
+ rewardId: z.string().describe("The reward ID (UUID) to purchase."),
77
+ memberId: z.string().describe("The member ID (UUID) purchasing the reward."),
78
+ quantity: z.number().optional().describe("Number of rewards to purchase (1-32, default: 1)."),
79
+ couponValue: z.number().optional().describe("Coupon value (for dynamic coupons)."),
80
+ withoutPoints: z.boolean().optional().describe("Admin only: skip points deduction."),
81
+ };
82
+ export const RewardRedeemInputSchema = {
83
+ 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."),
84
+ memberId: z.string().describe("The member ID (UUID) redeeming the coupon."),
85
+ couponCode: z.string().describe("The coupon code to redeem."),
86
+ };
87
+ export const RewardCategoryListInputSchema = {
88
+ 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."),
89
+ page: z.number().optional().describe("Page number (default: 1)."),
90
+ perPage: z.number().optional().describe("Items per page (default: 10)."),
91
+ active: z.boolean().optional().describe("Filter by active status."),
92
+ };
@@ -89,7 +89,7 @@ export declare function aclGetResources(): Promise<{
89
89
  total?: Record<string, unknown>;
90
90
  }>;
91
91
  export declare const roleToolDefinitions: readonly [{
92
- readonly name: "openloyalty_role_list";
92
+ readonly name: "ol_role_list";
93
93
  readonly title: "List Roles";
94
94
  readonly description: "List all roles with optional filtering. Returns paginated list of roles with id, name, permissions, master status, and default status.";
95
95
  readonly readOnly: true;
@@ -102,7 +102,7 @@ export declare const roleToolDefinitions: readonly [{
102
102
  };
103
103
  readonly handler: typeof roleList;
104
104
  }, {
105
- readonly name: "openloyalty_role_create";
105
+ readonly name: "ol_role_create";
106
106
  readonly title: "Create Role";
107
107
  readonly description: "Create a new role with permissions. Requires name. Optionally specify permissions (array of {resource, access, filterQuery}) and stores. Returns void on success (201 Created).";
108
108
  readonly readOnly: false;
@@ -126,7 +126,7 @@ export declare const roleToolDefinitions: readonly [{
126
126
  };
127
127
  readonly handler: typeof roleCreate;
128
128
  }, {
129
- readonly name: "openloyalty_role_get";
129
+ readonly name: "ol_role_get";
130
130
  readonly title: "Get Role Details";
131
131
  readonly description: "Get full role details by ID. Returns role with name, permissions array, master status, default status, and stores.";
132
132
  readonly readOnly: true;
@@ -135,7 +135,7 @@ export declare const roleToolDefinitions: readonly [{
135
135
  };
136
136
  readonly handler: typeof roleGet;
137
137
  }, {
138
- readonly name: "openloyalty_role_update";
138
+ readonly name: "ol_role_update";
139
139
  readonly title: "Update Role";
140
140
  readonly description: "Update a role's name, permissions, or stores. Returns void on success (204 No Content).";
141
141
  readonly readOnly: false;
@@ -160,7 +160,7 @@ export declare const roleToolDefinitions: readonly [{
160
160
  };
161
161
  readonly handler: typeof roleUpdate;
162
162
  }, {
163
- readonly name: "openloyalty_role_delete";
163
+ readonly name: "ol_role_delete";
164
164
  readonly title: "Delete Role (Permanent)";
165
165
  readonly description: "Delete a role by ID. Returns void on success (204 No Content). Cannot delete roles that are assigned to admin users.";
166
166
  readonly readOnly: false;
@@ -170,7 +170,7 @@ export declare const roleToolDefinitions: readonly [{
170
170
  };
171
171
  readonly handler: typeof roleDelete;
172
172
  }, {
173
- readonly name: "openloyalty_acl_get_resources";
173
+ readonly name: "ol_acl_get_resources";
174
174
  readonly title: "Get ACL Resources";
175
175
  readonly description: "Get list of available ACL resources. Returns items with code and name for each resource type. Use this to discover available permissions before creating roles.";
176
176
  readonly readOnly: true;
@@ -56,7 +56,7 @@ export async function roleList(input) {
56
56
  return response;
57
57
  }
58
58
  catch (error) {
59
- throw formatApiError(error, "openloyalty_role_list");
59
+ throw formatApiError(error, "ol_role_list");
60
60
  }
61
61
  }
62
62
  export async function roleCreate(input) {
@@ -73,7 +73,7 @@ export async function roleCreate(input) {
73
73
  await apiPost("/acl/role", { role: payload });
74
74
  }
75
75
  catch (error) {
76
- throw formatApiError(error, "openloyalty_role_create");
76
+ throw formatApiError(error, "ol_role_create");
77
77
  }
78
78
  }
79
79
  export async function roleGet(input) {
@@ -82,7 +82,7 @@ export async function roleGet(input) {
82
82
  return response;
83
83
  }
84
84
  catch (error) {
85
- throw formatApiError(error, "openloyalty_role_get");
85
+ throw formatApiError(error, "ol_role_get");
86
86
  }
87
87
  }
88
88
  export async function roleUpdate(input) {
@@ -99,7 +99,7 @@ export async function roleUpdate(input) {
99
99
  await apiPut(`/acl/role/${input.roleId}`, { role: payload });
100
100
  }
101
101
  catch (error) {
102
- throw formatApiError(error, "openloyalty_role_update");
102
+ throw formatApiError(error, "ol_role_update");
103
103
  }
104
104
  }
105
105
  export async function roleDelete(input) {
@@ -107,7 +107,7 @@ export async function roleDelete(input) {
107
107
  await apiDelete(`/acl/role/${input.roleId}`);
108
108
  }
109
109
  catch (error) {
110
- throw formatApiError(error, "openloyalty_role_delete");
110
+ throw formatApiError(error, "ol_role_delete");
111
111
  }
112
112
  }
113
113
  export async function aclGetResources() {
@@ -116,13 +116,13 @@ export async function aclGetResources() {
116
116
  return response;
117
117
  }
118
118
  catch (error) {
119
- throw formatApiError(error, "openloyalty_acl_get_resources");
119
+ throw formatApiError(error, "ol_acl_get_resources");
120
120
  }
121
121
  }
122
122
  // Tool definitions
123
123
  export const roleToolDefinitions = [
124
124
  {
125
- name: "openloyalty_role_list",
125
+ name: "ol_role_list",
126
126
  title: "List Roles",
127
127
  description: "List all roles with optional filtering. Returns paginated list of roles with id, name, permissions, master status, and default status.",
128
128
  readOnly: true,
@@ -130,7 +130,7 @@ export const roleToolDefinitions = [
130
130
  handler: roleList,
131
131
  },
132
132
  {
133
- name: "openloyalty_role_create",
133
+ name: "ol_role_create",
134
134
  title: "Create Role",
135
135
  description: "Create a new role with permissions. Requires name. Optionally specify permissions (array of {resource, access, filterQuery}) and stores. Returns void on success (201 Created).",
136
136
  readOnly: false,
@@ -138,7 +138,7 @@ export const roleToolDefinitions = [
138
138
  handler: roleCreate,
139
139
  },
140
140
  {
141
- name: "openloyalty_role_get",
141
+ name: "ol_role_get",
142
142
  title: "Get Role Details",
143
143
  description: "Get full role details by ID. Returns role with name, permissions array, master status, default status, and stores.",
144
144
  readOnly: true,
@@ -146,7 +146,7 @@ export const roleToolDefinitions = [
146
146
  handler: roleGet,
147
147
  },
148
148
  {
149
- name: "openloyalty_role_update",
149
+ name: "ol_role_update",
150
150
  title: "Update Role",
151
151
  description: "Update a role's name, permissions, or stores. Returns void on success (204 No Content).",
152
152
  readOnly: false,
@@ -154,7 +154,7 @@ export const roleToolDefinitions = [
154
154
  handler: roleUpdate,
155
155
  },
156
156
  {
157
- name: "openloyalty_role_delete",
157
+ name: "ol_role_delete",
158
158
  title: "Delete Role (Permanent)",
159
159
  description: "Delete a role by ID. Returns void on success (204 No Content). Cannot delete roles that are assigned to admin users.",
160
160
  readOnly: false,
@@ -163,7 +163,7 @@ export const roleToolDefinitions = [
163
163
  handler: roleDelete,
164
164
  },
165
165
  {
166
- name: "openloyalty_acl_get_resources",
166
+ name: "ol_acl_get_resources",
167
167
  title: "Get ACL Resources",
168
168
  description: "Get list of available ACL resources. Returns items with code and name for each resource type. Use this to discover available permissions before creating roles.",
169
169
  readOnly: true,
@@ -0,0 +1,87 @@
1
+ import { SegmentListItem } from "../../types/schemas/segment.js";
2
+ export declare function segmentList(input: {
3
+ storeCode?: string;
4
+ page?: number;
5
+ perPage?: number;
6
+ active?: boolean;
7
+ name?: string;
8
+ }): Promise<{
9
+ segments: SegmentListItem[];
10
+ total: {
11
+ all?: number;
12
+ filtered?: number;
13
+ };
14
+ }>;
15
+ interface SegmentCreateInput {
16
+ storeCode?: string;
17
+ name: string;
18
+ description?: string;
19
+ active?: boolean;
20
+ parts: Array<{
21
+ segmentPartId?: string;
22
+ criteria: Array<Record<string, unknown>>;
23
+ }>;
24
+ }
25
+ export declare function segmentCreate(input: SegmentCreateInput): Promise<{
26
+ segmentId: string;
27
+ }>;
28
+ export declare function segmentGet(input: {
29
+ storeCode?: string;
30
+ segmentId: string;
31
+ }): Promise<Record<string, unknown>>;
32
+ interface SegmentUpdateInput {
33
+ storeCode?: string;
34
+ segmentId: string;
35
+ name: string;
36
+ description?: string;
37
+ active?: boolean;
38
+ parts: Array<{
39
+ segmentPartId?: string;
40
+ criteria: Array<Record<string, unknown>>;
41
+ }>;
42
+ }
43
+ export declare function segmentUpdate(input: SegmentUpdateInput): Promise<void>;
44
+ export declare function segmentDelete(input: {
45
+ storeCode?: string;
46
+ segmentId: string;
47
+ }): Promise<void>;
48
+ interface SegmentMember {
49
+ customerId: string;
50
+ firstName?: string;
51
+ lastName?: string;
52
+ email?: string;
53
+ loyaltyCardNumber?: string;
54
+ active?: boolean;
55
+ }
56
+ export declare function segmentGetMembers(input: {
57
+ storeCode?: string;
58
+ segmentId: string;
59
+ page?: number;
60
+ perPage?: number;
61
+ }): Promise<{
62
+ members: SegmentMember[];
63
+ total: {
64
+ all?: number;
65
+ filtered?: number;
66
+ };
67
+ }>;
68
+ export declare function segmentActivate(input: {
69
+ storeCode?: string;
70
+ segmentId: string;
71
+ }): Promise<void>;
72
+ export declare function segmentDeactivate(input: {
73
+ storeCode?: string;
74
+ segmentId: string;
75
+ }): Promise<void>;
76
+ interface SegmentResource {
77
+ resourceId: string;
78
+ resourceType: string;
79
+ name?: string;
80
+ }
81
+ export declare function segmentGetResources(input: {
82
+ storeCode?: string;
83
+ segmentId: string;
84
+ }): Promise<{
85
+ resources: SegmentResource[];
86
+ }>;
87
+ export {};
@@ -0,0 +1,174 @@
1
+ import { apiGet, apiPost, apiPut, apiDelete } from "../../client/http.js";
2
+ import { formatApiError } from "../../utils/errors.js";
3
+ import { getStoreCode } from "../../config.js";
4
+ const DEFAULT_TRANSACTION_COUNT_MAX = 999999;
5
+ function normalizeSegmentParts(parts) {
6
+ return parts.map((part) => ({
7
+ ...part,
8
+ criteria: part.criteria.map((criterion) => {
9
+ if (!criterion || typeof criterion !== "object") {
10
+ return criterion;
11
+ }
12
+ const normalized = { ...criterion };
13
+ if (normalized.type === "transaction_count" &&
14
+ normalized.min !== undefined &&
15
+ normalized.max === undefined) {
16
+ normalized.max = DEFAULT_TRANSACTION_COUNT_MAX;
17
+ }
18
+ return normalized;
19
+ }),
20
+ }));
21
+ }
22
+ export async function segmentList(input) {
23
+ const storeCode = getStoreCode(input.storeCode);
24
+ const params = new URLSearchParams();
25
+ if (input.page)
26
+ params.append("_page", String(input.page));
27
+ if (input.perPage)
28
+ params.append("_itemsOnPage", String(input.perPage));
29
+ if (input.active !== undefined)
30
+ params.append("active", String(input.active));
31
+ if (input.name)
32
+ params.append("name", input.name);
33
+ const queryString = params.toString();
34
+ const url = `/${storeCode}/segment${queryString ? `?${queryString}` : ""}`;
35
+ try {
36
+ const response = await apiGet(url);
37
+ const segments = (response.items || []).map((item) => ({
38
+ segmentId: item.segmentId,
39
+ name: item.name,
40
+ description: item.description,
41
+ active: item.active,
42
+ customersCount: item.customersCount,
43
+ createdAt: item.createdAt,
44
+ }));
45
+ const total = response.total || {};
46
+ return {
47
+ segments,
48
+ total: {
49
+ all: typeof total.all === "number" ? total.all : undefined,
50
+ filtered: typeof total.filtered === "number" ? total.filtered : undefined,
51
+ },
52
+ };
53
+ }
54
+ catch (error) {
55
+ throw formatApiError(error, "ol_segment_list");
56
+ }
57
+ }
58
+ export async function segmentCreate(input) {
59
+ const storeCode = getStoreCode(input.storeCode);
60
+ const segmentPayload = {
61
+ name: input.name,
62
+ parts: normalizeSegmentParts(input.parts),
63
+ };
64
+ if (input.description)
65
+ segmentPayload.description = input.description;
66
+ if (input.active !== undefined)
67
+ segmentPayload.active = input.active;
68
+ try {
69
+ // CRITICAL: Wrap body as { segment: {...} }
70
+ const response = await apiPost(`/${storeCode}/segment`, { segment: segmentPayload });
71
+ return { segmentId: response.segmentId };
72
+ }
73
+ catch (error) {
74
+ throw formatApiError(error, "ol_segment_create");
75
+ }
76
+ }
77
+ export async function segmentGet(input) {
78
+ const storeCode = getStoreCode(input.storeCode);
79
+ try {
80
+ const response = await apiGet(`/${storeCode}/segment/${input.segmentId}`);
81
+ return response;
82
+ }
83
+ catch (error) {
84
+ throw formatApiError(error, "ol_segment_get");
85
+ }
86
+ }
87
+ export async function segmentUpdate(input) {
88
+ const storeCode = getStoreCode(input.storeCode);
89
+ const segmentPayload = {
90
+ name: input.name,
91
+ parts: normalizeSegmentParts(input.parts),
92
+ };
93
+ if (input.description !== undefined)
94
+ segmentPayload.description = input.description;
95
+ if (input.active !== undefined)
96
+ segmentPayload.active = input.active;
97
+ try {
98
+ // CRITICAL: Wrap body as { segment: {...} }
99
+ await apiPut(`/${storeCode}/segment/${input.segmentId}`, { segment: segmentPayload });
100
+ }
101
+ catch (error) {
102
+ throw formatApiError(error, "ol_segment_update");
103
+ }
104
+ }
105
+ export async function segmentDelete(input) {
106
+ const storeCode = getStoreCode(input.storeCode);
107
+ try {
108
+ await apiDelete(`/${storeCode}/segment/${input.segmentId}`);
109
+ }
110
+ catch (error) {
111
+ throw formatApiError(error, "ol_segment_delete");
112
+ }
113
+ }
114
+ export async function segmentGetMembers(input) {
115
+ const storeCode = getStoreCode(input.storeCode);
116
+ const params = new URLSearchParams();
117
+ if (input.page)
118
+ params.append("_page", String(input.page));
119
+ if (input.perPage)
120
+ params.append("_itemsOnPage", String(input.perPage));
121
+ const queryString = params.toString();
122
+ const url = `/${storeCode}/segment/${input.segmentId}/members${queryString ? `?${queryString}` : ""}`;
123
+ try {
124
+ const response = await apiGet(url);
125
+ const members = (response.items || []).map((item) => ({
126
+ customerId: item.customerId,
127
+ firstName: item.firstName,
128
+ lastName: item.lastName,
129
+ email: item.email,
130
+ loyaltyCardNumber: item.loyaltyCardNumber,
131
+ active: item.active,
132
+ }));
133
+ const total = response.total || {};
134
+ return {
135
+ members,
136
+ total: {
137
+ all: typeof total.all === "number" ? total.all : undefined,
138
+ filtered: typeof total.filtered === "number" ? total.filtered : undefined,
139
+ },
140
+ };
141
+ }
142
+ catch (error) {
143
+ throw formatApiError(error, "ol_segment_get_members");
144
+ }
145
+ }
146
+ export async function segmentActivate(input) {
147
+ const storeCode = getStoreCode(input.storeCode);
148
+ try {
149
+ await apiPost(`/${storeCode}/segment/${input.segmentId}/activate`, {});
150
+ }
151
+ catch (error) {
152
+ throw formatApiError(error, "ol_segment_activate");
153
+ }
154
+ }
155
+ export async function segmentDeactivate(input) {
156
+ const storeCode = getStoreCode(input.storeCode);
157
+ try {
158
+ await apiPost(`/${storeCode}/segment/${input.segmentId}/deactivate`, {});
159
+ }
160
+ catch (error) {
161
+ throw formatApiError(error, "ol_segment_deactivate");
162
+ }
163
+ }
164
+ export async function segmentGetResources(input) {
165
+ const storeCode = getStoreCode(input.storeCode);
166
+ try {
167
+ const response = await apiGet(`/${storeCode}/segment/${input.segmentId}/resources`);
168
+ const resources = response.items || response.resources || [];
169
+ return { resources };
170
+ }
171
+ catch (error) {
172
+ throw formatApiError(error, "ol_segment_get_resources");
173
+ }
174
+ }