dtc-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +344 -0
- package/dist/config.d.ts +17 -0
- package/dist/config.js +71 -0
- package/dist/config.js.map +1 -0
- package/dist/cross-platform/correlator.d.ts +10 -0
- package/dist/cross-platform/correlator.js +166 -0
- package/dist/cross-platform/correlator.js.map +1 -0
- package/dist/cross-platform/tools.d.ts +2 -0
- package/dist/cross-platform/tools.js +30 -0
- package/dist/cross-platform/tools.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/platforms/klaviyo/client.d.ts +91 -0
- package/dist/platforms/klaviyo/client.js +389 -0
- package/dist/platforms/klaviyo/client.js.map +1 -0
- package/dist/platforms/klaviyo/tools.d.ts +2 -0
- package/dist/platforms/klaviyo/tools.js +368 -0
- package/dist/platforms/klaviyo/tools.js.map +1 -0
- package/dist/platforms/klaviyo/transforms.d.ts +59 -0
- package/dist/platforms/klaviyo/transforms.js +326 -0
- package/dist/platforms/klaviyo/transforms.js.map +1 -0
- package/dist/platforms/shopify/client.d.ts +51 -0
- package/dist/platforms/shopify/client.js +366 -0
- package/dist/platforms/shopify/client.js.map +1 -0
- package/dist/platforms/shopify/tools.d.ts +2 -0
- package/dist/platforms/shopify/tools.js +253 -0
- package/dist/platforms/shopify/tools.js.map +1 -0
- package/dist/platforms/shopify/transforms.d.ts +88 -0
- package/dist/platforms/shopify/transforms.js +191 -0
- package/dist/platforms/shopify/transforms.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +15 -0
- package/dist/server.js.map +1 -0
- package/dist/shared/cache.d.ts +23 -0
- package/dist/shared/cache.js +62 -0
- package/dist/shared/cache.js.map +1 -0
- package/dist/shared/errors.d.ts +25 -0
- package/dist/shared/errors.js +96 -0
- package/dist/shared/errors.js.map +1 -0
- package/dist/shared/pagination.d.ts +21 -0
- package/dist/shared/pagination.js +36 -0
- package/dist/shared/pagination.js.map +1 -0
- package/dist/shared/types.d.ts +247 -0
- package/dist/shared/types.js +3 -0
- package/dist/shared/types.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { SalesSummary, SalesTimeSeries, ProductPerformanceItem, OrderSearchItem, InventoryAlertItem, CustomerCohort, RecentOrderItem } from "../../shared/types.js";
|
|
2
|
+
import type { RawSalesBucket } from "./client.js";
|
|
3
|
+
export interface SalesData {
|
|
4
|
+
grossRevenue: number;
|
|
5
|
+
netRevenue: number;
|
|
6
|
+
orderCount: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function transformSalesSummary(current: SalesData, days: number, previous?: SalesData): SalesSummary;
|
|
9
|
+
interface RawLineItem {
|
|
10
|
+
name: string;
|
|
11
|
+
product?: {
|
|
12
|
+
id: string;
|
|
13
|
+
title: string;
|
|
14
|
+
} | null;
|
|
15
|
+
quantity: number;
|
|
16
|
+
originalTotalSet?: {
|
|
17
|
+
shopMoney?: {
|
|
18
|
+
amount: string;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
interface RawOrder {
|
|
23
|
+
lineItems: {
|
|
24
|
+
nodes: RawLineItem[];
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export declare function transformProductPerformance(orders: RawOrder[], limit: number, metric: "revenue" | "units"): ProductPerformanceItem[];
|
|
28
|
+
interface RawSearchOrder {
|
|
29
|
+
name: string;
|
|
30
|
+
email?: string | null;
|
|
31
|
+
createdAt: string;
|
|
32
|
+
totalPriceSet: {
|
|
33
|
+
shopMoney: {
|
|
34
|
+
amount: string;
|
|
35
|
+
currencyCode: string;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
displayFinancialStatus: string;
|
|
39
|
+
displayFulfillmentStatus: string;
|
|
40
|
+
lineItems: {
|
|
41
|
+
nodes: Array<{
|
|
42
|
+
name: string;
|
|
43
|
+
quantity: number;
|
|
44
|
+
originalUnitPriceSet: {
|
|
45
|
+
shopMoney: {
|
|
46
|
+
amount: string;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
}>;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export declare function transformOrders(orders: RawSearchOrder[]): OrderSearchItem[];
|
|
53
|
+
interface RawVariant {
|
|
54
|
+
displayName: string;
|
|
55
|
+
sku: string | null;
|
|
56
|
+
inventoryQuantity: number;
|
|
57
|
+
product: {
|
|
58
|
+
title: string;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export declare function transformInventoryAlerts(variants: RawVariant[], threshold: number): InventoryAlertItem[];
|
|
62
|
+
interface RawCustomer {
|
|
63
|
+
id: string;
|
|
64
|
+
email?: string | null;
|
|
65
|
+
numberOfOrders: string;
|
|
66
|
+
amountSpent: {
|
|
67
|
+
amount: string;
|
|
68
|
+
currencyCode: string;
|
|
69
|
+
};
|
|
70
|
+
createdAt: string;
|
|
71
|
+
}
|
|
72
|
+
export declare function transformCustomerCohort(customers: RawCustomer[], days: number): CustomerCohort;
|
|
73
|
+
interface RawRecentOrder {
|
|
74
|
+
name: string;
|
|
75
|
+
email?: string | null;
|
|
76
|
+
createdAt: string;
|
|
77
|
+
totalPriceSet: {
|
|
78
|
+
shopMoney: {
|
|
79
|
+
amount: string;
|
|
80
|
+
currencyCode: string;
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
displayFinancialStatus: string;
|
|
84
|
+
displayFulfillmentStatus: string;
|
|
85
|
+
}
|
|
86
|
+
export declare function transformRecentOrders(orders: RawRecentOrder[]): RecentOrderItem[];
|
|
87
|
+
export declare function transformSalesTimeSeries(buckets: RawSalesBucket[], days: number, granularity: "daily" | "weekly" | "monthly", timezone: string): SalesTimeSeries;
|
|
88
|
+
export {};
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
export function transformSalesSummary(current, days, previous) {
|
|
2
|
+
const result = {
|
|
3
|
+
period: `last_${days}_days`,
|
|
4
|
+
gross_revenue: current.grossRevenue,
|
|
5
|
+
net_revenue: current.netRevenue,
|
|
6
|
+
order_count: current.orderCount,
|
|
7
|
+
aov: current.orderCount > 0
|
|
8
|
+
? Math.round((current.netRevenue / current.orderCount) * 100) / 100
|
|
9
|
+
: 0,
|
|
10
|
+
currency: "USD",
|
|
11
|
+
};
|
|
12
|
+
if (previous) {
|
|
13
|
+
const prevAov = previous.orderCount > 0
|
|
14
|
+
? Math.round((previous.netRevenue / previous.orderCount) * 100) / 100
|
|
15
|
+
: 0;
|
|
16
|
+
result.comparison = {
|
|
17
|
+
gross_revenue_delta_pct: pctChange(previous.grossRevenue, current.grossRevenue),
|
|
18
|
+
net_revenue_delta_pct: pctChange(previous.netRevenue, current.netRevenue),
|
|
19
|
+
orders_delta_pct: pctChange(previous.orderCount, current.orderCount),
|
|
20
|
+
aov_delta_pct: pctChange(prevAov, result.aov),
|
|
21
|
+
previous_gross_revenue: previous.grossRevenue,
|
|
22
|
+
previous_net_revenue: previous.netRevenue,
|
|
23
|
+
previous_orders: previous.orderCount,
|
|
24
|
+
previous_aov: prevAov,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
export function transformProductPerformance(orders, limit, metric) {
|
|
30
|
+
const productMap = new Map();
|
|
31
|
+
let orderIdx = 0;
|
|
32
|
+
for (const order of orders) {
|
|
33
|
+
orderIdx++;
|
|
34
|
+
for (const item of order.lineItems.nodes) {
|
|
35
|
+
const key = item.product?.id ?? item.name;
|
|
36
|
+
const existing = productMap.get(key) ?? {
|
|
37
|
+
title: item.product?.title ?? item.name,
|
|
38
|
+
vendor: null,
|
|
39
|
+
revenue: 0,
|
|
40
|
+
units: 0,
|
|
41
|
+
orderIds: new Set(),
|
|
42
|
+
};
|
|
43
|
+
const price = parseFloat(item.originalTotalSet?.shopMoney?.amount ?? "0");
|
|
44
|
+
existing.revenue += price;
|
|
45
|
+
existing.units += item.quantity;
|
|
46
|
+
existing.orderIds.add(String(orderIdx));
|
|
47
|
+
productMap.set(key, existing);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const products = Array.from(productMap.values()).map((p) => ({
|
|
51
|
+
product_title: p.title,
|
|
52
|
+
vendor: p.vendor,
|
|
53
|
+
revenue: Math.round(p.revenue * 100) / 100,
|
|
54
|
+
units_sold: p.units,
|
|
55
|
+
order_count: p.orderIds.size,
|
|
56
|
+
avg_price: p.units > 0 ? Math.round((p.revenue / p.units) * 100) / 100 : 0,
|
|
57
|
+
}));
|
|
58
|
+
products.sort((a, b) => metric === "revenue" ? b.revenue - a.revenue : b.units_sold - a.units_sold);
|
|
59
|
+
return products.slice(0, limit);
|
|
60
|
+
}
|
|
61
|
+
export function transformOrders(orders) {
|
|
62
|
+
return orders.map((o) => ({
|
|
63
|
+
order_number: o.name,
|
|
64
|
+
email: o.email ?? null,
|
|
65
|
+
date: o.createdAt,
|
|
66
|
+
total: o.totalPriceSet.shopMoney.amount,
|
|
67
|
+
currency: o.totalPriceSet.shopMoney.currencyCode,
|
|
68
|
+
financial_status: o.displayFinancialStatus,
|
|
69
|
+
fulfillment_status: o.displayFulfillmentStatus || null,
|
|
70
|
+
items: o.lineItems.nodes.map((li) => ({
|
|
71
|
+
title: li.name,
|
|
72
|
+
quantity: li.quantity,
|
|
73
|
+
price: li.originalUnitPriceSet.shopMoney.amount,
|
|
74
|
+
})),
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
77
|
+
export function transformInventoryAlerts(variants, threshold) {
|
|
78
|
+
return variants
|
|
79
|
+
.filter((v) => v.inventoryQuantity <= threshold)
|
|
80
|
+
.sort((a, b) => a.inventoryQuantity - b.inventoryQuantity)
|
|
81
|
+
.map((v) => ({
|
|
82
|
+
product_title: v.product.title,
|
|
83
|
+
variant_title: v.displayName,
|
|
84
|
+
sku: v.sku,
|
|
85
|
+
inventory_quantity: v.inventoryQuantity,
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
export function transformCustomerCohort(customers, days) {
|
|
89
|
+
// Customers are pre-filtered to those who ordered in the period (via last_order_date query).
|
|
90
|
+
// "New" = first-time buyer (only 1 lifetime order, so this period IS their first).
|
|
91
|
+
// "Returning" = repeat buyer (2+ lifetime orders, meaning they ordered before this period too).
|
|
92
|
+
const newCustomers = customers.filter((c) => parseInt(c.numberOfOrders) <= 1);
|
|
93
|
+
const returning = customers.filter((c) => parseInt(c.numberOfOrders) > 1);
|
|
94
|
+
const cohortBuckets = [
|
|
95
|
+
{ label: "First-time buyer", min: 1, max: 1, count: 0, totalSpent: 0 },
|
|
96
|
+
{ label: "2-3 lifetime orders", min: 2, max: 3, count: 0, totalSpent: 0 },
|
|
97
|
+
{ label: "4-10 lifetime orders", min: 4, max: 10, count: 0, totalSpent: 0 },
|
|
98
|
+
{ label: "10+ lifetime orders", min: 11, max: Infinity, count: 0, totalSpent: 0 },
|
|
99
|
+
];
|
|
100
|
+
let totalOrders = 0;
|
|
101
|
+
for (const customer of customers) {
|
|
102
|
+
const orders = parseInt(customer.numberOfOrders) || 0;
|
|
103
|
+
const spent = parseFloat(customer.amountSpent.amount) || 0;
|
|
104
|
+
totalOrders += orders;
|
|
105
|
+
for (const bucket of cohortBuckets) {
|
|
106
|
+
if (orders >= bucket.min && orders <= bucket.max) {
|
|
107
|
+
bucket.count++;
|
|
108
|
+
bucket.totalSpent += spent;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Top customers by total spent
|
|
114
|
+
const sorted = [...customers].sort((a, b) => parseFloat(b.amountSpent.amount) - parseFloat(a.amountSpent.amount));
|
|
115
|
+
return {
|
|
116
|
+
period_days: days,
|
|
117
|
+
total_customers: customers.length,
|
|
118
|
+
new_customers: newCustomers.length,
|
|
119
|
+
returning_customers: returning.length,
|
|
120
|
+
repeat_rate: customers.length > 0
|
|
121
|
+
? Math.round((returning.length / customers.length) * 10000) / 10000
|
|
122
|
+
: 0,
|
|
123
|
+
avg_orders_per_customer: customers.length > 0
|
|
124
|
+
? Math.round((totalOrders / customers.length) * 100) / 100
|
|
125
|
+
: 0,
|
|
126
|
+
cohorts: cohortBuckets
|
|
127
|
+
.filter((b) => b.count > 0)
|
|
128
|
+
.map((b) => ({
|
|
129
|
+
label: b.label,
|
|
130
|
+
count: b.count,
|
|
131
|
+
avg_spent: b.count > 0
|
|
132
|
+
? Math.round((b.totalSpent / b.count) * 100) / 100
|
|
133
|
+
: 0,
|
|
134
|
+
})),
|
|
135
|
+
top_customers: sorted.slice(0, 5).map((c) => ({
|
|
136
|
+
email: c.email ?? null,
|
|
137
|
+
orders: parseInt(c.numberOfOrders) || 0,
|
|
138
|
+
total_spent: parseFloat(c.amountSpent.amount) || 0,
|
|
139
|
+
})),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
export function transformRecentOrders(orders) {
|
|
143
|
+
return orders.map((o) => ({
|
|
144
|
+
order_number: o.name,
|
|
145
|
+
email: o.email ?? null,
|
|
146
|
+
date: o.createdAt,
|
|
147
|
+
total: o.totalPriceSet.shopMoney.amount,
|
|
148
|
+
currency: o.totalPriceSet.shopMoney.currencyCode,
|
|
149
|
+
financial_status: o.displayFinancialStatus,
|
|
150
|
+
fulfillment_status: o.displayFulfillmentStatus || null,
|
|
151
|
+
}));
|
|
152
|
+
}
|
|
153
|
+
// ---- Sales Time Series ----
|
|
154
|
+
export function transformSalesTimeSeries(buckets, days, granularity, timezone) {
|
|
155
|
+
let totalGross = 0;
|
|
156
|
+
let totalNet = 0;
|
|
157
|
+
let totalOrders = 0;
|
|
158
|
+
const transformed = buckets.map((b) => {
|
|
159
|
+
totalGross += b.grossRevenue;
|
|
160
|
+
totalNet += b.netRevenue;
|
|
161
|
+
totalOrders += b.orderCount;
|
|
162
|
+
return {
|
|
163
|
+
date: b.date,
|
|
164
|
+
gross_revenue: Math.round(b.grossRevenue * 100) / 100,
|
|
165
|
+
net_revenue: Math.round(b.netRevenue * 100) / 100,
|
|
166
|
+
order_count: b.orderCount,
|
|
167
|
+
aov: b.orderCount > 0 ? Math.round((b.netRevenue / b.orderCount) * 100) / 100 : 0,
|
|
168
|
+
};
|
|
169
|
+
});
|
|
170
|
+
totalGross = Math.round(totalGross * 100) / 100;
|
|
171
|
+
totalNet = Math.round(totalNet * 100) / 100;
|
|
172
|
+
return {
|
|
173
|
+
period_days: days,
|
|
174
|
+
granularity,
|
|
175
|
+
timezone,
|
|
176
|
+
currency: "USD",
|
|
177
|
+
buckets: transformed,
|
|
178
|
+
totals: {
|
|
179
|
+
revenue: totalNet,
|
|
180
|
+
order_count: totalOrders,
|
|
181
|
+
aov: totalOrders > 0 ? Math.round((totalNet / totalOrders) * 100) / 100 : 0,
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
// ---- Helpers ----
|
|
186
|
+
function pctChange(previous, current) {
|
|
187
|
+
if (previous === 0)
|
|
188
|
+
return current === 0 ? 0 : 100;
|
|
189
|
+
return Math.round(((current - previous) / previous) * 10000) / 100;
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=transforms.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transforms.js","sourceRoot":"","sources":["../../../src/platforms/shopify/transforms.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
package/dist/server.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { registerKlaviyoTools } from "./platforms/klaviyo/tools.js";
|
|
3
|
+
import { registerShopifyTools } from "./platforms/shopify/tools.js";
|
|
4
|
+
import { registerCrossPlatformTools } from "./cross-platform/tools.js";
|
|
5
|
+
export function createServer() {
|
|
6
|
+
const server = new McpServer({
|
|
7
|
+
name: "dtc-mcp",
|
|
8
|
+
version: "0.1.0",
|
|
9
|
+
});
|
|
10
|
+
registerKlaviyoTools(server);
|
|
11
|
+
registerShopifyTools(server);
|
|
12
|
+
registerCrossPlatformTools(server);
|
|
13
|
+
return server;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAEvE,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,0BAA0B,CAAC,MAAM,CAAC,CAAC;IAEnC,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple in-memory TTL cache.
|
|
3
|
+
* Critical for staying within Klaviyo reporting rate limits (1/s burst, 2/m steady).
|
|
4
|
+
*/
|
|
5
|
+
export declare class TTLCache<T> {
|
|
6
|
+
private defaultTTL;
|
|
7
|
+
private cache;
|
|
8
|
+
/**
|
|
9
|
+
* @param defaultTTL Default time-to-live in milliseconds
|
|
10
|
+
*/
|
|
11
|
+
constructor(defaultTTL: number);
|
|
12
|
+
get(key: string): T | undefined;
|
|
13
|
+
set(key: string, value: T, ttl?: number): void;
|
|
14
|
+
has(key: string): boolean;
|
|
15
|
+
delete(key: string): void;
|
|
16
|
+
clear(): void;
|
|
17
|
+
get size(): number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Build a stable cache key from an endpoint and params object.
|
|
21
|
+
* Sorts keys to ensure consistent ordering.
|
|
22
|
+
*/
|
|
23
|
+
export declare function buildCacheKey(endpoint: string, params: Record<string, unknown>): string;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple in-memory TTL cache.
|
|
3
|
+
* Critical for staying within Klaviyo reporting rate limits (1/s burst, 2/m steady).
|
|
4
|
+
*/
|
|
5
|
+
export class TTLCache {
|
|
6
|
+
defaultTTL;
|
|
7
|
+
cache = new Map();
|
|
8
|
+
/**
|
|
9
|
+
* @param defaultTTL Default time-to-live in milliseconds
|
|
10
|
+
*/
|
|
11
|
+
constructor(defaultTTL) {
|
|
12
|
+
this.defaultTTL = defaultTTL;
|
|
13
|
+
}
|
|
14
|
+
get(key) {
|
|
15
|
+
const entry = this.cache.get(key);
|
|
16
|
+
if (!entry)
|
|
17
|
+
return undefined;
|
|
18
|
+
if (Date.now() > entry.expires) {
|
|
19
|
+
this.cache.delete(key);
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
return entry.value;
|
|
23
|
+
}
|
|
24
|
+
set(key, value, ttl) {
|
|
25
|
+
this.cache.set(key, {
|
|
26
|
+
value,
|
|
27
|
+
expires: Date.now() + (ttl ?? this.defaultTTL),
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
has(key) {
|
|
31
|
+
return this.get(key) !== undefined;
|
|
32
|
+
}
|
|
33
|
+
delete(key) {
|
|
34
|
+
this.cache.delete(key);
|
|
35
|
+
}
|
|
36
|
+
clear() {
|
|
37
|
+
this.cache.clear();
|
|
38
|
+
}
|
|
39
|
+
get size() {
|
|
40
|
+
// Clean expired entries before reporting size
|
|
41
|
+
for (const [key, entry] of this.cache) {
|
|
42
|
+
if (Date.now() > entry.expires) {
|
|
43
|
+
this.cache.delete(key);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return this.cache.size;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Build a stable cache key from an endpoint and params object.
|
|
51
|
+
* Sorts keys to ensure consistent ordering.
|
|
52
|
+
*/
|
|
53
|
+
export function buildCacheKey(endpoint, params) {
|
|
54
|
+
const sorted = Object.keys(params)
|
|
55
|
+
.sort()
|
|
56
|
+
.reduce((acc, key) => {
|
|
57
|
+
acc[key] = params[key];
|
|
58
|
+
return acc;
|
|
59
|
+
}, {});
|
|
60
|
+
return `${endpoint}:${JSON.stringify(sorted)}`;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/shared/cache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,OAAO,QAAQ;IAMC;IALZ,KAAK,GAAG,IAAI,GAAG,EAAyC,CAAC;IAEjE;;OAEG;IACH,YAAoB,UAAkB;QAAlB,eAAU,GAAV,UAAU,CAAQ;IAAG,CAAC;IAE1C,GAAG,CAAC,GAAW;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAC7B,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;YAC/B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,KAAK,CAAC,KAAK,CAAC;IACrB,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,KAAQ,EAAE,GAAY;QACrC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YAClB,KAAK;YACL,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC;SAC/C,CAAC,CAAC;IACL,CAAC;IAED,GAAG,CAAC,GAAW;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC;IACrC,CAAC;IAED,MAAM,CAAC,GAAW;QAChB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,IAAI,IAAI;QACN,8CAA8C;QAC9C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACtC,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;gBAC/B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,QAAgB,EAChB,MAA+B;IAE/B,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;SAC/B,IAAI,EAAE;SACN,MAAM,CACL,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QACX,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACvB,OAAO,GAAG,CAAC;IACb,CAAC,EACD,EAA6B,CAC9B,CAAC;IACJ,OAAO,GAAG,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ToolResponse } from "./types.js";
|
|
2
|
+
export declare class KlaviyoApiError extends Error {
|
|
3
|
+
status: number;
|
|
4
|
+
constructor(status: number, message: string);
|
|
5
|
+
}
|
|
6
|
+
export declare class ShopifyApiError extends Error {
|
|
7
|
+
extensions?: Record<string, unknown> | undefined;
|
|
8
|
+
constructor(message: string, extensions?: Record<string, unknown> | undefined);
|
|
9
|
+
}
|
|
10
|
+
export declare class ConfigError extends Error {
|
|
11
|
+
constructor(message: string);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Format any error into an MCP tool error response.
|
|
15
|
+
* All errors are actionable — they include what the user needs to do.
|
|
16
|
+
*/
|
|
17
|
+
export declare function formatError(error: unknown): ToolResponse;
|
|
18
|
+
/**
|
|
19
|
+
* Return a "not configured" error for Shopify tools when credentials are missing.
|
|
20
|
+
*/
|
|
21
|
+
export declare function shopifyNotConfigured(): ToolResponse;
|
|
22
|
+
/**
|
|
23
|
+
* Create a successful tool response from a JSON-serializable value.
|
|
24
|
+
*/
|
|
25
|
+
export declare function toolResult(data: unknown): ToolResponse;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
export class KlaviyoApiError extends Error {
|
|
2
|
+
status;
|
|
3
|
+
constructor(status, message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.status = status;
|
|
6
|
+
this.name = "KlaviyoApiError";
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export class ShopifyApiError extends Error {
|
|
10
|
+
extensions;
|
|
11
|
+
constructor(message, extensions) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.extensions = extensions;
|
|
14
|
+
this.name = "ShopifyApiError";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export class ConfigError extends Error {
|
|
18
|
+
constructor(message) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.name = "ConfigError";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Format any error into an MCP tool error response.
|
|
25
|
+
* All errors are actionable — they include what the user needs to do.
|
|
26
|
+
*/
|
|
27
|
+
export function formatError(error) {
|
|
28
|
+
if (error instanceof KlaviyoApiError) {
|
|
29
|
+
let advice = "";
|
|
30
|
+
if (error.status === 401) {
|
|
31
|
+
advice =
|
|
32
|
+
" Check that KLAVIYO_API_KEY is a valid private key (starts with pk_).";
|
|
33
|
+
}
|
|
34
|
+
else if (error.status === 429) {
|
|
35
|
+
advice = " Rate limited. Try again in a few seconds.";
|
|
36
|
+
}
|
|
37
|
+
else if (error.status === 403) {
|
|
38
|
+
advice =
|
|
39
|
+
" Your API key may not have the required scopes. Check Klaviyo API key permissions.";
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
content: [
|
|
43
|
+
{
|
|
44
|
+
type: "text",
|
|
45
|
+
text: `Klaviyo API Error (${error.status}): ${error.message}${advice}`,
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
isError: true,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (error instanceof ShopifyApiError) {
|
|
52
|
+
return {
|
|
53
|
+
content: [
|
|
54
|
+
{
|
|
55
|
+
type: "text",
|
|
56
|
+
text: `Shopify API Error: ${error.message}`,
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
isError: true,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (error instanceof ConfigError) {
|
|
63
|
+
return {
|
|
64
|
+
content: [{ type: "text", text: error.message }],
|
|
65
|
+
isError: true,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
69
|
+
return {
|
|
70
|
+
content: [{ type: "text", text: `Error: ${msg}` }],
|
|
71
|
+
isError: true,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Return a "not configured" error for Shopify tools when credentials are missing.
|
|
76
|
+
*/
|
|
77
|
+
export function shopifyNotConfigured() {
|
|
78
|
+
return {
|
|
79
|
+
content: [
|
|
80
|
+
{
|
|
81
|
+
type: "text",
|
|
82
|
+
text: "Shopify not configured. Set SHOPIFY_STORE + SHOPIFY_CLIENT_ID + SHOPIFY_CLIENT_SECRET (Dev Dashboard app), or SHOPIFY_STORE + SHOPIFY_ACCESS_TOKEN (legacy app).",
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
isError: true,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Create a successful tool response from a JSON-serializable value.
|
|
90
|
+
*/
|
|
91
|
+
export function toolResult(data) {
|
|
92
|
+
return {
|
|
93
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/shared/errors.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAE/B;IADT,YACS,MAAc,EACrB,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAHR,WAAM,GAAN,MAAM,CAAQ;QAIrB,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AAED,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAG/B;IAFT,YACE,OAAe,EACR,UAAoC;QAE3C,KAAK,CAAC,OAAO,CAAC,CAAC;QAFR,eAAU,GAAV,UAAU,CAA0B;QAG3C,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AAED,MAAM,OAAO,WAAY,SAAQ,KAAK;IACpC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,KAAK,YAAY,eAAe,EAAE,CAAC;QACrC,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACzB,MAAM;gBACJ,uEAAuE,CAAC;QAC5E,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAChC,MAAM,GAAG,4CAA4C,CAAC;QACxD,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAChC,MAAM;gBACJ,oFAAoF,CAAC;QACzF,CAAC;QACD,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,sBAAsB,KAAK,CAAC,MAAM,MAAM,KAAK,CAAC,OAAO,GAAG,MAAM,EAAE;iBACvE;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IAED,IAAI,KAAK,YAAY,eAAe,EAAE,CAAC;QACrC,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,sBAAsB,KAAK,CAAC,OAAO,EAAE;iBAC5C;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IAED,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;QACjC,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;YAChD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACnE,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,EAAE,EAAE,CAAC;QAClD,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,kKAAkK;aACzK;SACF;QACD,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,IAAa;IACtC,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;KACjE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opaque cursor pagination helpers.
|
|
3
|
+
* Both Klaviyo and Shopify cursors are encoded into opaque base64url strings
|
|
4
|
+
* so the LLM never sees platform-specific pagination parameters.
|
|
5
|
+
*/
|
|
6
|
+
export declare function encodeCursor(raw: string): string;
|
|
7
|
+
export declare function decodeCursor(opaque: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Extract and encode cursor from Klaviyo's JSON:API `links.next` URL.
|
|
10
|
+
* Klaviyo returns: links.next = "https://a.klaviyo.com/api/campaigns?page[cursor]=XXXX"
|
|
11
|
+
*/
|
|
12
|
+
export declare function extractKlaviyoCursor(links?: {
|
|
13
|
+
next?: string;
|
|
14
|
+
}): string | null;
|
|
15
|
+
/**
|
|
16
|
+
* Extract and encode cursor from Shopify GraphQL pageInfo.
|
|
17
|
+
*/
|
|
18
|
+
export declare function extractShopifyCursor(pageInfo?: {
|
|
19
|
+
hasNextPage: boolean;
|
|
20
|
+
endCursor?: string | null;
|
|
21
|
+
}): string | null;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opaque cursor pagination helpers.
|
|
3
|
+
* Both Klaviyo and Shopify cursors are encoded into opaque base64url strings
|
|
4
|
+
* so the LLM never sees platform-specific pagination parameters.
|
|
5
|
+
*/
|
|
6
|
+
export function encodeCursor(raw) {
|
|
7
|
+
return Buffer.from(raw).toString("base64url");
|
|
8
|
+
}
|
|
9
|
+
export function decodeCursor(opaque) {
|
|
10
|
+
return Buffer.from(opaque, "base64url").toString();
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Extract and encode cursor from Klaviyo's JSON:API `links.next` URL.
|
|
14
|
+
* Klaviyo returns: links.next = "https://a.klaviyo.com/api/campaigns?page[cursor]=XXXX"
|
|
15
|
+
*/
|
|
16
|
+
export function extractKlaviyoCursor(links) {
|
|
17
|
+
if (!links?.next)
|
|
18
|
+
return null;
|
|
19
|
+
try {
|
|
20
|
+
const url = new URL(links.next);
|
|
21
|
+
const cursor = url.searchParams.get("page[cursor]");
|
|
22
|
+
return cursor ? encodeCursor(cursor) : null;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Extract and encode cursor from Shopify GraphQL pageInfo.
|
|
30
|
+
*/
|
|
31
|
+
export function extractShopifyCursor(pageInfo) {
|
|
32
|
+
if (!pageInfo?.hasNextPage || !pageInfo.endCursor)
|
|
33
|
+
return null;
|
|
34
|
+
return encodeCursor(pageInfo.endCursor);
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=pagination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../src/shared/pagination.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAC;AACrD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAEpC;IACC,IAAI,CAAC,KAAK,EAAE,IAAI;QAAE,OAAO,IAAI,CAAC;IAC9B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACpD,OAAO,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAGpC;IACC,IAAI,CAAC,QAAQ,EAAE,WAAW,IAAI,CAAC,QAAQ,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAC/D,OAAO,YAAY,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;AAC1C,CAAC"}
|