vite-plugin-smart-prefetch 0.3.5 → 0.3.6
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/index.cjs +257 -138
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +39 -1
- package/dist/index.d.ts +39 -1
- package/dist/index.js +256 -138
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
BigQueryAnalyticsConnector: () => BigQueryAnalyticsConnector,
|
|
33
34
|
smartPrefetch: () => smartPrefetch
|
|
34
35
|
});
|
|
35
36
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -42,7 +43,7 @@ var BigQueryAnalyticsConnector = class {
|
|
|
42
43
|
constructor(projectId, datasetId, location = "asia-south1", debug = false) {
|
|
43
44
|
this.projectId = projectId;
|
|
44
45
|
this.datasetId = datasetId;
|
|
45
|
-
this.location = location;
|
|
46
|
+
this.location = location && location !== "asia" ? location : "asia-south1";
|
|
46
47
|
this.debug = debug;
|
|
47
48
|
this.bigquery = new import_bigquery.BigQuery({
|
|
48
49
|
projectId
|
|
@@ -51,7 +52,8 @@ var BigQueryAnalyticsConnector = class {
|
|
|
51
52
|
console.log("\u2705 BigQuery Analytics connector initialized");
|
|
52
53
|
console.log(` Project ID: ${projectId}`);
|
|
53
54
|
console.log(` Dataset ID: ${datasetId}`);
|
|
54
|
-
console.log(` Location: ${location}`);
|
|
55
|
+
console.log(` Location: ${this.location}`);
|
|
56
|
+
console.log(` Querying daily events tables: ${projectId}.${datasetId}.events_*`);
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
59
|
/**
|
|
@@ -61,20 +63,27 @@ var BigQueryAnalyticsConnector = class {
|
|
|
61
63
|
async fetchNavigationSequences(config = {}) {
|
|
62
64
|
const { days = 30 } = config;
|
|
63
65
|
const minSessions = 1;
|
|
64
|
-
console.log(
|
|
65
|
-
|
|
66
|
+
console.log(`
|
|
67
|
+
${"\u2550".repeat(60)}`);
|
|
68
|
+
console.log(`\u{1F4CA} STAGE 1: PREPARING BIGQUERY QUERY`);
|
|
69
|
+
console.log(`${"\u2550".repeat(60)}`);
|
|
70
|
+
console.log(` Project ID: ${this.projectId}`);
|
|
71
|
+
console.log(` Dataset ID: ${this.datasetId}`);
|
|
72
|
+
console.log(` Location: ${this.location}`);
|
|
66
73
|
console.log(` Date range: Last ${days} days`);
|
|
74
|
+
console.log(` Daily tables pattern: events_*`);
|
|
75
|
+
console.log(` Event type filter: page_view`);
|
|
76
|
+
console.log(` Expected fields: user_pseudo_id, ga_session_id, page_path`);
|
|
67
77
|
try {
|
|
68
78
|
const query = `
|
|
69
79
|
WITH page_sessions AS (
|
|
70
80
|
SELECT
|
|
71
|
-
|
|
81
|
+
user_pseudo_id,
|
|
72
82
|
(SELECT value.int_value FROM UNNEST(event_params) WHERE KEY = 'ga_session_id' LIMIT 1) as session_id,
|
|
73
|
-
(SELECT value.string_value FROM UNNEST(event_params) WHERE KEY = 'page_location' LIMIT 1) as page_location,
|
|
74
83
|
(SELECT value.string_value FROM UNNEST(event_params) WHERE KEY = 'page_path' LIMIT 1) as page_path,
|
|
75
84
|
event_timestamp,
|
|
76
85
|
ROW_NUMBER() OVER (
|
|
77
|
-
PARTITION BY
|
|
86
|
+
PARTITION BY user_pseudo_id, (SELECT value.int_value FROM UNNEST(event_params) WHERE KEY = 'ga_session_id' LIMIT 1)
|
|
78
87
|
ORDER BY event_timestamp
|
|
79
88
|
) as page_sequence
|
|
80
89
|
FROM \`${this.projectId}.${this.datasetId}.events_*\`
|
|
@@ -88,7 +97,7 @@ var BigQueryAnalyticsConnector = class {
|
|
|
88
97
|
SELECT
|
|
89
98
|
COALESCE(curr.page_path, '(direct)') as from_page,
|
|
90
99
|
LEAD(curr.page_path) OVER (
|
|
91
|
-
PARTITION BY curr.
|
|
100
|
+
PARTITION BY curr.user_pseudo_id, curr.session_id
|
|
92
101
|
ORDER BY curr.page_sequence
|
|
93
102
|
) as to_page
|
|
94
103
|
FROM page_sessions curr
|
|
@@ -100,52 +109,132 @@ var BigQueryAnalyticsConnector = class {
|
|
|
100
109
|
COUNT(*) as transition_count
|
|
101
110
|
FROM transitions
|
|
102
111
|
WHERE to_page IS NOT NULL
|
|
103
|
-
GROUP BY
|
|
112
|
+
GROUP BY previous_page_path, page_path
|
|
104
113
|
ORDER BY transition_count DESC
|
|
105
114
|
LIMIT 10000
|
|
106
115
|
`;
|
|
107
116
|
if (this.debug) {
|
|
108
|
-
console.log(
|
|
117
|
+
console.log(`
|
|
118
|
+
\u{1F4E4} Full BigQuery Query:`);
|
|
119
|
+
console.log(`${"\u2500".repeat(60)}`);
|
|
109
120
|
console.log(query);
|
|
121
|
+
console.log(`${"\u2500".repeat(60)}`);
|
|
110
122
|
}
|
|
123
|
+
console.log(`
|
|
124
|
+
${"\u2550".repeat(60)}`);
|
|
125
|
+
console.log(`\u{1F4CA} STAGE 2: EXECUTING QUERY`);
|
|
126
|
+
console.log(`${"\u2550".repeat(60)}`);
|
|
127
|
+
console.log(` \u23F3 Querying BigQuery...`);
|
|
111
128
|
const [rows] = await this.bigquery.query({
|
|
112
129
|
query,
|
|
113
130
|
location: this.location
|
|
114
131
|
});
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
132
|
+
console.log(` \u2705 Query executed successfully`);
|
|
133
|
+
console.log(` \u{1F4C8} Total transitions returned: ${rows.length}`);
|
|
134
|
+
if (rows.length === 0) {
|
|
135
|
+
console.log(`
|
|
136
|
+
${"\u2550".repeat(60)}`);
|
|
137
|
+
console.log(`\u26A0\uFE0F STAGE 2: NO DATA RETURNED!`);
|
|
138
|
+
console.log(`${"\u2550".repeat(60)}`);
|
|
139
|
+
console.log(` \u274C BigQuery returned 0 rows`);
|
|
140
|
+
console.log(`
|
|
141
|
+
Possible causes:`);
|
|
142
|
+
console.log(` 1. No event tables in date range (events_YYYYMMDD)`);
|
|
143
|
+
console.log(` 2. No page_view events in those tables`);
|
|
144
|
+
console.log(` 3. page_path parameter not being tracked`);
|
|
145
|
+
console.log(` 4. Wrong location (currently: ${this.location})`);
|
|
146
|
+
console.log(` 5. Wrong dataset name: ${this.datasetId}`);
|
|
147
|
+
console.log(`
|
|
148
|
+
Troubleshooting:`);
|
|
149
|
+
console.log(` \u2022 Check BigQuery console for available event tables`);
|
|
150
|
+
console.log(` \u2022 Verify GA4 property is exporting to BigQuery`);
|
|
151
|
+
console.log(` \u2022 Confirm page_path is being captured in GA4`);
|
|
152
|
+
console.log(`${"\u2550".repeat(60)}
|
|
153
|
+
`);
|
|
154
|
+
return [];
|
|
118
155
|
}
|
|
156
|
+
console.log(`
|
|
157
|
+
${"\u2550".repeat(60)}`);
|
|
158
|
+
console.log(`\u{1F4CA} STAGE 3: PROCESSING RAW DATA`);
|
|
159
|
+
console.log(`${"\u2550".repeat(60)}`);
|
|
160
|
+
console.log(` Processing ${rows.length} raw transitions...`);
|
|
119
161
|
const navigationData = [];
|
|
162
|
+
let processedCount = 0;
|
|
163
|
+
let filteredCount = 0;
|
|
164
|
+
let emptyPathCount = 0;
|
|
165
|
+
let lowCountCount = 0;
|
|
120
166
|
const rawData = rows.map((row) => ({
|
|
121
167
|
previous_page_path: row.previous_page_path,
|
|
122
168
|
page_path: row.page_path,
|
|
123
169
|
transition_count: row.transition_count
|
|
124
170
|
}));
|
|
125
|
-
|
|
171
|
+
console.log(`
|
|
172
|
+
${"\u2500".repeat(56)}`);
|
|
173
|
+
console.log(` Processing each transition row...`);
|
|
174
|
+
console.log(` ${"\u2500".repeat(56)}`);
|
|
175
|
+
rows.forEach((row, index) => {
|
|
126
176
|
const previousPage = row.previous_page_path || "(direct)";
|
|
127
177
|
const currentPage = row.page_path || "";
|
|
128
178
|
const transitionCount = parseInt(row.transition_count || "0");
|
|
179
|
+
if (this.debug && index < 5) {
|
|
180
|
+
console.log(`
|
|
181
|
+
Row ${index + 1}:`);
|
|
182
|
+
console.log(` Raw: "${previousPage}" \u2192 "${currentPage}" (count: ${transitionCount})`);
|
|
183
|
+
}
|
|
129
184
|
const normalizedPrevious = previousPage === "(direct)" || previousPage === "(not set)" ? "(direct)" : this.normalizeRoute(previousPage);
|
|
130
185
|
const normalizedCurrent = this.normalizeRoute(currentPage);
|
|
186
|
+
if (this.debug && index < 5) {
|
|
187
|
+
console.log(` Normalized: "${normalizedPrevious}" \u2192 "${normalizedCurrent}"`);
|
|
188
|
+
}
|
|
131
189
|
if (normalizedCurrent && transitionCount >= minSessions) {
|
|
132
190
|
navigationData.push({
|
|
133
191
|
from: normalizedPrevious,
|
|
134
192
|
to: normalizedCurrent,
|
|
135
193
|
count: transitionCount
|
|
136
194
|
});
|
|
195
|
+
processedCount++;
|
|
196
|
+
if (this.debug && index < 5) {
|
|
197
|
+
console.log(` \u2705 ACCEPTED`);
|
|
198
|
+
}
|
|
199
|
+
} else {
|
|
200
|
+
filteredCount++;
|
|
201
|
+
if (!normalizedCurrent) {
|
|
202
|
+
emptyPathCount++;
|
|
203
|
+
if (this.debug && index < 5) {
|
|
204
|
+
console.log(` \u274C FILTERED: normalized to empty path (likely build artifact)`);
|
|
205
|
+
}
|
|
206
|
+
} else if (transitionCount < minSessions) {
|
|
207
|
+
lowCountCount++;
|
|
208
|
+
if (this.debug && index < 5) {
|
|
209
|
+
console.log(` \u274C FILTERED: transition count ${transitionCount} < minSessions ${minSessions}`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
137
212
|
}
|
|
138
213
|
});
|
|
214
|
+
console.log(`
|
|
215
|
+
${"\u2500".repeat(56)}`);
|
|
216
|
+
console.log(` Processing Summary:`);
|
|
217
|
+
console.log(` \u2705 Accepted: ${processedCount}`);
|
|
218
|
+
console.log(` \u274C Filtered out: ${filteredCount}`);
|
|
219
|
+
console.log(` \u2022 Empty paths: ${emptyPathCount}`);
|
|
220
|
+
console.log(` \u2022 Low transition count: ${lowCountCount}`);
|
|
139
221
|
this.saveDataForInspection(rawData, navigationData);
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
222
|
+
console.log(`
|
|
223
|
+
${"\u2550".repeat(60)}`);
|
|
224
|
+
console.log(`\u{1F4CA} STAGE 4: FINAL RESULTS`);
|
|
225
|
+
console.log(`${"\u2550".repeat(60)}`);
|
|
226
|
+
console.log(` Total valid transitions: ${navigationData.length}`);
|
|
227
|
+
if (navigationData.length === 0) {
|
|
228
|
+
console.log(`
|
|
229
|
+
\u26A0\uFE0F WARNING: All transitions were filtered out!`);
|
|
230
|
+
console.log(` Check the logs above to see why rows were rejected.`);
|
|
231
|
+
console.log(` Raw data saved to: .bigquery-raw-data/raw-bigquery-response.json`);
|
|
232
|
+
} else {
|
|
233
|
+
console.log(`
|
|
144
234
|
Top 5 transitions:`);
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
235
|
+
navigationData.slice(0, 5).forEach((nav, i) => {
|
|
236
|
+
console.log(` ${i + 1}. ${nav.from} \u2192 ${nav.to} (${nav.count})`);
|
|
237
|
+
});
|
|
149
238
|
const uniqueRoutes = /* @__PURE__ */ new Set();
|
|
150
239
|
navigationData.forEach((nav) => {
|
|
151
240
|
if (nav.from !== "(direct)") uniqueRoutes.add(nav.from);
|
|
@@ -155,85 +244,45 @@ var BigQueryAnalyticsConnector = class {
|
|
|
155
244
|
\u{1F4CA} Unique routes: ${uniqueRoutes.size}`);
|
|
156
245
|
console.log(` Routes: ${Array.from(uniqueRoutes).sort().join(", ")}`);
|
|
157
246
|
console.log(`
|
|
158
|
-
\u{1F4C1}
|
|
247
|
+
\u{1F4C1} Data inspection files created:`);
|
|
248
|
+
console.log(` \u2022 .bigquery-raw-data/raw-bigquery-response.json`);
|
|
249
|
+
console.log(` \u2022 .bigquery-raw-data/processed-navigation-data.json`);
|
|
250
|
+
console.log(` \u2022 .bigquery-raw-data/data-transformation-summary.json`);
|
|
159
251
|
}
|
|
252
|
+
console.log(`${"\u2550".repeat(60)}
|
|
253
|
+
`);
|
|
160
254
|
return navigationData;
|
|
161
255
|
} catch (error) {
|
|
162
|
-
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
256
|
+
const errorMessage = error instanceof Error ? error.message : String(error) || "Unknown error";
|
|
257
|
+
console.log(`
|
|
258
|
+
${"\u2550".repeat(60)}`);
|
|
259
|
+
console.log(`\u274C ERROR: QUERY EXECUTION FAILED`);
|
|
260
|
+
console.log(`${"\u2550".repeat(60)}`);
|
|
163
261
|
if (errorMessage.includes("bigquery.jobs.create") || errorMessage.includes("PERMISSION_DENIED")) {
|
|
164
|
-
console.error(
|
|
165
|
-
console.error(
|
|
166
|
-
console.error(
|
|
262
|
+
console.error(` \u274C Permission Denied`);
|
|
263
|
+
console.error(` Service account needs BigQuery Job User role in project: ${this.projectId}`);
|
|
264
|
+
console.error(` Error: ${errorMessage}`);
|
|
265
|
+
} else if (errorMessage.includes("was not found")) {
|
|
266
|
+
console.error(` \u274C Dataset not found`);
|
|
267
|
+
console.error(` Cannot find dataset: ${this.projectId}.${this.datasetId}`);
|
|
268
|
+
console.error(` Try a different location or check dataset name`);
|
|
269
|
+
console.error(` Current location: ${this.location}`);
|
|
270
|
+
console.error(` Error: ${errorMessage}`);
|
|
167
271
|
} else {
|
|
168
|
-
|
|
272
|
+
const errorType = error instanceof Error ? error.constructor.name : "Unknown";
|
|
273
|
+
console.error(` Error type: ${errorType}`);
|
|
274
|
+
console.error(` Message: ${errorMessage}`);
|
|
169
275
|
}
|
|
276
|
+
console.log(`${"\u2550".repeat(60)}
|
|
277
|
+
`);
|
|
170
278
|
throw new Error(
|
|
171
279
|
`BigQuery Analytics error: ${errorMessage}`
|
|
172
280
|
);
|
|
173
281
|
}
|
|
174
282
|
}
|
|
175
|
-
/**
|
|
176
|
-
* Map friendly page names (with spaces/capitals) back to route paths
|
|
177
|
-
* GA4 may log display names instead of URL paths
|
|
178
|
-
* Examples: "Audit Logs" → "/audit-logs", "API Documentation" → "/api-docs", "Home" → "/"
|
|
179
|
-
*/
|
|
180
|
-
friendlyNameToRoute(name) {
|
|
181
|
-
const friendlyToRoute = {
|
|
182
|
-
// Exact matches (with spaces and capitals)
|
|
183
|
-
"API Documentation": "/api-docs",
|
|
184
|
-
"Audit Logs": "/audit-logs",
|
|
185
|
-
"/Home": "/",
|
|
186
|
-
"/home": "/",
|
|
187
|
-
"Home": "/",
|
|
188
|
-
"/Dashboard": "/dashboard",
|
|
189
|
-
"Dashboard": "/dashboard",
|
|
190
|
-
// PascalCase variants (all 27 routes)
|
|
191
|
-
"Profile": "/profile",
|
|
192
|
-
"Settings": "/settings",
|
|
193
|
-
"Preferences": "/preferences",
|
|
194
|
-
"Privacy": "/privacy",
|
|
195
|
-
"Security": "/security",
|
|
196
|
-
"Analytics": "/analytics",
|
|
197
|
-
"Reports": "/reports",
|
|
198
|
-
"Metrics": "/metrics",
|
|
199
|
-
"Projects": "/projects",
|
|
200
|
-
"Tasks": "/tasks",
|
|
201
|
-
"Teams": "/teams",
|
|
202
|
-
"Workspaces": "/workspaces",
|
|
203
|
-
"Workflows": "/workflows",
|
|
204
|
-
"Templates": "/templates",
|
|
205
|
-
"Logs": "/logs",
|
|
206
|
-
"AuditLogs": "/audit-logs",
|
|
207
|
-
"Integrations": "/integrations",
|
|
208
|
-
"ApiDocs": "/api-docs",
|
|
209
|
-
"Support": "/support",
|
|
210
|
-
"Help": "/help",
|
|
211
|
-
"Billing": "/billing",
|
|
212
|
-
"Plans": "/plans",
|
|
213
|
-
"Usage": "/usage",
|
|
214
|
-
"Permissions": "/permissions",
|
|
215
|
-
"Notifications": "/notifications"
|
|
216
|
-
};
|
|
217
|
-
if (friendlyToRoute[name]) {
|
|
218
|
-
return friendlyToRoute[name];
|
|
219
|
-
}
|
|
220
|
-
const lowerName = name.toLowerCase();
|
|
221
|
-
for (const [key, value] of Object.entries(friendlyToRoute)) {
|
|
222
|
-
if (key.toLowerCase() === lowerName) {
|
|
223
|
-
return value;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
if (name.startsWith("/")) {
|
|
227
|
-
if (name === "/") {
|
|
228
|
-
return "/";
|
|
229
|
-
}
|
|
230
|
-
return name.toLowerCase();
|
|
231
|
-
}
|
|
232
|
-
return "/" + lowerName;
|
|
233
|
-
}
|
|
234
283
|
/**
|
|
235
284
|
* Normalize route paths
|
|
236
|
-
* Converts dynamic segments to parameters and
|
|
285
|
+
* Converts dynamic segments to parameters and standardizes format
|
|
237
286
|
*/
|
|
238
287
|
normalizeRoute(path2) {
|
|
239
288
|
const buildArtifacts = [
|
|
@@ -247,7 +296,7 @@ var BigQueryAnalyticsConnector = class {
|
|
|
247
296
|
if (buildArtifacts.some((pattern) => pattern.test(path2))) {
|
|
248
297
|
return "";
|
|
249
298
|
}
|
|
250
|
-
let normalized =
|
|
299
|
+
let normalized = path2;
|
|
251
300
|
normalized = normalized.split("?")[0].split("#")[0];
|
|
252
301
|
if (normalized.length > 1 && normalized.endsWith("/")) {
|
|
253
302
|
normalized = normalized.slice(0, -1);
|
|
@@ -304,28 +353,49 @@ var BigQueryAnalyticsConnector = class {
|
|
|
304
353
|
}
|
|
305
354
|
}
|
|
306
355
|
/**
|
|
307
|
-
* Fetch navigation data WITH segment information
|
|
308
|
-
*
|
|
309
|
-
* @param config - Data range configuration
|
|
310
|
-
* @returns Navigation data with segment field included
|
|
356
|
+
* Fetch navigation data WITH optional segment information
|
|
357
|
+
* Only includes segment/grouping field when explicitly requested
|
|
358
|
+
* @param config - Data range configuration with optional segmentField
|
|
359
|
+
* @returns Navigation data, optionally with segment field included
|
|
311
360
|
*/
|
|
312
361
|
async fetchNavigationWithSegments(config = {}) {
|
|
313
|
-
const { days = 30 } = config;
|
|
314
|
-
|
|
315
|
-
|
|
362
|
+
const { days = 30, segmentField } = config;
|
|
363
|
+
if (!segmentField) {
|
|
364
|
+
console.log(`
|
|
365
|
+
${"\u2550".repeat(60)}`);
|
|
366
|
+
console.log(`\u{1F4CA} STAGE 1: PREPARING BIGQUERY QUERY (SEGMENTED)`);
|
|
367
|
+
console.log(`${"\u2550".repeat(60)}`);
|
|
368
|
+
console.log(` \u26A0\uFE0F No segment field specified`);
|
|
369
|
+
console.log(` Falling back to fetchNavigationSequences (base data only)`);
|
|
370
|
+
console.log(` To include segments, pass: { segmentField: 'field_name' }`);
|
|
371
|
+
console.log(`${"\u2550".repeat(60)}
|
|
372
|
+
`);
|
|
373
|
+
return this.fetchNavigationSequences(config);
|
|
374
|
+
}
|
|
375
|
+
console.log(`
|
|
376
|
+
${"\u2550".repeat(60)}`);
|
|
377
|
+
console.log(`\u{1F4CA} STAGE 1: PREPARING SEGMENTED BIGQUERY QUERY`);
|
|
378
|
+
console.log(`${"\u2550".repeat(60)}`);
|
|
379
|
+
console.log(` Project ID: ${this.projectId}`);
|
|
380
|
+
console.log(` Dataset ID: ${this.datasetId}`);
|
|
381
|
+
console.log(` Location: ${this.location}`);
|
|
316
382
|
console.log(` Date range: Last ${days} days`);
|
|
383
|
+
console.log(` Daily tables pattern: events_*`);
|
|
384
|
+
console.log(` Event type filter: page_view`);
|
|
385
|
+
console.log(` Segment field: ${segmentField}`);
|
|
386
|
+
console.log(` Expected fields: user_pseudo_id, ga_session_id, page_path, ${segmentField}`);
|
|
317
387
|
try {
|
|
388
|
+
const segmentParam = `(SELECT value.string_value FROM UNNEST(event_params) WHERE KEY = '${segmentField}' LIMIT 1) as segment_value`;
|
|
318
389
|
const query = `
|
|
319
390
|
WITH page_sessions AS (
|
|
320
391
|
SELECT
|
|
321
|
-
|
|
392
|
+
user_pseudo_id,
|
|
322
393
|
(SELECT value.int_value FROM UNNEST(event_params) WHERE KEY = 'ga_session_id' LIMIT 1) as session_id,
|
|
323
394
|
(SELECT value.string_value FROM UNNEST(event_params) WHERE KEY = 'page_path' LIMIT 1) as page_path,
|
|
324
|
-
|
|
325
|
-
(SELECT value.string_value FROM UNNEST(event_params) WHERE KEY = 'user_segment' LIMIT 1) as user_segment,
|
|
395
|
+
${segmentParam},
|
|
326
396
|
event_timestamp,
|
|
327
397
|
ROW_NUMBER() OVER (
|
|
328
|
-
PARTITION BY
|
|
398
|
+
PARTITION BY user_pseudo_id, (SELECT value.int_value FROM UNNEST(event_params) WHERE KEY = 'ga_session_id' LIMIT 1)
|
|
329
399
|
ORDER BY event_timestamp
|
|
330
400
|
) as page_sequence
|
|
331
401
|
FROM \`${this.projectId}.${this.datasetId}.events_*\`
|
|
@@ -339,10 +409,10 @@ var BigQueryAnalyticsConnector = class {
|
|
|
339
409
|
SELECT
|
|
340
410
|
COALESCE(curr.page_path, '(direct)') as from_page,
|
|
341
411
|
LEAD(curr.page_path) OVER (
|
|
342
|
-
PARTITION BY curr.
|
|
412
|
+
PARTITION BY curr.user_pseudo_id, curr.session_id
|
|
343
413
|
ORDER BY curr.page_sequence
|
|
344
414
|
) as to_page,
|
|
345
|
-
COALESCE(curr.
|
|
415
|
+
COALESCE(curr.segment_value, 'unknown') as segment
|
|
346
416
|
FROM page_sessions curr
|
|
347
417
|
WHERE curr.page_sequence > 0
|
|
348
418
|
)
|
|
@@ -353,45 +423,104 @@ var BigQueryAnalyticsConnector = class {
|
|
|
353
423
|
COUNT(*) as transition_count
|
|
354
424
|
FROM transitions
|
|
355
425
|
WHERE to_page IS NOT NULL
|
|
356
|
-
GROUP BY
|
|
426
|
+
GROUP BY previous_page_path, page_path, segment
|
|
357
427
|
ORDER BY segment, transition_count DESC
|
|
358
428
|
LIMIT 50000
|
|
359
429
|
`;
|
|
360
430
|
if (this.debug) {
|
|
361
|
-
console.log(
|
|
431
|
+
console.log(`
|
|
432
|
+
\u{1F4E4} Full Query with segment field (${segmentField}):`);
|
|
433
|
+
console.log(`${"\u2500".repeat(60)}`);
|
|
362
434
|
console.log(query);
|
|
435
|
+
console.log(`${"\u2500".repeat(60)}`);
|
|
363
436
|
}
|
|
437
|
+
console.log(`
|
|
438
|
+
${"\u2550".repeat(60)}`);
|
|
439
|
+
console.log(`\u{1F4CA} STAGE 2: EXECUTING QUERY`);
|
|
440
|
+
console.log(`${"\u2550".repeat(60)}`);
|
|
441
|
+
console.log(` \u23F3 Querying BigQuery with segment field: ${segmentField}`);
|
|
364
442
|
const [rows] = await this.bigquery.query({
|
|
365
443
|
query,
|
|
366
444
|
location: this.location
|
|
367
445
|
});
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
446
|
+
console.log(` \u2705 Query executed successfully`);
|
|
447
|
+
console.log(` \u{1F4C8} Total transitions returned: ${rows.length}`);
|
|
448
|
+
if (rows.length === 0) {
|
|
449
|
+
console.log(`
|
|
450
|
+
${"\u2550".repeat(60)}`);
|
|
451
|
+
console.log(`\u26A0\uFE0F STAGE 2: NO DATA RETURNED!`);
|
|
452
|
+
console.log(`${"\u2550".repeat(60)}`);
|
|
453
|
+
console.log(` \u274C BigQuery returned 0 rows for segmented query`);
|
|
454
|
+
console.log(` Segment field: ${segmentField}`);
|
|
455
|
+
console.log(` Check if this field exists in your GA4 event_params`);
|
|
456
|
+
console.log(`${"\u2550".repeat(60)}
|
|
457
|
+
`);
|
|
458
|
+
return [];
|
|
371
459
|
}
|
|
460
|
+
console.log(`
|
|
461
|
+
${"\u2550".repeat(60)}`);
|
|
462
|
+
console.log(`\u{1F4CA} STAGE 3: PROCESSING SEGMENTED DATA`);
|
|
463
|
+
console.log(`${"\u2550".repeat(60)}`);
|
|
464
|
+
console.log(` Processing ${rows.length} raw transitions with segments...`);
|
|
372
465
|
const navigationData = [];
|
|
373
|
-
|
|
466
|
+
let processedCount = 0;
|
|
467
|
+
let filteredCount = 0;
|
|
468
|
+
const segmentCounts = /* @__PURE__ */ new Map();
|
|
469
|
+
console.log(`
|
|
470
|
+
${"\u2500".repeat(56)}`);
|
|
471
|
+
console.log(` Processing each transition row...`);
|
|
472
|
+
console.log(` ${"\u2500".repeat(56)}`);
|
|
473
|
+
rows.forEach((row, index) => {
|
|
374
474
|
const previousPage = row.previous_page_path || "(direct)";
|
|
375
475
|
const currentPage = row.page_path || "";
|
|
376
476
|
const transitionCount = parseInt(row.transition_count || "0");
|
|
377
477
|
const segment = row.segment || "unknown";
|
|
478
|
+
if (this.debug && index < 3) {
|
|
479
|
+
console.log(`
|
|
480
|
+
Row ${index + 1}:`);
|
|
481
|
+
console.log(` Raw: "${previousPage}" \u2192 "${currentPage}" | segment: "${segment}" (count: ${transitionCount})`);
|
|
482
|
+
}
|
|
378
483
|
const normalizedPrevious = previousPage === "(direct)" || previousPage === "(not set)" ? "(direct)" : this.normalizeRoute(previousPage);
|
|
379
484
|
const normalizedCurrent = this.normalizeRoute(currentPage);
|
|
485
|
+
if (this.debug && index < 3) {
|
|
486
|
+
console.log(` Normalized: "${normalizedPrevious}" \u2192 "${normalizedCurrent}" | segment: "${segment}"`);
|
|
487
|
+
}
|
|
380
488
|
if (normalizedCurrent && transitionCount >= 1) {
|
|
381
489
|
navigationData.push({
|
|
382
490
|
from: normalizedPrevious,
|
|
383
491
|
to: normalizedCurrent,
|
|
384
492
|
count: transitionCount,
|
|
385
493
|
segment
|
|
386
|
-
// Include segment/role field
|
|
387
494
|
});
|
|
495
|
+
processedCount++;
|
|
496
|
+
segmentCounts.set(segment, (segmentCounts.get(segment) || 0) + 1);
|
|
497
|
+
if (this.debug && index < 3) {
|
|
498
|
+
console.log(` \u2705 ACCEPTED`);
|
|
499
|
+
}
|
|
500
|
+
} else {
|
|
501
|
+
filteredCount++;
|
|
502
|
+
if (this.debug && index < 3) {
|
|
503
|
+
console.log(` \u274C FILTERED`);
|
|
504
|
+
}
|
|
388
505
|
}
|
|
389
506
|
});
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
507
|
+
console.log(`
|
|
508
|
+
${"\u2500".repeat(56)}`);
|
|
509
|
+
console.log(` Processing Summary:`);
|
|
510
|
+
console.log(` \u2705 Accepted: ${processedCount}`);
|
|
511
|
+
console.log(` \u274C Filtered out: ${filteredCount}`);
|
|
512
|
+
console.log(`
|
|
513
|
+
${"\u2550".repeat(60)}`);
|
|
514
|
+
console.log(`\u{1F4CA} STAGE 4: FINAL RESULTS (SEGMENTED)`);
|
|
515
|
+
console.log(`${"\u2550".repeat(60)}`);
|
|
516
|
+
console.log(` Total valid transitions: ${navigationData.length}`);
|
|
517
|
+
if (navigationData.length > 0) {
|
|
518
|
+
const uniqueSegments = Array.from(segmentCounts.keys()).sort();
|
|
393
519
|
console.log(`
|
|
394
|
-
Detected segments: ${
|
|
520
|
+
\u{1F4CA} Detected segments: ${uniqueSegments.length}`);
|
|
521
|
+
uniqueSegments.forEach((seg) => {
|
|
522
|
+
console.log(` \u2022 ${seg} (${segmentCounts.get(seg)} transitions)`);
|
|
523
|
+
});
|
|
395
524
|
const bySegment = /* @__PURE__ */ new Map();
|
|
396
525
|
navigationData.forEach((d) => {
|
|
397
526
|
if (!bySegment.has(d.segment)) {
|
|
@@ -401,42 +530,31 @@ var BigQueryAnalyticsConnector = class {
|
|
|
401
530
|
});
|
|
402
531
|
bySegment.forEach((transitions, segment) => {
|
|
403
532
|
console.log(`
|
|
404
|
-
Top 3 transitions for ${segment}:`);
|
|
533
|
+
Top 3 transitions for segment "${segment}":`);
|
|
405
534
|
transitions.sort((a, b) => b.count - a.count).slice(0, 3).forEach((nav, i) => {
|
|
406
|
-
console.log(`
|
|
535
|
+
console.log(` ${i + 1}. ${nav.from} \u2192 ${nav.to} (${nav.count})`);
|
|
407
536
|
});
|
|
408
537
|
});
|
|
538
|
+
} else {
|
|
539
|
+
console.log(` \u26A0\uFE0F WARNING: All transitions were filtered out!`);
|
|
409
540
|
}
|
|
541
|
+
console.log(`${"\u2550".repeat(60)}
|
|
542
|
+
`);
|
|
410
543
|
return navigationData;
|
|
411
544
|
} catch (error) {
|
|
412
545
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
546
|
+
console.log(`
|
|
547
|
+
${"\u2550".repeat(60)}`);
|
|
548
|
+
console.log(`\u274C ERROR: SEGMENTED QUERY EXECUTION FAILED`);
|
|
549
|
+
console.log(`${"\u2550".repeat(60)}`);
|
|
550
|
+
console.log(` Segment field: ${segmentField}`);
|
|
551
|
+
console.log(` Error: ${errorMessage}`);
|
|
552
|
+
console.log(`${"\u2550".repeat(60)}
|
|
553
|
+
`);
|
|
413
554
|
console.warn(`\u26A0\uFE0F Failed to fetch navigation data with segments: ${errorMessage}`);
|
|
414
555
|
return [];
|
|
415
556
|
}
|
|
416
557
|
}
|
|
417
|
-
/**
|
|
418
|
-
* Test connection to BigQuery
|
|
419
|
-
* Note: May fail if service account lacks bigquery.jobs.create permission
|
|
420
|
-
* but actual queries may still work. This is expected for viewer-only accounts.
|
|
421
|
-
*/
|
|
422
|
-
async testConnection() {
|
|
423
|
-
try {
|
|
424
|
-
const query = `SELECT 1 as test_value`;
|
|
425
|
-
await this.bigquery.query({
|
|
426
|
-
query,
|
|
427
|
-
location: this.location
|
|
428
|
-
});
|
|
429
|
-
if (this.debug) {
|
|
430
|
-
console.log("\u2705 BigQuery connection test successful");
|
|
431
|
-
}
|
|
432
|
-
return true;
|
|
433
|
-
} catch (error) {
|
|
434
|
-
if (this.debug) {
|
|
435
|
-
console.warn("\u26A0\uFE0F BigQuery connection test failed (may be expected for read-only accounts)");
|
|
436
|
-
}
|
|
437
|
-
return false;
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
558
|
};
|
|
441
559
|
|
|
442
560
|
// src/plugin/model/guessjs-ml-trainer.ts
|
|
@@ -1855,6 +1973,7 @@ function generateDashboard(config) {
|
|
|
1855
1973
|
}
|
|
1856
1974
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1857
1975
|
0 && (module.exports = {
|
|
1976
|
+
BigQueryAnalyticsConnector,
|
|
1858
1977
|
smartPrefetch
|
|
1859
1978
|
});
|
|
1860
1979
|
//# sourceMappingURL=index.cjs.map
|