medusa-analytics 0.0.13 → 0.0.15

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.
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GET = GET;
4
+ const shared_1 = require("../products/shared");
5
+ async function GET(req, res) {
6
+ try {
7
+ const salesChannels = await (0, shared_1.listSalesChannels)(req);
8
+ const body = {
9
+ salesChannels,
10
+ };
11
+ res.json(body);
12
+ }
13
+ catch (err) {
14
+ console.error("Products filters analytics error:", err);
15
+ res.status(500).json({
16
+ error: "Failed to fetch product analytics filters",
17
+ message: err instanceof Error ? err.message : String(err),
18
+ });
19
+ }
20
+ }
21
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2FuYWx5dGljcy9wcm9kdWN0cy1maWx0ZXJzL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBSUEsa0JBa0JDO0FBcEJELCtDQUFzRDtBQUUvQyxLQUFLLFVBQVUsR0FBRyxDQUN2QixHQUFrQixFQUNsQixHQUFtQjtJQUVuQixJQUFJLENBQUM7UUFDSCxNQUFNLGFBQWEsR0FBRyxNQUFNLElBQUEsMEJBQWlCLEVBQUMsR0FBRyxDQUFDLENBQUE7UUFDbEQsTUFBTSxJQUFJLEdBQXVCO1lBQy9CLGFBQWE7U0FDZCxDQUFBO1FBRUQsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUNoQixDQUFDO0lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztRQUNiLE9BQU8sQ0FBQyxLQUFLLENBQUMsbUNBQW1DLEVBQUUsR0FBRyxDQUFDLENBQUE7UUFDdkQsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUM7WUFDbkIsS0FBSyxFQUFFLDJDQUEyQztZQUNsRCxPQUFPLEVBQUUsR0FBRyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQztTQUMxRCxDQUFDLENBQUE7SUFDSixDQUFDO0FBQ0gsQ0FBQyJ9
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2FuYWx5dGljcy9wcm9kdWN0cy1maWx0ZXJzL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIifQ==
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GET = GET;
4
+ const shared_1 = require("../products/shared");
5
+ async function GET(req, res) {
6
+ const period = (0, shared_1.parseOverTimePeriod)(req.query?.period);
7
+ const salesChannelId = (0, shared_1.parseSalesChannelId)(req.query?.sales_channel_id);
8
+ try {
9
+ const result = await (0, shared_1.getProductsOverTime)(req, period, salesChannelId);
10
+ const body = {
11
+ series: result.series,
12
+ productViewsConnected: result.productViewsConnected,
13
+ };
14
+ res.json(body);
15
+ }
16
+ catch (err) {
17
+ console.error("Products over time analytics error:", err);
18
+ res.status(500).json({
19
+ error: "Failed to fetch products over time",
20
+ message: err instanceof Error ? err.message : String(err),
21
+ });
22
+ }
23
+ }
24
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2FuYWx5dGljcy9wcm9kdWN0cy1vdmVyLXRpbWUvcm91dGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFRQSxrQkF1QkM7QUE3QkQsK0NBSTJCO0FBRXBCLEtBQUssVUFBVSxHQUFHLENBQ3ZCLEdBQWtCLEVBQ2xCLEdBQW1CO0lBRW5CLE1BQU0sTUFBTSxHQUFHLElBQUEsNEJBQW1CLEVBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQTtJQUNyRCxNQUFNLGNBQWMsR0FBRyxJQUFBLDRCQUFtQixFQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQTtJQUV2RSxJQUFJLENBQUM7UUFDSCxNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUEsNEJBQW1CLEVBQUMsR0FBRyxFQUFFLE1BQU0sRUFBRSxjQUFjLENBQUMsQ0FBQTtRQUVyRSxNQUFNLElBQUksR0FBd0I7WUFDaEMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxNQUFNO1lBQ3JCLHFCQUFxQixFQUFFLE1BQU0sQ0FBQyxxQkFBcUI7U0FDcEQsQ0FBQTtRQUVELEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUE7SUFDaEIsQ0FBQztJQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDYixPQUFPLENBQUMsS0FBSyxDQUFDLHFDQUFxQyxFQUFFLEdBQUcsQ0FBQyxDQUFBO1FBQ3pELEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDO1lBQ25CLEtBQUssRUFBRSxvQ0FBb0M7WUFDM0MsT0FBTyxFQUFFLEdBQUcsWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUM7U0FDMUQsQ0FBQyxDQUFBO0lBQ0osQ0FBQztBQUNILENBQUMifQ==
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2FuYWx5dGljcy9wcm9kdWN0cy1vdmVyLXRpbWUvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GET = GET;
4
+ const shared_1 = require("../products/shared");
5
+ async function GET(req, res) {
6
+ const days = (0, shared_1.parseDaysParam)(req.query?.days);
7
+ const salesChannelId = (0, shared_1.parseSalesChannelId)(req.query?.sales_channel_id);
8
+ const range = (0, shared_1.getRangeFromDays)(days);
9
+ try {
10
+ const [sales, views] = await Promise.all([
11
+ (0, shared_1.aggregateProductSales)(req, range, salesChannelId),
12
+ (0, shared_1.aggregateProductViews)(req, range, salesChannelId),
13
+ ]);
14
+ const combined = (0, shared_1.combineSalesAndViews)(sales.products, views.products);
15
+ const topViewedProducts = combined
16
+ .filter((row) => row.total_views > 0)
17
+ .sort((left, right) => {
18
+ if (right.total_views !== left.total_views) {
19
+ return right.total_views - left.total_views;
20
+ }
21
+ return right.units_sold - left.units_sold;
22
+ })
23
+ .slice(0, 10);
24
+ const viewOpportunities = combined
25
+ .filter((row) => row.total_views > 0)
26
+ .sort((left, right) => {
27
+ const leftScore = left.views_per_unit ?? 0;
28
+ const rightScore = right.views_per_unit ?? 0;
29
+ if (rightScore !== leftScore) {
30
+ return rightScore - leftScore;
31
+ }
32
+ return right.total_views - left.total_views;
33
+ })
34
+ .slice(0, 10);
35
+ const body = {
36
+ topViewedProducts,
37
+ viewOpportunities,
38
+ totalViews: views.totalViews,
39
+ productViewsConnected: views.connected,
40
+ };
41
+ res.json(body);
42
+ }
43
+ catch (err) {
44
+ console.error("Products performance analytics error:", err);
45
+ res.status(500).json({
46
+ error: "Failed to fetch products performance analytics",
47
+ message: err instanceof Error ? err.message : String(err),
48
+ });
49
+ }
50
+ }
51
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2FuYWx5dGljcy9wcm9kdWN0cy1wZXJmb3JtYW5jZS9yb3V0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQWNBLGtCQW9EQztBQTdERCwrQ0FPMkI7QUFFcEIsS0FBSyxVQUFVLEdBQUcsQ0FDdkIsR0FBa0IsRUFDbEIsR0FBbUI7SUFFbkIsTUFBTSxJQUFJLEdBQUcsSUFBQSx1QkFBYyxFQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLENBQUE7SUFDNUMsTUFBTSxjQUFjLEdBQUcsSUFBQSw0QkFBbUIsRUFBQyxHQUFHLENBQUMsS0FBSyxFQUFFLGdCQUFnQixDQUFDLENBQUE7SUFDdkUsTUFBTSxLQUFLLEdBQUcsSUFBQSx5QkFBZ0IsRUFBQyxJQUFJLENBQUMsQ0FBQTtJQUVwQyxJQUFJLENBQUM7UUFDSCxNQUFNLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQztZQUN2QyxJQUFBLDhCQUFxQixFQUFDLEdBQUcsRUFBRSxLQUFLLEVBQUUsY0FBYyxDQUFDO1lBQ2pELElBQUEsOEJBQXFCLEVBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxjQUFjLENBQUM7U0FDbEQsQ0FBQyxDQUFBO1FBRUYsTUFBTSxRQUFRLEdBQUcsSUFBQSw2QkFBb0IsRUFBQyxLQUFLLENBQUMsUUFBUSxFQUFFLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQTtRQUNyRSxNQUFNLGlCQUFpQixHQUE0QixRQUFRO2FBQ3hELE1BQU0sQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLFdBQVcsR0FBRyxDQUFDLENBQUM7YUFDcEMsSUFBSSxDQUFDLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFO1lBQ3BCLElBQUksS0FBSyxDQUFDLFdBQVcsS0FBSyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7Z0JBQzNDLE9BQU8sS0FBSyxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFBO1lBQzdDLENBQUM7WUFDRCxPQUFPLEtBQUssQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQTtRQUMzQyxDQUFDLENBQUM7YUFDRCxLQUFLLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFBO1FBRWYsTUFBTSxpQkFBaUIsR0FBNEIsUUFBUTthQUN4RCxNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxXQUFXLEdBQUcsQ0FBQyxDQUFDO2FBQ3BDLElBQUksQ0FBQyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRTtZQUNwQixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsY0FBYyxJQUFJLENBQUMsQ0FBQTtZQUMxQyxNQUFNLFVBQVUsR0FBRyxLQUFLLENBQUMsY0FBYyxJQUFJLENBQUMsQ0FBQTtZQUM1QyxJQUFJLFVBQVUsS0FBSyxTQUFTLEVBQUUsQ0FBQztnQkFDN0IsT0FBTyxVQUFVLEdBQUcsU0FBUyxDQUFBO1lBQy9CLENBQUM7WUFDRCxPQUFPLEtBQUssQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQTtRQUM3QyxDQUFDLENBQUM7YUFDRCxLQUFLLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFBO1FBRWYsTUFBTSxJQUFJLEdBQW1DO1lBQzNDLGlCQUFpQjtZQUNqQixpQkFBaUI7WUFDakIsVUFBVSxFQUFFLEtBQUssQ0FBQyxVQUFVO1lBQzVCLHFCQUFxQixFQUFFLEtBQUssQ0FBQyxTQUFTO1NBQ3ZDLENBQUE7UUFFRCxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFBO0lBQ2hCLENBQUM7SUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1FBQ2IsT0FBTyxDQUFDLEtBQUssQ0FBQyx1Q0FBdUMsRUFBRSxHQUFHLENBQUMsQ0FBQTtRQUMzRCxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQztZQUNuQixLQUFLLEVBQUUsZ0RBQWdEO1lBQ3ZELE9BQU8sRUFBRSxHQUFHLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDO1NBQzFELENBQUMsQ0FBQTtJQUNKLENBQUM7QUFDSCxDQUFDIn0=
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2FuYWx5dGljcy9wcm9kdWN0cy1wZXJmb3JtYW5jZS90eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GET = GET;
4
+ const shared_1 = require("../products/shared");
5
+ async function GET(req, res) {
6
+ const days = (0, shared_1.parseDaysParam)(req.query?.days);
7
+ const salesChannelId = (0, shared_1.parseSalesChannelId)(req.query?.sales_channel_id);
8
+ const range = (0, shared_1.getRangeFromDays)(days);
9
+ try {
10
+ const [sales, views] = await Promise.all([
11
+ (0, shared_1.aggregateProductSales)(req, range, salesChannelId),
12
+ (0, shared_1.aggregateProductViews)(req, range, salesChannelId),
13
+ ]);
14
+ const viewToOrderRatio = sales.totals.ordersWithProducts > 0
15
+ ? Math.round((views.totalViews / sales.totals.ordersWithProducts) * 100) / 100
16
+ : null;
17
+ const body = {
18
+ unitsSold: sales.totals.unitsSold,
19
+ productRevenue: sales.totals.productRevenue,
20
+ ordersWithProducts: sales.totals.ordersWithProducts,
21
+ activeProductsSold: sales.totals.activeProductsSold,
22
+ totalProductViews: views.totalViews,
23
+ viewToOrderRatio,
24
+ productViewsConnected: views.connected,
25
+ };
26
+ res.json(body);
27
+ }
28
+ catch (err) {
29
+ console.error("Products summary analytics error:", err);
30
+ res.status(500).json({
31
+ error: "Failed to fetch products summary",
32
+ message: err instanceof Error ? err.message : String(err),
33
+ });
34
+ }
35
+ }
36
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2FuYWx5dGljcy9wcm9kdWN0cy1zdW1tYXJ5L3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBVUEsa0JBdUNDO0FBL0NELCtDQU0yQjtBQUVwQixLQUFLLFVBQVUsR0FBRyxDQUN2QixHQUFrQixFQUNsQixHQUFtQjtJQUVuQixNQUFNLElBQUksR0FBRyxJQUFBLHVCQUFjLEVBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQTtJQUM1QyxNQUFNLGNBQWMsR0FBRyxJQUFBLDRCQUFtQixFQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQTtJQUN2RSxNQUFNLEtBQUssR0FBRyxJQUFBLHlCQUFnQixFQUFDLElBQUksQ0FBQyxDQUFBO0lBRXBDLElBQUksQ0FBQztRQUNILE1BQU0sQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDO1lBQ3ZDLElBQUEsOEJBQXFCLEVBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxjQUFjLENBQUM7WUFDakQsSUFBQSw4QkFBcUIsRUFBQyxHQUFHLEVBQUUsS0FBSyxFQUFFLGNBQWMsQ0FBQztTQUNsRCxDQUFDLENBQUE7UUFFRixNQUFNLGdCQUFnQixHQUNwQixLQUFLLENBQUMsTUFBTSxDQUFDLGtCQUFrQixHQUFHLENBQUM7WUFDakMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQ1IsQ0FBQyxLQUFLLENBQUMsVUFBVSxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsa0JBQWtCLENBQUMsR0FBRyxHQUFHLENBQzNELEdBQUcsR0FBRztZQUNULENBQUMsQ0FBQyxJQUFJLENBQUE7UUFFVixNQUFNLElBQUksR0FBdUI7WUFDL0IsU0FBUyxFQUFFLEtBQUssQ0FBQyxNQUFNLENBQUMsU0FBUztZQUNqQyxjQUFjLEVBQUUsS0FBSyxDQUFDLE1BQU0sQ0FBQyxjQUFjO1lBQzNDLGtCQUFrQixFQUFFLEtBQUssQ0FBQyxNQUFNLENBQUMsa0JBQWtCO1lBQ25ELGtCQUFrQixFQUFFLEtBQUssQ0FBQyxNQUFNLENBQUMsa0JBQWtCO1lBQ25ELGlCQUFpQixFQUFFLEtBQUssQ0FBQyxVQUFVO1lBQ25DLGdCQUFnQjtZQUNoQixxQkFBcUIsRUFBRSxLQUFLLENBQUMsU0FBUztTQUN2QyxDQUFBO1FBRUQsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUNoQixDQUFDO0lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztRQUNiLE9BQU8sQ0FBQyxLQUFLLENBQUMsbUNBQW1DLEVBQUUsR0FBRyxDQUFDLENBQUE7UUFDdkQsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUM7WUFDbkIsS0FBSyxFQUFFLGtDQUFrQztZQUN6QyxPQUFPLEVBQUUsR0FBRyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQztTQUMxRCxDQUFDLENBQUE7SUFDSixDQUFDO0FBQ0gsQ0FBQyJ9
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2FuYWx5dGljcy9wcm9kdWN0cy1zdW1tYXJ5L3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIifQ==
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GET = GET;
4
+ const shared_1 = require("../products/shared");
5
+ async function GET(req, res) {
6
+ const period = (0, shared_1.parseTopSellerPeriod)(req.query?.period);
7
+ const salesChannelId = (0, shared_1.parseSalesChannelId)(req.query?.sales_channel_id);
8
+ const range = (0, shared_1.getRangeFromTopSellerPeriod)(period);
9
+ try {
10
+ const [sales, views] = await Promise.all([
11
+ (0, shared_1.aggregateProductSales)(req, range, salesChannelId),
12
+ (0, shared_1.aggregateProductViews)(req, range, salesChannelId),
13
+ ]);
14
+ const products = (0, shared_1.combineSalesAndViews)(sales.products, views.products)
15
+ .sort((left, right) => {
16
+ if (right.units_sold !== left.units_sold) {
17
+ return right.units_sold - left.units_sold;
18
+ }
19
+ if (right.revenue !== left.revenue) {
20
+ return right.revenue - left.revenue;
21
+ }
22
+ return right.order_count - left.order_count;
23
+ })
24
+ .slice(0, 10)
25
+ .map((row) => ({
26
+ product_id: row.product_id,
27
+ product_title: row.product_title,
28
+ units_sold: row.units_sold,
29
+ revenue: row.revenue,
30
+ order_count: row.order_count,
31
+ total_views: row.total_views,
32
+ }));
33
+ const body = {
34
+ period,
35
+ products,
36
+ productViewsConnected: views.connected,
37
+ };
38
+ res.json(body);
39
+ }
40
+ catch (err) {
41
+ console.error("Products top sellers analytics error:", err);
42
+ res.status(500).json({
43
+ error: "Failed to fetch product top sellers",
44
+ message: err instanceof Error ? err.message : String(err),
45
+ });
46
+ }
47
+ }
48
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2FuYWx5dGljcy9wcm9kdWN0cy10b3Atc2VsbGVycy9yb3V0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQVdBLGtCQW1EQztBQTVERCwrQ0FPMkI7QUFFcEIsS0FBSyxVQUFVLEdBQUcsQ0FDdkIsR0FBa0IsRUFDbEIsR0FBbUI7SUFFbkIsTUFBTSxNQUFNLEdBQUcsSUFBQSw2QkFBb0IsRUFBQyxHQUFHLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFBO0lBQ3RELE1BQU0sY0FBYyxHQUFHLElBQUEsNEJBQW1CLEVBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxnQkFBZ0IsQ0FBQyxDQUFBO0lBQ3ZFLE1BQU0sS0FBSyxHQUFHLElBQUEsb0NBQTJCLEVBQUMsTUFBTSxDQUFDLENBQUE7SUFFakQsSUFBSSxDQUFDO1FBQ0gsTUFBTSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsR0FBRyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUM7WUFDdkMsSUFBQSw4QkFBcUIsRUFBQyxHQUFHLEVBQUUsS0FBSyxFQUFFLGNBQWMsQ0FBQztZQUNqRCxJQUFBLDhCQUFxQixFQUFDLEdBQUcsRUFBRSxLQUFLLEVBQUUsY0FBYyxDQUFDO1NBQ2xELENBQUMsQ0FBQTtRQUVGLE1BQU0sUUFBUSxHQUEwQixJQUFBLDZCQUFvQixFQUMxRCxLQUFLLENBQUMsUUFBUSxFQUNkLEtBQUssQ0FBQyxRQUFRLENBQ2Y7YUFDRSxJQUFJLENBQUMsQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLEVBQUU7WUFDcEIsSUFBSSxLQUFLLENBQUMsVUFBVSxLQUFLLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztnQkFDekMsT0FBTyxLQUFLLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUE7WUFDM0MsQ0FBQztZQUNELElBQUksS0FBSyxDQUFDLE9BQU8sS0FBSyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ25DLE9BQU8sS0FBSyxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFBO1lBQ3JDLENBQUM7WUFDRCxPQUFPLEtBQUssQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQTtRQUM3QyxDQUFDLENBQUM7YUFDRCxLQUFLLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQzthQUNaLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUNiLFVBQVUsRUFBRSxHQUFHLENBQUMsVUFBVTtZQUMxQixhQUFhLEVBQUUsR0FBRyxDQUFDLGFBQWE7WUFDaEMsVUFBVSxFQUFFLEdBQUcsQ0FBQyxVQUFVO1lBQzFCLE9BQU8sRUFBRSxHQUFHLENBQUMsT0FBTztZQUNwQixXQUFXLEVBQUUsR0FBRyxDQUFDLFdBQVc7WUFDNUIsV0FBVyxFQUFFLEdBQUcsQ0FBQyxXQUFXO1NBQzdCLENBQUMsQ0FBQyxDQUFBO1FBRUwsTUFBTSxJQUFJLEdBQTBCO1lBQ2xDLE1BQU07WUFDTixRQUFRO1lBQ1IscUJBQXFCLEVBQUUsS0FBSyxDQUFDLFNBQVM7U0FDdkMsQ0FBQTtRQUVELEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUE7SUFDaEIsQ0FBQztJQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDYixPQUFPLENBQUMsS0FBSyxDQUFDLHVDQUF1QyxFQUFFLEdBQUcsQ0FBQyxDQUFBO1FBQzNELEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDO1lBQ25CLEtBQUssRUFBRSxxQ0FBcUM7WUFDNUMsT0FBTyxFQUFFLEdBQUcsWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUM7U0FDMUQsQ0FBQyxDQUFBO0lBQ0osQ0FBQztBQUNILENBQUMifQ==
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2FuYWx5dGljcy9wcm9kdWN0cy10b3Atc2VsbGVycy90eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=
package/README.md CHANGED
@@ -131,6 +131,51 @@ The dashboard loads extensions by **package name** from `node_modules`. Using a
131
131
  On the server: startup logs for any error when loading `medusa-analytics` or `medusa-analytics/admin`.
