medusa-stats 1.0.8 → 1.0.10

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.
@@ -44,4 +44,4 @@ const registerProvidersInDb = async ({ container, }) => {
44
44
  }
45
45
  await financialSummaryService.upsert(upsertData);
46
46
  };
47
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbG9hZGVycy9zdGF0aXN0aWNzL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsdURBQW1GO0FBQ25GLGlFQUFzRTtBQVF0RSxxREFBa0Y7QUFLbEYsbURBQTZEO0FBRTdELE1BQU0seUJBQXlCLEdBQUcsZ0JBQWdCLENBQUE7QUFFbEQsTUFBTSxjQUFjLEdBQUcsS0FBSyxFQUFFLEtBQVUsRUFBRSxTQUEwQixFQUFFLGFBQWtCLEVBQUUsRUFBRTtJQUN4RixJQUFJLENBQUMsS0FBSyxFQUFFLFVBQVUsRUFBRSxDQUFDO1FBQ3JCLE1BQU0sSUFBSSxtQkFBVyxDQUNqQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsRUFDbEMseUVBQXlFLENBQzVFLENBQUE7SUFDTCxDQUFDO0lBRUQsTUFBTSxHQUFHLEdBQUcsTUFBTSxLQUFLLENBQUMsVUFBVSxHQUFHLGFBQWEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksYUFBYSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUM3RSxFQUFFLENBQUE7SUFLTixTQUFTLENBQUMsUUFBUSxDQUFDO1FBQ2YsQ0FBQyxHQUFHLENBQUMsRUFBRSxJQUFBLGdCQUFPLEVBQUMsS0FBSyxDQUFDO0tBQ3hCLENBQUMsQ0FBQztJQUlILGtCQUFNLENBQUMsSUFBSSxDQUFDLG1DQUFtQyxLQUFLLENBQUMsVUFBVSxjQUFjLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDcEYsU0FBUyxDQUFDLFdBQVcsQ0FBQyx5QkFBeUIsRUFBRSxJQUFBLGdCQUFPLEVBQUMsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLFlBQVksRUFBRSxLQUFLLENBQUMsV0FBVyxJQUFJLEtBQUssQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUE7QUFDL0gsQ0FBQyxDQUFBO0FBRUQsa0JBQWUsS0FBSyxFQUFFLEVBQ2xCLFNBQVMsRUFDVCxPQUFPLEdBUVYsRUFBaUIsRUFBRTtJQUNoQixNQUFNLElBQUEsa0NBQW9CLEVBQUM7UUFDdkIsU0FBUztRQUNULFNBQVMsRUFBRSxPQUFPLEVBQUUsU0FBUyxJQUFJLEVBQUU7UUFDbkMsaUJBQWlCLEVBQUUsY0FBYztLQUNwQyxDQUFDLENBQUE7SUFFRixNQUFNLHFCQUFxQixDQUFDLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQTtBQUM5QyxDQUFDLENBQUE7QUFFRCxNQUFNLHFCQUFxQixHQUFHLEtBQUssRUFBRSxFQUNqQyxTQUFTLEdBQ0csRUFBaUIsRUFBRTtJQUMvQixNQUFNLGVBQWUsR0FBRyxTQUFTLENBQUMsT0FBTyxDQUF5Qyx5QkFBeUIsRUFBRTtRQUN6RyxpQkFBaUIsRUFBRSxJQUFJO0tBQzFCLENBQUMsQ0FBQTtJQUVGLElBQUksQ0FBQyxlQUFlLEVBQUUsTUFBTSxFQUFFLENBQUM7UUFDM0IsT0FBTTtJQUNWLENBQUM7SUFFRCxNQUFNLHVCQUF1QixHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQzdDLDJCQUEyQixDQUM5QixDQUFDO0lBRUYsTUFBTSxpQkFBaUIsR0FBRyxNQUFNLHVCQUF1QixDQUFDLElBQUksQ0FDeEQsRUFBRSxFQUFFLEVBQUUsZUFBZSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUN0QyxFQUFFLENBQ0wsQ0FBQTtJQUVELE1BQU0sVUFBVSxHQUFnRSxFQUFFLENBQUE7SUFFbEYsS0FBSyxNQUFNLEVBQUUsRUFBRSxFQUFFLFlBQVksRUFBRSxJQUFJLGlCQUFpQixFQUFFLENBQUM7UUFDbkQsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLENBQUM7WUFDMUMsVUFBVSxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRSxDQUFDLENBQUE7UUFDNUQsQ0FBQztJQUNMLENBQUM7SUFFRCxLQUFLLE1BQU0sRUFBRSxFQUFFLEVBQUUsWUFBWSxFQUFFLElBQUksZUFBZSxFQUFFLENBQUM7UUFDakQsVUFBVSxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsRUFBRSxVQUFVLEVBQUUsSUFBSSxFQUFFLFlBQVksRUFBRSxDQUFDLENBQUE7SUFDM0QsQ0FBQztJQUVELE1BQU0sdUJBQXVCLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFBO0FBQ3BELENBQUMsQ0FBQSJ9
47
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbG9hZGVycy9zdGF0aXN0aWNzL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsdURBQW1GO0FBQ25GLGlFQUFzRTtBQVF0RSxxREFBa0Y7QUFLbEYsbURBQTZEO0FBRTdELE1BQU0seUJBQXlCLEdBQUcsZ0JBQWdCLENBQUE7QUFFbEQsTUFBTSxjQUFjLEdBQUcsS0FBSyxFQUFFLEtBQVUsRUFBRSxTQUEwQixFQUFFLGFBQWtCLEVBQUUsRUFBRTtJQUN4RixJQUFJLENBQUMsS0FBSyxFQUFFLFVBQVUsRUFBRSxDQUFDO1FBQ3JCLE1BQU0sSUFBSSxtQkFBVyxDQUNqQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsRUFDbEMseUVBQXlFLENBQzVFLENBQUE7SUFDTCxDQUFDO0lBRUQsTUFBTSxHQUFHLEdBQUcsTUFBTSxLQUFLLENBQUMsVUFBVSxHQUFHLGFBQWEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksYUFBYSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQztJQUV0RixTQUFTLENBQUMsUUFBUSxDQUFDO1FBQ2YsQ0FBQyxHQUFHLENBQUMsRUFBRSxJQUFBLGdCQUFPLEVBQUMsS0FBSyxDQUFDO0tBQ3hCLENBQUMsQ0FBQztJQUlILGtCQUFNLENBQUMsSUFBSSxDQUFDLG1DQUFtQyxLQUFLLENBQUMsVUFBVSxjQUFjLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDcEYsU0FBUyxDQUFDLFdBQVcsQ0FBQyx5QkFBeUIsRUFBRSxJQUFBLGdCQUFPLEVBQUMsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLFlBQVksRUFBRSxLQUFLLENBQUMsV0FBVyxJQUFJLEtBQUssQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUE7QUFDL0gsQ0FBQyxDQUFBO0FBRUQsa0JBQWUsS0FBSyxFQUFFLEVBQ2xCLFNBQVMsRUFDVCxPQUFPLEdBUVYsRUFBaUIsRUFBRTtJQUNoQixNQUFNLElBQUEsa0NBQW9CLEVBQUM7UUFDdkIsU0FBUztRQUNULFNBQVMsRUFBRSxPQUFPLEVBQUUsU0FBUyxJQUFJLEVBQUU7UUFDbkMsaUJBQWlCLEVBQUUsY0FBYztLQUNwQyxDQUFDLENBQUE7SUFFRixNQUFNLHFCQUFxQixDQUFDLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQTtBQUM5QyxDQUFDLENBQUE7QUFFRCxNQUFNLHFCQUFxQixHQUFHLEtBQUssRUFBRSxFQUNqQyxTQUFTLEdBQ0csRUFBaUIsRUFBRTtJQUMvQixNQUFNLGVBQWUsR0FBRyxTQUFTLENBQUMsT0FBTyxDQUF5Qyx5QkFBeUIsRUFBRTtRQUN6RyxpQkFBaUIsRUFBRSxJQUFJO0tBQzFCLENBQUMsQ0FBQTtJQUVGLElBQUksQ0FBQyxlQUFlLEVBQUUsTUFBTSxFQUFFLENBQUM7UUFDM0IsT0FBTTtJQUNWLENBQUM7SUFFRCxNQUFNLHVCQUF1QixHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQzdDLDJCQUEyQixDQUM5QixDQUFDO0lBRUYsTUFBTSxpQkFBaUIsR0FBRyxNQUFNLHVCQUF1QixDQUFDLElBQUksQ0FDeEQsRUFBRSxFQUFFLEVBQUUsZUFBZSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUN0QyxFQUFFLENBQ0wsQ0FBQTtJQUVELE1BQU0sVUFBVSxHQUFnRSxFQUFFLENBQUE7SUFFbEYsS0FBSyxNQUFNLEVBQUUsRUFBRSxFQUFFLFlBQVksRUFBRSxJQUFJLGlCQUFpQixFQUFFLENBQUM7UUFDbkQsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLENBQUM7WUFDMUMsVUFBVSxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRSxDQUFDLENBQUE7UUFDNUQsQ0FBQztJQUNMLENBQUM7SUFFRCxLQUFLLE1BQU0sRUFBRSxFQUFFLEVBQUUsWUFBWSxFQUFFLElBQUksZUFBZSxFQUFFLENBQUM7UUFDakQsVUFBVSxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsRUFBRSxVQUFVLEVBQUUsSUFBSSxFQUFFLFlBQVksRUFBRSxDQUFDLENBQUE7SUFDM0QsQ0FBQztJQUVELE1BQU0sdUJBQXVCLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFBO0FBQ3BELENBQUMsQ0FBQSJ9
package/README.md CHANGED
@@ -1,310 +1,317 @@
1
- <p align="center">
2
- <a href="https://www.medusajs.com">
3
- <picture>
4
- <source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/59018053/229103275-b5e482bb-4601-46e6-8142-244f531cebdb.svg">
5
- <source media="(prefers-color-scheme: light)" srcset="https://user-images.githubusercontent.com/59018053/229103726-e5b529a3-9b3f-4970-8a1f-c6af37f087bf.svg">
6
- <img alt="Medusa logo" src="https://user-images.githubusercontent.com/59018053/229103726-e5b529a3-9b3f-4970-8a1f-c6af37f087bf.svg">
7
- </picture>
8
- </a>
9
- </p>
10
-
11
- <h2 align="center">
12
- Medusa Stats
13
- </h2>
14
-
15
- <br>
16
-
17
- ## Overview
18
-
19
- `medusa-stats` is a flexible statistics module for Medusa that features:
20
-
21
- - Pluggable statistics providers
22
- - Views, options, and chart composition
23
- - Composite statistics (statistics depending on other statistics)
24
- - Statistics-triggered configurable alerts
25
- - UI interface and admin routes for full statistics lifecycle management
26
- - Caching for optimized performance
27
-
28
- ## Installation
29
-
30
- ```bash
31
- npm install medusa-stats
32
- # or
33
- yarn add medusa-stats
34
- ```
35
-
36
-
37
-
38
- ## Configuration
39
-
40
- Add the plugin to your `medusa-config.ts`:
41
-
42
- ```typescript
43
- modules: [
44
- {
45
- resolve: "medusa-stats/modules/statistics",
46
- dependencies: [ContainerRegistrationKeys.QUERY], // Query dependency is required in order to be injected into the providers
47
- options: {
48
- providers: [
49
- {
50
- resolve: "medusa-stats/providers/common",
51
- },
52
- ],
53
- },
54
- },
55
- ],
56
- plugins: [
57
- `medusa-stats`
58
- ]
59
- ```
60
-
61
- ## Basic Usage
62
- The plugin provides a framework for defining and calculating statistics as well as an admin interface for their management and visualization. The primary goal of the module is to provide a flexible way to create custom statistics and views that suit your business needs, without being limited to predefined metrics.
63
-
64
- The module can also be used out-of-the-box with pre-defined statistics providers and the admin interface.
65
-
66
- ### Views
67
- Views are collections of related statistics visualizations. They allow you to organize statistics in any way that suits your needs. Every chart in a view can display multiple statistical measurements, each based on a different statistic option.
68
-
69
- ![Views Image](https://github.com/tax1driver/medusa-stats/blob/bf9e67fccc7fb29c2153e4b06194309b6177c12b/public/view.png)
70
-
71
- ### Options
72
- Options are instances of statistics that are calculated with specific parameters. By changing an option's parameters, you can adjust the underlying statistic calculation.
73
-
74
- ![Options Parameters Image](https://github.com/tax1driver/medusa-stats/blob/bf9e67fccc7fb29c2153e4b06194309b6177c12b/public/params.png)
75
-
76
- When editing, options can also be configured in terms of their visualization (chart type, dimensions, etc.), cache settings and other parameters.
77
-
78
- ![Visualization Settings Image](https://github.com/tax1driver/medusa-stats/blob/bf9e67fccc7fb29c2153e4b06194309b6177c12b/public/visualizations.png)
79
-
80
- ## Providers
81
-
82
- Providers define what statistics are available and how they are calculated.
83
-
84
- ### Add provider to project
85
-
86
- Register your provider in `medusa-config.ts` under the `medusa-stats` module:
87
-
88
- ```typescript
89
- modules: [
90
- {
91
- resolve: "medusa-stats",
92
- options: {
93
- providers: [
94
- { resolve: "medusa-stats/providers/common" },
95
- { resolve: "medusa-stats/providers/composite" },
96
- { resolve: "./src/providers/statistics/my-provider" },
97
- ],
98
- },
99
- },
100
- ]
101
- ```
102
- ### Included providers
103
-
104
- `medusa-stats` includes two built-in providers:
105
-
106
- - `medusa-stats/providers/common`
107
- - General commerce statistics (orders, carts, sales, channels, regions, and related aggregates).
108
- - `medusa-stats/providers/composite`
109
- - Composite/stat-transform statistics that consume other statistic outputs.
110
- - Included statistics: `moving_average`, `rate_of_change`.
111
-
112
-
113
- ### Creating a Statistics Provider
114
-
115
- Create a provider class by extending `AbstractStatisticsProvider`, expose available statistics in `getAvailableStatistics`, and implement calculation logic in `calculateStatistic`.
116
-
117
- Example: a `total_cart_value` statistic (available in the Common Statistics Provider) with filters for currency and cart status.
118
-
119
- ```typescript
120
- import { ModuleProvider } from "@medusajs/framework/utils"
121
- import {
122
- AbstractStatisticsProvider,
123
- StatBuilder,
124
- createTimeSeries,
125
- sum,
126
- type AvailableStatistic,
127
- type CalculateStatisticInput,
128
- type StatisticResult,
129
- } from "medusa-stats"
130
-
131
- class MyStatisticsProvider extends AbstractStatisticsProvider {
132
- static identifier = "my-statistics"
133
- static displayName = "My Statistics Provider"
134
-
135
- async getAvailableStatistics(): Promise<AvailableStatistic[]> {
136
- return [
137
- new StatBuilder("total_cart_value", "Total Cart Value")
138
- .description("Total value of all carts over time")
139
- .field({
140
- name: "currency_code",
141
- label: "Currency",
142
- description: "Filter by currency code",
143
- schema: z.string().optional(),
144
- fieldType: "text",
145
- placeholder: "USD"
146
- })
147
- .chart("line")
148
- .dimension("time")
149
- .build(),
150
- ]
151
- }
152
-
153
- async calculateStatistic(input: CalculateStatisticInput): Promise<StatisticResult> {
154
- const { id, parameters, periodStart, periodEnd, interval } = input;
155
-
156
- switch(id) {
157
- case "total_cart_value": {
158
- const currencyCode = parameters.currency_code;
159
-
160
- const filters: any = {
161
- created_at: { $gte: periodStart, $lte: periodEnd }
162
- };
163
-
164
- if (currencyCode) {
165
- filters.currency_code = currencyCode;
166
- }
167
-
168
- const { data: carts } = await this.query.graph({
169
- entity: "cart",
170
- fields: ["id", "created_at", "total"],
171
- filters
172
- });
173
-
174
- const timeSeries = createTimeSeries( // helper function for time series creation
175
- carts,
176
- periodStart,
177
- periodEnd,
178
- interval,
179
- sum('total') // helper accumulator function
180
- );
181
-
182
- return {
183
- value: timeSeries,
184
- metadata: { totalCarts: carts.length }
185
- };
186
- }
187
- }
188
- }
189
- }
190
-
191
- export default ModuleProvider("statistics", {
192
- services: [MyStatisticsProvider],
193
- })
194
- ```
195
-
196
-
197
-
198
- ## Composite Statistics
199
-
200
- Composite statistics allow one statistic option to use another option's output as an input.
201
-
202
- ### Admin Usage
203
- A stat option can be configured to receive another statistic's output by settings its value in the Dependecnies section when editing a stat instance in the admin dashboard.
204
-
205
- ![Dependencies Image](https://github.com/tax1driver/medusa-stats/blob/bf9e67fccc7fb29c2153e4b06194309b6177c12b/public/composite.png)
206
-
207
- ### Using composite fields in providers
208
-
209
- To make a statistic composable, define a provider parameter with `fieldType: "stat"`.
210
- At runtime, that parameter receives dependency output data and can be processed like any other input.
211
-
212
- ```typescript
213
- import { z } from "zod"
214
- import { StatBuilder } from "medusa-stats"
215
-
216
- new StatBuilder("moving_average", "Moving Average")
217
- .description("Smooth a time series by averaging values over a rolling window")
218
- .field(
219
- {
220
- name: "input_series",
221
- label: "Input Series",
222
- description: "Dependency result to analyze",
223
- fieldType: "stat",
224
- schema: TimeSeriesSchema
225
- }
226
- )
227
- .field(
228
- {
229
- name: "window_size",
230
- label: "Window Size",
231
- fieldType: "number",
232
- schema: z.number().int().min(2).max(365).default(7),
233
- },
234
- 7 // initial value
235
- )
236
- .build()
237
- ```
238
-
239
- ## Alerts
240
-
241
- Alerts can be configured per option to trigger when conditions are met.
242
-
243
- ### Features
244
-
245
- - Absolute and comparative conditions
246
- - Alert logs
247
- - Scheduled evaluation job
248
- - Event emission for custom handling
249
-
250
- ### Emitted Events
251
- To handle the alert triggers, register a subscriber for the `statistics.alert` event type.
252
-
253
- ```typescript
254
- type StatisticsAlertEventData = {
255
- alert_id: string
256
- alert_name: string
257
- severity: "info" | "warning" | "critical"
258
- option_id: string
259
- current_value: number
260
- reference_value: number | null
261
- compare_value: number | [number, number]
262
- operator: "lt" | "gt" | "lte" | "gte" | "eq" | "neq" | "between"
263
- comparison_type: string
264
- }
265
- ```
266
-
267
- ## Caching
268
- In order to optimize performance, statistic results are cached for a configurable amount of time. When a statistic is requested, the module first checks if a valid cached result exists and returns it if available. If not, it calculates the statistic, stores the result in the cache, and then returns it.
269
-
270
- ### Cache Configuration
271
- To use caching, `CachingModule` must be enabled in the Medusa project.
272
-
273
- ```typescript
274
- {
275
- resolve: "@medusajs/medusa/caching",
276
- options: {
277
- providers: [
278
- {
279
- resolve: "@medusajs/caching-redis",
280
- id: "caching-redis",
281
- is_default: true,
282
- options: {
283
- redisUrl: process.env.CACHE_REDIS_URL,
284
- },
285
- },
286
- ],
287
- },
288
- },
289
- ```
290
-
291
- The CachingModule's feature flag needs to be enabled as well:
292
-
293
- *in `.env` file:*
294
- ```env
295
- MEDUSA_FF_CACHING=true
296
- ```
297
-
298
- or
299
-
300
- *in `medusa-config.ts`:*
301
- ```typescript
302
- featureFlags: {
303
- caching: true,
304
- }
305
- ```
306
-
307
- ## Planned features and improvements
308
- - More built-in chart types and visualization options
309
- - Visualization providers for custom chart types and UI components
310
- - Visualization on entities' details pages (e.g. product statistics on product page)
1
+ <p align="center">
2
+ <a href="https://www.medusajs.com">
3
+ <picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/59018053/229103275-b5e482bb-4601-46e6-8142-244f531cebdb.svg">
5
+ <source media="(prefers-color-scheme: light)" srcset="https://user-images.githubusercontent.com/59018053/229103726-e5b529a3-9b3f-4970-8a1f-c6af37f087bf.svg">
6
+ <img alt="Medusa logo" src="https://user-images.githubusercontent.com/59018053/229103726-e5b529a3-9b3f-4970-8a1f-c6af37f087bf.svg">
7
+ </picture>
8
+ </a>
9
+ </p>
10
+
11
+ <h2 align="center">
12
+ Medusa Stats
13
+ </h2>
14
+
15
+ <h5 align="center">
16
+ <a href="https://docs.medusajs.com">MedusaJS</a> |
17
+ <a href="https://www.npmjs.com/package/medusa-stats">npm</a> |
18
+ <a href="https://github.com/tax1driver/medusa-stats">Repository</a>
19
+ </h5>
20
+
21
+
22
+ <br>
23
+
24
+ ## Overview
25
+
26
+ `medusa-stats` is a flexible statistics module for Medusa that features:
27
+
28
+ - Pluggable statistics providers
29
+ - Views, options, and chart composition
30
+ - Composite statistics (statistics depending on other statistics)
31
+ - Statistics-triggered configurable alerts
32
+ - UI interface and admin routes for full statistics lifecycle management
33
+ - Caching for optimized performance
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ npm install medusa-stats
39
+ # or
40
+ yarn add medusa-stats
41
+ ```
42
+
43
+
44
+
45
+ ## Configuration
46
+
47
+ Add the plugin to your `medusa-config.ts`:
48
+
49
+ ```typescript
50
+ modules: [
51
+ {
52
+ resolve: "medusa-stats/modules/statistics",
53
+ dependencies: [ContainerRegistrationKeys.QUERY], // Query dependency is required in order to be injected into the providers
54
+ options: {
55
+ providers: [
56
+ {
57
+ resolve: "medusa-stats/providers/common",
58
+ },
59
+ ],
60
+ },
61
+ },
62
+ ],
63
+ plugins: [
64
+ `medusa-stats`
65
+ ]
66
+ ```
67
+
68
+ ## Basic Usage
69
+ The plugin provides a framework for defining and calculating statistics as well as an admin interface for their management and visualization. The primary goal of the module is to provide a flexible way to create custom statistics and views that suit your business needs, without being limited to predefined metrics.
70
+
71
+ The module can also be used out-of-the-box with pre-defined statistics providers and the admin interface.
72
+
73
+ ### Views
74
+ Views are collections of related statistics visualizations. They allow you to organize statistics in any way that suits your needs. Every chart in a view can display multiple statistical measurements, each based on a different statistic option.
75
+
76
+ ![Views Image](https://github.com/tax1driver/medusa-stats/blob/master/docs/static/view.png)
77
+
78
+ ### Options
79
+ Options are instances of statistics that are calculated with specific parameters. By changing an option's parameters, you can adjust the underlying statistic calculation.
80
+
81
+ ![Options Parameters Image](https://github.com/tax1driver/medusa-stats/blob/master/docs/static/params.png)
82
+
83
+ When editing, options can also be configured in terms of their visualization (chart type, dimensions, etc.), cache settings and other parameters.
84
+
85
+ ![Visualization Settings Image](https://github.com/tax1driver/medusa-stats/blob/master/docs/static/visualizations.png)
86
+
87
+ ## Providers
88
+
89
+ Providers define what statistics are available and how they are calculated.
90
+
91
+ ### Add provider to project
92
+
93
+ Register your provider in `medusa-config.ts` under the `medusa-stats` module:
94
+
95
+ ```typescript
96
+ modules: [
97
+ {
98
+ resolve: "medusa-stats",
99
+ options: {
100
+ providers: [
101
+ { resolve: "medusa-stats/providers/common" },
102
+ { resolve: "medusa-stats/providers/composite" },
103
+ { resolve: "./src/providers/statistics/my-provider" },
104
+ ],
105
+ },
106
+ },
107
+ ]
108
+ ```
109
+ ### Included providers
110
+
111
+ `medusa-stats` includes two built-in providers:
112
+
113
+ - `medusa-stats/providers/common`
114
+ - General commerce statistics (orders, carts, sales, channels, regions, and related aggregates).
115
+ - `medusa-stats/providers/composite`
116
+ - Composite/stat-transform statistics that consume other statistic outputs.
117
+ - Included statistics: `moving_average`, `rate_of_change`.
118
+
119
+
120
+ ### Creating a Statistics Provider
121
+
122
+ Create a provider class by extending `AbstractStatisticsProvider`, expose available statistics in `getAvailableStatistics`, and implement calculation logic in `calculateStatistic`.
123
+
124
+ Example: a `total_cart_value` statistic (available in the Common Statistics Provider) with filters for currency and cart status.
125
+
126
+ ```typescript
127
+ import { ModuleProvider } from "@medusajs/framework/utils"
128
+ import {
129
+ AbstractStatisticsProvider,
130
+ StatBuilder,
131
+ createTimeSeries,
132
+ sum,
133
+ type AvailableStatistic,
134
+ type CalculateStatisticInput,
135
+ type StatisticResult,
136
+ } from "medusa-stats"
137
+
138
+ class MyStatisticsProvider extends AbstractStatisticsProvider {
139
+ static identifier = "my-statistics"
140
+ static displayName = "My Statistics Provider"
141
+
142
+ async getAvailableStatistics(): Promise<AvailableStatistic[]> {
143
+ return [
144
+ new StatBuilder("total_cart_value", "Total Cart Value")
145
+ .description("Total value of all carts over time")
146
+ .field({
147
+ name: "currency_code",
148
+ label: "Currency",
149
+ description: "Filter by currency code",
150
+ schema: z.string().optional(),
151
+ fieldType: "text",
152
+ placeholder: "USD"
153
+ })
154
+ .chart("line")
155
+ .dimension("time")
156
+ .build(),
157
+ ]
158
+ }
159
+
160
+ async calculateStatistic(input: CalculateStatisticInput): Promise<StatisticResult> {
161
+ const { id, parameters, periodStart, periodEnd, interval } = input;
162
+
163
+ switch(id) {
164
+ case "total_cart_value": {
165
+ const currencyCode = parameters.currency_code;
166
+
167
+ const filters: any = {
168
+ created_at: { $gte: periodStart, $lte: periodEnd }
169
+ };
170
+
171
+ if (currencyCode) {
172
+ filters.currency_code = currencyCode;
173
+ }
174
+
175
+ const { data: carts } = await this.query.graph({
176
+ entity: "cart",
177
+ fields: ["id", "created_at", "total"],
178
+ filters
179
+ });
180
+
181
+ const timeSeries = createTimeSeries( // helper function for time series creation
182
+ carts,
183
+ periodStart,
184
+ periodEnd,
185
+ interval,
186
+ sum('total') // helper accumulator function
187
+ );
188
+
189
+ return {
190
+ value: timeSeries,
191
+ metadata: { totalCarts: carts.length }
192
+ };
193
+ }
194
+ }
195
+ }
196
+ }
197
+
198
+ export default ModuleProvider("statistics", {
199
+ services: [MyStatisticsProvider],
200
+ })
201
+ ```
202
+
203
+
204
+
205
+ ## Composite Statistics
206
+
207
+ Composite statistics allow one statistic option to use another option's output as an input.
208
+
209
+ ### Admin Usage
210
+ A stat option can be configured to receive another statistic's output by settings its value in the Dependecnies section when editing a stat instance in the admin dashboard.
211
+
212
+ ![Dependencies Image](https://github.com/tax1driver/medusa-stats/blob/master/docs/static/composite.png)
213
+
214
+ ### Using composite fields in providers
215
+
216
+ To make a statistic composable, define a provider parameter with `fieldType: "stat"`.
217
+ At runtime, that parameter receives dependency output data and can be processed like any other input.
218
+
219
+ ```typescript
220
+ import { z } from "zod"
221
+ import { StatBuilder } from "medusa-stats"
222
+
223
+ new StatBuilder("moving_average", "Moving Average")
224
+ .description("Smooth a time series by averaging values over a rolling window")
225
+ .field(
226
+ {
227
+ name: "input_series",
228
+ label: "Input Series",
229
+ description: "Dependency result to analyze",
230
+ fieldType: "stat",
231
+ schema: TimeSeriesSchema
232
+ }
233
+ )
234
+ .field(
235
+ {
236
+ name: "window_size",
237
+ label: "Window Size",
238
+ fieldType: "number",
239
+ schema: z.number().int().min(2).max(365).default(7),
240
+ },
241
+ 7 // initial value
242
+ )
243
+ .build()
244
+ ```
245
+
246
+ ## Alerts
247
+
248
+ Alerts can be configured per option to trigger when conditions are met.
249
+
250
+ ### Features
251
+
252
+ - Absolute and comparative conditions
253
+ - Alert logs
254
+ - Scheduled evaluation job
255
+ - Event emission for custom handling
256
+
257
+ ### Emitted Events
258
+ To handle the alert triggers, register a subscriber for the `statistics.alert` event type.
259
+
260
+ ```typescript
261
+ type StatisticsAlertEventData = {
262
+ alert_id: string
263
+ alert_name: string
264
+ severity: "info" | "warning" | "critical"
265
+ option_id: string
266
+ current_value: number
267
+ reference_value: number | null
268
+ compare_value: number | [number, number]
269
+ operator: "lt" | "gt" | "lte" | "gte" | "eq" | "neq" | "between"
270
+ comparison_type: string
271
+ }
272
+ ```
273
+
274
+ ## Caching
275
+ In order to optimize performance, statistic results are cached for a configurable amount of time. When a statistic is requested, the module first checks if a valid cached result exists and returns it if available. If not, it calculates the statistic, stores the result in the cache, and then returns it.
276
+
277
+ ### Cache Configuration
278
+ To use caching, `CachingModule` must be enabled in the Medusa project.
279
+
280
+ ```typescript
281
+ {
282
+ resolve: "@medusajs/medusa/caching",
283
+ options: {
284
+ providers: [
285
+ {
286
+ resolve: "@medusajs/caching-redis",
287
+ id: "caching-redis",
288
+ is_default: true,
289
+ options: {
290
+ redisUrl: process.env.CACHE_REDIS_URL,
291
+ },
292
+ },
293
+ ],
294
+ },
295
+ },
296
+ ```
297
+
298
+ The CachingModule's feature flag needs to be enabled as well:
299
+
300
+ *in `.env` file:*
301
+ ```env
302
+ MEDUSA_FF_CACHING=true
303
+ ```
304
+
305
+ or
306
+
307
+ *in `medusa-config.ts`:*
308
+ ```typescript
309
+ featureFlags: {
310
+ caching: true,
311
+ }
312
+ ```
313
+
314
+ ## Planned features and improvements
315
+ - More built-in chart types and visualization options
316
+ - Visualization providers for custom chart types and UI components
317
+ - Visualization on entities' details pages (e.g. product statistics on product page)
package/package.json CHANGED
@@ -1,88 +1,92 @@
1
- {
2
- "name": "medusa-stats",
3
- "version": "1.0.8",
4
- "description": "The most flexible statistics plugin for the most flexible commerce platform.",
5
- "author": "Maciej (https://github.com/tax1driver)",
6
- "license": "MIT",
7
- "files": [
8
- ".medusa/server"
9
- ],
10
- "exports": {
11
- "./package.json": "./package.json",
12
- "./workflows": "./.medusa/server/src/workflows/index.js",
13
- "./.medusa/server/src/modules/*": "./.medusa/server/src/modules/*/index.js",
14
- "./modules/*": "./.medusa/server/src/modules/*/index.js",
15
- "./providers/*": "./.medusa/server/src/providers/*/index.js",
16
- "./*": "./.medusa/server/src/*.js",
17
- "./admin": {
18
- "import": "./.medusa/server/src/admin/index.mjs",
19
- "require": "./.medusa/server/src/admin/index.js",
20
- "default": "./.medusa/server/src/admin/index.js"
21
- },
22
- ".": {
23
- "import": "./.medusa/server/src/index.mjs",
24
- "require": "./.medusa/server/src/index.js",
25
- "default": "./.medusa/server/src/index.js"
26
- }
27
- },
28
- "keywords": [
29
- "medusa",
30
- "plugin",
31
- "medusa-plugin-stats",
32
- "medusa-plugin-metrics",
33
- "medusa-plugin",
34
- "medusa-plugin-analytics",
35
- "medusa-v2"
36
- ],
37
- "scripts": {
38
- "build": "medusa plugin:build",
39
- "dev": "medusa plugin:develop",
40
- "dev:publish": "yarn version patch && medusa plugin:publish",
41
- "prepublishOnly": "medusa plugin:build",
42
- "test:integration:http": "TEST_TYPE=integration:http NODE_OPTIONS=--experimental-vm-modules jest --silent=false --runInBand --forceExit",
43
- "test:integration:modules": "TEST_TYPE=integration:modules NODE_OPTIONS=--experimental-vm-modules jest --silent=false --runInBand --forceExit",
44
- "test:unit": "TEST_TYPE=unit NODE_OPTIONS=--experimental-vm-modules jest --silent --runInBand --forceExit"
45
- },
46
- "devDependencies": {
47
- "@medusajs/admin-sdk": "2.12.4",
48
- "@medusajs/cli": "2.12.4",
49
- "@medusajs/framework": "2.12.4",
50
- "@medusajs/icons": "2.12.4",
51
- "@medusajs/medusa": "2.12.4",
52
- "@medusajs/test-utils": "^2.13.1",
53
- "@medusajs/ui": "4.0.25",
54
- "@swc/core": "^1.7.28",
55
- "@swc/jest": "^0.2.39",
56
- "@types/jest": "^30.0.0",
57
- "@types/node": "^20.0.0",
58
- "@types/react": "^18.3.2",
59
- "@types/react-dom": "^18.2.25",
60
- "@uiw/react-json-view": "^2.0.0-alpha.41",
61
- "date-fns": "^4.1.0",
62
- "jest": "^30.2.0",
63
- "prop-types": "^15.8.1",
64
- "react": "^18.2.0",
65
- "react-dom": "^18.2.0",
66
- "ts-node": "^10.9.2",
67
- "typescript": "^5.6.2",
68
- "vite": "^5.2.11",
69
- "yalc": "^1.0.0-pre.53"
70
- },
71
- "peerDependencies": {
72
- "@medusajs/admin-sdk": "^2.12.4",
73
- "@medusajs/cli": "^2.12.4",
74
- "@medusajs/framework": "^2.12.4",
75
- "@medusajs/icons": "^2.12.4",
76
- "@medusajs/medusa": "^2.12.4",
77
- "@medusajs/test-utils": "^2.12.4",
78
- "@medusajs/ui": "^4.0.25"
79
- },
80
- "dependencies": {
81
- "react-colorful": "^5.6.1",
82
- "recharts": "^3.7.0"
83
- },
84
- "engines": {
85
- "node": ">=20"
86
- },
87
- "packageManager": "yarn@4.12.0"
88
- }
1
+ {
2
+ "name": "medusa-stats",
3
+ "version": "1.0.10",
4
+ "description": "The most flexible statistics plugin for the most flexible commerce platform.",
5
+ "author": "Maciej (https://github.com/tax1driver)",
6
+ "license": "MIT",
7
+ "files": [
8
+ ".medusa/server"
9
+ ],
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/tax1driver/medusa-stats.git"
13
+ },
14
+ "exports": {
15
+ "./package.json": "./package.json",
16
+ "./workflows": "./.medusa/server/src/workflows/index.js",
17
+ "./.medusa/server/src/modules/*": "./.medusa/server/src/modules/*/index.js",
18
+ "./modules/*": "./.medusa/server/src/modules/*/index.js",
19
+ "./providers/*": "./.medusa/server/src/providers/*/index.js",
20
+ "./*": "./.medusa/server/src/*.js",
21
+ "./admin": {
22
+ "import": "./.medusa/server/src/admin/index.mjs",
23
+ "require": "./.medusa/server/src/admin/index.js",
24
+ "default": "./.medusa/server/src/admin/index.js"
25
+ },
26
+ ".": {
27
+ "import": "./.medusa/server/src/index.mjs",
28
+ "require": "./.medusa/server/src/index.js",
29
+ "default": "./.medusa/server/src/index.js"
30
+ }
31
+ },
32
+ "keywords": [
33
+ "medusa",
34
+ "plugin",
35
+ "medusa-plugin-stats",
36
+ "medusa-plugin-metrics",
37
+ "medusa-plugin",
38
+ "medusa-plugin-analytics",
39
+ "medusa-v2"
40
+ ],
41
+ "scripts": {
42
+ "build": "medusa plugin:build",
43
+ "dev": "medusa plugin:develop",
44
+ "dev:publish": "yarn version patch && medusa plugin:publish",
45
+ "prepublishOnly": "medusa plugin:build",
46
+ "test:integration:http": "TEST_TYPE=integration:http NODE_OPTIONS=--experimental-vm-modules jest --silent=false --runInBand --forceExit",
47
+ "test:integration:modules": "TEST_TYPE=integration:modules NODE_OPTIONS=--experimental-vm-modules jest --silent=false --runInBand --forceExit",
48
+ "test:unit": "TEST_TYPE=unit NODE_OPTIONS=--experimental-vm-modules jest --silent --runInBand --forceExit"
49
+ },
50
+ "devDependencies": {
51
+ "@medusajs/admin-sdk": "2.12.4",
52
+ "@medusajs/cli": "2.12.4",
53
+ "@medusajs/framework": "2.12.4",
54
+ "@medusajs/icons": "2.12.4",
55
+ "@medusajs/medusa": "2.12.4",
56
+ "@medusajs/test-utils": "^2.13.1",
57
+ "@medusajs/ui": "4.0.25",
58
+ "@swc/core": "^1.7.28",
59
+ "@swc/jest": "^0.2.39",
60
+ "@types/jest": "^30.0.0",
61
+ "@types/node": "^20.0.0",
62
+ "@types/react": "^18.3.2",
63
+ "@types/react-dom": "^18.2.25",
64
+ "@uiw/react-json-view": "^2.0.0-alpha.41",
65
+ "date-fns": "^4.1.0",
66
+ "jest": "^30.2.0",
67
+ "prop-types": "^15.8.1",
68
+ "react": "^18.2.0",
69
+ "react-dom": "^18.2.0",
70
+ "ts-node": "^10.9.2",
71
+ "typescript": "^5.6.2",
72
+ "vite": "^5.2.11",
73
+ "yalc": "^1.0.0-pre.53"
74
+ },
75
+ "peerDependencies": {
76
+ "@medusajs/admin-sdk": "^2.12.4",
77
+ "@medusajs/cli": "^2.12.4",
78
+ "@medusajs/framework": "^2.12.4",
79
+ "@medusajs/icons": "^2.12.4",
80
+ "@medusajs/medusa": "^2.12.4",
81
+ "@medusajs/test-utils": "^2.12.4",
82
+ "@medusajs/ui": "^4.0.25"
83
+ },
84
+ "dependencies": {
85
+ "react-colorful": "^5.6.1",
86
+ "recharts": "^3.7.0"
87
+ },
88
+ "engines": {
89
+ "node": ">=20"
90
+ },
91
+ "packageManager": "yarn@4.12.0"
92
+ }
Binary file
Binary file