blixify-server 0.3.8 → 0.3.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.
- package/dist/apis/googleAnalyticsWrapper.d.ts +13 -0
- package/dist/apis/googleAnalyticsWrapper.d.ts.map +1 -0
- package/dist/apis/googleAnalyticsWrapper.js +223 -0
- package/dist/apis/index.d.ts +1 -0
- package/dist/apis/index.d.ts.map +1 -1
- package/dist/apis/index.js +3 -1
- package/dist/apis/mongoWrapper.js +5 -5
- package/package.json +4 -1
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { WrapperLib } from "./mongoWrapper";
|
|
2
|
+
export declare class GoogleAnalyticsWrapper {
|
|
3
|
+
private analyticsClient;
|
|
4
|
+
private bigQueryClient;
|
|
5
|
+
private defaultConfig;
|
|
6
|
+
lib: WrapperLib;
|
|
7
|
+
constructor(configData: any, lib: WrapperLib);
|
|
8
|
+
initRunReport: (req: any, res: any) => Promise<any>;
|
|
9
|
+
initRunRealtimeReport: (req: any, res: any) => Promise<any>;
|
|
10
|
+
initRunBigQuery: (req: any, res: any) => Promise<void>;
|
|
11
|
+
init: () => any;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=googleAnalyticsWrapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"googleAnalyticsWrapper.d.ts","sourceRoot":"","sources":["../../src/apis/googleAnalyticsWrapper.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAa5C,qBAAa,sBAAsB;IACjC,OAAO,CAAC,eAAe,CAA0B;IACjD,OAAO,CAAC,cAAc,CAAW;IACjC,OAAO,CAAC,aAAa,CAAM;IAC3B,GAAG,EAAE,UAAU,CAAC;gBAEJ,UAAU,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU;IAY5C,aAAa,QAAe,GAAG,OAAO,GAAG,kBA2FvC;IAEF,qBAAqB,QAAe,GAAG,OAAO,GAAG,kBAgG/C;IAEF,eAAe,QAAe,GAAG,OAAO,GAAG,mBAgCzC;IAEF,IAAI,YAqBF;CACH"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.GoogleAnalyticsWrapper = void 0;
|
|
13
|
+
const data_1 = require("@google-analytics/data");
|
|
14
|
+
const bigquery_1 = require("@google-cloud/bigquery");
|
|
15
|
+
class GoogleAnalyticsWrapper {
|
|
16
|
+
constructor(configData, lib) {
|
|
17
|
+
this.initRunReport = (req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
18
|
+
var _a;
|
|
19
|
+
const { metrics, dimensions, dateRange, filters } = req.body || {};
|
|
20
|
+
const startDate = (dateRange === null || dateRange === void 0 ? void 0 : dateRange.startDate) || "2025-05-01"; // Use a valid past date
|
|
21
|
+
const endDate = (dateRange === null || dateRange === void 0 ? void 0 : dateRange.endDate) || "2025-05-31";
|
|
22
|
+
const queryMetrics = metrics || ["sessions", "screenPageViews"];
|
|
23
|
+
const queryDimensions = dimensions || ["date"];
|
|
24
|
+
// Validate date range
|
|
25
|
+
if (new Date(startDate) > new Date(endDate)) {
|
|
26
|
+
return res.status(400).send({
|
|
27
|
+
status: "error",
|
|
28
|
+
message: "startDate cannot be after endDate",
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(startDate) ||
|
|
32
|
+
!/^\d{4}-\d{2}-\d{2}$/.test(endDate)) {
|
|
33
|
+
return res.status(400).send({
|
|
34
|
+
status: "error",
|
|
35
|
+
message: "Invalid date format, use YYYY-MM-DD",
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const response = yield this.analyticsClient.runReport({
|
|
40
|
+
property: `properties/${this.defaultConfig.propertyId}`,
|
|
41
|
+
dateRanges: [{ startDate, endDate }],
|
|
42
|
+
dimensions: queryDimensions.map((name) => ({ name })),
|
|
43
|
+
metrics: queryMetrics.map((name) => {
|
|
44
|
+
if (name.startsWith("eventCount:")) {
|
|
45
|
+
return {
|
|
46
|
+
name: "eventCount",
|
|
47
|
+
expression: `eventName:${name.split(":")[1]}`,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return { name };
|
|
51
|
+
}),
|
|
52
|
+
dimensionFilter: filters
|
|
53
|
+
? {
|
|
54
|
+
andGroup: {
|
|
55
|
+
expressions: filters.map((f) => ({
|
|
56
|
+
filter: Object.assign(Object.assign({ fieldName: f.fieldName }, (f.value ? { stringFilter: { value: f.value } } : {})), (f.inList
|
|
57
|
+
? { inListFilter: { values: f.inList } }
|
|
58
|
+
: {})),
|
|
59
|
+
})),
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
: undefined,
|
|
63
|
+
});
|
|
64
|
+
const reportData = ((_a = response[0].rows) === null || _a === void 0 ? void 0 : _a.map((row) => {
|
|
65
|
+
if (!row.dimensionValues || !row.metricValues) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
const data = {};
|
|
69
|
+
queryDimensions.forEach((dim, i) => {
|
|
70
|
+
var _a;
|
|
71
|
+
data[dim] = ((_a = row.dimensionValues[i]) === null || _a === void 0 ? void 0 : _a.value) || "unknown";
|
|
72
|
+
});
|
|
73
|
+
queryMetrics.forEach((met, i) => {
|
|
74
|
+
var _a;
|
|
75
|
+
data[met.replace("eventCount:", "")] =
|
|
76
|
+
((_a = row.metricValues[i]) === null || _a === void 0 ? void 0 : _a.value) || "0";
|
|
77
|
+
});
|
|
78
|
+
return data;
|
|
79
|
+
}).filter((row) => row !== null)) || [];
|
|
80
|
+
res.send({
|
|
81
|
+
status: "success",
|
|
82
|
+
data: reportData,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
res.status(500).send({
|
|
87
|
+
status: "error",
|
|
88
|
+
message: `Failed to run report: ${error.message}`,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
this.initRunRealtimeReport = (req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
93
|
+
var _b;
|
|
94
|
+
const { metrics, dimensions, minuteRanges, filters } = req.body || {};
|
|
95
|
+
const queryMetrics = metrics || ["activeUsers"];
|
|
96
|
+
const validRealtimeDimensions = [
|
|
97
|
+
"unifiedScreenName",
|
|
98
|
+
"eventName",
|
|
99
|
+
"country",
|
|
100
|
+
"city",
|
|
101
|
+
"region",
|
|
102
|
+
"audienceName",
|
|
103
|
+
];
|
|
104
|
+
const queryDimensions = (dimensions === null || dimensions === void 0 ? void 0 : dimensions.filter((dim) => validRealtimeDimensions.includes(dim))) || ["eventName"];
|
|
105
|
+
const queryMinuteRanges = minuteRanges || [
|
|
106
|
+
{ startMinutesAgo: 29, endMinutesAgo: 0 },
|
|
107
|
+
];
|
|
108
|
+
// Validate minuteRanges
|
|
109
|
+
for (const range of queryMinuteRanges) {
|
|
110
|
+
if (range.startMinutesAgo > 29 ||
|
|
111
|
+
range.endMinutesAgo < 0 ||
|
|
112
|
+
range.startMinutesAgo < range.endMinutesAgo) {
|
|
113
|
+
return res.status(400).send({
|
|
114
|
+
status: "error",
|
|
115
|
+
message: "Invalid minuteRanges: startMinutesAgo must be <= 29 and >= endMinutesAgo",
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
const response = yield this.analyticsClient.runRealtimeReport({
|
|
121
|
+
property: `properties/${this.defaultConfig.propertyId}`,
|
|
122
|
+
dimensions: queryDimensions.map((name) => ({ name })),
|
|
123
|
+
metrics: queryMetrics.map((name) => ({ name })),
|
|
124
|
+
dimensionFilter: filters
|
|
125
|
+
? {
|
|
126
|
+
andGroup: {
|
|
127
|
+
expressions: filters.map((f) => ({
|
|
128
|
+
filter: Object.assign(Object.assign({ fieldName: f.fieldName }, (f.value ? { stringFilter: { value: f.value } } : {})), (f.inList
|
|
129
|
+
? { inListFilter: { values: f.inList } }
|
|
130
|
+
: {})),
|
|
131
|
+
})),
|
|
132
|
+
},
|
|
133
|
+
}
|
|
134
|
+
: undefined,
|
|
135
|
+
minuteRanges: queryMinuteRanges.map((r) => ({
|
|
136
|
+
startMinutesAgo: r.startMinutesAgo,
|
|
137
|
+
endMinutesAgo: r.endMinutesAgo,
|
|
138
|
+
})),
|
|
139
|
+
});
|
|
140
|
+
const reportData = ((_b = response[0].rows) === null || _b === void 0 ? void 0 : _b.map((row) => {
|
|
141
|
+
if (!row.dimensionValues || !row.metricValues) {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
const data = {};
|
|
145
|
+
queryDimensions.forEach((dim, i) => {
|
|
146
|
+
var _a;
|
|
147
|
+
data[dim] = ((_a = row.dimensionValues[i]) === null || _a === void 0 ? void 0 : _a.value) || "unknown";
|
|
148
|
+
});
|
|
149
|
+
queryMetrics.forEach((met, i) => {
|
|
150
|
+
var _a;
|
|
151
|
+
data[met] = ((_a = row.metricValues[i]) === null || _a === void 0 ? void 0 : _a.value) || "0";
|
|
152
|
+
});
|
|
153
|
+
return data;
|
|
154
|
+
}).filter((row) => row !== null)) || [];
|
|
155
|
+
res.send({
|
|
156
|
+
status: "success",
|
|
157
|
+
data: reportData,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
res.status(400).send({
|
|
162
|
+
status: "error",
|
|
163
|
+
message: `Failed to run realtime report: ${error.message}`,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
this.initRunBigQuery = (req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
168
|
+
const { sqlQuery } = req.body || {};
|
|
169
|
+
if (!sqlQuery) {
|
|
170
|
+
throw new Error("SQL query is required");
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
const options = {
|
|
174
|
+
query: sqlQuery,
|
|
175
|
+
location: this.defaultConfig.location || "US",
|
|
176
|
+
};
|
|
177
|
+
const [rows] = yield this.bigQueryClient.query(options);
|
|
178
|
+
const reportData = rows.map((row) => {
|
|
179
|
+
const data = {};
|
|
180
|
+
for (const key in row) {
|
|
181
|
+
data[key] = row[key] !== null ? row[key] : "null";
|
|
182
|
+
}
|
|
183
|
+
return data;
|
|
184
|
+
});
|
|
185
|
+
res.send({
|
|
186
|
+
status: "success",
|
|
187
|
+
data: reportData,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
throw new Error(`Failed to run BigQuery SQL: ${error.message}`);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
this.init = () => {
|
|
195
|
+
const router = this.lib.express.Router();
|
|
196
|
+
/**
|
|
197
|
+
* @Input :
|
|
198
|
+
* data - Model
|
|
199
|
+
* unique - string (Optional)
|
|
200
|
+
*/
|
|
201
|
+
router.post("/runReport", (req, res) => {
|
|
202
|
+
this.initRunReport(req, res);
|
|
203
|
+
});
|
|
204
|
+
router.post("/realTimeReport", (req, res) => {
|
|
205
|
+
this.initRunRealtimeReport(req, res);
|
|
206
|
+
});
|
|
207
|
+
router.post("/runBigQuery", (req, res) => {
|
|
208
|
+
this.initRunBigQuery(req, res);
|
|
209
|
+
});
|
|
210
|
+
return router;
|
|
211
|
+
};
|
|
212
|
+
this.defaultConfig = configData.defaultConfig;
|
|
213
|
+
this.analyticsClient = new data_1.BetaAnalyticsDataClient({
|
|
214
|
+
credentials: this.defaultConfig.credentials,
|
|
215
|
+
});
|
|
216
|
+
this.bigQueryClient = new bigquery_1.BigQuery({
|
|
217
|
+
credentials: this.defaultConfig.credentials,
|
|
218
|
+
projectId: this.defaultConfig.projectId,
|
|
219
|
+
});
|
|
220
|
+
this.lib = lib;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
exports.GoogleAnalyticsWrapper = GoogleAnalyticsWrapper;
|
package/dist/apis/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { AuthWrapper } from "./authWrapper";
|
|
2
2
|
export { CryptoMiddleware } from "./crypto";
|
|
3
3
|
export { FirebaseWrapper } from "./fbWrapper";
|
|
4
|
+
export { GoogleAnalyticsWrapper } from "./googleAnalyticsWrapper";
|
|
4
5
|
export { MondayWrapper } from "./mondayWrapper";
|
|
5
6
|
export { MongoWrapper } from "./mongoWrapper";
|
|
6
7
|
export { SecurityMiddleware } from "./security";
|
package/dist/apis/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/apis/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/apis/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/apis/index.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.UploadWrapper = exports.TrackVisionWrapper = exports.SecurityMiddleware = exports.MongoWrapper = exports.MondayWrapper = exports.FirebaseWrapper = exports.CryptoMiddleware = exports.AuthWrapper = void 0;
|
|
3
|
+
exports.UploadWrapper = exports.TrackVisionWrapper = exports.SecurityMiddleware = exports.MongoWrapper = exports.MondayWrapper = exports.GoogleAnalyticsWrapper = exports.FirebaseWrapper = exports.CryptoMiddleware = exports.AuthWrapper = void 0;
|
|
4
4
|
var authWrapper_1 = require("./authWrapper");
|
|
5
5
|
Object.defineProperty(exports, "AuthWrapper", { enumerable: true, get: function () { return authWrapper_1.AuthWrapper; } });
|
|
6
6
|
var crypto_1 = require("./crypto");
|
|
7
7
|
Object.defineProperty(exports, "CryptoMiddleware", { enumerable: true, get: function () { return crypto_1.CryptoMiddleware; } });
|
|
8
8
|
var fbWrapper_1 = require("./fbWrapper");
|
|
9
9
|
Object.defineProperty(exports, "FirebaseWrapper", { enumerable: true, get: function () { return fbWrapper_1.FirebaseWrapper; } });
|
|
10
|
+
var googleAnalyticsWrapper_1 = require("./googleAnalyticsWrapper");
|
|
11
|
+
Object.defineProperty(exports, "GoogleAnalyticsWrapper", { enumerable: true, get: function () { return googleAnalyticsWrapper_1.GoogleAnalyticsWrapper; } });
|
|
10
12
|
var mondayWrapper_1 = require("./mondayWrapper");
|
|
11
13
|
Object.defineProperty(exports, "MondayWrapper", { enumerable: true, get: function () { return mondayWrapper_1.MondayWrapper; } });
|
|
12
14
|
var mongoWrapper_1 = require("./mongoWrapper");
|
|
@@ -824,7 +824,7 @@ class MongoWrapper {
|
|
|
824
824
|
const dataList = [];
|
|
825
825
|
const queryId = (_u = aggregate.queryId) !== null && _u !== void 0 ? _u : "";
|
|
826
826
|
const dateId = (_v = aggregate.dateId) !== null && _v !== void 0 ? _v : "baseUpdatedAt";
|
|
827
|
-
const timezone = aggregate.timezone || "Asia/
|
|
827
|
+
const timezone = aggregate.timezone || "Asia/Kuala_Lumpur";
|
|
828
828
|
const dateRanges = (_w = aggregate.range) !== null && _w !== void 0 ? _w : [
|
|
829
829
|
(0, moment_timezone_1.default)().tz(timezone).format("DD/MM/YYYY HH:mm:ss"),
|
|
830
830
|
];
|
|
@@ -837,11 +837,11 @@ class MongoWrapper {
|
|
|
837
837
|
const isDuration = date.length === 2;
|
|
838
838
|
const isValidStartDate = (0, moment_timezone_1.default)(startDate, "DD/MM/YYYY").isValid();
|
|
839
839
|
const isValidEndDate = (0, moment_timezone_1.default)(endDate, "DD/MM/YYYY").isValid();
|
|
840
|
-
const isoStartDate =
|
|
841
|
-
.tz(timezone)
|
|
840
|
+
const isoStartDate = moment_timezone_1.default
|
|
841
|
+
.tz(startDate, "DD/MM/YYYY HH:mm:ss", timezone)
|
|
842
842
|
.toDate();
|
|
843
|
-
const isoEndDate =
|
|
844
|
-
.tz(timezone)
|
|
843
|
+
const isoEndDate = moment_timezone_1.default
|
|
844
|
+
.tz(endDate, "DD/MM/YYYY HH:mm:ss", timezone)
|
|
845
845
|
.toDate();
|
|
846
846
|
if (!isValidStartDate || !isValidEndDate) {
|
|
847
847
|
res
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blixify-server",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.10",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/apis/index.js",
|
|
6
6
|
"private": false,
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"start:aws": "cd dist && node awsServer.js",
|
|
30
30
|
"start:monday": "cd dist && node mondayServer.js",
|
|
31
31
|
"start:trackVision": "cd dist && node trackVisionServer.js",
|
|
32
|
+
"start:analytics": "cd dist && node analyticsServer.js",
|
|
32
33
|
"install:husky": "yarn husky install"
|
|
33
34
|
},
|
|
34
35
|
"config": {
|
|
@@ -39,6 +40,8 @@
|
|
|
39
40
|
}
|
|
40
41
|
},
|
|
41
42
|
"dependencies": {
|
|
43
|
+
"@google-analytics/data": "^5.1.0",
|
|
44
|
+
"@google-cloud/bigquery": "^8.1.0",
|
|
42
45
|
"@types/uuid": "^9.0.7",
|
|
43
46
|
"axios": "^1.4.0",
|
|
44
47
|
"crypto-js": "^4.2.0",
|