befly 3.19.0 → 3.19.5

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/sql/befly.sql CHANGED
@@ -171,4 +171,58 @@ CREATE TABLE IF NOT EXISTS `befly_sys_config` (
171
171
  `updated_at` BIGINT NOT NULL DEFAULT 0,
172
172
  `deleted_at` BIGINT NULL DEFAULT NULL,
173
173
  PRIMARY KEY (`id`)
174
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
175
+
176
+ CREATE TABLE IF NOT EXISTS `befly_visit_stats` (
177
+ `id` BIGINT NOT NULL,
178
+ `bucket_time` BIGINT NOT NULL DEFAULT 0,
179
+ `bucket_date` INT NOT NULL DEFAULT 0,
180
+ `pv` BIGINT NOT NULL DEFAULT 0,
181
+ `uv` BIGINT NOT NULL DEFAULT 0,
182
+ `error_count` BIGINT NOT NULL DEFAULT 0,
183
+ `duration_sum` BIGINT NOT NULL DEFAULT 0,
184
+ `duration_count` BIGINT NOT NULL DEFAULT 0,
185
+ `avg_duration` BIGINT NOT NULL DEFAULT 0,
186
+ `state` TINYINT NOT NULL DEFAULT 1,
187
+ `created_at` BIGINT NOT NULL DEFAULT 0,
188
+ `updated_at` BIGINT NOT NULL DEFAULT 0,
189
+ `deleted_at` BIGINT NULL DEFAULT NULL,
190
+ PRIMARY KEY (`id`),
191
+ UNIQUE KEY `uk_befly_visit_stats_bucket_time` (`bucket_time`),
192
+ KEY `idx_befly_visit_stats_bucket_date` (`bucket_date`)
193
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
194
+
195
+ CREATE TABLE IF NOT EXISTS `befly_error_report` (
196
+ `id` BIGINT NOT NULL,
197
+ `report_time` BIGINT NOT NULL DEFAULT 0,
198
+ `first_report_time` BIGINT NOT NULL DEFAULT 0,
199
+ `bucket_time` BIGINT NOT NULL DEFAULT 0,
200
+ `bucket_date` INT NOT NULL DEFAULT 0,
201
+ `hit_count` BIGINT NOT NULL DEFAULT 1,
202
+ `source` VARCHAR(50) NOT NULL DEFAULT '',
203
+ `product_name` VARCHAR(100) NOT NULL DEFAULT '',
204
+ `product_code` VARCHAR(100) NOT NULL DEFAULT '',
205
+ `product_version` VARCHAR(100) NOT NULL DEFAULT '',
206
+ `page_path` VARCHAR(200) NOT NULL DEFAULT '',
207
+ `page_name` VARCHAR(100) NOT NULL DEFAULT '',
208
+ `error_type` VARCHAR(50) NOT NULL DEFAULT '',
209
+ `message` VARCHAR(500) NOT NULL DEFAULT '',
210
+ `detail` TEXT NULL,
211
+ `user_agent` VARCHAR(500) NOT NULL DEFAULT '',
212
+ `browser_name` VARCHAR(100) NOT NULL DEFAULT '',
213
+ `browser_version` VARCHAR(100) NOT NULL DEFAULT '',
214
+ `os_name` VARCHAR(100) NOT NULL DEFAULT '',
215
+ `os_version` VARCHAR(100) NOT NULL DEFAULT '',
216
+ `device_type` VARCHAR(50) NOT NULL DEFAULT '',
217
+ `device_vendor` VARCHAR(100) NOT NULL DEFAULT '',
218
+ `device_model` VARCHAR(100) NOT NULL DEFAULT '',
219
+ `engine_name` VARCHAR(100) NOT NULL DEFAULT '',
220
+ `cpu_architecture` VARCHAR(100) NOT NULL DEFAULT '',
221
+ `state` TINYINT NOT NULL DEFAULT 1,
222
+ `created_at` BIGINT NOT NULL DEFAULT 0,
223
+ `updated_at` BIGINT NOT NULL DEFAULT 0,
224
+ `deleted_at` BIGINT NULL DEFAULT NULL,
225
+ PRIMARY KEY (`id`),
226
+ KEY `idx_befly_error_report_time` (`report_time`),
227
+ KEY `idx_befly_error_report_bucket_date` (`bucket_date`)
174
228
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
@@ -0,0 +1,76 @@
1
+ const visitStatsDateFormatter = new Intl.DateTimeFormat("en-CA", {
2
+ year: "numeric",
3
+ month: "2-digit",
4
+ day: "2-digit"
5
+ });
6
+
7
+ export const DAY_MS = 24 * 60 * 60 * 1000;
8
+
9
+ function toDate(value = Date.now()) {
10
+ if (value instanceof Date) {
11
+ return value;
12
+ }
13
+
14
+ return Reflect.construct(Date, [value]);
15
+ }
16
+
17
+ function padDatePart(value) {
18
+ if (value < 10) {
19
+ return `0${value}`;
20
+ }
21
+
22
+ return String(value);
23
+ }
24
+
25
+ export function addDays(timestamp = Date.now(), days = 0) {
26
+ return Number(timestamp || 0) + Number(days || 0) * DAY_MS;
27
+ }
28
+
29
+ export function getDateYmdNumber(timestamp = Date.now()) {
30
+ return Number(visitStatsDateFormatter.format(timestamp).replace(/[^0-9]/g, ""));
31
+ }
32
+
33
+ export function getDayStartTime(timestamp = Date.now()) {
34
+ const date = toDate(timestamp);
35
+ return Reflect.construct(Date, [date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0]).getTime();
36
+ }
37
+
38
+ export function getDayEndTime(timestamp = Date.now()) {
39
+ return getDayStartTime(timestamp) + DAY_MS - 1;
40
+ }
41
+
42
+ export function getTimeBucketStart(timestamp = Date.now(), bucketMs = 0) {
43
+ const bucket = Number(bucketMs || 0);
44
+ if (bucket <= 0) {
45
+ return Number(timestamp || 0);
46
+ }
47
+
48
+ const time = Number(timestamp || 0);
49
+ return time - (time % bucket);
50
+ }
51
+
52
+ export function formatYmdHms(value = Date.now(), format = "dateTime") {
53
+ const date = toDate(value);
54
+ const y = date.getFullYear();
55
+ const m = date.getMonth() + 1;
56
+ const d = date.getDate();
57
+ const h = date.getHours();
58
+ const mi = date.getMinutes();
59
+ const s = date.getSeconds();
60
+
61
+ const mm = padDatePart(m);
62
+ const dd = padDatePart(d);
63
+ const hh = padDatePart(h);
64
+ const mii = padDatePart(mi);
65
+ const ss = padDatePart(s);
66
+
67
+ if (format === "date") {
68
+ return `${y}-${mm}-${dd}`;
69
+ }
70
+
71
+ if (format === "time") {
72
+ return `${hh}:${mii}:${ss}`;
73
+ }
74
+
75
+ return `${y}-${mm}-${dd} ${hh}:${mii}:${ss}`;
76
+ }
@@ -0,0 +1,121 @@
1
+ export const VISIT_STATS_REDIS_TTL_SECONDS = 7 * 24 * 60 * 60;
2
+ export const VISIT_STATS_ONLINE_TTL_SECONDS = 10 * 60;
3
+ export const VISIT_STATS_BUCKET_MS = 30 * 60 * 1000;
4
+ export const VISIT_STATS_UA_FIELDS = [
5
+ { field: "deviceType", defaultValue: "desktop" },
6
+ { field: "browserName", defaultValue: "Unknown" },
7
+ { field: "browserVersion", defaultValue: "Unknown" },
8
+ { field: "osName", defaultValue: "Unknown" },
9
+ { field: "osVersion", defaultValue: "Unknown" },
10
+ { field: "deviceVendor", defaultValue: "Unknown" },
11
+ { field: "deviceModel", defaultValue: "Unknown" },
12
+ { field: "engineName", defaultValue: "Unknown" },
13
+ { field: "cpuArchitecture", defaultValue: "Unknown" }
14
+ ];
15
+ export const VISIT_STATS_PRODUCT_FIELDS = [
16
+ { field: "productName", defaultValue: "Unknown" },
17
+ { field: "productCode", defaultValue: "unknown" },
18
+ { field: "productVersion", defaultValue: "Unknown" }
19
+ ];
20
+
21
+ export function getVisitStatsBucketKey(bucketTime) {
22
+ return `visitStats:bucket:${bucketTime}`;
23
+ }
24
+
25
+ export function getVisitStatsDayKey(bucketDate) {
26
+ return `visitStats:day:${bucketDate}`;
27
+ }
28
+
29
+ export function normalizeVisitStatsUaValue(value, defaultValue = "Unknown") {
30
+ const text = String(value || "").trim();
31
+ if (!text) {
32
+ return defaultValue;
33
+ }
34
+
35
+ return text;
36
+ }
37
+
38
+ export function normalizeVisitStatsProductValue(value, defaultValue = "Unknown") {
39
+ const text = String(value || "")
40
+ .trim()
41
+ .slice(0, 100);
42
+
43
+ if (!text) {
44
+ return defaultValue;
45
+ }
46
+
47
+ return text;
48
+ }
49
+
50
+ export function getVisitStatsProductMeta(productData = {}) {
51
+ return {
52
+ productName: normalizeVisitStatsProductValue(productData.productName, "Unknown"),
53
+ productCode: normalizeVisitStatsProductValue(productData.productCode, "unknown"),
54
+ productVersion: normalizeVisitStatsProductValue(productData.productVersion, "Unknown")
55
+ };
56
+ }
57
+
58
+ export function getVisitStatsProductKey(productData = {}) {
59
+ const meta = getVisitStatsProductMeta(productData);
60
+ return [meta.productCode, meta.productVersion, meta.productName].map((item) => encodeURIComponent(item)).join("|");
61
+ }
62
+
63
+ export function parseVisitStatsProductKey(productKey) {
64
+ const parts = String(productKey || "")
65
+ .split("|")
66
+ .map((item) => decodeURIComponent(item || ""));
67
+
68
+ return getVisitStatsProductMeta({
69
+ productCode: parts[0],
70
+ productVersion: parts[1],
71
+ productName: parts[2]
72
+ });
73
+ }
74
+
75
+ export function getVisitStatsDayUaValuesKey(bucketDate, field) {
76
+ return `visitStats:day:${bucketDate}:ua:${field}:values`;
77
+ }
78
+
79
+ export function getVisitStatsDayUaCountKey(bucketDate, field, value) {
80
+ return `visitStats:day:${bucketDate}:ua:${field}:count:${encodeURIComponent(String(value || ""))}`;
81
+ }
82
+
83
+ export function getVisitStatsDayProductValuesKey(bucketDate, field) {
84
+ return `visitStats:day:${bucketDate}:product:${field}:values`;
85
+ }
86
+
87
+ export function getVisitStatsDayProductCountKey(bucketDate, field, value) {
88
+ return `visitStats:day:${bucketDate}:product:${field}:count:${encodeURIComponent(String(value || ""))}`;
89
+ }
90
+
91
+ export function getVisitStatsDayProductKeysKey(bucketDate) {
92
+ return `visitStats:day:${bucketDate}:product:keys`;
93
+ }
94
+
95
+ export function getVisitStatsProductMetaKey(productKey) {
96
+ return `visitStats:product:meta:${productKey}`;
97
+ }
98
+
99
+ export function getVisitStatsBucketProductPvKey(bucketTime, productKey) {
100
+ return `visitStats:bucket:${bucketTime}:product:${productKey}:pv`;
101
+ }
102
+
103
+ export function getVisitStatsBucketProductUvKey(bucketTime, productKey) {
104
+ return `visitStats:bucket:${bucketTime}:product:${productKey}:uv`;
105
+ }
106
+
107
+ export function getVisitStatsDayProductPvKey(bucketDate, productKey) {
108
+ return `visitStats:day:${bucketDate}:product:${productKey}:pv`;
109
+ }
110
+
111
+ export function getVisitStatsDayProductUvKey(bucketDate, productKey) {
112
+ return `visitStats:day:${bucketDate}:product:${productKey}:uv`;
113
+ }
114
+
115
+ export function toVisitStatsNumber(value) {
116
+ const num = Number(value);
117
+ if (!Number.isFinite(num)) {
118
+ return 0;
119
+ }
120
+ return num;
121
+ }
@@ -1,23 +0,0 @@
1
- export function formatYmdHms(date, format = "dateTime") {
2
- const y = date.getFullYear();
3
- const m = date.getMonth() + 1;
4
- const d = date.getDate();
5
- const h = date.getHours();
6
- const mi = date.getMinutes();
7
- const s = date.getSeconds();
8
-
9
- const mm = m < 10 ? `0${m}` : String(m);
10
- const dd = d < 10 ? `0${d}` : String(d);
11
- const hh = h < 10 ? `0${h}` : String(h);
12
- const mii = mi < 10 ? `0${mi}` : String(mi);
13
- const ss = s < 10 ? `0${s}` : String(s);
14
-
15
- if (format === "date") {
16
- return `${y}-${mm}-${dd}`;
17
- }
18
- if (format === "time") {
19
- return `${hh}:${mii}:${ss}`;
20
- }
21
-
22
- return `${y}-${mm}-${dd} ${hh}:${mii}:${ss}`;
23
- }