@oneclick.dev/cms-core-modules 0.0.82 → 0.0.83
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/{ContentEditor-4e80zFyn.js → ContentEditor-CRFkD4tE.js} +33 -33
- package/dist/{ContentEditor-Dk-iDEjl.mjs → ContentEditor-CxKirDdL.mjs} +2861 -2854
- package/dist/{Create-DtFzwxn_.mjs → Create-CsqVYhPO.mjs} +1 -1
- package/dist/{Create-CRn2sMHp.js → Create-ip0MnS0o.js} +1 -1
- package/dist/{DateFormatter-DfIwyrnF.mjs → DateFormatter-CvOfaUnU.mjs} +137 -134
- package/dist/DateFormatter-ls6HfWpS.js +1 -0
- package/dist/{Detail-BwDnY42G.mjs → Detail-CbLk1v37.mjs} +1 -1
- package/dist/{Detail-Bxi7lG9x.js → Detail-RMXFuSRQ.js} +1 -1
- package/dist/{NewReservationDialog.vue_vue_type_script_setup_true_lang-Ds7z0qeH.mjs → NewReservationDialog.vue_vue_type_script_setup_true_lang-CDc8MIq2.mjs} +1 -1
- package/dist/{NewReservationDialog.vue_vue_type_script_setup_true_lang-C5YczjNb.js → NewReservationDialog.vue_vue_type_script_setup_true_lang-StaNp-3y.js} +1 -1
- package/dist/{Overview-pCO_47Zt.js → Overview-B2bFNGhH.js} +1 -1
- package/dist/{Overview-CuCQgqVp.mjs → Overview-Cczt_dcE.mjs} +1 -1
- package/dist/{SeoHealth-EZzDmPDM.js → SeoHealth-DFZ0LLBH.js} +1 -1
- package/dist/{SeoHealth-CC0rW1AG.mjs → SeoHealth-ZpvB7CS2.mjs} +1 -1
- package/dist/{TableView-DRQvOW85.mjs → TableView-BUPPcHUW.mjs} +28920 -28605
- package/dist/{TableView-Ce8H65pL.js → TableView-CksiPsTL.js} +152 -152
- package/dist/{agenda-XqvbrU72.mjs → agenda-Cl3s_FIE.mjs} +2 -2
- package/dist/{agenda-wNFDKn0G.js → agenda-rlFma_wn.js} +1 -1
- package/dist/{exceptions-wEQEVzIs.js → exceptions-BA3PsW4n.js} +1 -1
- package/dist/{exceptions-CLgeeUSy.mjs → exceptions-DQPSFSj7.mjs} +1 -1
- package/dist/floating-ui.dom-B9WYoHj2.js +1 -0
- package/dist/{floating-ui.dom-BO2Hr6mz.mjs → floating-ui.dom-fpIfhXTZ.mjs} +400 -401
- package/dist/{index-DTzdHh6g.js → index-CBC9dWZ9.js} +1 -1
- package/dist/{index-DYpruS-A-D38FBcI3.mjs → index-DYpruS-A-Cw57iwdY.mjs} +2 -3
- package/dist/{index-DYpruS-A-CA2jEOA3.js → index-DYpruS-A-DwDXo9Tq.js} +5 -5
- package/dist/{index-N0NoDEsI.mjs → index-YOOlBEZB.mjs} +2 -2
- package/dist/index.cjs.js +1 -1
- package/dist/index.mjs +38 -24
- package/dist/orders-DZzdsHOW.mjs +397 -0
- package/dist/orders-tP4WdF5q.js +1 -0
- package/dist/server-handlers.cjs.js +1 -1
- package/dist/server-handlers.mjs +334 -293
- package/dist/src/contentManager/config.d.ts +28 -0
- package/dist/src/contentManager/index.d.ts +28 -0
- package/dist/src/contentManager/server.d.ts +7 -0
- package/dist/src/server-handlers.d.ts +1 -0
- package/package.json +2 -2
- package/dist/DateFormatter-C9qfmQnP.js +0 -1
- package/dist/floating-ui.dom-CAr9LGoC.js +0 -1
- package/dist/orders-Bqa3Z3tH.mjs +0 -356
- package/dist/orders-D5GJOZXN.js +0 -1
package/dist/server-handlers.mjs
CHANGED
|
@@ -1,87 +1,87 @@
|
|
|
1
|
-
import { createRouter as
|
|
1
|
+
import { createRouter as M, defineEventHandler as y, createError as w, getRouterParam as N, getQuery as D } from "h3";
|
|
2
2
|
import "vue";
|
|
3
|
-
function
|
|
4
|
-
const { initFirebase:
|
|
5
|
-
async function
|
|
6
|
-
const { supabase: c, instanceId:
|
|
7
|
-
if (
|
|
8
|
-
throw
|
|
3
|
+
function O(f) {
|
|
4
|
+
const { initFirebase: R, normalizeTimestamps: A } = f, g = M();
|
|
5
|
+
async function u(d) {
|
|
6
|
+
const { supabase: c, instanceId: m } = d.context.module, { data: e, error: a } = await c.from("project_modules").select("config").eq("id", m).single();
|
|
7
|
+
if (a || !e?.config)
|
|
8
|
+
throw w({ statusCode: 500, statusMessage: "Failed to load module config." });
|
|
9
9
|
const n = e.config, t = n.project, s = n.productCollection || "products";
|
|
10
10
|
if (!t)
|
|
11
|
-
throw
|
|
12
|
-
return { firebase: await
|
|
11
|
+
throw w({ statusCode: 400, statusMessage: "Products module has no Firebase integration configured." });
|
|
12
|
+
return { firebase: await R(d, t), collection: s };
|
|
13
13
|
}
|
|
14
|
-
return
|
|
14
|
+
return g.get("/products", y(async (d) => {
|
|
15
15
|
try {
|
|
16
|
-
const { firebase: c, collection:
|
|
17
|
-
return (await c.firestore().collection(
|
|
18
|
-
id:
|
|
19
|
-
...
|
|
16
|
+
const { firebase: c, collection: m } = await u(d);
|
|
17
|
+
return (await c.firestore().collection(m).get()).docs.map((a) => A({
|
|
18
|
+
id: a.id,
|
|
19
|
+
...a.data()
|
|
20
20
|
}));
|
|
21
21
|
} catch (c) {
|
|
22
|
-
throw console.error("Products handler — list error:", c),
|
|
22
|
+
throw console.error("Products handler — list error:", c), w({
|
|
23
23
|
statusCode: c.statusCode || 500,
|
|
24
24
|
statusMessage: c.statusMessage || "Failed to list products"
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
|
-
})),
|
|
28
|
-
const c =
|
|
27
|
+
})), g.get("/products/:productId", y(async (d) => {
|
|
28
|
+
const c = N(d, "productId");
|
|
29
29
|
if (!c)
|
|
30
|
-
throw
|
|
30
|
+
throw w({ statusCode: 400, statusMessage: "Product ID is required." });
|
|
31
31
|
try {
|
|
32
|
-
const { firebase:
|
|
33
|
-
if (!
|
|
34
|
-
throw
|
|
32
|
+
const { firebase: m, collection: e } = await u(d), a = await m.firestore().collection(e).doc(c).get();
|
|
33
|
+
if (!a.exists)
|
|
34
|
+
throw w({ statusCode: 404, statusMessage: "Product not found." });
|
|
35
35
|
return A({
|
|
36
|
-
id:
|
|
37
|
-
...
|
|
36
|
+
id: a.id,
|
|
37
|
+
...a.data()
|
|
38
38
|
});
|
|
39
|
-
} catch (
|
|
40
|
-
throw console.error("Products handler — get error:",
|
|
41
|
-
statusCode:
|
|
42
|
-
statusMessage:
|
|
39
|
+
} catch (m) {
|
|
40
|
+
throw console.error("Products handler — get error:", m), w({
|
|
41
|
+
statusCode: m.statusCode || 500,
|
|
42
|
+
statusMessage: m.statusMessage || "Failed to get product"
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
|
-
})),
|
|
46
|
-
const
|
|
45
|
+
})), g.get("/empty-stock", y(async (d) => {
|
|
46
|
+
const m = D(d).category;
|
|
47
47
|
try {
|
|
48
|
-
const { firebase: e, collection:
|
|
49
|
-
let n = e.firestore().collection(
|
|
50
|
-
|
|
51
|
-
const s = (await n.get()).docs.map((
|
|
52
|
-
id:
|
|
53
|
-
...
|
|
48
|
+
const { firebase: e, collection: a } = await u(d);
|
|
49
|
+
let n = e.firestore().collection(a).where("stock", "==", 0);
|
|
50
|
+
m && (n = n.where("collections", "array-contains", m));
|
|
51
|
+
const s = (await n.get()).docs.map((o) => A({
|
|
52
|
+
id: o.id,
|
|
53
|
+
...o.data()
|
|
54
54
|
}));
|
|
55
55
|
return {
|
|
56
56
|
count: s.length,
|
|
57
|
-
products: s.map((
|
|
58
|
-
id:
|
|
59
|
-
title:
|
|
60
|
-
slug:
|
|
61
|
-
stock:
|
|
62
|
-
price:
|
|
63
|
-
currency:
|
|
64
|
-
status:
|
|
57
|
+
products: s.map((o) => ({
|
|
58
|
+
id: o.id,
|
|
59
|
+
title: o.title,
|
|
60
|
+
slug: o.slug,
|
|
61
|
+
stock: o.stock,
|
|
62
|
+
price: o.price,
|
|
63
|
+
currency: o.currency,
|
|
64
|
+
status: o.status
|
|
65
65
|
}))
|
|
66
66
|
};
|
|
67
67
|
} catch (e) {
|
|
68
|
-
throw console.error("Products handler — empty-stock error:", e),
|
|
68
|
+
throw console.error("Products handler — empty-stock error:", e), w({
|
|
69
69
|
statusCode: e.statusCode || 500,
|
|
70
70
|
statusMessage: e.statusMessage || "Failed to query empty stock"
|
|
71
71
|
});
|
|
72
72
|
}
|
|
73
|
-
})),
|
|
73
|
+
})), g.handler;
|
|
74
74
|
}
|
|
75
|
-
function G(
|
|
76
|
-
const { initFirebase:
|
|
77
|
-
async function
|
|
78
|
-
const { supabase:
|
|
79
|
-
if (n || !
|
|
80
|
-
throw
|
|
81
|
-
const t =
|
|
75
|
+
function G(f) {
|
|
76
|
+
const { initFirebase: R, normalizeTimestamps: A } = f, g = M();
|
|
77
|
+
async function u(c) {
|
|
78
|
+
const { supabase: m, instanceId: e } = c.context.module, { data: a, error: n } = await m.from("project_modules").select("config").eq("id", e).single();
|
|
79
|
+
if (n || !a?.config)
|
|
80
|
+
throw w({ statusCode: 500, statusMessage: "Failed to load module config." });
|
|
81
|
+
const t = a.config, s = t.project, o = t.reservationsCollection || "bookings_orders", r = t.agendaCollection || "agendas";
|
|
82
82
|
if (!s)
|
|
83
|
-
throw
|
|
84
|
-
return { firebase: await
|
|
83
|
+
throw w({ statusCode: 400, statusMessage: "Appointments module has no Firebase integration configured." });
|
|
84
|
+
return { firebase: await R(c, s), reservationsCollection: o, agendaCollection: r };
|
|
85
85
|
}
|
|
86
86
|
function d(c) {
|
|
87
87
|
return (c.reservations || []).map((e) => ({
|
|
@@ -104,98 +104,98 @@ function G(w) {
|
|
|
104
104
|
createdAt: c.createdAt
|
|
105
105
|
}));
|
|
106
106
|
}
|
|
107
|
-
return
|
|
108
|
-
const
|
|
107
|
+
return g.get("/appointments", y(async (c) => {
|
|
108
|
+
const m = D(c), e = Math.min(Number(m.quantity) || 20, 100);
|
|
109
109
|
try {
|
|
110
|
-
const { firebase:
|
|
111
|
-
(
|
|
110
|
+
const { firebase: a, reservationsCollection: n } = await u(c), s = (await a.firestore().collection(n).orderBy("createdAt", "desc").limit(e).get()).docs.flatMap(
|
|
111
|
+
(o) => d(A({ id: o.id, ...o.data() }))
|
|
112
112
|
);
|
|
113
113
|
return {
|
|
114
114
|
count: s.length,
|
|
115
115
|
appointments: s
|
|
116
116
|
};
|
|
117
|
-
} catch (
|
|
118
|
-
throw console.error("Appointments handler — list error:",
|
|
119
|
-
statusCode:
|
|
120
|
-
statusMessage:
|
|
117
|
+
} catch (a) {
|
|
118
|
+
throw console.error("Appointments handler — list error:", a), w({
|
|
119
|
+
statusCode: a.statusCode || 500,
|
|
120
|
+
statusMessage: a.statusMessage || "Failed to list appointments"
|
|
121
121
|
});
|
|
122
122
|
}
|
|
123
|
-
})),
|
|
124
|
-
const
|
|
123
|
+
})), g.get("/appointments/find", y(async (c) => {
|
|
124
|
+
const m = D(c), e = (m.name || "").toLowerCase().trim(), a = (m.email || "").toLowerCase().trim(), n = m.date;
|
|
125
125
|
try {
|
|
126
|
-
const { firebase: t, reservationsCollection: s } = await
|
|
127
|
-
let
|
|
128
|
-
|
|
129
|
-
let i = (await
|
|
130
|
-
(
|
|
126
|
+
const { firebase: t, reservationsCollection: s } = await u(c);
|
|
127
|
+
let o = t.firestore().collection(s);
|
|
128
|
+
a && (o = o.where("customerInfo.email", "==", a));
|
|
129
|
+
let i = (await o.orderBy("createdAt", "desc").limit(200).get()).docs.flatMap(
|
|
130
|
+
(l) => d(A({ id: l.id, ...l.data() }))
|
|
131
131
|
);
|
|
132
|
-
return n && (i = i.filter((
|
|
133
|
-
const p = (
|
|
134
|
-
return p.includes(e) ||
|
|
132
|
+
return n && (i = i.filter((l) => l.date === n)), e && (i = i.filter((l) => {
|
|
133
|
+
const p = (l.customerInfo?.firstName || "").toLowerCase(), h = (l.customerInfo?.lastName || "").toLowerCase();
|
|
134
|
+
return p.includes(e) || h.includes(e) || `${p} ${h}`.includes(e);
|
|
135
135
|
})), {
|
|
136
136
|
count: i.length,
|
|
137
137
|
appointments: i
|
|
138
138
|
};
|
|
139
139
|
} catch (t) {
|
|
140
|
-
throw console.error("Appointments handler — find error:", t),
|
|
140
|
+
throw console.error("Appointments handler — find error:", t), w({
|
|
141
141
|
statusCode: t.statusCode || 500,
|
|
142
142
|
statusMessage: t.statusMessage || "Failed to find appointments"
|
|
143
143
|
});
|
|
144
144
|
}
|
|
145
|
-
})),
|
|
146
|
-
const
|
|
147
|
-
if (!
|
|
148
|
-
throw
|
|
145
|
+
})), g.get("/appointments/:appointmentId", y(async (c) => {
|
|
146
|
+
const m = N(c, "appointmentId");
|
|
147
|
+
if (!m)
|
|
148
|
+
throw w({ statusCode: 400, statusMessage: "Appointment ID is required." });
|
|
149
149
|
try {
|
|
150
|
-
const { firebase: e, reservationsCollection:
|
|
151
|
-
console.log("Fetching appointment with ID:",
|
|
152
|
-
const n = await e.firestore().collection(
|
|
150
|
+
const { firebase: e, reservationsCollection: a } = await u(c);
|
|
151
|
+
console.log("Fetching appointment with ID:", m, a);
|
|
152
|
+
const n = await e.firestore().collection(a).doc(m).get();
|
|
153
153
|
if (!n.exists)
|
|
154
|
-
throw
|
|
154
|
+
throw w({ statusCode: 404, statusMessage: "Appointment not found." });
|
|
155
155
|
const t = A({ id: n.id, ...n.data() });
|
|
156
156
|
return {
|
|
157
157
|
...t,
|
|
158
158
|
reservations: d(t)
|
|
159
159
|
};
|
|
160
160
|
} catch (e) {
|
|
161
|
-
throw console.error("Appointments handler — get error:", e),
|
|
161
|
+
throw console.error("Appointments handler — get error:", e), w({
|
|
162
162
|
statusCode: e.statusCode || 500,
|
|
163
163
|
statusMessage: e.statusMessage || "Failed to get appointment"
|
|
164
164
|
});
|
|
165
165
|
}
|
|
166
|
-
})),
|
|
166
|
+
})), g.handler;
|
|
167
167
|
}
|
|
168
|
-
const
|
|
168
|
+
const q = "https://analyticsdata.googleapis.com/v1beta", F = [
|
|
169
169
|
"https://www.googleapis.com/auth/analytics.readonly",
|
|
170
170
|
"https://www.googleapis.com/auth/webmasters.readonly"
|
|
171
|
-
],
|
|
172
|
-
function x(
|
|
173
|
-
const { decrypt:
|
|
174
|
-
async function
|
|
175
|
-
const { supabase:
|
|
171
|
+
], b = "https://searchconsole.googleapis.com/webmasters/v3";
|
|
172
|
+
function x(f) {
|
|
173
|
+
const { decrypt: R, getGoogleAccessToken: A } = f, g = M();
|
|
174
|
+
async function u(e) {
|
|
175
|
+
const { supabase: a, instanceId: n } = e.context.module, { data: t, error: s } = await a.from("project_modules").select("config").eq("id", n).single();
|
|
176
176
|
if (s || !t?.config)
|
|
177
|
-
throw
|
|
178
|
-
const
|
|
177
|
+
throw w({ statusCode: 500, statusMessage: "Failed to load module config." });
|
|
178
|
+
const o = t.config, r = o.propertyId, i = o.serviceAccount, l = o.siteUrl || "";
|
|
179
179
|
if (!i)
|
|
180
|
-
throw
|
|
180
|
+
throw w({ statusCode: 400, statusMessage: "No Google Service Account configured for this module." });
|
|
181
181
|
if (!r)
|
|
182
|
-
throw
|
|
183
|
-
const { data: p, error:
|
|
182
|
+
throw w({ statusCode: 400, statusMessage: "No GA4 Property ID configured for this module." });
|
|
183
|
+
const { data: p, error: h } = await a.from("integrations").select("config").eq("id", i).single();
|
|
184
184
|
let C = p?.config;
|
|
185
|
-
if (
|
|
186
|
-
const { data:
|
|
187
|
-
if (
|
|
188
|
-
throw
|
|
189
|
-
C =
|
|
185
|
+
if (h || !C) {
|
|
186
|
+
const { data: v, error: U } = await a.from("agency_integrations").select("config").eq("id", i).single();
|
|
187
|
+
if (U || !v?.config)
|
|
188
|
+
throw w({ statusCode: 500, statusMessage: "Failed to load Google Service Account credentials." });
|
|
189
|
+
C = v.config;
|
|
190
190
|
}
|
|
191
|
-
const
|
|
191
|
+
const S = R(C.clientEmail), k = R(C.privateKey), P = R(C.projectId);
|
|
192
192
|
return { accessToken: await A(
|
|
193
|
-
{ clientEmail:
|
|
193
|
+
{ clientEmail: S, privateKey: k, projectId: P },
|
|
194
194
|
F
|
|
195
|
-
), propertyId: r, siteUrl:
|
|
195
|
+
), propertyId: r, siteUrl: l };
|
|
196
196
|
}
|
|
197
|
-
async function d(e,
|
|
198
|
-
const t = await fetch(`${
|
|
197
|
+
async function d(e, a, n) {
|
|
198
|
+
const t = await fetch(`${q}/properties/${a}:runReport`, {
|
|
199
199
|
method: "POST",
|
|
200
200
|
headers: {
|
|
201
201
|
Authorization: `Bearer ${e}`,
|
|
@@ -205,17 +205,17 @@ function x(w) {
|
|
|
205
205
|
});
|
|
206
206
|
if (!t.ok) {
|
|
207
207
|
const s = await t.json().catch(() => ({}));
|
|
208
|
-
throw console.error("GA4 runReport failed:", s),
|
|
208
|
+
throw console.error("GA4 runReport failed:", s), w({
|
|
209
209
|
statusCode: t.status,
|
|
210
210
|
statusMessage: s?.error?.message || "GA4 API request failed"
|
|
211
211
|
});
|
|
212
212
|
}
|
|
213
213
|
return t.json();
|
|
214
214
|
}
|
|
215
|
-
|
|
215
|
+
g.get(
|
|
216
216
|
"/report",
|
|
217
217
|
y(async (e) => {
|
|
218
|
-
const { accessToken:
|
|
218
|
+
const { accessToken: a, propertyId: n } = await u(e), t = D(e), s = t.startDate || "30daysAgo", o = t.endDate || "today", r = s.match(/^(\d+)daysAgo$/), i = r ? parseInt(r[1], 10) : 30, l = `${i * 2}daysAgo`, p = `${i + 1}daysAgo`, h = [
|
|
219
219
|
{ name: "sessions" },
|
|
220
220
|
{ name: "totalUsers" },
|
|
221
221
|
{ name: "screenPageViews" },
|
|
@@ -226,38 +226,38 @@ function x(w) {
|
|
|
226
226
|
{ name: "sessionsPerUser" },
|
|
227
227
|
{ name: "screenPageViewsPerSession" }
|
|
228
228
|
];
|
|
229
|
-
let C,
|
|
229
|
+
let C, S = !0;
|
|
230
230
|
try {
|
|
231
|
-
C = await d(
|
|
231
|
+
C = await d(a, n, {
|
|
232
232
|
dateRanges: [
|
|
233
|
-
{ startDate: s, endDate:
|
|
234
|
-
{ startDate:
|
|
233
|
+
{ startDate: s, endDate: o, name: "current" },
|
|
234
|
+
{ startDate: l, endDate: p, name: "previous" }
|
|
235
235
|
],
|
|
236
236
|
dimensions: [{ name: "date" }],
|
|
237
|
-
metrics:
|
|
237
|
+
metrics: h,
|
|
238
238
|
metricAggregations: ["TOTAL"],
|
|
239
239
|
orderBys: [{ dimension: { dimensionName: "date" } }]
|
|
240
240
|
});
|
|
241
241
|
} catch {
|
|
242
|
-
|
|
243
|
-
dateRanges: [{ startDate: s, endDate:
|
|
242
|
+
S = !1, C = await d(a, n, {
|
|
243
|
+
dateRanges: [{ startDate: s, endDate: o }],
|
|
244
244
|
dimensions: [{ name: "date" }],
|
|
245
|
-
metrics:
|
|
245
|
+
metrics: h,
|
|
246
246
|
metricAggregations: ["TOTAL"],
|
|
247
247
|
orderBys: [{ dimension: { dimensionName: "date" } }]
|
|
248
248
|
});
|
|
249
249
|
}
|
|
250
|
-
return V(C,
|
|
250
|
+
return V(C, S);
|
|
251
251
|
})
|
|
252
|
-
),
|
|
252
|
+
), g.get(
|
|
253
253
|
"/realtime",
|
|
254
254
|
y(async (e) => {
|
|
255
|
-
const { accessToken:
|
|
256
|
-
`${
|
|
255
|
+
const { accessToken: a, propertyId: n } = await u(e), t = await fetch(
|
|
256
|
+
`${q}/properties/${n}:runRealtimeReport`,
|
|
257
257
|
{
|
|
258
258
|
method: "POST",
|
|
259
259
|
headers: {
|
|
260
|
-
Authorization: `Bearer ${
|
|
260
|
+
Authorization: `Bearer ${a}`,
|
|
261
261
|
"Content-Type": "application/json"
|
|
262
262
|
},
|
|
263
263
|
body: JSON.stringify({
|
|
@@ -270,22 +270,22 @@ function x(w) {
|
|
|
270
270
|
);
|
|
271
271
|
if (!t.ok) {
|
|
272
272
|
const i = await t.json().catch(() => ({}));
|
|
273
|
-
throw
|
|
273
|
+
throw w({ statusCode: t.status, statusMessage: i?.error?.message || "Realtime API failed" });
|
|
274
274
|
}
|
|
275
|
-
const s = await t.json(),
|
|
276
|
-
(i,
|
|
275
|
+
const s = await t.json(), o = (s?.rows || []).reduce(
|
|
276
|
+
(i, l) => i + parseInt(l.metricValues?.[0]?.value || "0", 10),
|
|
277
277
|
0
|
|
278
278
|
), r = (s?.rows || []).map((i) => ({
|
|
279
279
|
page: i.dimensionValues?.[0]?.value || "(not set)",
|
|
280
280
|
activeUsers: parseInt(i.metricValues?.[0]?.value || "0", 10)
|
|
281
281
|
}));
|
|
282
|
-
return { activeUsers:
|
|
282
|
+
return { activeUsers: o, activePages: r };
|
|
283
283
|
})
|
|
284
|
-
),
|
|
284
|
+
), g.get(
|
|
285
285
|
"/top-pages",
|
|
286
286
|
y(async (e) => {
|
|
287
|
-
const { accessToken:
|
|
288
|
-
dateRanges: [{ startDate: s, endDate:
|
|
287
|
+
const { accessToken: a, propertyId: n } = await u(e), t = D(e), s = t.startDate || "30daysAgo", o = t.endDate || "today", r = parseInt(t.limit || "10", 10), i = await d(a, n, {
|
|
288
|
+
dateRanges: [{ startDate: s, endDate: o }],
|
|
289
289
|
dimensions: [{ name: "pagePath" }],
|
|
290
290
|
metrics: [
|
|
291
291
|
{ name: "screenPageViews" },
|
|
@@ -295,23 +295,23 @@ function x(w) {
|
|
|
295
295
|
orderBys: [{ metric: { metricName: "screenPageViews" }, desc: !0 }],
|
|
296
296
|
limit: r * 2
|
|
297
297
|
// fetch extra to account for duplicates before aggregation
|
|
298
|
-
}),
|
|
299
|
-
for (const C of
|
|
300
|
-
const
|
|
301
|
-
if (
|
|
302
|
-
|
|
303
|
-
const
|
|
304
|
-
|
|
298
|
+
}), l = I(i, "pagePath"), p = /* @__PURE__ */ new Map();
|
|
299
|
+
for (const C of l.rows) {
|
|
300
|
+
const S = C.pagePath.toLowerCase().replace(/\/+$/, ""), k = p.get(S);
|
|
301
|
+
if (k) {
|
|
302
|
+
k.screenPageViews += C.screenPageViews || 0, k.totalUsers += C.totalUsers || 0;
|
|
303
|
+
const P = k.screenPageViews;
|
|
304
|
+
P > 0 && (k.averageSessionDuration = (k.averageSessionDuration * (P - (C.screenPageViews || 0)) + (C.averageSessionDuration || 0) * (C.screenPageViews || 0)) / P);
|
|
305
305
|
} else
|
|
306
|
-
p.set(
|
|
306
|
+
p.set(S, { ...C });
|
|
307
307
|
}
|
|
308
|
-
return { rows: [...p.values()].sort((C,
|
|
308
|
+
return { rows: [...p.values()].sort((C, S) => (S.screenPageViews || 0) - (C.screenPageViews || 0)).slice(0, r), rowCount: l.rowCount };
|
|
309
309
|
})
|
|
310
|
-
),
|
|
310
|
+
), g.get(
|
|
311
311
|
"/top-sources",
|
|
312
312
|
y(async (e) => {
|
|
313
|
-
const { accessToken:
|
|
314
|
-
dateRanges: [{ startDate: s, endDate:
|
|
313
|
+
const { accessToken: a, propertyId: n } = await u(e), t = D(e), s = t.startDate || "30daysAgo", o = t.endDate || "today", r = await d(a, n, {
|
|
314
|
+
dateRanges: [{ startDate: s, endDate: o }],
|
|
315
315
|
dimensions: [{ name: "sessionSource" }],
|
|
316
316
|
metrics: [
|
|
317
317
|
{ name: "sessions" },
|
|
@@ -322,11 +322,11 @@ function x(w) {
|
|
|
322
322
|
});
|
|
323
323
|
return I(r, "sessionSource");
|
|
324
324
|
})
|
|
325
|
-
),
|
|
325
|
+
), g.get(
|
|
326
326
|
"/devices",
|
|
327
327
|
y(async (e) => {
|
|
328
|
-
const { accessToken:
|
|
329
|
-
dateRanges: [{ startDate: s, endDate:
|
|
328
|
+
const { accessToken: a, propertyId: n } = await u(e), t = D(e), s = t.startDate || "30daysAgo", o = t.endDate || "today", r = await d(a, n, {
|
|
329
|
+
dateRanges: [{ startDate: s, endDate: o }],
|
|
330
330
|
dimensions: [{ name: "deviceCategory" }],
|
|
331
331
|
metrics: [
|
|
332
332
|
{ name: "sessions" },
|
|
@@ -336,11 +336,11 @@ function x(w) {
|
|
|
336
336
|
});
|
|
337
337
|
return I(r, "deviceCategory");
|
|
338
338
|
})
|
|
339
|
-
),
|
|
339
|
+
), g.get(
|
|
340
340
|
"/countries",
|
|
341
341
|
y(async (e) => {
|
|
342
|
-
const { accessToken:
|
|
343
|
-
dateRanges: [{ startDate: s, endDate:
|
|
342
|
+
const { accessToken: a, propertyId: n } = await u(e), t = D(e), s = t.startDate || "30daysAgo", o = t.endDate || "today", r = await d(a, n, {
|
|
343
|
+
dateRanges: [{ startDate: s, endDate: o }],
|
|
344
344
|
dimensions: [{ name: "country" }],
|
|
345
345
|
metrics: [
|
|
346
346
|
{ name: "sessions" },
|
|
@@ -351,11 +351,11 @@ function x(w) {
|
|
|
351
351
|
});
|
|
352
352
|
return I(r, "country");
|
|
353
353
|
})
|
|
354
|
-
),
|
|
354
|
+
), g.get(
|
|
355
355
|
"/acquisition/channels",
|
|
356
356
|
y(async (e) => {
|
|
357
|
-
const { accessToken:
|
|
358
|
-
dateRanges: [{ startDate: s, endDate:
|
|
357
|
+
const { accessToken: a, propertyId: n } = await u(e), t = D(e), s = t.startDate || "30daysAgo", o = t.endDate || "today", r = await d(a, n, {
|
|
358
|
+
dateRanges: [{ startDate: s, endDate: o }],
|
|
359
359
|
dimensions: [{ name: "sessionDefaultChannelGroup" }],
|
|
360
360
|
metrics: [
|
|
361
361
|
{ name: "sessions" },
|
|
@@ -371,11 +371,11 @@ function x(w) {
|
|
|
371
371
|
});
|
|
372
372
|
return I(r, "sessionDefaultChannelGroup");
|
|
373
373
|
})
|
|
374
|
-
),
|
|
374
|
+
), g.get(
|
|
375
375
|
"/acquisition/source-medium",
|
|
376
376
|
y(async (e) => {
|
|
377
|
-
const { accessToken:
|
|
378
|
-
dateRanges: [{ startDate: s, endDate:
|
|
377
|
+
const { accessToken: a, propertyId: n } = await u(e), t = D(e), s = t.startDate || "30daysAgo", o = t.endDate || "today", r = await d(a, n, {
|
|
378
|
+
dateRanges: [{ startDate: s, endDate: o }],
|
|
379
379
|
dimensions: [{ name: "sessionSourceMedium" }],
|
|
380
380
|
metrics: [
|
|
381
381
|
{ name: "sessions" },
|
|
@@ -390,11 +390,11 @@ function x(w) {
|
|
|
390
390
|
});
|
|
391
391
|
return I(r, "sessionSourceMedium");
|
|
392
392
|
})
|
|
393
|
-
),
|
|
393
|
+
), g.get(
|
|
394
394
|
"/acquisition/referrals",
|
|
395
395
|
y(async (e) => {
|
|
396
|
-
const { accessToken:
|
|
397
|
-
dateRanges: [{ startDate: s, endDate:
|
|
396
|
+
const { accessToken: a, propertyId: n } = await u(e), t = D(e), s = t.startDate || "30daysAgo", o = t.endDate || "today", r = await d(a, n, {
|
|
397
|
+
dateRanges: [{ startDate: s, endDate: o }],
|
|
398
398
|
dimensions: [{ name: "sessionSource" }],
|
|
399
399
|
dimensionFilter: {
|
|
400
400
|
filter: {
|
|
@@ -413,11 +413,11 @@ function x(w) {
|
|
|
413
413
|
});
|
|
414
414
|
return I(r, "sessionSource");
|
|
415
415
|
})
|
|
416
|
-
),
|
|
416
|
+
), g.get(
|
|
417
417
|
"/acquisition/campaigns",
|
|
418
418
|
y(async (e) => {
|
|
419
|
-
const { accessToken:
|
|
420
|
-
dateRanges: [{ startDate: s, endDate:
|
|
419
|
+
const { accessToken: a, propertyId: n } = await u(e), t = D(e), s = t.startDate || "30daysAgo", o = t.endDate || "today", r = await d(a, n, {
|
|
420
|
+
dateRanges: [{ startDate: s, endDate: o }],
|
|
421
421
|
dimensions: [{ name: "sessionCampaignName" }],
|
|
422
422
|
dimensionFilter: {
|
|
423
423
|
notExpression: {
|
|
@@ -438,11 +438,11 @@ function x(w) {
|
|
|
438
438
|
});
|
|
439
439
|
return I(r, "sessionCampaignName");
|
|
440
440
|
})
|
|
441
|
-
),
|
|
441
|
+
), g.get(
|
|
442
442
|
"/content/all-pages",
|
|
443
443
|
y(async (e) => {
|
|
444
|
-
const { accessToken:
|
|
445
|
-
dateRanges: [{ startDate: s, endDate:
|
|
444
|
+
const { accessToken: a, propertyId: n } = await u(e), t = D(e), s = t.startDate || "30daysAgo", o = t.endDate || "today", r = parseInt(t.limit || "50", 10), i = await d(a, n, {
|
|
445
|
+
dateRanges: [{ startDate: s, endDate: o }],
|
|
446
446
|
dimensions: [{ name: "pagePath" }],
|
|
447
447
|
metrics: [
|
|
448
448
|
{ name: "screenPageViews" },
|
|
@@ -458,11 +458,11 @@ function x(w) {
|
|
|
458
458
|
});
|
|
459
459
|
return I(i, "pagePath");
|
|
460
460
|
})
|
|
461
|
-
),
|
|
461
|
+
), g.get(
|
|
462
462
|
"/content/landing-pages",
|
|
463
463
|
y(async (e) => {
|
|
464
|
-
const { accessToken:
|
|
465
|
-
dateRanges: [{ startDate: s, endDate:
|
|
464
|
+
const { accessToken: a, propertyId: n } = await u(e), t = D(e), s = t.startDate || "30daysAgo", o = t.endDate || "today", r = await d(a, n, {
|
|
465
|
+
dateRanges: [{ startDate: s, endDate: o }],
|
|
466
466
|
dimensions: [{ name: "landingPagePlusQueryString" }],
|
|
467
467
|
metrics: [
|
|
468
468
|
{ name: "sessions" },
|
|
@@ -477,11 +477,11 @@ function x(w) {
|
|
|
477
477
|
});
|
|
478
478
|
return I(r, "landingPagePlusQueryString");
|
|
479
479
|
})
|
|
480
|
-
),
|
|
480
|
+
), g.get(
|
|
481
481
|
"/content/exit-pages",
|
|
482
482
|
y(async (e) => {
|
|
483
|
-
const { accessToken:
|
|
484
|
-
dateRanges: [{ startDate: s, endDate:
|
|
483
|
+
const { accessToken: a, propertyId: n } = await u(e), t = D(e), s = t.startDate || "30daysAgo", o = t.endDate || "today", r = await d(a, n, {
|
|
484
|
+
dateRanges: [{ startDate: s, endDate: o }],
|
|
485
485
|
dimensions: [{ name: "pagePath" }],
|
|
486
486
|
metrics: [
|
|
487
487
|
{ name: "sessions" },
|
|
@@ -492,53 +492,53 @@ function x(w) {
|
|
|
492
492
|
orderBys: [{ metric: { metricName: "screenPageViews" }, desc: !0 }],
|
|
493
493
|
limit: 20
|
|
494
494
|
}), i = I(r, "pagePath");
|
|
495
|
-
return i.rows = i.rows.map((
|
|
496
|
-
...
|
|
497
|
-
exitRate:
|
|
495
|
+
return i.rows = i.rows.map((l) => ({
|
|
496
|
+
...l,
|
|
497
|
+
exitRate: l.bounceRate || 0
|
|
498
498
|
})), i;
|
|
499
499
|
})
|
|
500
|
-
),
|
|
500
|
+
), g.get(
|
|
501
501
|
"/content/search-terms",
|
|
502
502
|
y(async (e) => {
|
|
503
|
-
const { accessToken:
|
|
503
|
+
const { accessToken: a, propertyId: n, siteUrl: t } = await u(e), s = D(e), o = s.startDate || "30daysAgo", r = s.endDate || "today";
|
|
504
504
|
if (t)
|
|
505
505
|
try {
|
|
506
|
-
const p = `${
|
|
506
|
+
const p = `${b}/sites/${encodeURIComponent(t)}/searchAnalytics/query`;
|
|
507
507
|
console.log("[GA Module] Attempting Search Console query for site:", t);
|
|
508
|
-
const
|
|
508
|
+
const h = await fetch(
|
|
509
509
|
p,
|
|
510
510
|
{
|
|
511
511
|
method: "POST",
|
|
512
512
|
headers: {
|
|
513
|
-
Authorization: `Bearer ${
|
|
513
|
+
Authorization: `Bearer ${a}`,
|
|
514
514
|
"Content-Type": "application/json"
|
|
515
515
|
},
|
|
516
516
|
body: JSON.stringify({
|
|
517
|
-
startDate: c(
|
|
517
|
+
startDate: c(o),
|
|
518
518
|
endDate: c(r),
|
|
519
519
|
dimensions: ["query"],
|
|
520
520
|
rowLimit: 30
|
|
521
521
|
})
|
|
522
522
|
}
|
|
523
523
|
);
|
|
524
|
-
if (
|
|
525
|
-
const
|
|
526
|
-
query:
|
|
527
|
-
clicks:
|
|
528
|
-
impressions:
|
|
529
|
-
ctr:
|
|
530
|
-
position:
|
|
524
|
+
if (h.ok) {
|
|
525
|
+
const S = ((await h.json()).rows || []).map((k) => ({
|
|
526
|
+
query: k.keys[0],
|
|
527
|
+
clicks: k.clicks,
|
|
528
|
+
impressions: k.impressions,
|
|
529
|
+
ctr: k.ctr,
|
|
530
|
+
position: k.position
|
|
531
531
|
}));
|
|
532
|
-
if (
|
|
533
|
-
return console.log(`[GA Module] Search Console returned ${
|
|
534
|
-
rows:
|
|
535
|
-
rowCount:
|
|
532
|
+
if (S.length > 0)
|
|
533
|
+
return console.log(`[GA Module] Search Console returned ${S.length} keyword rows`), {
|
|
534
|
+
rows: S,
|
|
535
|
+
rowCount: S.length,
|
|
536
536
|
source: "search_console"
|
|
537
537
|
};
|
|
538
538
|
console.log("[GA Module] Search Console returned 0 rows, falling through");
|
|
539
539
|
} else {
|
|
540
|
-
const C = await
|
|
541
|
-
console.error(`[GA Module] Search Console API error (${
|
|
540
|
+
const C = await h.text().catch(() => "");
|
|
541
|
+
console.error(`[GA Module] Search Console API error (${h.status}):`, C);
|
|
542
542
|
}
|
|
543
543
|
} catch (p) {
|
|
544
544
|
console.error("[GA Module] Search Console request failed:", p?.message || p);
|
|
@@ -546,8 +546,8 @@ function x(w) {
|
|
|
546
546
|
else
|
|
547
547
|
console.log("[GA Module] No siteUrl configured, skipping Search Console");
|
|
548
548
|
try {
|
|
549
|
-
const p = await d(
|
|
550
|
-
dateRanges: [{ startDate:
|
|
549
|
+
const p = await d(a, n, {
|
|
550
|
+
dateRanges: [{ startDate: o, endDate: r }],
|
|
551
551
|
dimensions: [{ name: "sessionGoogleAdsQuery" }],
|
|
552
552
|
metrics: [
|
|
553
553
|
{ name: "sessions" },
|
|
@@ -578,13 +578,13 @@ function x(w) {
|
|
|
578
578
|
},
|
|
579
579
|
orderBys: [{ metric: { metricName: "sessions" }, desc: !0 }],
|
|
580
580
|
limit: 30
|
|
581
|
-
}),
|
|
582
|
-
if (
|
|
583
|
-
return { ...
|
|
581
|
+
}), h = I(p, "sessionGoogleAdsQuery");
|
|
582
|
+
if (h.rows.length > 0)
|
|
583
|
+
return { ...h, source: "google_ads" };
|
|
584
584
|
} catch {
|
|
585
585
|
}
|
|
586
|
-
const i = await d(
|
|
587
|
-
dateRanges: [{ startDate:
|
|
586
|
+
const i = await d(a, n, {
|
|
587
|
+
dateRanges: [{ startDate: o, endDate: r }],
|
|
588
588
|
dimensions: [{ name: "landingPagePlusQueryString" }],
|
|
589
589
|
metrics: [
|
|
590
590
|
{ name: "sessions" },
|
|
@@ -619,11 +619,11 @@ function x(w) {
|
|
|
619
619
|
});
|
|
620
620
|
return { ...I(i, "landingPagePlusQueryString"), source: "organic_landing_pages" };
|
|
621
621
|
})
|
|
622
|
-
),
|
|
622
|
+
), g.get(
|
|
623
623
|
"/audience/overview",
|
|
624
624
|
y(async (e) => {
|
|
625
|
-
const { accessToken:
|
|
626
|
-
dateRanges: [{ startDate: s, endDate:
|
|
625
|
+
const { accessToken: a, propertyId: n } = await u(e), t = D(e), s = t.startDate || "30daysAgo", o = t.endDate || "today", r = await d(a, n, {
|
|
626
|
+
dateRanges: [{ startDate: s, endDate: o }],
|
|
627
627
|
dimensions: [{ name: "newVsReturning" }],
|
|
628
628
|
metrics: [
|
|
629
629
|
{ name: "totalUsers" },
|
|
@@ -636,12 +636,12 @@ function x(w) {
|
|
|
636
636
|
});
|
|
637
637
|
return I(r, "newVsReturning");
|
|
638
638
|
})
|
|
639
|
-
),
|
|
639
|
+
), g.get(
|
|
640
640
|
"/audience/technology",
|
|
641
641
|
y(async (e) => {
|
|
642
|
-
const { accessToken:
|
|
643
|
-
dateRanges: [{ startDate: s, endDate:
|
|
644
|
-
dimensions: [{ name:
|
|
642
|
+
const { accessToken: a, propertyId: n } = await u(e), t = D(e), s = t.startDate || "30daysAgo", o = t.endDate || "today", r = t.dimension || "browser", l = ["browser", "operatingSystem", "screenResolution"].includes(r) ? r : "browser", p = await d(a, n, {
|
|
643
|
+
dateRanges: [{ startDate: s, endDate: o }],
|
|
644
|
+
dimensions: [{ name: l }],
|
|
645
645
|
metrics: [
|
|
646
646
|
{ name: "totalUsers" },
|
|
647
647
|
{ name: "sessions" },
|
|
@@ -650,13 +650,13 @@ function x(w) {
|
|
|
650
650
|
orderBys: [{ metric: { metricName: "totalUsers" }, desc: !0 }],
|
|
651
651
|
limit: 10
|
|
652
652
|
});
|
|
653
|
-
return I(p,
|
|
653
|
+
return I(p, l);
|
|
654
654
|
})
|
|
655
|
-
),
|
|
655
|
+
), g.get(
|
|
656
656
|
"/audience/languages",
|
|
657
657
|
y(async (e) => {
|
|
658
|
-
const { accessToken:
|
|
659
|
-
dateRanges: [{ startDate: s, endDate:
|
|
658
|
+
const { accessToken: a, propertyId: n } = await u(e), t = D(e), s = t.startDate || "30daysAgo", o = t.endDate || "today", r = await d(a, n, {
|
|
659
|
+
dateRanges: [{ startDate: s, endDate: o }],
|
|
660
660
|
dimensions: [{ name: "language" }],
|
|
661
661
|
metrics: [
|
|
662
662
|
{ name: "totalUsers" },
|
|
@@ -667,11 +667,11 @@ function x(w) {
|
|
|
667
667
|
});
|
|
668
668
|
return I(r, "language");
|
|
669
669
|
})
|
|
670
|
-
),
|
|
670
|
+
), g.get(
|
|
671
671
|
"/audience/hours",
|
|
672
672
|
y(async (e) => {
|
|
673
|
-
const { accessToken:
|
|
674
|
-
dateRanges: [{ startDate: s, endDate:
|
|
673
|
+
const { accessToken: a, propertyId: n } = await u(e), t = D(e), s = t.startDate || "30daysAgo", o = t.endDate || "today", r = await d(a, n, {
|
|
674
|
+
dateRanges: [{ startDate: s, endDate: o }],
|
|
675
675
|
dimensions: [{ name: "dayOfWeekName" }, { name: "hour" }],
|
|
676
676
|
metrics: [{ name: "sessions" }],
|
|
677
677
|
orderBys: [
|
|
@@ -681,13 +681,13 @@ function x(w) {
|
|
|
681
681
|
limit: 168
|
|
682
682
|
// 7 days × 24 hours
|
|
683
683
|
});
|
|
684
|
-
return
|
|
684
|
+
return T(r, ["dayOfWeekName", "hour"]);
|
|
685
685
|
})
|
|
686
|
-
),
|
|
686
|
+
), g.get(
|
|
687
687
|
"/audience/cities",
|
|
688
688
|
y(async (e) => {
|
|
689
|
-
const { accessToken:
|
|
690
|
-
dateRanges: [{ startDate: s, endDate:
|
|
689
|
+
const { accessToken: a, propertyId: n } = await u(e), t = D(e), s = t.startDate || "30daysAgo", o = t.endDate || "today", r = await d(a, n, {
|
|
690
|
+
dateRanges: [{ startDate: s, endDate: o }],
|
|
691
691
|
dimensions: [{ name: "city" }, { name: "country" }],
|
|
692
692
|
metrics: [
|
|
693
693
|
{ name: "totalUsers" },
|
|
@@ -704,14 +704,14 @@ function x(w) {
|
|
|
704
704
|
orderBys: [{ metric: { metricName: "totalUsers" }, desc: !0 }],
|
|
705
705
|
limit: 20
|
|
706
706
|
});
|
|
707
|
-
return
|
|
707
|
+
return T(r, ["city", "country"]);
|
|
708
708
|
})
|
|
709
709
|
);
|
|
710
710
|
function c(e) {
|
|
711
|
-
const
|
|
712
|
-
if (
|
|
711
|
+
const a = e.match(/^(\d+)daysAgo$/);
|
|
712
|
+
if (a) {
|
|
713
713
|
const n = /* @__PURE__ */ new Date();
|
|
714
|
-
return n.setDate(n.getDate() - parseInt(
|
|
714
|
+
return n.setDate(n.getDate() - parseInt(a[1], 10)), n.toISOString().slice(0, 10);
|
|
715
715
|
}
|
|
716
716
|
if (e === "today") return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
717
717
|
if (e === "yesterday") {
|
|
@@ -720,8 +720,8 @@ function x(w) {
|
|
|
720
720
|
}
|
|
721
721
|
return e;
|
|
722
722
|
}
|
|
723
|
-
async function
|
|
724
|
-
const t = `${
|
|
723
|
+
async function m(e, a, n) {
|
|
724
|
+
const t = `${b}/sites/${encodeURIComponent(a)}/searchAnalytics/query`, s = await fetch(t, {
|
|
725
725
|
method: "POST",
|
|
726
726
|
headers: {
|
|
727
727
|
Authorization: `Bearer ${e}`,
|
|
@@ -730,69 +730,69 @@ function x(w) {
|
|
|
730
730
|
body: JSON.stringify(n)
|
|
731
731
|
});
|
|
732
732
|
if (!s.ok) {
|
|
733
|
-
const
|
|
734
|
-
throw
|
|
733
|
+
const o = await s.json().catch(() => ({}));
|
|
734
|
+
throw w({
|
|
735
735
|
statusCode: s.status,
|
|
736
|
-
statusMessage:
|
|
736
|
+
statusMessage: o?.error?.message || "Search Console API request failed"
|
|
737
737
|
});
|
|
738
738
|
}
|
|
739
739
|
return s.json();
|
|
740
740
|
}
|
|
741
|
-
return
|
|
741
|
+
return g.get(
|
|
742
742
|
"/seo/keywords",
|
|
743
743
|
y(async (e) => {
|
|
744
|
-
const { accessToken:
|
|
744
|
+
const { accessToken: a, siteUrl: n } = await u(e);
|
|
745
745
|
if (!n)
|
|
746
|
-
throw
|
|
747
|
-
const t =
|
|
746
|
+
throw w({ statusCode: 400, statusMessage: "Search Console Site URL is not configured. Add it in module settings." });
|
|
747
|
+
const t = D(e), s = c(t.startDate || "30daysAgo"), o = c(t.endDate || "today"), r = Math.min(parseInt(t.limit) || 50, 100), i = await m(a, n, {
|
|
748
748
|
startDate: s,
|
|
749
|
-
endDate:
|
|
749
|
+
endDate: o,
|
|
750
750
|
dimensions: ["query"],
|
|
751
751
|
rowLimit: r
|
|
752
752
|
});
|
|
753
753
|
return {
|
|
754
|
-
rows: (i.rows || []).map((
|
|
755
|
-
query:
|
|
756
|
-
clicks:
|
|
757
|
-
impressions:
|
|
758
|
-
ctr:
|
|
759
|
-
position:
|
|
754
|
+
rows: (i.rows || []).map((l) => ({
|
|
755
|
+
query: l.keys[0],
|
|
756
|
+
clicks: l.clicks,
|
|
757
|
+
impressions: l.impressions,
|
|
758
|
+
ctr: l.ctr,
|
|
759
|
+
position: l.position
|
|
760
760
|
})),
|
|
761
761
|
rowCount: i.rows?.length || 0
|
|
762
762
|
};
|
|
763
763
|
})
|
|
764
|
-
),
|
|
764
|
+
), g.get(
|
|
765
765
|
"/seo/pages",
|
|
766
766
|
y(async (e) => {
|
|
767
|
-
const { accessToken:
|
|
767
|
+
const { accessToken: a, siteUrl: n } = await u(e);
|
|
768
768
|
if (!n)
|
|
769
|
-
throw
|
|
770
|
-
const t =
|
|
769
|
+
throw w({ statusCode: 400, statusMessage: "Search Console Site URL is not configured." });
|
|
770
|
+
const t = D(e), s = c(t.startDate || "30daysAgo"), o = c(t.endDate || "today"), r = Math.min(parseInt(t.limit) || 50, 100), i = await m(a, n, {
|
|
771
771
|
startDate: s,
|
|
772
|
-
endDate:
|
|
772
|
+
endDate: o,
|
|
773
773
|
dimensions: ["page"],
|
|
774
774
|
rowLimit: r
|
|
775
775
|
});
|
|
776
776
|
return {
|
|
777
|
-
rows: (i.rows || []).map((
|
|
778
|
-
page:
|
|
779
|
-
clicks:
|
|
780
|
-
impressions:
|
|
781
|
-
ctr:
|
|
782
|
-
position:
|
|
777
|
+
rows: (i.rows || []).map((l) => ({
|
|
778
|
+
page: l.keys[0],
|
|
779
|
+
clicks: l.clicks,
|
|
780
|
+
impressions: l.impressions,
|
|
781
|
+
ctr: l.ctr,
|
|
782
|
+
position: l.position
|
|
783
783
|
})),
|
|
784
784
|
rowCount: i.rows?.length || 0
|
|
785
785
|
};
|
|
786
786
|
})
|
|
787
|
-
),
|
|
787
|
+
), g.get(
|
|
788
788
|
"/seo/trends",
|
|
789
789
|
y(async (e) => {
|
|
790
|
-
const { accessToken:
|
|
790
|
+
const { accessToken: a, siteUrl: n } = await u(e);
|
|
791
791
|
if (!n)
|
|
792
|
-
throw
|
|
793
|
-
const t =
|
|
792
|
+
throw w({ statusCode: 400, statusMessage: "Search Console Site URL is not configured." });
|
|
793
|
+
const t = D(e), s = c(t.startDate || "30daysAgo"), o = c(t.endDate || "today"), i = ((await m(a, n, {
|
|
794
794
|
startDate: s,
|
|
795
|
-
endDate:
|
|
795
|
+
endDate: o,
|
|
796
796
|
dimensions: ["date"],
|
|
797
797
|
rowLimit: 500
|
|
798
798
|
})).rows || []).map((p) => ({
|
|
@@ -801,24 +801,24 @@ function x(w) {
|
|
|
801
801
|
impressions: p.impressions,
|
|
802
802
|
ctr: p.ctr,
|
|
803
803
|
position: p.position
|
|
804
|
-
})).sort((p,
|
|
805
|
-
(p,
|
|
806
|
-
clicks: p.clicks +
|
|
807
|
-
impressions: p.impressions +
|
|
804
|
+
})).sort((p, h) => p.date.localeCompare(h.date)), l = i.reduce(
|
|
805
|
+
(p, h) => ({
|
|
806
|
+
clicks: p.clicks + h.clicks,
|
|
807
|
+
impressions: p.impressions + h.impressions
|
|
808
808
|
}),
|
|
809
809
|
{ clicks: 0, impressions: 0 }
|
|
810
810
|
);
|
|
811
|
-
return
|
|
811
|
+
return l.ctr = l.impressions > 0 ? l.clicks / l.impressions : 0, l.avgPosition = i.length > 0 ? i.reduce((p, h) => p + h.position, 0) / i.length : 0, { rows: i, totals: l, rowCount: i.length };
|
|
812
812
|
})
|
|
813
|
-
),
|
|
813
|
+
), g.get(
|
|
814
814
|
"/seo/query-pages",
|
|
815
815
|
y(async (e) => {
|
|
816
|
-
const { accessToken:
|
|
816
|
+
const { accessToken: a, siteUrl: n } = await u(e);
|
|
817
817
|
if (!n)
|
|
818
|
-
throw
|
|
819
|
-
const t =
|
|
818
|
+
throw w({ statusCode: 400, statusMessage: "Search Console Site URL is not configured." });
|
|
819
|
+
const t = D(e), s = c(t.startDate || "30daysAgo"), o = c(t.endDate || "today"), r = await m(a, n, {
|
|
820
820
|
startDate: s,
|
|
821
|
-
endDate:
|
|
821
|
+
endDate: o,
|
|
822
822
|
dimensions: ["query", "page"],
|
|
823
823
|
rowLimit: 100
|
|
824
824
|
});
|
|
@@ -834,65 +834,106 @@ function x(w) {
|
|
|
834
834
|
rowCount: r.rows?.length || 0
|
|
835
835
|
};
|
|
836
836
|
})
|
|
837
|
-
),
|
|
837
|
+
), g.handler;
|
|
838
838
|
}
|
|
839
|
-
function V(
|
|
840
|
-
const A = (
|
|
841
|
-
(
|
|
842
|
-
const
|
|
843
|
-
if (!
|
|
844
|
-
const i = { date: `${
|
|
845
|
-
A.forEach((
|
|
846
|
-
i[
|
|
839
|
+
function V(f, R = !0) {
|
|
840
|
+
const A = (f.metricHeaders || []).map((s) => s.name), u = (f.dimensionHeaders || []).map((s) => s.name).indexOf("date"), d = [];
|
|
841
|
+
(f.rows || []).forEach((s) => {
|
|
842
|
+
const o = u >= 0 ? s.dimensionValues[u]?.value : s.dimensionValues[0]?.value;
|
|
843
|
+
if (!o || o.length < 8) return;
|
|
844
|
+
const i = { date: `${o.slice(0, 4)}-${o.slice(4, 6)}-${o.slice(6, 8)}` };
|
|
845
|
+
A.forEach((l, p) => {
|
|
846
|
+
i[l] = parseFloat(s.metricValues[p]?.value || "0");
|
|
847
847
|
}), d.push(i);
|
|
848
848
|
});
|
|
849
|
-
const c = {},
|
|
850
|
-
|
|
851
|
-
c[s] = parseFloat(
|
|
852
|
-
}) :
|
|
853
|
-
c[s] = parseFloat(
|
|
849
|
+
const c = {}, m = {};
|
|
850
|
+
f.totals && f.totals.length >= 2 ? A.forEach((s, o) => {
|
|
851
|
+
c[s] = parseFloat(f.totals[0]?.metricValues?.[o]?.value || "0"), m[s] = parseFloat(f.totals[1]?.metricValues?.[o]?.value || "0");
|
|
852
|
+
}) : f.totals && f.totals.length === 1 && A.forEach((s, o) => {
|
|
853
|
+
c[s] = parseFloat(f.totals[0]?.metricValues?.[o]?.value || "0");
|
|
854
854
|
});
|
|
855
855
|
const e = {};
|
|
856
856
|
A.forEach((s) => {
|
|
857
|
-
const
|
|
858
|
-
r !== void 0 && r !== 0 ? e[s] = (
|
|
857
|
+
const o = c[s] || 0, r = m[s];
|
|
858
|
+
r !== void 0 && r !== 0 ? e[s] = (o - r) / r * 100 : e[s] = null;
|
|
859
859
|
});
|
|
860
|
-
const
|
|
860
|
+
const a = /* @__PURE__ */ new Map();
|
|
861
861
|
for (const s of d)
|
|
862
|
-
|
|
863
|
-
const n = Array.from(
|
|
862
|
+
a.has(s.date) || a.set(s.date, s);
|
|
863
|
+
const n = Array.from(a.values()).sort((s, o) => s.date.localeCompare(o.date)), t = R && f.totals && f.totals.length >= 2 ? n.slice(-Math.ceil(n.length / 2)) : n;
|
|
864
864
|
return {
|
|
865
865
|
rows: t,
|
|
866
866
|
totals: c,
|
|
867
|
-
previousTotals:
|
|
867
|
+
previousTotals: m,
|
|
868
868
|
changes: e,
|
|
869
869
|
rowCount: t.length
|
|
870
870
|
};
|
|
871
871
|
}
|
|
872
|
-
function I(
|
|
873
|
-
const A = (
|
|
872
|
+
function I(f, R) {
|
|
873
|
+
const A = (f.metricHeaders || []).map((u) => u.name), g = (f.rows || []).map((u) => {
|
|
874
874
|
const d = {
|
|
875
|
-
[
|
|
875
|
+
[R]: u.dimensionValues[0].value
|
|
876
876
|
};
|
|
877
|
-
return A.forEach((c,
|
|
878
|
-
d[c] = parseFloat(
|
|
877
|
+
return A.forEach((c, m) => {
|
|
878
|
+
d[c] = parseFloat(u.metricValues[m].value);
|
|
879
879
|
}), d;
|
|
880
880
|
});
|
|
881
|
-
return { rows:
|
|
881
|
+
return { rows: g, rowCount: f.rowCount || g.length };
|
|
882
882
|
}
|
|
883
|
-
function
|
|
884
|
-
const A = (
|
|
883
|
+
function T(f, R) {
|
|
884
|
+
const A = (f.metricHeaders || []).map((u) => u.name), g = (f.rows || []).map((u) => {
|
|
885
885
|
const d = {};
|
|
886
|
-
return
|
|
887
|
-
d[c] =
|
|
888
|
-
}), A.forEach((c,
|
|
889
|
-
d[c] = parseFloat(
|
|
886
|
+
return R.forEach((c, m) => {
|
|
887
|
+
d[c] = u.dimensionValues[m]?.value || "";
|
|
888
|
+
}), A.forEach((c, m) => {
|
|
889
|
+
d[c] = parseFloat(u.metricValues[m].value);
|
|
890
890
|
}), d;
|
|
891
891
|
});
|
|
892
|
-
return { rows:
|
|
892
|
+
return { rows: g, rowCount: f.rowCount || g.length };
|
|
893
|
+
}
|
|
894
|
+
function j(f) {
|
|
895
|
+
const { decrypt: R } = f, A = M();
|
|
896
|
+
async function g(u) {
|
|
897
|
+
const { supabase: d, instanceId: c } = u.context.module, { data: m, error: e } = await d.from("project_modules").select("config").eq("id", c).single();
|
|
898
|
+
if (e || !m?.config)
|
|
899
|
+
throw w({ statusCode: 500, statusMessage: "Failed to load module config." });
|
|
900
|
+
const a = m.config, n = a.githubIntegration, t = a.githubRepo, s = a.githubOwner;
|
|
901
|
+
if (!n || !t || !s)
|
|
902
|
+
throw w({ statusCode: 400, statusMessage: "No GitHub integration configured for this module." });
|
|
903
|
+
const { data: o, error: r } = await d.from("integrations").select("config").eq("id", n).single();
|
|
904
|
+
let i = o?.config;
|
|
905
|
+
if (r || !i) {
|
|
906
|
+
const { data: p, error: h } = await d.from("agency_integrations").select("config").eq("id", n).single();
|
|
907
|
+
if (h || !p?.config)
|
|
908
|
+
throw w({ statusCode: 500, statusMessage: "Failed to load Github credentials." });
|
|
909
|
+
i = p.config;
|
|
910
|
+
}
|
|
911
|
+
return { token: R(i.token), repo: t, owner: s };
|
|
912
|
+
}
|
|
913
|
+
return A.post(
|
|
914
|
+
"/github/deploy",
|
|
915
|
+
y(async (u) => {
|
|
916
|
+
try {
|
|
917
|
+
const { token: d, repo: c, owner: m } = await g(u);
|
|
918
|
+
await fetch(`https://api.github.com/repos/${m}/${c}/dispatches`, {
|
|
919
|
+
method: "POST",
|
|
920
|
+
headers: {
|
|
921
|
+
Authorization: `Bearer ${d}`,
|
|
922
|
+
Accept: "application/vnd.github+json"
|
|
923
|
+
},
|
|
924
|
+
body: JSON.stringify({
|
|
925
|
+
event_type: "deploy-site"
|
|
926
|
+
})
|
|
927
|
+
});
|
|
928
|
+
} catch (d) {
|
|
929
|
+
throw console.error("Error triggering GitHub deployment:", d), w({ statusCode: 500, statusMessage: "Failed to trigger deployment." });
|
|
930
|
+
}
|
|
931
|
+
})
|
|
932
|
+
), A.handler;
|
|
893
933
|
}
|
|
894
934
|
export {
|
|
895
935
|
G as appointments,
|
|
936
|
+
j as contentManager,
|
|
896
937
|
x as googleAnalytics,
|
|
897
|
-
|
|
938
|
+
O as products
|
|
898
939
|
};
|