@oneclick.dev/cms-core-modules 0.0.101 → 0.0.103
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/Acquisition-Br1Pfny3.js +1 -0
- package/dist/{Acquisition-BJXNY4ko.mjs → Acquisition-CPlZzUBo.mjs} +40 -40
- package/dist/AgendaOpeningHoursCard-B7ROIPWw.js +1 -0
- package/dist/AgendaOpeningHoursCard-Cp4wxUeK.mjs +172 -0
- package/dist/AppointmentListTable-DZJNmTMb.mjs +177 -0
- package/dist/AppointmentListTable-Dieu9US_.js +1 -0
- package/dist/Audience-BfkrmBuQ.js +1 -0
- package/dist/{Audience-CIzVtUvV.mjs → Audience-DTblSAiL.mjs} +89 -89
- package/dist/Content-BHr_rPVY.js +1 -0
- package/dist/{Content-CWhjurn_.mjs → Content-CYOZKvWK.mjs} +56 -56
- package/dist/{ContentEditor-Cjqgb64R.mjs → ContentEditor-B1nfKG_5.mjs} +706 -677
- package/dist/{ContentEditor-YgOS3kxS.js → ContentEditor-DdFU8piH.js} +15 -16
- package/dist/{Create-6uT9HWar.mjs → Create-BRBh0xjM.mjs} +2 -2
- package/dist/{Create-DuZ5nZrX.js → Create-qPeQxkdl.js} +1 -1
- package/dist/{DateFormatter-2B0R-DY4.mjs → DateFormatter-Bw-87W31.mjs} +212 -227
- package/dist/DateFormatter-CYAD4GBN.js +1 -0
- package/dist/{Detail-BZ-iE9vf.js → Detail-C857g62L.js} +1 -1
- package/dist/{Detail-CJVMJDP7.mjs → Detail-CujdFApD.mjs} +2 -2
- package/dist/EditLayout.vue_vue_type_script_setup_true_lang-DWMqQvHl.mjs +76 -0
- package/dist/EditLayout.vue_vue_type_script_setup_true_lang-kpjbVSXg.js +1 -0
- package/dist/{Entries-DkRhOt95.js → Entries-BaS6H6ak.js} +1 -1
- package/dist/{Entries-dLlCrXXe.mjs → Entries-C8UJkrVC.mjs} +1 -1
- package/dist/{Find-Bd1uLqSa.mjs → Find-B24ZEhYM.mjs} +1 -1
- package/dist/{NewReservationDialog.vue_vue_type_script_setup_true_lang-Bc946oSc.mjs → NewReservationDialog.vue_vue_type_script_setup_true_lang-9Q7TMm4u.mjs} +37 -37
- package/dist/{NewReservationDialog.vue_vue_type_script_setup_true_lang-CqERfyYb.js → NewReservationDialog.vue_vue_type_script_setup_true_lang-DiNzGl-q.js} +1 -1
- package/dist/{Overview-DoOASlNz.mjs → Overview-3HWhsqaz.mjs} +2 -2
- package/dist/Overview-BrCwozey.js +1 -0
- package/dist/{Overview-37nilXzE.js → Overview-CpHhuiaV.js} +1 -1
- package/dist/{Overview-DeQQ0FY3.js → Overview-DAxCu9XC.js} +1 -1
- package/dist/{Overview-C--dq51X.mjs → Overview-D_T3K6aq.mjs} +1 -1
- package/dist/{Overview-CGo4jaaA.mjs → Overview-kaMhsIUq.mjs} +21 -21
- package/dist/ReservationDetailDialog.vue_vue_type_script_setup_true_lang-Cz_22Oce.mjs +2927 -0
- package/dist/ReservationDetailDialog.vue_vue_type_script_setup_true_lang-DPPNc-Z5.js +349 -0
- package/dist/SeoHealth-09sEOu3G.js +1 -0
- package/dist/{SeoHealth-DVFDz3em.mjs → SeoHealth-BzcWd_w7.mjs} +29 -29
- package/dist/TableView-CPAw3h8g.js +4 -0
- package/dist/TableView-DXmEF6pY.mjs +6143 -0
- package/dist/agenda-BNG05SAq.js +1 -0
- package/dist/agenda-D1RxMxBS.mjs +1152 -0
- package/dist/availability-CMrRa5y2.mjs +269 -0
- package/dist/availability-Cf2YfMwM.js +1 -0
- package/dist/booking-data-DgJd0BcM.mjs +889 -0
- package/dist/booking-data-Di5GmH_8.js +1 -0
- package/dist/cms-core-modules.css +1 -1
- package/dist/{exceptions-Bp5BSvxO.js → exceptions-CI0B4xVj.js} +1 -1
- package/dist/{exceptions-C97cNZYl.mjs → exceptions-vo8SA5SE.mjs} +68 -68
- package/dist/index-BtujSJeg.js +35 -0
- package/dist/{index-CrGjxSwa.mjs → index-CrgzoTyR.mjs} +1 -1
- package/dist/{index-D2a6wEPh.js → index-DPd3waTN.js} +1 -1
- package/dist/{index-CABh6Qn6.mjs → index-DrXxXB2F.mjs} +15 -15
- package/dist/{index-B-lVEpFX.mjs → index-MYWjg0zi.mjs} +3 -3
- package/dist/index-dOdMm1pV.mjs +1105 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.mjs +201 -148
- package/dist/interpolation-DEDSLETn.mjs +128 -0
- package/dist/interpolation-DERg6Lwt.js +1 -0
- package/dist/orders-CzzcFQha.mjs +559 -0
- package/dist/orders-ETtbA4aQ.js +1 -0
- package/dist/{payment-Bosr0m3u.mjs → payment-C3ohkehF.mjs} +1 -1
- package/dist/{payment-DDnC03jb.js → payment-Dfr-Ro-a.js} +1 -1
- package/dist/{resources-BtF5RUUq.js → resources-CxeFd57z.js} +1 -1
- package/dist/{resources-B7qDBC91.mjs → resources-WI_4SO6T.mjs} +2 -2
- package/dist/server-handlers.cjs.js +1 -1
- package/dist/server-handlers.mjs +457 -387
- package/dist/src/appointments/chat-components/AgendaOpeningHoursCard.vue.d.ts +15 -0
- package/dist/src/appointments/components/edit/CustomerInformationFieldEditorDialog.vue.d.ts +17 -5
- package/dist/src/appointments/components/edit/EventDialog/BookingsList.vue.d.ts +8 -3
- package/dist/src/appointments/components/edit/EventDialog/EventDialog.vue.d.ts +1 -0
- package/dist/src/appointments/components/edit/EventDialog/ReservationDetailDialog.vue.d.ts +6 -3
- package/dist/src/appointments/components/edit/EventTimeline.vue.d.ts +3 -0
- package/dist/src/appointments/components/edit/EventView.vue.d.ts +6 -1
- package/dist/src/appointments/components/edit/MetadataSchemaEditorDialog.vue.d.ts +12 -0
- package/dist/src/appointments/components/edit/OrderMetadataDisplay.vue.d.ts +21 -0
- package/dist/src/appointments/components/edit/dashboard/BookingsList.vue.d.ts +8 -3
- package/dist/src/appointments/index.d.ts +53 -0
- package/dist/src/appointments/pages/edit/agenda.vue.d.ts +3 -1
- package/dist/src/appointments/pages/edit/availability.vue.d.ts +1 -26
- package/dist/src/appointments/pages/edit/booking-data.vue.d.ts +65 -0
- package/dist/src/appointments/pages/edit/orders.vue.d.ts +7 -3
- package/dist/src/appointments/tools.d.ts +52 -0
- package/dist/src/appointments/types.d.ts +12 -0
- package/dist/src/table/config.d.ts +200 -0
- package/dist/src/table/get_data_flow-DEFAULT.json.d.ts +129 -0
- package/dist/src/table/index.d.ts +200 -0
- package/dist/utils-CanmrIWO.mjs +47 -0
- package/dist/utils-Yd6F5mea.js +3 -0
- package/package.json +2 -2
- package/src/appointments/tools.ts +38 -0
- package/dist/Acquisition-DPScJD4t.js +0 -1
- package/dist/AppointmentListTable-CQ0WIXtj.js +0 -1
- package/dist/AppointmentListTable-aV_UJd6j.mjs +0 -159
- package/dist/Audience-Csw1QLmw.js +0 -1
- package/dist/Content-dYr7kYT0.js +0 -1
- package/dist/DateFormatter-DbtOLV0L.js +0 -1
- package/dist/EditLayout.vue_vue_type_script_setup_true_lang-DXa-Xxue.mjs +0 -74
- package/dist/EditLayout.vue_vue_type_script_setup_true_lang-ozYrxb2g.js +0 -1
- package/dist/Overview-DBu86Ikb.js +0 -1
- package/dist/ReservationDetailDialog.vue_vue_type_script_setup_true_lang-COfCOMsz.js +0 -349
- package/dist/ReservationDetailDialog.vue_vue_type_script_setup_true_lang-CYXkhhdp.mjs +0 -2383
- package/dist/SeoHealth-DzftZW1m.js +0 -1
- package/dist/TableView-CIJs118q.mjs +0 -5929
- package/dist/TableView-DzZYf34i.js +0 -4
- package/dist/agenda-DMT75Qfo.mjs +0 -1133
- package/dist/agenda-DxD4RMsy.js +0 -1
- package/dist/availability-B1D4Fyzi.mjs +0 -629
- package/dist/availability-DxrUcYbW.js +0 -1
- package/dist/index-BbqRTXuU.js +0 -35
- package/dist/index-D4GsbUId.mjs +0 -1091
- package/dist/interpolation-BBwG_ON6.mjs +0 -65
- package/dist/interpolation-CsOrww73.js +0 -1
- package/dist/orders-BRfXlWgV.mjs +0 -397
- package/dist/orders-CrCz1WTR.js +0 -1
- package/dist/regular-slots-Cc1jmKuC.mjs +0 -222
- package/dist/regular-slots-DBs1XVeN.js +0 -1
- package/dist/src/appointments/pages/edit/regular-slots.vue.d.ts +0 -2
- package/dist/utils-BVKy9S2J.mjs +0 -29
- package/dist/utils-D6CaKJbp.js +0 -2
package/dist/server-handlers.mjs
CHANGED
|
@@ -1,219 +1,289 @@
|
|
|
1
|
-
import { createRouter as v, defineEventHandler as
|
|
1
|
+
import { createRouter as v, defineEventHandler as w, createError as y, getRouterParam as q, getQuery as C } from "h3";
|
|
2
2
|
import "vue";
|
|
3
|
-
function $(
|
|
4
|
-
const { initFirebase:
|
|
5
|
-
async function m(
|
|
6
|
-
const { supabase:
|
|
7
|
-
if (
|
|
8
|
-
throw
|
|
9
|
-
const
|
|
3
|
+
function $(h) {
|
|
4
|
+
const { initFirebase: P, normalizeTimestamps: A } = h, g = v();
|
|
5
|
+
async function m(u) {
|
|
6
|
+
const { supabase: i, instanceId: d } = u.context.module, { data: e, error: o } = await i.from("project_modules").select("config").eq("id", d).single();
|
|
7
|
+
if (o || !e?.config)
|
|
8
|
+
throw y({ statusCode: 500, statusMessage: "Failed to load module config." });
|
|
9
|
+
const s = e.config, t = s.project, a = s.productCollection || "products";
|
|
10
10
|
if (!t)
|
|
11
|
-
throw
|
|
12
|
-
return { firebase: await
|
|
11
|
+
throw y({ statusCode: 400, statusMessage: "Products module has no Firebase integration configured." });
|
|
12
|
+
return { firebase: await P(u, t), collection: a };
|
|
13
13
|
}
|
|
14
|
-
return g.get("/products",
|
|
14
|
+
return g.get("/products", w(async (u) => {
|
|
15
15
|
try {
|
|
16
|
-
const { firebase:
|
|
17
|
-
return (await
|
|
18
|
-
id:
|
|
19
|
-
...
|
|
16
|
+
const { firebase: i, collection: d } = await m(u);
|
|
17
|
+
return (await i.firestore().collection(d).get()).docs.map((o) => A({
|
|
18
|
+
id: o.id,
|
|
19
|
+
...o.data()
|
|
20
20
|
}));
|
|
21
|
-
} catch (
|
|
22
|
-
throw console.error("Products handler — list error:",
|
|
23
|
-
statusCode:
|
|
24
|
-
statusMessage:
|
|
21
|
+
} catch (i) {
|
|
22
|
+
throw console.error("Products handler — list error:", i), y({
|
|
23
|
+
statusCode: i.statusCode || 500,
|
|
24
|
+
statusMessage: i.statusMessage || "Failed to list products"
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
|
-
})), g.get("/products/:productId",
|
|
28
|
-
const
|
|
29
|
-
if (!
|
|
30
|
-
throw
|
|
27
|
+
})), g.get("/products/:productId", w(async (u) => {
|
|
28
|
+
const i = q(u, "productId");
|
|
29
|
+
if (!i)
|
|
30
|
+
throw y({ statusCode: 400, statusMessage: "Product ID is required." });
|
|
31
31
|
try {
|
|
32
|
-
const { firebase:
|
|
33
|
-
if (!
|
|
34
|
-
throw
|
|
32
|
+
const { firebase: d, collection: e } = await m(u), o = await d.firestore().collection(e).doc(i).get();
|
|
33
|
+
if (!o.exists)
|
|
34
|
+
throw y({ statusCode: 404, statusMessage: "Product not found." });
|
|
35
35
|
return A({
|
|
36
|
-
id:
|
|
37
|
-
...
|
|
36
|
+
id: o.id,
|
|
37
|
+
...o.data()
|
|
38
38
|
});
|
|
39
|
-
} catch (
|
|
40
|
-
throw console.error("Products handler — get error:",
|
|
41
|
-
statusCode:
|
|
42
|
-
statusMessage:
|
|
39
|
+
} catch (d) {
|
|
40
|
+
throw console.error("Products handler — get error:", d), y({
|
|
41
|
+
statusCode: d.statusCode || 500,
|
|
42
|
+
statusMessage: d.statusMessage || "Failed to get product"
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
|
-
})), g.get("/empty-stock",
|
|
46
|
-
const
|
|
45
|
+
})), g.get("/empty-stock", w(async (u) => {
|
|
46
|
+
const d = C(u).category;
|
|
47
47
|
try {
|
|
48
|
-
const { firebase: e, collection:
|
|
49
|
-
let
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
id:
|
|
53
|
-
...
|
|
48
|
+
const { firebase: e, collection: o } = await m(u);
|
|
49
|
+
let s = e.firestore().collection(o).where("stock", "==", 0);
|
|
50
|
+
d && (s = s.where("collections", "array-contains", d));
|
|
51
|
+
const a = (await s.get()).docs.map((n) => A({
|
|
52
|
+
id: n.id,
|
|
53
|
+
...n.data()
|
|
54
54
|
}));
|
|
55
55
|
return {
|
|
56
|
-
count:
|
|
57
|
-
products:
|
|
58
|
-
id:
|
|
59
|
-
title:
|
|
60
|
-
slug:
|
|
61
|
-
stock:
|
|
62
|
-
price:
|
|
63
|
-
currency:
|
|
64
|
-
status:
|
|
56
|
+
count: a.length,
|
|
57
|
+
products: a.map((n) => ({
|
|
58
|
+
id: n.id,
|
|
59
|
+
title: n.title,
|
|
60
|
+
slug: n.slug,
|
|
61
|
+
stock: n.stock,
|
|
62
|
+
price: n.price,
|
|
63
|
+
currency: n.currency,
|
|
64
|
+
status: n.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), y({
|
|
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 x(
|
|
76
|
-
const { initFirebase:
|
|
77
|
-
async function m(
|
|
78
|
-
const { supabase:
|
|
79
|
-
if (
|
|
80
|
-
throw
|
|
81
|
-
const t =
|
|
82
|
-
if (!
|
|
83
|
-
throw
|
|
84
|
-
return { firebase: await
|
|
75
|
+
function x(h) {
|
|
76
|
+
const { initFirebase: P, normalizeTimestamps: A } = h, g = v();
|
|
77
|
+
async function m(i) {
|
|
78
|
+
const { supabase: d, instanceId: e } = i.context.module, { data: o, error: s } = await d.from("project_modules").select("config").eq("id", e).single();
|
|
79
|
+
if (s || !o?.config)
|
|
80
|
+
throw y({ statusCode: 500, statusMessage: "Failed to load module config." });
|
|
81
|
+
const t = o.config, a = t.project, n = t.reservationsCollection || "bookings_orders", r = t.agendaCollection || "agendas";
|
|
82
|
+
if (!a)
|
|
83
|
+
throw y({ statusCode: 400, statusMessage: "Appointments module has no Firebase integration configured." });
|
|
84
|
+
return { firebase: await P(i, a), reservationsCollection: n, agendaCollection: r };
|
|
85
85
|
}
|
|
86
|
-
function
|
|
87
|
-
return (
|
|
88
|
-
orderId:
|
|
86
|
+
function u(i) {
|
|
87
|
+
return (i.reservations || []).map((e) => ({
|
|
88
|
+
orderId: i.id,
|
|
89
89
|
reservationId: e.id,
|
|
90
|
-
customerInfo:
|
|
90
|
+
customerInfo: i.customerInfo,
|
|
91
91
|
date: e.date,
|
|
92
92
|
startTime: e.timeslot?.startTime,
|
|
93
93
|
endTime: e.timeslot?.endTime,
|
|
94
94
|
spots: e.spots,
|
|
95
|
-
status:
|
|
95
|
+
status: i.status,
|
|
96
96
|
reservationStatus: e.status,
|
|
97
97
|
resourceId: e.resourceId,
|
|
98
98
|
reservationPrice: e.totalPrice,
|
|
99
99
|
reservationBasePrice: e.basePrice,
|
|
100
100
|
reservationAddOnsPrice: e.addOnsPrice,
|
|
101
101
|
pricingOption: e.pricingOption,
|
|
102
|
-
amountDue:
|
|
103
|
-
amountPaid:
|
|
104
|
-
createdAt:
|
|
102
|
+
amountDue: i.amountDue,
|
|
103
|
+
amountPaid: i.amountPaid,
|
|
104
|
+
createdAt: i.createdAt,
|
|
105
|
+
metadata: i.metadata || {},
|
|
106
|
+
reservationMetadata: e.metadata || {}
|
|
105
107
|
}));
|
|
106
108
|
}
|
|
107
|
-
return g.get("/
|
|
108
|
-
const l = D(c), e = Math.min(Number(l.quantity) || 20, 100);
|
|
109
|
+
return g.get("/agendas", w(async (i) => {
|
|
109
110
|
try {
|
|
110
|
-
const { firebase:
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
const { firebase: d, agendaCollection: e } = await m(i), s = (await d.firestore().collection(e).get()).docs.map((t) => {
|
|
112
|
+
const a = t.data();
|
|
113
|
+
return {
|
|
114
|
+
id: t.id,
|
|
115
|
+
serviceName: a.serviceName || "",
|
|
116
|
+
type: a.type || "regular"
|
|
117
|
+
};
|
|
118
|
+
});
|
|
113
119
|
return {
|
|
114
120
|
count: s.length,
|
|
115
|
-
|
|
121
|
+
agendas: s
|
|
122
|
+
};
|
|
123
|
+
} catch (d) {
|
|
124
|
+
throw console.error("Appointments handler — list agendas error:", d), y({
|
|
125
|
+
statusCode: d.statusCode || 500,
|
|
126
|
+
statusMessage: d.statusMessage || "Failed to list agendas"
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
})), g.get("/agendas/:agendaId/opening-hours", w(async (i) => {
|
|
130
|
+
const d = q(i, "agendaId"), o = C(i).date;
|
|
131
|
+
if (!d)
|
|
132
|
+
throw y({ statusCode: 400, statusMessage: "Agenda ID is required." });
|
|
133
|
+
if (!o)
|
|
134
|
+
throw y({ statusCode: 400, statusMessage: "Date is required (YYYY-MM-DD)." });
|
|
135
|
+
try {
|
|
136
|
+
const { firebase: s, agendaCollection: t } = await m(i), a = await s.firestore().collection(t).doc(d).get();
|
|
137
|
+
if (!a.exists)
|
|
138
|
+
throw y({ statusCode: 404, statusMessage: "Agenda not found." });
|
|
139
|
+
const n = a.data(), r = (n.resources || []).filter((f) => f.isActive), c = n.exceptions || [], p = (/* @__PURE__ */ new Date(o + "T00:00:00")).getDay(), D = r.map((f) => {
|
|
140
|
+
const R = f.openingHours?.[p] || [], I = c.find((S) => {
|
|
141
|
+
const b = o >= S.startDate && o <= S.endDate, M = !S.resourceIds || S.resourceIds.length === 0 || S.resourceIds.includes(f.id);
|
|
142
|
+
return b && M;
|
|
143
|
+
});
|
|
144
|
+
return I ? {
|
|
145
|
+
resourceId: f.id,
|
|
146
|
+
resourceName: f.name,
|
|
147
|
+
date: o,
|
|
148
|
+
dayOfWeek: p,
|
|
149
|
+
isClosed: I.isClosed,
|
|
150
|
+
hours: I.isClosed ? [] : (I.timeslots || []).map((S) => ({
|
|
151
|
+
start: S.startTime,
|
|
152
|
+
end: S.endTime
|
|
153
|
+
})),
|
|
154
|
+
isException: !0
|
|
155
|
+
} : {
|
|
156
|
+
resourceId: f.id,
|
|
157
|
+
resourceName: f.name,
|
|
158
|
+
date: o,
|
|
159
|
+
dayOfWeek: p,
|
|
160
|
+
isClosed: R.length === 0,
|
|
161
|
+
hours: R,
|
|
162
|
+
isException: !1
|
|
163
|
+
};
|
|
164
|
+
});
|
|
165
|
+
return {
|
|
166
|
+
agendaId: d,
|
|
167
|
+
serviceName: n.serviceName || "",
|
|
168
|
+
date: o,
|
|
169
|
+
resources: D
|
|
170
|
+
};
|
|
171
|
+
} catch (s) {
|
|
172
|
+
throw console.error("Appointments handler — opening hours error:", s), y({
|
|
173
|
+
statusCode: s.statusCode || 500,
|
|
174
|
+
statusMessage: s.statusMessage || "Failed to get opening hours"
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
})), g.get("/appointments", w(async (i) => {
|
|
178
|
+
const d = C(i), e = Math.min(Number(d.quantity) || 20, 100), o = d.status || "confirmed";
|
|
179
|
+
try {
|
|
180
|
+
const { firebase: s, reservationsCollection: t } = await m(i), n = (await s.firestore().collection(t).orderBy("createdAt", "desc").where("status", "==", o).limit(e).get()).docs.flatMap(
|
|
181
|
+
(r) => u(A({ id: r.id, ...r.data() }))
|
|
182
|
+
);
|
|
183
|
+
return {
|
|
184
|
+
count: n.length,
|
|
185
|
+
appointments: n
|
|
116
186
|
};
|
|
117
|
-
} catch (
|
|
118
|
-
throw console.error("Appointments handler — list error:",
|
|
119
|
-
statusCode:
|
|
120
|
-
statusMessage:
|
|
187
|
+
} catch (s) {
|
|
188
|
+
throw console.error("Appointments handler — list error:", s), y({
|
|
189
|
+
statusCode: s.statusCode || 500,
|
|
190
|
+
statusMessage: s.statusMessage || "Failed to list appointments"
|
|
121
191
|
});
|
|
122
192
|
}
|
|
123
|
-
})), g.get("/appointments/find",
|
|
124
|
-
const
|
|
193
|
+
})), g.get("/appointments/find", w(async (i) => {
|
|
194
|
+
const d = C(i), e = (d.name || "").toLowerCase().trim(), o = (d.email || "").toLowerCase().trim(), s = d.date;
|
|
125
195
|
try {
|
|
126
|
-
const { firebase: t, reservationsCollection:
|
|
127
|
-
let
|
|
128
|
-
|
|
129
|
-
let
|
|
130
|
-
(
|
|
196
|
+
const { firebase: t, reservationsCollection: a } = await m(i);
|
|
197
|
+
let n = t.firestore().collection(a);
|
|
198
|
+
o && (n = n.where("customerInfo.email", "==", o));
|
|
199
|
+
let c = (await n.orderBy("createdAt", "desc").limit(200).get()).docs.flatMap(
|
|
200
|
+
(l) => u(A({ id: l.id, ...l.data() }))
|
|
131
201
|
);
|
|
132
|
-
return
|
|
133
|
-
const p = (
|
|
134
|
-
return p.includes(e) ||
|
|
202
|
+
return s && (c = c.filter((l) => l.date === s)), e && (c = c.filter((l) => {
|
|
203
|
+
const p = (l.customerInfo?.firstName || "").toLowerCase(), D = (l.customerInfo?.lastName || "").toLowerCase();
|
|
204
|
+
return p.includes(e) || D.includes(e) || `${p} ${D}`.includes(e);
|
|
135
205
|
})), {
|
|
136
|
-
count:
|
|
137
|
-
appointments:
|
|
206
|
+
count: c.length,
|
|
207
|
+
appointments: c
|
|
138
208
|
};
|
|
139
209
|
} catch (t) {
|
|
140
|
-
throw console.error("Appointments handler — find error:", t),
|
|
210
|
+
throw console.error("Appointments handler — find error:", t), y({
|
|
141
211
|
statusCode: t.statusCode || 500,
|
|
142
212
|
statusMessage: t.statusMessage || "Failed to find appointments"
|
|
143
213
|
});
|
|
144
214
|
}
|
|
145
|
-
})), g.get("/appointments/:appointmentId",
|
|
146
|
-
const
|
|
147
|
-
if (!
|
|
148
|
-
throw
|
|
215
|
+
})), g.get("/appointments/:appointmentId", w(async (i) => {
|
|
216
|
+
const d = q(i, "appointmentId");
|
|
217
|
+
if (!d)
|
|
218
|
+
throw y({ statusCode: 400, statusMessage: "Appointment ID is required." });
|
|
149
219
|
try {
|
|
150
|
-
const { firebase: e, reservationsCollection:
|
|
151
|
-
if (!
|
|
152
|
-
throw
|
|
153
|
-
const t = A({ id:
|
|
220
|
+
const { firebase: e, reservationsCollection: o } = await m(i), s = await e.firestore().collection(o).doc(d).get();
|
|
221
|
+
if (!s.exists)
|
|
222
|
+
throw y({ statusCode: 404, statusMessage: "Appointment not found." });
|
|
223
|
+
const t = A({ id: s.id, ...s.data() });
|
|
154
224
|
return {
|
|
155
225
|
...t,
|
|
156
|
-
reservations:
|
|
226
|
+
reservations: u(t)
|
|
157
227
|
};
|
|
158
228
|
} catch (e) {
|
|
159
|
-
throw console.error("Appointments handler — get error:", e),
|
|
229
|
+
throw console.error("Appointments handler — get error:", e), y({
|
|
160
230
|
statusCode: e.statusCode || 500,
|
|
161
231
|
statusMessage: e.statusMessage || "Failed to get appointment"
|
|
162
232
|
});
|
|
163
233
|
}
|
|
164
234
|
})), g.handler;
|
|
165
235
|
}
|
|
166
|
-
const
|
|
236
|
+
const T = "https://analyticsdata.googleapis.com/v1beta", V = [
|
|
167
237
|
"https://www.googleapis.com/auth/analytics.readonly",
|
|
168
238
|
"https://www.googleapis.com/auth/webmasters.readonly"
|
|
169
|
-
],
|
|
170
|
-
function G(
|
|
171
|
-
const { decrypt:
|
|
239
|
+
], N = "https://searchconsole.googleapis.com/webmasters/v3";
|
|
240
|
+
function G(h) {
|
|
241
|
+
const { decrypt: P, getGoogleAccessToken: A } = h, g = v();
|
|
172
242
|
async function m(e) {
|
|
173
|
-
const { supabase:
|
|
174
|
-
if (
|
|
175
|
-
throw
|
|
176
|
-
const
|
|
177
|
-
if (!
|
|
178
|
-
throw
|
|
243
|
+
const { supabase: o, instanceId: s } = e.context.module, { data: t, error: a } = await o.from("project_modules").select("config").eq("id", s).single();
|
|
244
|
+
if (a || !t?.config)
|
|
245
|
+
throw y({ statusCode: 500, statusMessage: "Failed to load module config." });
|
|
246
|
+
const n = t.config, r = n.propertyId, c = n.serviceAccount, l = n.siteUrl || "";
|
|
247
|
+
if (!c)
|
|
248
|
+
throw y({ statusCode: 400, statusMessage: "No Google Service Account configured for this module." });
|
|
179
249
|
if (!r)
|
|
180
|
-
throw
|
|
181
|
-
const { data: p, error:
|
|
182
|
-
let
|
|
183
|
-
if (
|
|
184
|
-
const { data:
|
|
185
|
-
if (
|
|
186
|
-
throw
|
|
187
|
-
|
|
250
|
+
throw y({ statusCode: 400, statusMessage: "No GA4 Property ID configured for this module." });
|
|
251
|
+
const { data: p, error: D } = await o.from("integrations").select("config").eq("id", c).single();
|
|
252
|
+
let f = p?.config;
|
|
253
|
+
if (D || !f) {
|
|
254
|
+
const { data: M, error: F } = await o.from("agency_integrations").select("config").eq("id", c).single();
|
|
255
|
+
if (F || !M?.config)
|
|
256
|
+
throw y({ statusCode: 500, statusMessage: "Failed to load Google Service Account credentials." });
|
|
257
|
+
f = M.config;
|
|
188
258
|
}
|
|
189
|
-
const
|
|
259
|
+
const R = P(f.clientEmail), I = P(f.privateKey), S = P(f.projectId);
|
|
190
260
|
return { accessToken: await A(
|
|
191
|
-
{ clientEmail:
|
|
192
|
-
|
|
193
|
-
), propertyId: r, siteUrl:
|
|
261
|
+
{ clientEmail: R, privateKey: I, projectId: S },
|
|
262
|
+
V
|
|
263
|
+
), propertyId: r, siteUrl: l };
|
|
194
264
|
}
|
|
195
|
-
async function
|
|
196
|
-
const t = await fetch(`${
|
|
265
|
+
async function u(e, o, s) {
|
|
266
|
+
const t = await fetch(`${T}/properties/${o}:runReport`, {
|
|
197
267
|
method: "POST",
|
|
198
268
|
headers: {
|
|
199
269
|
Authorization: `Bearer ${e}`,
|
|
200
270
|
"Content-Type": "application/json"
|
|
201
271
|
},
|
|
202
|
-
body: JSON.stringify(
|
|
272
|
+
body: JSON.stringify(s)
|
|
203
273
|
});
|
|
204
274
|
if (!t.ok) {
|
|
205
|
-
const
|
|
206
|
-
throw console.error("GA4 runReport failed:",
|
|
275
|
+
const a = await t.json().catch(() => ({}));
|
|
276
|
+
throw console.error("GA4 runReport failed:", a), y({
|
|
207
277
|
statusCode: t.status,
|
|
208
|
-
statusMessage:
|
|
278
|
+
statusMessage: a?.error?.message || "GA4 API request failed"
|
|
209
279
|
});
|
|
210
280
|
}
|
|
211
281
|
return t.json();
|
|
212
282
|
}
|
|
213
283
|
g.get(
|
|
214
284
|
"/report",
|
|
215
|
-
|
|
216
|
-
const { accessToken:
|
|
285
|
+
w(async (e) => {
|
|
286
|
+
const { accessToken: o, propertyId: s } = await m(e), t = C(e), a = t.startDate || "30daysAgo", n = t.endDate || "today", r = a.match(/^(\d+)daysAgo$/), c = r ? parseInt(r[1], 10) : 30, l = `${c * 2}daysAgo`, p = `${c + 1}daysAgo`, D = [
|
|
217
287
|
{ name: "sessions" },
|
|
218
288
|
{ name: "totalUsers" },
|
|
219
289
|
{ name: "screenPageViews" },
|
|
@@ -224,38 +294,38 @@ function G(f) {
|
|
|
224
294
|
{ name: "sessionsPerUser" },
|
|
225
295
|
{ name: "screenPageViewsPerSession" }
|
|
226
296
|
];
|
|
227
|
-
let
|
|
297
|
+
let f, R = !0;
|
|
228
298
|
try {
|
|
229
|
-
|
|
299
|
+
f = await u(o, s, {
|
|
230
300
|
dateRanges: [
|
|
231
|
-
{ startDate:
|
|
232
|
-
{ startDate:
|
|
301
|
+
{ startDate: a, endDate: n, name: "current" },
|
|
302
|
+
{ startDate: l, endDate: p, name: "previous" }
|
|
233
303
|
],
|
|
234
304
|
dimensions: [{ name: "date" }],
|
|
235
|
-
metrics:
|
|
305
|
+
metrics: D,
|
|
236
306
|
metricAggregations: ["TOTAL"],
|
|
237
307
|
orderBys: [{ dimension: { dimensionName: "date" } }]
|
|
238
308
|
});
|
|
239
309
|
} catch {
|
|
240
|
-
|
|
241
|
-
dateRanges: [{ startDate:
|
|
310
|
+
R = !1, f = await u(o, s, {
|
|
311
|
+
dateRanges: [{ startDate: a, endDate: n }],
|
|
242
312
|
dimensions: [{ name: "date" }],
|
|
243
|
-
metrics:
|
|
313
|
+
metrics: D,
|
|
244
314
|
metricAggregations: ["TOTAL"],
|
|
245
315
|
orderBys: [{ dimension: { dimensionName: "date" } }]
|
|
246
316
|
});
|
|
247
317
|
}
|
|
248
|
-
return
|
|
318
|
+
return E(f, R);
|
|
249
319
|
})
|
|
250
320
|
), g.get(
|
|
251
321
|
"/realtime",
|
|
252
|
-
|
|
253
|
-
const { accessToken:
|
|
254
|
-
`${
|
|
322
|
+
w(async (e) => {
|
|
323
|
+
const { accessToken: o, propertyId: s } = await m(e), t = await fetch(
|
|
324
|
+
`${T}/properties/${s}:runRealtimeReport`,
|
|
255
325
|
{
|
|
256
326
|
method: "POST",
|
|
257
327
|
headers: {
|
|
258
|
-
Authorization: `Bearer ${
|
|
328
|
+
Authorization: `Bearer ${o}`,
|
|
259
329
|
"Content-Type": "application/json"
|
|
260
330
|
},
|
|
261
331
|
body: JSON.stringify({
|
|
@@ -267,23 +337,23 @@ function G(f) {
|
|
|
267
337
|
}
|
|
268
338
|
);
|
|
269
339
|
if (!t.ok) {
|
|
270
|
-
const
|
|
271
|
-
throw
|
|
340
|
+
const c = await t.json().catch(() => ({}));
|
|
341
|
+
throw y({ statusCode: t.status, statusMessage: c?.error?.message || "Realtime API failed" });
|
|
272
342
|
}
|
|
273
|
-
const
|
|
274
|
-
(
|
|
343
|
+
const a = await t.json(), n = (a?.rows || []).reduce(
|
|
344
|
+
(c, l) => c + parseInt(l.metricValues?.[0]?.value || "0", 10),
|
|
275
345
|
0
|
|
276
|
-
), r = (
|
|
277
|
-
page:
|
|
278
|
-
activeUsers: parseInt(
|
|
346
|
+
), r = (a?.rows || []).map((c) => ({
|
|
347
|
+
page: c.dimensionValues?.[0]?.value || "(not set)",
|
|
348
|
+
activeUsers: parseInt(c.metricValues?.[0]?.value || "0", 10)
|
|
279
349
|
}));
|
|
280
|
-
return { activeUsers:
|
|
350
|
+
return { activeUsers: n, activePages: r };
|
|
281
351
|
})
|
|
282
352
|
), g.get(
|
|
283
353
|
"/top-pages",
|
|
284
|
-
|
|
285
|
-
const { accessToken:
|
|
286
|
-
dateRanges: [{ startDate:
|
|
354
|
+
w(async (e) => {
|
|
355
|
+
const { accessToken: o, propertyId: s } = await m(e), t = C(e), a = t.startDate || "30daysAgo", n = t.endDate || "today", r = parseInt(t.limit || "10", 10), c = await u(o, s, {
|
|
356
|
+
dateRanges: [{ startDate: a, endDate: n }],
|
|
287
357
|
dimensions: [{ name: "pagePath" }],
|
|
288
358
|
metrics: [
|
|
289
359
|
{ name: "screenPageViews" },
|
|
@@ -293,23 +363,23 @@ function G(f) {
|
|
|
293
363
|
orderBys: [{ metric: { metricName: "screenPageViews" }, desc: !0 }],
|
|
294
364
|
limit: r * 2
|
|
295
365
|
// fetch extra to account for duplicates before aggregation
|
|
296
|
-
}),
|
|
297
|
-
for (const
|
|
298
|
-
const
|
|
299
|
-
if (
|
|
300
|
-
|
|
301
|
-
const S =
|
|
302
|
-
S > 0 && (
|
|
366
|
+
}), l = k(c, "pagePath"), p = /* @__PURE__ */ new Map();
|
|
367
|
+
for (const f of l.rows) {
|
|
368
|
+
const R = f.pagePath.toLowerCase().replace(/\/+$/, ""), I = p.get(R);
|
|
369
|
+
if (I) {
|
|
370
|
+
I.screenPageViews += f.screenPageViews || 0, I.totalUsers += f.totalUsers || 0;
|
|
371
|
+
const S = I.screenPageViews;
|
|
372
|
+
S > 0 && (I.averageSessionDuration = (I.averageSessionDuration * (S - (f.screenPageViews || 0)) + (f.averageSessionDuration || 0) * (f.screenPageViews || 0)) / S);
|
|
303
373
|
} else
|
|
304
|
-
p.set(
|
|
374
|
+
p.set(R, { ...f });
|
|
305
375
|
}
|
|
306
|
-
return { rows: [...p.values()].sort((
|
|
376
|
+
return { rows: [...p.values()].sort((f, R) => (R.screenPageViews || 0) - (f.screenPageViews || 0)).slice(0, r), rowCount: l.rowCount };
|
|
307
377
|
})
|
|
308
378
|
), g.get(
|
|
309
379
|
"/top-sources",
|
|
310
|
-
|
|
311
|
-
const { accessToken:
|
|
312
|
-
dateRanges: [{ startDate:
|
|
380
|
+
w(async (e) => {
|
|
381
|
+
const { accessToken: o, propertyId: s } = await m(e), t = C(e), a = t.startDate || "30daysAgo", n = t.endDate || "today", r = await u(o, s, {
|
|
382
|
+
dateRanges: [{ startDate: a, endDate: n }],
|
|
313
383
|
dimensions: [{ name: "sessionSource" }],
|
|
314
384
|
metrics: [
|
|
315
385
|
{ name: "sessions" },
|
|
@@ -318,13 +388,13 @@ function G(f) {
|
|
|
318
388
|
orderBys: [{ metric: { metricName: "sessions" }, desc: !0 }],
|
|
319
389
|
limit: 10
|
|
320
390
|
});
|
|
321
|
-
return
|
|
391
|
+
return k(r, "sessionSource");
|
|
322
392
|
})
|
|
323
393
|
), g.get(
|
|
324
394
|
"/devices",
|
|
325
|
-
|
|
326
|
-
const { accessToken:
|
|
327
|
-
dateRanges: [{ startDate:
|
|
395
|
+
w(async (e) => {
|
|
396
|
+
const { accessToken: o, propertyId: s } = await m(e), t = C(e), a = t.startDate || "30daysAgo", n = t.endDate || "today", r = await u(o, s, {
|
|
397
|
+
dateRanges: [{ startDate: a, endDate: n }],
|
|
328
398
|
dimensions: [{ name: "deviceCategory" }],
|
|
329
399
|
metrics: [
|
|
330
400
|
{ name: "sessions" },
|
|
@@ -332,13 +402,13 @@ function G(f) {
|
|
|
332
402
|
],
|
|
333
403
|
orderBys: [{ metric: { metricName: "sessions" }, desc: !0 }]
|
|
334
404
|
});
|
|
335
|
-
return
|
|
405
|
+
return k(r, "deviceCategory");
|
|
336
406
|
})
|
|
337
407
|
), g.get(
|
|
338
408
|
"/countries",
|
|
339
|
-
|
|
340
|
-
const { accessToken:
|
|
341
|
-
dateRanges: [{ startDate:
|
|
409
|
+
w(async (e) => {
|
|
410
|
+
const { accessToken: o, propertyId: s } = await m(e), t = C(e), a = t.startDate || "30daysAgo", n = t.endDate || "today", r = await u(o, s, {
|
|
411
|
+
dateRanges: [{ startDate: a, endDate: n }],
|
|
342
412
|
dimensions: [{ name: "country" }],
|
|
343
413
|
metrics: [
|
|
344
414
|
{ name: "sessions" },
|
|
@@ -347,13 +417,13 @@ function G(f) {
|
|
|
347
417
|
orderBys: [{ metric: { metricName: "sessions" }, desc: !0 }],
|
|
348
418
|
limit: 10
|
|
349
419
|
});
|
|
350
|
-
return
|
|
420
|
+
return k(r, "country");
|
|
351
421
|
})
|
|
352
422
|
), g.get(
|
|
353
423
|
"/acquisition/channels",
|
|
354
|
-
|
|
355
|
-
const { accessToken:
|
|
356
|
-
dateRanges: [{ startDate:
|
|
424
|
+
w(async (e) => {
|
|
425
|
+
const { accessToken: o, propertyId: s } = await m(e), t = C(e), a = t.startDate || "30daysAgo", n = t.endDate || "today", r = await u(o, s, {
|
|
426
|
+
dateRanges: [{ startDate: a, endDate: n }],
|
|
357
427
|
dimensions: [{ name: "sessionDefaultChannelGroup" }],
|
|
358
428
|
metrics: [
|
|
359
429
|
{ name: "sessions" },
|
|
@@ -367,13 +437,13 @@ function G(f) {
|
|
|
367
437
|
orderBys: [{ metric: { metricName: "sessions" }, desc: !0 }],
|
|
368
438
|
limit: 15
|
|
369
439
|
});
|
|
370
|
-
return
|
|
440
|
+
return k(r, "sessionDefaultChannelGroup");
|
|
371
441
|
})
|
|
372
442
|
), g.get(
|
|
373
443
|
"/acquisition/source-medium",
|
|
374
|
-
|
|
375
|
-
const { accessToken:
|
|
376
|
-
dateRanges: [{ startDate:
|
|
444
|
+
w(async (e) => {
|
|
445
|
+
const { accessToken: o, propertyId: s } = await m(e), t = C(e), a = t.startDate || "30daysAgo", n = t.endDate || "today", r = await u(o, s, {
|
|
446
|
+
dateRanges: [{ startDate: a, endDate: n }],
|
|
377
447
|
dimensions: [{ name: "sessionSourceMedium" }],
|
|
378
448
|
metrics: [
|
|
379
449
|
{ name: "sessions" },
|
|
@@ -386,13 +456,13 @@ function G(f) {
|
|
|
386
456
|
orderBys: [{ metric: { metricName: "sessions" }, desc: !0 }],
|
|
387
457
|
limit: 20
|
|
388
458
|
});
|
|
389
|
-
return
|
|
459
|
+
return k(r, "sessionSourceMedium");
|
|
390
460
|
})
|
|
391
461
|
), g.get(
|
|
392
462
|
"/acquisition/referrals",
|
|
393
|
-
|
|
394
|
-
const { accessToken:
|
|
395
|
-
dateRanges: [{ startDate:
|
|
463
|
+
w(async (e) => {
|
|
464
|
+
const { accessToken: o, propertyId: s } = await m(e), t = C(e), a = t.startDate || "30daysAgo", n = t.endDate || "today", r = await u(o, s, {
|
|
465
|
+
dateRanges: [{ startDate: a, endDate: n }],
|
|
396
466
|
dimensions: [{ name: "sessionSource" }],
|
|
397
467
|
dimensionFilter: {
|
|
398
468
|
filter: {
|
|
@@ -409,13 +479,13 @@ function G(f) {
|
|
|
409
479
|
orderBys: [{ metric: { metricName: "sessions" }, desc: !0 }],
|
|
410
480
|
limit: 20
|
|
411
481
|
});
|
|
412
|
-
return
|
|
482
|
+
return k(r, "sessionSource");
|
|
413
483
|
})
|
|
414
484
|
), g.get(
|
|
415
485
|
"/acquisition/campaigns",
|
|
416
|
-
|
|
417
|
-
const { accessToken:
|
|
418
|
-
dateRanges: [{ startDate:
|
|
486
|
+
w(async (e) => {
|
|
487
|
+
const { accessToken: o, propertyId: s } = await m(e), t = C(e), a = t.startDate || "30daysAgo", n = t.endDate || "today", r = await u(o, s, {
|
|
488
|
+
dateRanges: [{ startDate: a, endDate: n }],
|
|
419
489
|
dimensions: [{ name: "sessionCampaignName" }],
|
|
420
490
|
dimensionFilter: {
|
|
421
491
|
notExpression: {
|
|
@@ -434,13 +504,13 @@ function G(f) {
|
|
|
434
504
|
orderBys: [{ metric: { metricName: "sessions" }, desc: !0 }],
|
|
435
505
|
limit: 20
|
|
436
506
|
});
|
|
437
|
-
return
|
|
507
|
+
return k(r, "sessionCampaignName");
|
|
438
508
|
})
|
|
439
509
|
), g.get(
|
|
440
510
|
"/content/all-pages",
|
|
441
|
-
|
|
442
|
-
const { accessToken:
|
|
443
|
-
dateRanges: [{ startDate:
|
|
511
|
+
w(async (e) => {
|
|
512
|
+
const { accessToken: o, propertyId: s } = await m(e), t = C(e), a = t.startDate || "30daysAgo", n = t.endDate || "today", r = parseInt(t.limit || "50", 10), c = await u(o, s, {
|
|
513
|
+
dateRanges: [{ startDate: a, endDate: n }],
|
|
444
514
|
dimensions: [{ name: "pagePath" }],
|
|
445
515
|
metrics: [
|
|
446
516
|
{ name: "screenPageViews" },
|
|
@@ -454,13 +524,13 @@ function G(f) {
|
|
|
454
524
|
orderBys: [{ metric: { metricName: "screenPageViews" }, desc: !0 }],
|
|
455
525
|
limit: r
|
|
456
526
|
});
|
|
457
|
-
return
|
|
527
|
+
return k(c, "pagePath");
|
|
458
528
|
})
|
|
459
529
|
), g.get(
|
|
460
530
|
"/content/landing-pages",
|
|
461
|
-
|
|
462
|
-
const { accessToken:
|
|
463
|
-
dateRanges: [{ startDate:
|
|
531
|
+
w(async (e) => {
|
|
532
|
+
const { accessToken: o, propertyId: s } = await m(e), t = C(e), a = t.startDate || "30daysAgo", n = t.endDate || "today", r = await u(o, s, {
|
|
533
|
+
dateRanges: [{ startDate: a, endDate: n }],
|
|
464
534
|
dimensions: [{ name: "landingPagePlusQueryString" }],
|
|
465
535
|
metrics: [
|
|
466
536
|
{ name: "sessions" },
|
|
@@ -473,13 +543,13 @@ function G(f) {
|
|
|
473
543
|
orderBys: [{ metric: { metricName: "sessions" }, desc: !0 }],
|
|
474
544
|
limit: 30
|
|
475
545
|
});
|
|
476
|
-
return
|
|
546
|
+
return k(r, "landingPagePlusQueryString");
|
|
477
547
|
})
|
|
478
548
|
), g.get(
|
|
479
549
|
"/content/exit-pages",
|
|
480
|
-
|
|
481
|
-
const { accessToken:
|
|
482
|
-
dateRanges: [{ startDate:
|
|
550
|
+
w(async (e) => {
|
|
551
|
+
const { accessToken: o, propertyId: s } = await m(e), t = C(e), a = t.startDate || "30daysAgo", n = t.endDate || "today", r = await u(o, s, {
|
|
552
|
+
dateRanges: [{ startDate: a, endDate: n }],
|
|
483
553
|
dimensions: [{ name: "pagePath" }],
|
|
484
554
|
metrics: [
|
|
485
555
|
{ name: "sessions" },
|
|
@@ -489,51 +559,51 @@ function G(f) {
|
|
|
489
559
|
],
|
|
490
560
|
orderBys: [{ metric: { metricName: "screenPageViews" }, desc: !0 }],
|
|
491
561
|
limit: 20
|
|
492
|
-
}),
|
|
493
|
-
return
|
|
494
|
-
...
|
|
495
|
-
exitRate:
|
|
496
|
-
})),
|
|
562
|
+
}), c = k(r, "pagePath");
|
|
563
|
+
return c.rows = c.rows.map((l) => ({
|
|
564
|
+
...l,
|
|
565
|
+
exitRate: l.bounceRate || 0
|
|
566
|
+
})), c;
|
|
497
567
|
})
|
|
498
568
|
), g.get(
|
|
499
569
|
"/content/search-terms",
|
|
500
|
-
|
|
501
|
-
const { accessToken:
|
|
570
|
+
w(async (e) => {
|
|
571
|
+
const { accessToken: o, propertyId: s, siteUrl: t } = await m(e), a = C(e), n = a.startDate || "30daysAgo", r = a.endDate || "today";
|
|
502
572
|
if (t)
|
|
503
573
|
try {
|
|
504
|
-
const p = `${
|
|
574
|
+
const p = `${N}/sites/${encodeURIComponent(t)}/searchAnalytics/query`, D = await fetch(
|
|
505
575
|
p,
|
|
506
576
|
{
|
|
507
577
|
method: "POST",
|
|
508
578
|
headers: {
|
|
509
|
-
Authorization: `Bearer ${
|
|
579
|
+
Authorization: `Bearer ${o}`,
|
|
510
580
|
"Content-Type": "application/json"
|
|
511
581
|
},
|
|
512
582
|
body: JSON.stringify({
|
|
513
|
-
startDate:
|
|
514
|
-
endDate:
|
|
583
|
+
startDate: i(n),
|
|
584
|
+
endDate: i(r),
|
|
515
585
|
dimensions: ["query"],
|
|
516
586
|
rowLimit: 30
|
|
517
587
|
})
|
|
518
588
|
}
|
|
519
589
|
);
|
|
520
|
-
if (
|
|
521
|
-
const
|
|
522
|
-
query:
|
|
523
|
-
clicks:
|
|
524
|
-
impressions:
|
|
525
|
-
ctr:
|
|
526
|
-
position:
|
|
590
|
+
if (D.ok) {
|
|
591
|
+
const R = ((await D.json()).rows || []).map((I) => ({
|
|
592
|
+
query: I.keys[0],
|
|
593
|
+
clicks: I.clicks,
|
|
594
|
+
impressions: I.impressions,
|
|
595
|
+
ctr: I.ctr,
|
|
596
|
+
position: I.position
|
|
527
597
|
}));
|
|
528
|
-
if (
|
|
598
|
+
if (R.length > 0)
|
|
529
599
|
return {
|
|
530
|
-
rows:
|
|
531
|
-
rowCount:
|
|
600
|
+
rows: R,
|
|
601
|
+
rowCount: R.length,
|
|
532
602
|
source: "search_console"
|
|
533
603
|
};
|
|
534
604
|
} else {
|
|
535
|
-
const
|
|
536
|
-
console.error(`[GA Module] Search Console API error (${
|
|
605
|
+
const f = await D.text().catch(() => "");
|
|
606
|
+
console.error(`[GA Module] Search Console API error (${D.status}):`, f);
|
|
537
607
|
}
|
|
538
608
|
} catch (p) {
|
|
539
609
|
console.error("[GA Module] Search Console request failed:", p?.message || p);
|
|
@@ -541,8 +611,8 @@ function G(f) {
|
|
|
541
611
|
else
|
|
542
612
|
console.log("[GA Module] No siteUrl configured, skipping Search Console");
|
|
543
613
|
try {
|
|
544
|
-
const p = await
|
|
545
|
-
dateRanges: [{ startDate:
|
|
614
|
+
const p = await u(o, s, {
|
|
615
|
+
dateRanges: [{ startDate: n, endDate: r }],
|
|
546
616
|
dimensions: [{ name: "sessionGoogleAdsQuery" }],
|
|
547
617
|
metrics: [
|
|
548
618
|
{ name: "sessions" },
|
|
@@ -573,13 +643,13 @@ function G(f) {
|
|
|
573
643
|
},
|
|
574
644
|
orderBys: [{ metric: { metricName: "sessions" }, desc: !0 }],
|
|
575
645
|
limit: 30
|
|
576
|
-
}),
|
|
577
|
-
if (
|
|
578
|
-
return { ...
|
|
646
|
+
}), D = k(p, "sessionGoogleAdsQuery");
|
|
647
|
+
if (D.rows.length > 0)
|
|
648
|
+
return { ...D, source: "google_ads" };
|
|
579
649
|
} catch {
|
|
580
650
|
}
|
|
581
|
-
const
|
|
582
|
-
dateRanges: [{ startDate:
|
|
651
|
+
const c = await u(o, s, {
|
|
652
|
+
dateRanges: [{ startDate: n, endDate: r }],
|
|
583
653
|
dimensions: [{ name: "landingPagePlusQueryString" }],
|
|
584
654
|
metrics: [
|
|
585
655
|
{ name: "sessions" },
|
|
@@ -612,13 +682,13 @@ function G(f) {
|
|
|
612
682
|
orderBys: [{ metric: { metricName: "sessions" }, desc: !0 }],
|
|
613
683
|
limit: 30
|
|
614
684
|
});
|
|
615
|
-
return { ...
|
|
685
|
+
return { ...k(c, "landingPagePlusQueryString"), source: "organic_landing_pages" };
|
|
616
686
|
})
|
|
617
687
|
), g.get(
|
|
618
688
|
"/audience/overview",
|
|
619
|
-
|
|
620
|
-
const { accessToken:
|
|
621
|
-
dateRanges: [{ startDate:
|
|
689
|
+
w(async (e) => {
|
|
690
|
+
const { accessToken: o, propertyId: s } = await m(e), t = C(e), a = t.startDate || "30daysAgo", n = t.endDate || "today", r = await u(o, s, {
|
|
691
|
+
dateRanges: [{ startDate: a, endDate: n }],
|
|
622
692
|
dimensions: [{ name: "newVsReturning" }],
|
|
623
693
|
metrics: [
|
|
624
694
|
{ name: "totalUsers" },
|
|
@@ -629,14 +699,14 @@ function G(f) {
|
|
|
629
699
|
],
|
|
630
700
|
metricAggregations: ["TOTAL"]
|
|
631
701
|
});
|
|
632
|
-
return
|
|
702
|
+
return k(r, "newVsReturning");
|
|
633
703
|
})
|
|
634
704
|
), g.get(
|
|
635
705
|
"/audience/technology",
|
|
636
|
-
|
|
637
|
-
const { accessToken:
|
|
638
|
-
dateRanges: [{ startDate:
|
|
639
|
-
dimensions: [{ name:
|
|
706
|
+
w(async (e) => {
|
|
707
|
+
const { accessToken: o, propertyId: s } = await m(e), t = C(e), a = t.startDate || "30daysAgo", n = t.endDate || "today", r = t.dimension || "browser", l = ["browser", "operatingSystem", "screenResolution"].includes(r) ? r : "browser", p = await u(o, s, {
|
|
708
|
+
dateRanges: [{ startDate: a, endDate: n }],
|
|
709
|
+
dimensions: [{ name: l }],
|
|
640
710
|
metrics: [
|
|
641
711
|
{ name: "totalUsers" },
|
|
642
712
|
{ name: "sessions" },
|
|
@@ -645,13 +715,13 @@ function G(f) {
|
|
|
645
715
|
orderBys: [{ metric: { metricName: "totalUsers" }, desc: !0 }],
|
|
646
716
|
limit: 10
|
|
647
717
|
});
|
|
648
|
-
return
|
|
718
|
+
return k(p, l);
|
|
649
719
|
})
|
|
650
720
|
), g.get(
|
|
651
721
|
"/audience/languages",
|
|
652
|
-
|
|
653
|
-
const { accessToken:
|
|
654
|
-
dateRanges: [{ startDate:
|
|
722
|
+
w(async (e) => {
|
|
723
|
+
const { accessToken: o, propertyId: s } = await m(e), t = C(e), a = t.startDate || "30daysAgo", n = t.endDate || "today", r = await u(o, s, {
|
|
724
|
+
dateRanges: [{ startDate: a, endDate: n }],
|
|
655
725
|
dimensions: [{ name: "language" }],
|
|
656
726
|
metrics: [
|
|
657
727
|
{ name: "totalUsers" },
|
|
@@ -660,13 +730,13 @@ function G(f) {
|
|
|
660
730
|
orderBys: [{ metric: { metricName: "totalUsers" }, desc: !0 }],
|
|
661
731
|
limit: 15
|
|
662
732
|
});
|
|
663
|
-
return
|
|
733
|
+
return k(r, "language");
|
|
664
734
|
})
|
|
665
735
|
), g.get(
|
|
666
736
|
"/audience/hours",
|
|
667
|
-
|
|
668
|
-
const { accessToken:
|
|
669
|
-
dateRanges: [{ startDate:
|
|
737
|
+
w(async (e) => {
|
|
738
|
+
const { accessToken: o, propertyId: s } = await m(e), t = C(e), a = t.startDate || "30daysAgo", n = t.endDate || "today", r = await u(o, s, {
|
|
739
|
+
dateRanges: [{ startDate: a, endDate: n }],
|
|
670
740
|
dimensions: [{ name: "dayOfWeekName" }, { name: "hour" }],
|
|
671
741
|
metrics: [{ name: "sessions" }],
|
|
672
742
|
orderBys: [
|
|
@@ -676,13 +746,13 @@ function G(f) {
|
|
|
676
746
|
limit: 168
|
|
677
747
|
// 7 days × 24 hours
|
|
678
748
|
});
|
|
679
|
-
return
|
|
749
|
+
return U(r, ["dayOfWeekName", "hour"]);
|
|
680
750
|
})
|
|
681
751
|
), g.get(
|
|
682
752
|
"/audience/cities",
|
|
683
|
-
|
|
684
|
-
const { accessToken:
|
|
685
|
-
dateRanges: [{ startDate:
|
|
753
|
+
w(async (e) => {
|
|
754
|
+
const { accessToken: o, propertyId: s } = await m(e), t = C(e), a = t.startDate || "30daysAgo", n = t.endDate || "today", r = await u(o, s, {
|
|
755
|
+
dateRanges: [{ startDate: a, endDate: n }],
|
|
686
756
|
dimensions: [{ name: "city" }, { name: "country" }],
|
|
687
757
|
metrics: [
|
|
688
758
|
{ name: "totalUsers" },
|
|
@@ -699,95 +769,95 @@ function G(f) {
|
|
|
699
769
|
orderBys: [{ metric: { metricName: "totalUsers" }, desc: !0 }],
|
|
700
770
|
limit: 20
|
|
701
771
|
});
|
|
702
|
-
return
|
|
772
|
+
return U(r, ["city", "country"]);
|
|
703
773
|
})
|
|
704
774
|
);
|
|
705
|
-
function
|
|
706
|
-
const
|
|
707
|
-
if (
|
|
708
|
-
const
|
|
709
|
-
return
|
|
775
|
+
function i(e) {
|
|
776
|
+
const o = e.match(/^(\d+)daysAgo$/);
|
|
777
|
+
if (o) {
|
|
778
|
+
const s = /* @__PURE__ */ new Date();
|
|
779
|
+
return s.setDate(s.getDate() - parseInt(o[1], 10)), s.toISOString().slice(0, 10);
|
|
710
780
|
}
|
|
711
781
|
if (e === "today") return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
712
782
|
if (e === "yesterday") {
|
|
713
|
-
const
|
|
714
|
-
return
|
|
783
|
+
const s = /* @__PURE__ */ new Date();
|
|
784
|
+
return s.setDate(s.getDate() - 1), s.toISOString().slice(0, 10);
|
|
715
785
|
}
|
|
716
786
|
return e;
|
|
717
787
|
}
|
|
718
|
-
async function
|
|
719
|
-
const t = `${
|
|
788
|
+
async function d(e, o, s) {
|
|
789
|
+
const t = `${N}/sites/${encodeURIComponent(o)}/searchAnalytics/query`, a = await fetch(t, {
|
|
720
790
|
method: "POST",
|
|
721
791
|
headers: {
|
|
722
792
|
Authorization: `Bearer ${e}`,
|
|
723
793
|
"Content-Type": "application/json"
|
|
724
794
|
},
|
|
725
|
-
body: JSON.stringify(
|
|
795
|
+
body: JSON.stringify(s)
|
|
726
796
|
});
|
|
727
|
-
if (!
|
|
728
|
-
const
|
|
729
|
-
throw
|
|
730
|
-
statusCode:
|
|
731
|
-
statusMessage:
|
|
797
|
+
if (!a.ok) {
|
|
798
|
+
const n = await a.json().catch(() => ({}));
|
|
799
|
+
throw y({
|
|
800
|
+
statusCode: a.status,
|
|
801
|
+
statusMessage: n?.error?.message || "Search Console API request failed"
|
|
732
802
|
});
|
|
733
803
|
}
|
|
734
|
-
return
|
|
804
|
+
return a.json();
|
|
735
805
|
}
|
|
736
806
|
return g.get(
|
|
737
807
|
"/seo/keywords",
|
|
738
|
-
|
|
739
|
-
const { accessToken:
|
|
740
|
-
if (!
|
|
741
|
-
throw
|
|
742
|
-
const t =
|
|
743
|
-
startDate:
|
|
744
|
-
endDate:
|
|
808
|
+
w(async (e) => {
|
|
809
|
+
const { accessToken: o, siteUrl: s } = await m(e);
|
|
810
|
+
if (!s)
|
|
811
|
+
throw y({ statusCode: 400, statusMessage: "Search Console Site URL is not configured. Add it in module settings." });
|
|
812
|
+
const t = C(e), a = i(t.startDate || "30daysAgo"), n = i(t.endDate || "today"), r = Math.min(parseInt(t.limit) || 50, 100), c = await d(o, s, {
|
|
813
|
+
startDate: a,
|
|
814
|
+
endDate: n,
|
|
745
815
|
dimensions: ["query"],
|
|
746
816
|
rowLimit: r
|
|
747
817
|
});
|
|
748
818
|
return {
|
|
749
|
-
rows: (
|
|
750
|
-
query:
|
|
751
|
-
clicks:
|
|
752
|
-
impressions:
|
|
753
|
-
ctr:
|
|
754
|
-
position:
|
|
819
|
+
rows: (c.rows || []).map((l) => ({
|
|
820
|
+
query: l.keys[0],
|
|
821
|
+
clicks: l.clicks,
|
|
822
|
+
impressions: l.impressions,
|
|
823
|
+
ctr: l.ctr,
|
|
824
|
+
position: l.position
|
|
755
825
|
})),
|
|
756
|
-
rowCount:
|
|
826
|
+
rowCount: c.rows?.length || 0
|
|
757
827
|
};
|
|
758
828
|
})
|
|
759
829
|
), g.get(
|
|
760
830
|
"/seo/pages",
|
|
761
|
-
|
|
762
|
-
const { accessToken:
|
|
763
|
-
if (!
|
|
764
|
-
throw
|
|
765
|
-
const t =
|
|
766
|
-
startDate:
|
|
767
|
-
endDate:
|
|
831
|
+
w(async (e) => {
|
|
832
|
+
const { accessToken: o, siteUrl: s } = await m(e);
|
|
833
|
+
if (!s)
|
|
834
|
+
throw y({ statusCode: 400, statusMessage: "Search Console Site URL is not configured." });
|
|
835
|
+
const t = C(e), a = i(t.startDate || "30daysAgo"), n = i(t.endDate || "today"), r = Math.min(parseInt(t.limit) || 50, 100), c = await d(o, s, {
|
|
836
|
+
startDate: a,
|
|
837
|
+
endDate: n,
|
|
768
838
|
dimensions: ["page"],
|
|
769
839
|
rowLimit: r
|
|
770
840
|
});
|
|
771
841
|
return {
|
|
772
|
-
rows: (
|
|
773
|
-
page:
|
|
774
|
-
clicks:
|
|
775
|
-
impressions:
|
|
776
|
-
ctr:
|
|
777
|
-
position:
|
|
842
|
+
rows: (c.rows || []).map((l) => ({
|
|
843
|
+
page: l.keys[0],
|
|
844
|
+
clicks: l.clicks,
|
|
845
|
+
impressions: l.impressions,
|
|
846
|
+
ctr: l.ctr,
|
|
847
|
+
position: l.position
|
|
778
848
|
})),
|
|
779
|
-
rowCount:
|
|
849
|
+
rowCount: c.rows?.length || 0
|
|
780
850
|
};
|
|
781
851
|
})
|
|
782
852
|
), g.get(
|
|
783
853
|
"/seo/trends",
|
|
784
|
-
|
|
785
|
-
const { accessToken:
|
|
786
|
-
if (!
|
|
787
|
-
throw
|
|
788
|
-
const t =
|
|
789
|
-
startDate:
|
|
790
|
-
endDate:
|
|
854
|
+
w(async (e) => {
|
|
855
|
+
const { accessToken: o, siteUrl: s } = await m(e);
|
|
856
|
+
if (!s)
|
|
857
|
+
throw y({ statusCode: 400, statusMessage: "Search Console Site URL is not configured." });
|
|
858
|
+
const t = C(e), a = i(t.startDate || "30daysAgo"), n = i(t.endDate || "today"), c = ((await d(o, s, {
|
|
859
|
+
startDate: a,
|
|
860
|
+
endDate: n,
|
|
791
861
|
dimensions: ["date"],
|
|
792
862
|
rowLimit: 500
|
|
793
863
|
})).rows || []).map((p) => ({
|
|
@@ -796,132 +866,132 @@ function G(f) {
|
|
|
796
866
|
impressions: p.impressions,
|
|
797
867
|
ctr: p.ctr,
|
|
798
868
|
position: p.position
|
|
799
|
-
})).sort((p,
|
|
800
|
-
(p,
|
|
801
|
-
clicks: p.clicks +
|
|
802
|
-
impressions: p.impressions +
|
|
869
|
+
})).sort((p, D) => p.date.localeCompare(D.date)), l = c.reduce(
|
|
870
|
+
(p, D) => ({
|
|
871
|
+
clicks: p.clicks + D.clicks,
|
|
872
|
+
impressions: p.impressions + D.impressions
|
|
803
873
|
}),
|
|
804
874
|
{ clicks: 0, impressions: 0 }
|
|
805
875
|
);
|
|
806
|
-
return
|
|
876
|
+
return l.ctr = l.impressions > 0 ? l.clicks / l.impressions : 0, l.avgPosition = c.length > 0 ? c.reduce((p, D) => p + D.position, 0) / c.length : 0, { rows: c, totals: l, rowCount: c.length };
|
|
807
877
|
})
|
|
808
878
|
), g.get(
|
|
809
879
|
"/seo/query-pages",
|
|
810
|
-
|
|
811
|
-
const { accessToken:
|
|
812
|
-
if (!
|
|
813
|
-
throw
|
|
814
|
-
const t =
|
|
815
|
-
startDate:
|
|
816
|
-
endDate:
|
|
880
|
+
w(async (e) => {
|
|
881
|
+
const { accessToken: o, siteUrl: s } = await m(e);
|
|
882
|
+
if (!s)
|
|
883
|
+
throw y({ statusCode: 400, statusMessage: "Search Console Site URL is not configured." });
|
|
884
|
+
const t = C(e), a = i(t.startDate || "30daysAgo"), n = i(t.endDate || "today"), r = await d(o, s, {
|
|
885
|
+
startDate: a,
|
|
886
|
+
endDate: n,
|
|
817
887
|
dimensions: ["query", "page"],
|
|
818
888
|
rowLimit: 100
|
|
819
889
|
});
|
|
820
890
|
return {
|
|
821
|
-
rows: (r.rows || []).map((
|
|
822
|
-
query:
|
|
823
|
-
page:
|
|
824
|
-
clicks:
|
|
825
|
-
impressions:
|
|
826
|
-
ctr:
|
|
827
|
-
position:
|
|
891
|
+
rows: (r.rows || []).map((c) => ({
|
|
892
|
+
query: c.keys[0],
|
|
893
|
+
page: c.keys[1],
|
|
894
|
+
clicks: c.clicks,
|
|
895
|
+
impressions: c.impressions,
|
|
896
|
+
ctr: c.ctr,
|
|
897
|
+
position: c.position
|
|
828
898
|
})),
|
|
829
899
|
rowCount: r.rows?.length || 0
|
|
830
900
|
};
|
|
831
901
|
})
|
|
832
902
|
), g.handler;
|
|
833
903
|
}
|
|
834
|
-
function
|
|
835
|
-
const A = (
|
|
836
|
-
(
|
|
837
|
-
const
|
|
838
|
-
if (!
|
|
839
|
-
const
|
|
840
|
-
A.forEach((
|
|
841
|
-
|
|
842
|
-
}),
|
|
904
|
+
function E(h, P = !0) {
|
|
905
|
+
const A = (h.metricHeaders || []).map((a) => a.name), m = (h.dimensionHeaders || []).map((a) => a.name).indexOf("date"), u = [];
|
|
906
|
+
(h.rows || []).forEach((a) => {
|
|
907
|
+
const n = m >= 0 ? a.dimensionValues[m]?.value : a.dimensionValues[0]?.value;
|
|
908
|
+
if (!n || n.length < 8) return;
|
|
909
|
+
const c = { date: `${n.slice(0, 4)}-${n.slice(4, 6)}-${n.slice(6, 8)}` };
|
|
910
|
+
A.forEach((l, p) => {
|
|
911
|
+
c[l] = parseFloat(a.metricValues[p]?.value || "0");
|
|
912
|
+
}), u.push(c);
|
|
843
913
|
});
|
|
844
|
-
const
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
}) :
|
|
848
|
-
|
|
914
|
+
const i = {}, d = {};
|
|
915
|
+
h.totals && h.totals.length >= 2 ? A.forEach((a, n) => {
|
|
916
|
+
i[a] = parseFloat(h.totals[0]?.metricValues?.[n]?.value || "0"), d[a] = parseFloat(h.totals[1]?.metricValues?.[n]?.value || "0");
|
|
917
|
+
}) : h.totals && h.totals.length === 1 && A.forEach((a, n) => {
|
|
918
|
+
i[a] = parseFloat(h.totals[0]?.metricValues?.[n]?.value || "0");
|
|
849
919
|
});
|
|
850
920
|
const e = {};
|
|
851
|
-
A.forEach((
|
|
852
|
-
const
|
|
853
|
-
r !== void 0 && r !== 0 ? e[
|
|
921
|
+
A.forEach((a) => {
|
|
922
|
+
const n = i[a] || 0, r = d[a];
|
|
923
|
+
r !== void 0 && r !== 0 ? e[a] = (n - r) / r * 100 : e[a] = null;
|
|
854
924
|
});
|
|
855
|
-
const
|
|
856
|
-
for (const
|
|
857
|
-
|
|
858
|
-
const
|
|
925
|
+
const o = /* @__PURE__ */ new Map();
|
|
926
|
+
for (const a of u)
|
|
927
|
+
o.has(a.date) || o.set(a.date, a);
|
|
928
|
+
const s = Array.from(o.values()).sort((a, n) => a.date.localeCompare(n.date)), t = P && h.totals && h.totals.length >= 2 ? s.slice(-Math.ceil(s.length / 2)) : s;
|
|
859
929
|
return {
|
|
860
930
|
rows: t,
|
|
861
|
-
totals:
|
|
862
|
-
previousTotals:
|
|
931
|
+
totals: i,
|
|
932
|
+
previousTotals: d,
|
|
863
933
|
changes: e,
|
|
864
934
|
rowCount: t.length
|
|
865
935
|
};
|
|
866
936
|
}
|
|
867
|
-
function
|
|
868
|
-
const A = (
|
|
869
|
-
const
|
|
870
|
-
[
|
|
937
|
+
function k(h, P) {
|
|
938
|
+
const A = (h.metricHeaders || []).map((m) => m.name), g = (h.rows || []).map((m) => {
|
|
939
|
+
const u = {
|
|
940
|
+
[P]: m.dimensionValues[0].value
|
|
871
941
|
};
|
|
872
|
-
return A.forEach((
|
|
873
|
-
|
|
874
|
-
}),
|
|
942
|
+
return A.forEach((i, d) => {
|
|
943
|
+
u[i] = parseFloat(m.metricValues[d].value);
|
|
944
|
+
}), u;
|
|
875
945
|
});
|
|
876
|
-
return { rows: g, rowCount:
|
|
946
|
+
return { rows: g, rowCount: h.rowCount || g.length };
|
|
877
947
|
}
|
|
878
|
-
function
|
|
879
|
-
const A = (
|
|
880
|
-
const
|
|
881
|
-
return
|
|
882
|
-
|
|
883
|
-
}), A.forEach((
|
|
884
|
-
|
|
885
|
-
}),
|
|
948
|
+
function U(h, P) {
|
|
949
|
+
const A = (h.metricHeaders || []).map((m) => m.name), g = (h.rows || []).map((m) => {
|
|
950
|
+
const u = {};
|
|
951
|
+
return P.forEach((i, d) => {
|
|
952
|
+
u[i] = m.dimensionValues[d]?.value || "";
|
|
953
|
+
}), A.forEach((i, d) => {
|
|
954
|
+
u[i] = parseFloat(m.metricValues[d].value);
|
|
955
|
+
}), u;
|
|
886
956
|
});
|
|
887
|
-
return { rows: g, rowCount:
|
|
957
|
+
return { rows: g, rowCount: h.rowCount || g.length };
|
|
888
958
|
}
|
|
889
|
-
function j(
|
|
890
|
-
const { decrypt:
|
|
959
|
+
function j(h) {
|
|
960
|
+
const { decrypt: P } = h, A = v();
|
|
891
961
|
async function g(m) {
|
|
892
|
-
const { supabase:
|
|
893
|
-
if (e || !
|
|
894
|
-
throw
|
|
895
|
-
const
|
|
896
|
-
if (!
|
|
897
|
-
throw
|
|
898
|
-
const { data:
|
|
899
|
-
let
|
|
900
|
-
if (r || !
|
|
901
|
-
const { data: p, error:
|
|
902
|
-
if (
|
|
903
|
-
throw
|
|
904
|
-
|
|
962
|
+
const { supabase: u, instanceId: i } = m.context.module, { data: d, error: e } = await u.from("project_modules").select("config").eq("id", i).single();
|
|
963
|
+
if (e || !d?.config)
|
|
964
|
+
throw y({ statusCode: 500, statusMessage: "Failed to load module config." });
|
|
965
|
+
const o = d.config, s = o.githubIntegration, t = o.githubRepo, a = o.githubOwner;
|
|
966
|
+
if (!s || !t || !a)
|
|
967
|
+
throw y({ statusCode: 400, statusMessage: "No GitHub integration configured for this module." });
|
|
968
|
+
const { data: n, error: r } = await u.from("integrations").select("config").eq("id", s).single();
|
|
969
|
+
let c = n?.config;
|
|
970
|
+
if (r || !c) {
|
|
971
|
+
const { data: p, error: D } = await u.from("agency_integrations").select("config").eq("id", s).single();
|
|
972
|
+
if (D || !p?.config)
|
|
973
|
+
throw y({ statusCode: 500, statusMessage: "Failed to load Github credentials." });
|
|
974
|
+
c = p.config;
|
|
905
975
|
}
|
|
906
|
-
return { token:
|
|
976
|
+
return { token: P(c.token), repo: t, owner: a };
|
|
907
977
|
}
|
|
908
978
|
return A.post(
|
|
909
979
|
"/github/deploy",
|
|
910
|
-
|
|
980
|
+
w(async (m) => {
|
|
911
981
|
try {
|
|
912
|
-
const { token:
|
|
913
|
-
await fetch(`https://api.github.com/repos/${
|
|
982
|
+
const { token: u, repo: i, owner: d } = await g(m);
|
|
983
|
+
await fetch(`https://api.github.com/repos/${d}/${i}/dispatches`, {
|
|
914
984
|
method: "POST",
|
|
915
985
|
headers: {
|
|
916
|
-
Authorization: `Bearer ${
|
|
986
|
+
Authorization: `Bearer ${u}`,
|
|
917
987
|
Accept: "application/vnd.github+json"
|
|
918
988
|
},
|
|
919
989
|
body: JSON.stringify({
|
|
920
990
|
event_type: "deploy-site"
|
|
921
991
|
})
|
|
922
992
|
});
|
|
923
|
-
} catch (
|
|
924
|
-
throw console.error("Error triggering GitHub deployment:",
|
|
993
|
+
} catch (u) {
|
|
994
|
+
throw console.error("Error triggering GitHub deployment:", u), y({ statusCode: 500, statusMessage: "Failed to trigger deployment." });
|
|
925
995
|
}
|
|
926
996
|
})
|
|
927
997
|
), A.handler;
|