132
132
  If the admin module fails to load (e.g. missing dependency or wrong path), that plugin’s menu items will not appear.
133
133
 
134
+ ## Features
135
+
136
+ - Orders dashboard with KPI cards, status breakdowns, and order trends.
137
+ - Customers dashboard with registration mix and customer growth trends.
138
+ - Products dashboard with units sold, product revenue, top sellers, product views, and view-to-sales opportunity tables.
139
+
140
+ ## Product Analytics Notes
141
+
142
+ The `Products` tab is built into the Analytics admin page and combines two data sources:
143
+
144
+ - Sales metrics come from Medusa orders and order line items.
145
+ - Product view metrics come from the `product_view` module provided by `medusa-product-helper`.
146
+
147
+ If `medusa-product-helper` is not installed or storefront product views are not being tracked yet, the Products dashboard still shows sales analytics, but view-based cards and charts will appear empty or unavailable.
148
+
149
+ ### Recommended plugin setup for full Products analytics
150
+
151
+ Register both plugins in your Medusa app:
152
+
153
+ ```ts
154
+ plugins: [
155
+ {
156
+ resolve: "medusa-analytics",
157
+ options: {},
158
+ },
159
+ {
160
+ resolve: "medusa-product-helper",
161
+ options: {},
162
+ },
163
+ ]
164
+ ```
165
+
166
+ With both plugins enabled, the Products dashboard can show:
167
+
168
+ - Best sellers by `units sold` for week, month, year, and all time.
169
+ - Product sales and revenue trends over time.
170
+ - Most-viewed products based on tracked product view events.
171
+ - View-to-sales opportunity rows to identify high-interest products with weak sell-through.
172
+ - Sales channel filtering for product analytics in the admin dashboard.
173
+
174
+ When a sales channel is selected in the Products dashboard:
175
+
176
+ - Sales metrics are filtered by `order.sales_channel_id`.
177
+ - Product view metrics are scoped to products assigned to that sales channel.
178
+
134
179
  ## What is Medusa
135
180
 
136
181
  Medusa is a set of commerce modules and tools that allow you to build rich, reliable, and performant commerce applications without reinventing core commerce logic. The modules can be customized and used to build advanced ecommerce stores, marketplaces, or any product that needs foundational commerce primitives. All modules are open-source and freely available on npm.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "medusa-analytics",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "description": "A starter for Medusa plugins.",
5
5
  "author": "Medusa (https://medusajs.com)",
6
6
  "license": "MIT",