@oneclick.dev/cms-core-modules 0.0.115 → 0.0.116
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-MctMvN7D.js → ContentEditor-CsbOFg3a.js} +52 -52
- package/dist/{ContentEditor-C5yNNLeV.mjs → ContentEditor-Df5uWpVC.mjs} +10337 -8677
- package/dist/EditLayout.vue_vue_type_script_setup_true_lang-gozJKXvM.js +1 -0
- package/dist/EditLayout.vue_vue_type_script_setup_true_lang-pDO9b4Pv.mjs +77 -0
- package/dist/NewReservationDialog.vue_vue_type_script_setup_true_lang-BHeMJ6nr.mjs +1476 -0
- package/dist/NewReservationDialog.vue_vue_type_script_setup_true_lang-C2zwt5UF.js +1 -0
- package/dist/OrderDetailDialog.vue_vue_type_script_setup_true_lang-BYSeUW_V.js +925 -0
- package/dist/OrderDetailDialog.vue_vue_type_script_setup_true_lang-DwAUYR8p.mjs +5021 -0
- package/dist/Overview-CBahJviK.js +1 -0
- package/dist/Overview-CVQ1pkuD.mjs +527 -0
- package/dist/TableView-Csv5Lycy.mjs +6234 -0
- package/dist/TableView-Cwal0BPW.js +4 -0
- package/dist/agenda-BSdlrfxv.mjs +1253 -0
- package/dist/agenda-Bev1mO7E.js +1 -0
- package/dist/availability-ClBGVgE9.js +1 -0
- package/dist/availability-D8JdA4rP.mjs +274 -0
- package/dist/booking-data-Px7XCIfU.mjs +1024 -0
- package/dist/booking-data-aMS1p_3g.js +1 -0
- package/dist/cms-core-modules.css +1 -1
- package/dist/exceptions-CqityDo9.mjs +651 -0
- package/dist/exceptions-DXqc0Nza.js +1 -0
- package/dist/index-CM4eaK5T.mjs +1245 -0
- package/dist/index-DliTZzwI.js +35 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.mjs +12 -11
- package/dist/orders-1swJVKw2.js +1 -0
- package/dist/orders-D41GbzIa.mjs +624 -0
- package/dist/payment-BJHgpaeT.js +1 -0
- package/dist/payment-D5j-68Ig.mjs +1278 -0
- package/dist/refunds-D9nTeD2d.mjs +436 -0
- package/dist/refunds-oVB2Opib.js +1 -0
- package/dist/resources-8WouFvJe.js +1 -0
- package/dist/resources-B-D5MUhV.mjs +975 -0
- package/dist/server-handlers.cjs.js +1 -1
- package/dist/server-handlers.mjs +626 -515
- package/dist/src/appointments/components/edit/EventDialog/BookingsList.vue.d.ts +146 -5
- package/dist/src/appointments/components/edit/EventDialog/CancelRefundReservationDialog.vue.d.ts +33 -0
- package/dist/src/appointments/components/edit/EventDialog/OrderDetailDialog.vue.d.ts +26 -8
- package/dist/src/appointments/components/edit/EventDialog/RefundDetailsDisplay.vue.d.ts +8 -0
- package/dist/src/appointments/components/edit/EventDialog/ReservationDetailDialog.vue.d.ts +91 -5
- package/dist/src/appointments/components/edit/EventDialog/TransferReservationDialog.vue.d.ts +20 -3
- package/dist/src/appointments/components/edit/NewReservationDialog/ReservationLines.vue.d.ts +5 -0
- package/dist/src/appointments/components/edit/OrderMetadataDisplay.vue.d.ts +20 -2
- package/dist/src/appointments/components/edit/dashboard/BookingsList.vue.d.ts +240 -0
- package/dist/src/appointments/composables/useAgendaMetadataSchema.d.ts +37 -0
- package/dist/src/appointments/pages/edit/orders.vue.d.ts +225 -0
- package/dist/src/appointments/pages/edit/refunds.vue.d.ts +2 -0
- package/dist/src/appointments/server.d.ts +2 -0
- package/dist/src/appointments/types.d.ts +6 -0
- package/dist/src/appointments/utils/printReservation.d.ts +65 -3
- package/dist/src/contentManager/components/content-editor/tiptap-extensions/table/Table.d.ts +36 -0
- package/dist/src/contentManager/components/content-editor/tiptap-extensions/table/Table.vue.d.ts +95 -0
- package/dist/src/contentManager/components/content-editor/tiptap-extensions/table/TableCell.d.ts +13 -0
- package/dist/src/contentManager/components/content-editor/tiptap-extensions/table/TableHeader.d.ts +6 -0
- package/dist/src/contentManager/components/content-editor/tiptap-extensions/table/TableRow.d.ts +6 -0
- package/dist/src/contentManager/components/content-editor/tiptap-extensions/table/index.d.ts +4 -0
- package/dist/src/contentManager/components/content-editor/tiptap-menus/element-editor-views/TableMenu.vue.d.ts +13 -0
- package/dist/src/contentManager/components/content-editor/tiptap-menus/element-editor-views/index.d.ts +14 -0
- package/package.json +2 -2
- package/dist/EditLayout.vue_vue_type_script_setup_true_lang-DWMqQvHl.mjs +0 -76
- package/dist/EditLayout.vue_vue_type_script_setup_true_lang-kpjbVSXg.js +0 -1
- package/dist/NewReservationDialog.vue_vue_type_script_setup_true_lang-Baqy-rTT.js +0 -1
- package/dist/NewReservationDialog.vue_vue_type_script_setup_true_lang-Dx4Bpa2m.mjs +0 -1263
- package/dist/OrderDetailDialog.vue_vue_type_script_setup_true_lang-COrK1j0S.js +0 -1
- package/dist/OrderDetailDialog.vue_vue_type_script_setup_true_lang-Vb3q8EVv.mjs +0 -330
- package/dist/Overview-98nkJUWN.mjs +0 -481
- package/dist/Overview-Dl8cMlsr.js +0 -1
- package/dist/ReservationDetailDialog.vue_vue_type_script_setup_true_lang-CuwREvXD.js +0 -349
- package/dist/ReservationDetailDialog.vue_vue_type_script_setup_true_lang-GYNZ_yhD.mjs +0 -3077
- package/dist/TableView-CVfkyj1k.js +0 -4
- package/dist/TableView-zDx0IegJ.mjs +0 -6096
- package/dist/agenda-BaJu3-1c.js +0 -1
- package/dist/agenda-BwVY_8oM.mjs +0 -1165
- package/dist/availability-CMrRa5y2.mjs +0 -269
- package/dist/availability-Cf2YfMwM.js +0 -1
- package/dist/booking-data-DgJd0BcM.mjs +0 -889
- package/dist/booking-data-Di5GmH_8.js +0 -1
- package/dist/exceptions-B6P9UiCj.js +0 -1
- package/dist/exceptions-De9-FvdP.mjs +0 -646
- package/dist/index-DL6orwdK.js +0 -35
- package/dist/index-hH3e-IYz.mjs +0 -1187
- package/dist/orders-C65SlpJy.mjs +0 -618
- package/dist/orders-XVzWAgG1.js +0 -1
- package/dist/payment-C3ohkehF.mjs +0 -1080
- package/dist/payment-Dfr-Ro-a.js +0 -1
- package/dist/resources-CxeFd57z.js +0 -1
- package/dist/resources-DwYxn2Vi.mjs +0 -811
package/dist/server-handlers.mjs
CHANGED
|
@@ -1,289 +1,400 @@
|
|
|
1
|
-
import { createRouter as
|
|
1
|
+
import { createRouter as E, defineEventHandler as h, createError as p, getRouterParam as F, getQuery as I, readBody as O } from "h3";
|
|
2
2
|
import "vue";
|
|
3
|
-
function
|
|
4
|
-
const { initFirebase: P, normalizeTimestamps:
|
|
5
|
-
async function
|
|
6
|
-
const { supabase:
|
|
7
|
-
if (
|
|
8
|
-
throw
|
|
9
|
-
const
|
|
10
|
-
if (!
|
|
11
|
-
throw
|
|
12
|
-
return { firebase: await P(
|
|
3
|
+
function z(A) {
|
|
4
|
+
const { initFirebase: P, normalizeTimestamps: S } = A, f = E();
|
|
5
|
+
async function u(l) {
|
|
6
|
+
const { supabase: y, instanceId: D } = l.context.module, { data: t, error: c } = await y.from("project_modules").select("config").eq("id", D).single();
|
|
7
|
+
if (c || !t?.config)
|
|
8
|
+
throw p({ statusCode: 500, statusMessage: "Failed to load module config." });
|
|
9
|
+
const i = t.config, s = i.project, a = i.productCollection || "products";
|
|
10
|
+
if (!s)
|
|
11
|
+
throw p({ statusCode: 400, statusMessage: "Products module has no Firebase integration configured." });
|
|
12
|
+
return { firebase: await P(l, s), collection: a };
|
|
13
13
|
}
|
|
14
|
-
return
|
|
14
|
+
return f.get("/products", h(async (l) => {
|
|
15
15
|
try {
|
|
16
|
-
const { firebase:
|
|
17
|
-
return (await
|
|
18
|
-
id:
|
|
19
|
-
...
|
|
16
|
+
const { firebase: y, collection: D } = await u(l);
|
|
17
|
+
return (await y.firestore().collection(D).get()).docs.map((c) => S({
|
|
18
|
+
id: c.id,
|
|
19
|
+
...c.data()
|
|
20
20
|
}));
|
|
21
|
-
} catch (
|
|
22
|
-
throw console.error("Products handler — list error:",
|
|
23
|
-
statusCode:
|
|
24
|
-
statusMessage:
|
|
21
|
+
} catch (y) {
|
|
22
|
+
throw console.error("Products handler — list error:", y), p({
|
|
23
|
+
statusCode: y.statusCode || 500,
|
|
24
|
+
statusMessage: y.statusMessage || "Failed to list products"
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
|
-
})),
|
|
28
|
-
const
|
|
29
|
-
if (!
|
|
30
|
-
throw
|
|
27
|
+
})), f.get("/products/:productId", h(async (l) => {
|
|
28
|
+
const y = F(l, "productId");
|
|
29
|
+
if (!y)
|
|
30
|
+
throw p({ statusCode: 400, statusMessage: "Product ID is required." });
|
|
31
31
|
try {
|
|
32
|
-
const { firebase:
|
|
33
|
-
if (!
|
|
34
|
-
throw
|
|
35
|
-
return
|
|
36
|
-
id:
|
|
37
|
-
...
|
|
38
|
-
});
|
|
39
|
-
} catch (
|
|
40
|
-
throw console.error("Products handler — get error:",
|
|
41
|
-
statusCode:
|
|
42
|
-
statusMessage:
|
|
32
|
+
const { firebase: D, collection: t } = await u(l), c = await D.firestore().collection(t).doc(y).get();
|
|
33
|
+
if (!c.exists)
|
|
34
|
+
throw p({ statusCode: 404, statusMessage: "Product not found." });
|
|
35
|
+
return S({
|
|
36
|
+
id: c.id,
|
|
37
|
+
...c.data()
|
|
38
|
+
});
|
|
39
|
+
} catch (D) {
|
|
40
|
+
throw console.error("Products handler — get error:", D), p({
|
|
41
|
+
statusCode: D.statusCode || 500,
|
|
42
|
+
statusMessage: D.statusMessage || "Failed to get product"
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
|
-
})),
|
|
46
|
-
const
|
|
45
|
+
})), f.get("/empty-stock", h(async (l) => {
|
|
46
|
+
const D = I(l).category;
|
|
47
47
|
try {
|
|
48
|
-
const { firebase:
|
|
49
|
-
let
|
|
50
|
-
|
|
51
|
-
const a = (await
|
|
52
|
-
id:
|
|
53
|
-
...
|
|
48
|
+
const { firebase: t, collection: c } = await u(l);
|
|
49
|
+
let i = t.firestore().collection(c).where("stock", "==", 0);
|
|
50
|
+
D && (i = i.where("collections", "array-contains", D));
|
|
51
|
+
const a = (await i.get()).docs.map((r) => S({
|
|
52
|
+
id: r.id,
|
|
53
|
+
...r.data()
|
|
54
54
|
}));
|
|
55
55
|
return {
|
|
56
56
|
count: a.length,
|
|
57
|
-
products: a.map((
|
|
58
|
-
id:
|
|
59
|
-
title:
|
|
60
|
-
slug:
|
|
61
|
-
stock:
|
|
62
|
-
price:
|
|
63
|
-
currency:
|
|
64
|
-
status:
|
|
57
|
+
products: a.map((r) => ({
|
|
58
|
+
id: r.id,
|
|
59
|
+
title: r.title,
|
|
60
|
+
slug: r.slug,
|
|
61
|
+
stock: r.stock,
|
|
62
|
+
price: r.price,
|
|
63
|
+
currency: r.currency,
|
|
64
|
+
status: r.status
|
|
65
65
|
}))
|
|
66
66
|
};
|
|
67
|
-
} catch (
|
|
68
|
-
throw console.error("Products handler — empty-stock error:",
|
|
69
|
-
statusCode:
|
|
70
|
-
statusMessage:
|
|
67
|
+
} catch (t) {
|
|
68
|
+
throw console.error("Products handler — empty-stock error:", t), p({
|
|
69
|
+
statusCode: t.statusCode || 500,
|
|
70
|
+
statusMessage: t.statusMessage || "Failed to query empty stock"
|
|
71
71
|
});
|
|
72
72
|
}
|
|
73
|
-
})),
|
|
73
|
+
})), f.handler;
|
|
74
74
|
}
|
|
75
|
-
function
|
|
76
|
-
const { initFirebase: P, normalizeTimestamps:
|
|
77
|
-
async function
|
|
78
|
-
const { supabase:
|
|
79
|
-
if (
|
|
80
|
-
throw
|
|
81
|
-
const
|
|
82
|
-
if (!
|
|
83
|
-
throw
|
|
84
|
-
return { firebase: await P(
|
|
75
|
+
function J(A) {
|
|
76
|
+
const { initFirebase: P, normalizeTimestamps: S, deleteField: f } = A, u = E(), l = "privateSettings", y = "refundFlow", D = "metadataSchema";
|
|
77
|
+
async function t(e) {
|
|
78
|
+
const { supabase: n, instanceId: o } = e.context.module, { data: d, error: g } = await n.from("project_modules").select("config").eq("id", o).single();
|
|
79
|
+
if (g || !d?.config)
|
|
80
|
+
throw p({ statusCode: 500, statusMessage: "Failed to load module config." });
|
|
81
|
+
const m = d.config, w = m.project, C = m.reservationsCollection || "bookings_orders", R = m.agendaCollection || "agendas";
|
|
82
|
+
if (!w)
|
|
83
|
+
throw p({ statusCode: 400, statusMessage: "Appointments module has no Firebase integration configured." });
|
|
84
|
+
return { firebase: await P(e, w), reservationsCollection: C, agendaCollection: R };
|
|
85
85
|
}
|
|
86
|
-
function
|
|
87
|
-
return (
|
|
88
|
-
orderId:
|
|
89
|
-
reservationId:
|
|
90
|
-
customerInfo:
|
|
91
|
-
date:
|
|
92
|
-
startTime:
|
|
93
|
-
endTime:
|
|
94
|
-
spots:
|
|
95
|
-
status:
|
|
96
|
-
reservationStatus:
|
|
97
|
-
resourceId:
|
|
98
|
-
reservationPrice:
|
|
99
|
-
reservationBasePrice:
|
|
100
|
-
reservationAddOnsPrice:
|
|
101
|
-
pricingOption:
|
|
102
|
-
amountDue:
|
|
103
|
-
amountPaid:
|
|
104
|
-
createdAt:
|
|
105
|
-
metadata:
|
|
106
|
-
reservationMetadata:
|
|
86
|
+
function c(e) {
|
|
87
|
+
return (e.reservations || []).map((o) => ({
|
|
88
|
+
orderId: e.id,
|
|
89
|
+
reservationId: o.id,
|
|
90
|
+
customerInfo: e.customerInfo,
|
|
91
|
+
date: o.date,
|
|
92
|
+
startTime: o.timeslot?.startTime,
|
|
93
|
+
endTime: o.timeslot?.endTime,
|
|
94
|
+
spots: o.spots,
|
|
95
|
+
status: e.status,
|
|
96
|
+
reservationStatus: o.status,
|
|
97
|
+
resourceId: o.resourceId,
|
|
98
|
+
reservationPrice: o.totalPrice,
|
|
99
|
+
reservationBasePrice: o.basePrice,
|
|
100
|
+
reservationAddOnsPrice: o.addOnsPrice,
|
|
101
|
+
pricingOption: o.pricingOption,
|
|
102
|
+
amountDue: e.amountDue,
|
|
103
|
+
amountPaid: e.amountPaid,
|
|
104
|
+
createdAt: e.createdAt,
|
|
105
|
+
metadata: e.metadata || {},
|
|
106
|
+
reservationMetadata: o.metadata || {}
|
|
107
107
|
}));
|
|
108
108
|
}
|
|
109
|
-
|
|
109
|
+
function i(e) {
|
|
110
|
+
return {
|
|
111
|
+
showAmount: e?.showAmount !== !1,
|
|
112
|
+
fields: Array.isArray(e?.fields) ? e.fields : []
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function s() {
|
|
116
|
+
return f ? {
|
|
117
|
+
refundFlow: f(),
|
|
118
|
+
refundFlowEnabled: f(),
|
|
119
|
+
refundDialog: f()
|
|
120
|
+
} : {
|
|
121
|
+
refundFlow: null,
|
|
122
|
+
refundFlowEnabled: null,
|
|
123
|
+
refundDialog: null
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function a(e) {
|
|
127
|
+
return Array.isArray(e) ? e : [];
|
|
128
|
+
}
|
|
129
|
+
function r() {
|
|
130
|
+
return f ? {
|
|
131
|
+
metadataSchema: f()
|
|
132
|
+
} : {
|
|
133
|
+
metadataSchema: null
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return u.get("/agendas", h(async (e) => {
|
|
110
137
|
try {
|
|
111
|
-
const { firebase:
|
|
112
|
-
const
|
|
138
|
+
const { firebase: n, agendaCollection: o } = await t(e), g = (await n.firestore().collection(o).get()).docs.map((m) => {
|
|
139
|
+
const w = m.data();
|
|
113
140
|
return {
|
|
114
|
-
id:
|
|
115
|
-
serviceName:
|
|
116
|
-
type:
|
|
141
|
+
id: m.id,
|
|
142
|
+
serviceName: w.serviceName || "",
|
|
143
|
+
type: w.type || "regular"
|
|
117
144
|
};
|
|
118
145
|
});
|
|
119
146
|
return {
|
|
120
|
-
count:
|
|
121
|
-
agendas:
|
|
147
|
+
count: g.length,
|
|
148
|
+
agendas: g
|
|
122
149
|
};
|
|
123
|
-
} catch (
|
|
124
|
-
throw console.error("Appointments handler — list agendas error:",
|
|
125
|
-
statusCode:
|
|
126
|
-
statusMessage:
|
|
150
|
+
} catch (n) {
|
|
151
|
+
throw console.error("Appointments handler — list agendas error:", n), p({
|
|
152
|
+
statusCode: n.statusCode || 500,
|
|
153
|
+
statusMessage: n.statusMessage || "Failed to list agendas"
|
|
127
154
|
});
|
|
128
155
|
}
|
|
129
|
-
})),
|
|
130
|
-
const
|
|
156
|
+
})), u.get("/agendas/:agendaId/opening-hours", h(async (e) => {
|
|
157
|
+
const n = F(e, "agendaId"), d = I(e).date;
|
|
158
|
+
if (!n)
|
|
159
|
+
throw p({ statusCode: 400, statusMessage: "Agenda ID is required." });
|
|
131
160
|
if (!d)
|
|
132
|
-
throw
|
|
133
|
-
if (!o)
|
|
134
|
-
throw y({ statusCode: 400, statusMessage: "Date is required (YYYY-MM-DD)." });
|
|
161
|
+
throw p({ statusCode: 400, statusMessage: "Date is required (YYYY-MM-DD)." });
|
|
135
162
|
try {
|
|
136
|
-
const { firebase:
|
|
137
|
-
if (!
|
|
138
|
-
throw
|
|
139
|
-
const
|
|
140
|
-
const
|
|
141
|
-
const
|
|
142
|
-
return
|
|
163
|
+
const { firebase: g, agendaCollection: m } = await t(e), w = await g.firestore().collection(m).doc(n).get();
|
|
164
|
+
if (!w.exists)
|
|
165
|
+
throw p({ statusCode: 404, statusMessage: "Agenda not found." });
|
|
166
|
+
const C = w.data(), R = (C.resources || []).filter((v) => v.isActive), M = C.exceptions || [], q = (/* @__PURE__ */ new Date(d + "T00:00:00")).getDay(), N = R.map((v) => {
|
|
167
|
+
const V = v.openingHours?.[q] || [], U = M.find((T) => {
|
|
168
|
+
const G = d >= T.startDate && d <= T.endDate, j = !T.resourceIds || T.resourceIds.length === 0 || T.resourceIds.includes(v.id);
|
|
169
|
+
return G && j;
|
|
143
170
|
});
|
|
144
|
-
return
|
|
145
|
-
resourceId:
|
|
146
|
-
resourceName:
|
|
147
|
-
date:
|
|
148
|
-
dayOfWeek:
|
|
149
|
-
isClosed:
|
|
150
|
-
hours:
|
|
151
|
-
start:
|
|
152
|
-
end:
|
|
171
|
+
return U ? {
|
|
172
|
+
resourceId: v.id,
|
|
173
|
+
resourceName: v.name,
|
|
174
|
+
date: d,
|
|
175
|
+
dayOfWeek: q,
|
|
176
|
+
isClosed: U.isClosed,
|
|
177
|
+
hours: U.isClosed ? [] : (U.timeslots || []).map((T) => ({
|
|
178
|
+
start: T.startTime,
|
|
179
|
+
end: T.endTime
|
|
153
180
|
})),
|
|
154
181
|
isException: !0
|
|
155
182
|
} : {
|
|
156
|
-
resourceId:
|
|
157
|
-
resourceName:
|
|
158
|
-
date:
|
|
159
|
-
dayOfWeek:
|
|
160
|
-
isClosed:
|
|
161
|
-
hours:
|
|
183
|
+
resourceId: v.id,
|
|
184
|
+
resourceName: v.name,
|
|
185
|
+
date: d,
|
|
186
|
+
dayOfWeek: q,
|
|
187
|
+
isClosed: V.length === 0,
|
|
188
|
+
hours: V,
|
|
162
189
|
isException: !1
|
|
163
190
|
};
|
|
164
191
|
});
|
|
165
192
|
return {
|
|
166
|
-
agendaId:
|
|
167
|
-
serviceName:
|
|
168
|
-
date:
|
|
169
|
-
resources:
|
|
193
|
+
agendaId: n,
|
|
194
|
+
serviceName: C.serviceName || "",
|
|
195
|
+
date: d,
|
|
196
|
+
resources: N
|
|
197
|
+
};
|
|
198
|
+
} catch (g) {
|
|
199
|
+
throw console.error("Appointments handler — opening hours error:", g), p({
|
|
200
|
+
statusCode: g.statusCode || 500,
|
|
201
|
+
statusMessage: g.statusMessage || "Failed to get opening hours"
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
})), u.get("/agendas/:agendaId/refund-flow", h(async (e) => {
|
|
205
|
+
const n = F(e, "agendaId");
|
|
206
|
+
if (!n)
|
|
207
|
+
throw p({ statusCode: 400, statusMessage: "Agenda ID is required." });
|
|
208
|
+
try {
|
|
209
|
+
const { firebase: o, agendaCollection: d } = await t(e), m = o.firestore().collection(d).doc(n), w = m.collection(l).doc(y), [C, R] = await Promise.all([
|
|
210
|
+
m.get(),
|
|
211
|
+
w.get()
|
|
212
|
+
]);
|
|
213
|
+
if (!C.exists)
|
|
214
|
+
throw p({ statusCode: 404, statusMessage: "Agenda not found." });
|
|
215
|
+
const M = R.exists ? R.data() || {} : {};
|
|
216
|
+
return {
|
|
217
|
+
refundFlow: M.flow || {},
|
|
218
|
+
refundFlowEnabled: M.enabled !== !1,
|
|
219
|
+
refundDialog: i(M.dialog)
|
|
170
220
|
};
|
|
171
|
-
} catch (
|
|
172
|
-
throw console.error("Appointments handler —
|
|
173
|
-
statusCode:
|
|
174
|
-
statusMessage:
|
|
221
|
+
} catch (o) {
|
|
222
|
+
throw console.error("Appointments handler — refund flow load error:", o), p({
|
|
223
|
+
statusCode: o.statusCode || 500,
|
|
224
|
+
statusMessage: o.statusMessage || "Failed to load refund flow"
|
|
175
225
|
});
|
|
176
226
|
}
|
|
177
|
-
})),
|
|
178
|
-
const
|
|
227
|
+
})), u.patch("/agendas/:agendaId/refund-flow", h(async (e) => {
|
|
228
|
+
const n = F(e, "agendaId");
|
|
229
|
+
if (!n)
|
|
230
|
+
throw p({ statusCode: 400, statusMessage: "Agenda ID is required." });
|
|
179
231
|
try {
|
|
180
|
-
const { firebase:
|
|
181
|
-
|
|
232
|
+
const o = await O(e), { firebase: d, agendaCollection: g } = await t(e), m = d.firestore(), w = m.collection(g).doc(n), C = w.collection(l).doc(y), R = i(o?.refundDialog);
|
|
233
|
+
if (!(await w.get()).exists)
|
|
234
|
+
throw p({ statusCode: 404, statusMessage: "Agenda not found." });
|
|
235
|
+
const k = m.batch();
|
|
236
|
+
return k.set(C, {
|
|
237
|
+
flow: o?.refundFlow || {},
|
|
238
|
+
enabled: o?.refundFlowEnabled !== !1,
|
|
239
|
+
dialog: R,
|
|
240
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
241
|
+
}, { merge: !0 }), k.set(w, s(), { merge: !0 }), await k.commit(), { success: !0 };
|
|
242
|
+
} catch (o) {
|
|
243
|
+
throw console.error("Appointments handler — refund flow save error:", o), p({
|
|
244
|
+
statusCode: o.statusCode || 500,
|
|
245
|
+
statusMessage: o.statusMessage || "Failed to save refund flow"
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
})), u.get("/agendas/:agendaId/metadata-schema", h(async (e) => {
|
|
249
|
+
const n = F(e, "agendaId");
|
|
250
|
+
if (!n)
|
|
251
|
+
throw p({ statusCode: 400, statusMessage: "Agenda ID is required." });
|
|
252
|
+
try {
|
|
253
|
+
const { firebase: o, agendaCollection: d } = await t(e), m = o.firestore().collection(d).doc(n), w = m.collection(l).doc(D), [C, R] = await Promise.all([
|
|
254
|
+
m.get(),
|
|
255
|
+
w.get()
|
|
256
|
+
]);
|
|
257
|
+
if (!C.exists)
|
|
258
|
+
throw p({ statusCode: 404, statusMessage: "Agenda not found." });
|
|
259
|
+
const M = R.exists ? R.data() || {} : {};
|
|
260
|
+
return {
|
|
261
|
+
metadataSchema: a(M.schema)
|
|
262
|
+
};
|
|
263
|
+
} catch (o) {
|
|
264
|
+
throw console.error("Appointments handler — metadata schema load error:", o), p({
|
|
265
|
+
statusCode: o.statusCode || 500,
|
|
266
|
+
statusMessage: o.statusMessage || "Failed to load metadata schema"
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
})), u.patch("/agendas/:agendaId/metadata-schema", h(async (e) => {
|
|
270
|
+
const n = F(e, "agendaId");
|
|
271
|
+
if (!n)
|
|
272
|
+
throw p({ statusCode: 400, statusMessage: "Agenda ID is required." });
|
|
273
|
+
try {
|
|
274
|
+
const o = await O(e), { firebase: d, agendaCollection: g } = await t(e), m = d.firestore(), w = m.collection(g).doc(n), C = w.collection(l).doc(D);
|
|
275
|
+
if (!(await w.get()).exists)
|
|
276
|
+
throw p({ statusCode: 404, statusMessage: "Agenda not found." });
|
|
277
|
+
const M = m.batch();
|
|
278
|
+
return M.set(C, {
|
|
279
|
+
schema: a(o?.metadataSchema),
|
|
280
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
281
|
+
}, { merge: !0 }), M.set(w, r(), { merge: !0 }), await M.commit(), { success: !0 };
|
|
282
|
+
} catch (o) {
|
|
283
|
+
throw console.error("Appointments handler — metadata schema save error:", o), p({
|
|
284
|
+
statusCode: o.statusCode || 500,
|
|
285
|
+
statusMessage: o.statusMessage || "Failed to save metadata schema"
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
})), u.get("/appointments", h(async (e) => {
|
|
289
|
+
const n = I(e), o = Math.min(Number(n.quantity) || 20, 100), d = n.status || "confirmed";
|
|
290
|
+
try {
|
|
291
|
+
const { firebase: g, reservationsCollection: m } = await t(e), C = (await g.firestore().collection(m).orderBy("createdAt", "desc").where("status", "==", d).limit(o).get()).docs.flatMap(
|
|
292
|
+
(R) => c(S({ id: R.id, ...R.data() }))
|
|
182
293
|
);
|
|
183
294
|
return {
|
|
184
|
-
count:
|
|
185
|
-
appointments:
|
|
295
|
+
count: C.length,
|
|
296
|
+
appointments: C
|
|
186
297
|
};
|
|
187
|
-
} catch (
|
|
188
|
-
throw console.error("Appointments handler — list error:",
|
|
189
|
-
statusCode:
|
|
190
|
-
statusMessage:
|
|
298
|
+
} catch (g) {
|
|
299
|
+
throw console.error("Appointments handler — list error:", g), p({
|
|
300
|
+
statusCode: g.statusCode || 500,
|
|
301
|
+
statusMessage: g.statusMessage || "Failed to list appointments"
|
|
191
302
|
});
|
|
192
303
|
}
|
|
193
|
-
})),
|
|
194
|
-
const
|
|
304
|
+
})), u.get("/appointments/find", h(async (e) => {
|
|
305
|
+
const n = I(e), o = (n.name || "").toLowerCase().trim(), d = (n.email || "").toLowerCase().trim(), g = n.date;
|
|
195
306
|
try {
|
|
196
|
-
const { firebase:
|
|
197
|
-
let
|
|
198
|
-
|
|
199
|
-
let
|
|
200
|
-
(
|
|
307
|
+
const { firebase: m, reservationsCollection: w } = await t(e);
|
|
308
|
+
let C = m.firestore().collection(w);
|
|
309
|
+
d && (C = C.where("customerInfo.email", "==", d));
|
|
310
|
+
let M = (await C.orderBy("createdAt", "desc").limit(200).get()).docs.flatMap(
|
|
311
|
+
(k) => c(S({ id: k.id, ...k.data() }))
|
|
201
312
|
);
|
|
202
|
-
return
|
|
203
|
-
const
|
|
204
|
-
return
|
|
313
|
+
return g && (M = M.filter((k) => k.date === g)), o && (M = M.filter((k) => {
|
|
314
|
+
const q = (k.customerInfo?.firstName || "").toLowerCase(), N = (k.customerInfo?.lastName || "").toLowerCase();
|
|
315
|
+
return q.includes(o) || N.includes(o) || `${q} ${N}`.includes(o);
|
|
205
316
|
})), {
|
|
206
|
-
count:
|
|
207
|
-
appointments:
|
|
317
|
+
count: M.length,
|
|
318
|
+
appointments: M
|
|
208
319
|
};
|
|
209
|
-
} catch (
|
|
210
|
-
throw console.error("Appointments handler — find error:",
|
|
211
|
-
statusCode:
|
|
212
|
-
statusMessage:
|
|
320
|
+
} catch (m) {
|
|
321
|
+
throw console.error("Appointments handler — find error:", m), p({
|
|
322
|
+
statusCode: m.statusCode || 500,
|
|
323
|
+
statusMessage: m.statusMessage || "Failed to find appointments"
|
|
213
324
|
});
|
|
214
325
|
}
|
|
215
|
-
})),
|
|
216
|
-
const
|
|
217
|
-
if (!
|
|
218
|
-
throw
|
|
326
|
+
})), u.get("/appointments/:appointmentId", h(async (e) => {
|
|
327
|
+
const n = F(e, "appointmentId");
|
|
328
|
+
if (!n)
|
|
329
|
+
throw p({ statusCode: 400, statusMessage: "Appointment ID is required." });
|
|
219
330
|
try {
|
|
220
|
-
const { firebase:
|
|
221
|
-
if (!
|
|
222
|
-
throw
|
|
223
|
-
const
|
|
331
|
+
const { firebase: o, reservationsCollection: d } = await t(e), g = await o.firestore().collection(d).doc(n).get();
|
|
332
|
+
if (!g.exists)
|
|
333
|
+
throw p({ statusCode: 404, statusMessage: "Appointment not found." });
|
|
334
|
+
const m = S({ id: g.id, ...g.data() });
|
|
224
335
|
return {
|
|
225
|
-
...
|
|
226
|
-
reservations:
|
|
336
|
+
...m,
|
|
337
|
+
reservations: c(m)
|
|
227
338
|
};
|
|
228
|
-
} catch (
|
|
229
|
-
throw console.error("Appointments handler — get error:",
|
|
230
|
-
statusCode:
|
|
231
|
-
statusMessage:
|
|
339
|
+
} catch (o) {
|
|
340
|
+
throw console.error("Appointments handler — get error:", o), p({
|
|
341
|
+
statusCode: o.statusCode || 500,
|
|
342
|
+
statusMessage: o.statusMessage || "Failed to get appointment"
|
|
232
343
|
});
|
|
233
344
|
}
|
|
234
|
-
})),
|
|
345
|
+
})), u.handler;
|
|
235
346
|
}
|
|
236
|
-
const
|
|
347
|
+
const x = "https://analyticsdata.googleapis.com/v1beta", H = [
|
|
237
348
|
"https://www.googleapis.com/auth/analytics.readonly",
|
|
238
349
|
"https://www.googleapis.com/auth/webmasters.readonly"
|
|
239
|
-
],
|
|
240
|
-
function
|
|
241
|
-
const { decrypt: P, getGoogleAccessToken:
|
|
242
|
-
async function
|
|
243
|
-
const { supabase:
|
|
244
|
-
if (a || !
|
|
245
|
-
throw
|
|
246
|
-
const
|
|
247
|
-
if (!
|
|
248
|
-
throw
|
|
249
|
-
if (!
|
|
250
|
-
throw
|
|
251
|
-
const { data:
|
|
252
|
-
let
|
|
253
|
-
if (
|
|
254
|
-
const { data:
|
|
255
|
-
if (
|
|
256
|
-
throw
|
|
257
|
-
|
|
350
|
+
], B = "https://searchconsole.googleapis.com/webmasters/v3";
|
|
351
|
+
function W(A) {
|
|
352
|
+
const { decrypt: P, getGoogleAccessToken: S } = A, f = E();
|
|
353
|
+
async function u(t) {
|
|
354
|
+
const { supabase: c, instanceId: i } = t.context.module, { data: s, error: a } = await c.from("project_modules").select("config").eq("id", i).single();
|
|
355
|
+
if (a || !s?.config)
|
|
356
|
+
throw p({ statusCode: 500, statusMessage: "Failed to load module config." });
|
|
357
|
+
const r = s.config, e = r.propertyId, n = r.serviceAccount, o = r.siteUrl || "";
|
|
358
|
+
if (!n)
|
|
359
|
+
throw p({ statusCode: 400, statusMessage: "No Google Service Account configured for this module." });
|
|
360
|
+
if (!e)
|
|
361
|
+
throw p({ statusCode: 400, statusMessage: "No GA4 Property ID configured for this module." });
|
|
362
|
+
const { data: d, error: g } = await c.from("integrations").select("config").eq("id", n).single();
|
|
363
|
+
let m = d?.config;
|
|
364
|
+
if (g || !m) {
|
|
365
|
+
const { data: k, error: q } = await c.from("agency_integrations").select("config").eq("id", n).single();
|
|
366
|
+
if (q || !k?.config)
|
|
367
|
+
throw p({ statusCode: 500, statusMessage: "Failed to load Google Service Account credentials." });
|
|
368
|
+
m = k.config;
|
|
258
369
|
}
|
|
259
|
-
const
|
|
260
|
-
return { accessToken: await
|
|
261
|
-
{ clientEmail:
|
|
262
|
-
|
|
263
|
-
), propertyId:
|
|
370
|
+
const w = P(m.clientEmail), C = P(m.privateKey), R = P(m.projectId);
|
|
371
|
+
return { accessToken: await S(
|
|
372
|
+
{ clientEmail: w, privateKey: C, projectId: R },
|
|
373
|
+
H
|
|
374
|
+
), propertyId: e, siteUrl: o };
|
|
264
375
|
}
|
|
265
|
-
async function
|
|
266
|
-
const
|
|
376
|
+
async function l(t, c, i) {
|
|
377
|
+
const s = await fetch(`${x}/properties/${c}:runReport`, {
|
|
267
378
|
method: "POST",
|
|
268
379
|
headers: {
|
|
269
|
-
Authorization: `Bearer ${
|
|
380
|
+
Authorization: `Bearer ${t}`,
|
|
270
381
|
"Content-Type": "application/json"
|
|
271
382
|
},
|
|
272
|
-
body: JSON.stringify(
|
|
383
|
+
body: JSON.stringify(i)
|
|
273
384
|
});
|
|
274
|
-
if (!
|
|
275
|
-
const a = await
|
|
276
|
-
throw console.error("GA4 runReport failed:", a),
|
|
277
|
-
statusCode:
|
|
385
|
+
if (!s.ok) {
|
|
386
|
+
const a = await s.json().catch(() => ({}));
|
|
387
|
+
throw console.error("GA4 runReport failed:", a), p({
|
|
388
|
+
statusCode: s.status,
|
|
278
389
|
statusMessage: a?.error?.message || "GA4 API request failed"
|
|
279
390
|
});
|
|
280
391
|
}
|
|
281
|
-
return
|
|
392
|
+
return s.json();
|
|
282
393
|
}
|
|
283
|
-
|
|
394
|
+
f.get(
|
|
284
395
|
"/report",
|
|
285
|
-
|
|
286
|
-
const { accessToken:
|
|
396
|
+
h(async (t) => {
|
|
397
|
+
const { accessToken: c, propertyId: i } = await u(t), s = I(t), a = s.startDate || "30daysAgo", r = s.endDate || "today", e = a.match(/^(\d+)daysAgo$/), n = e ? parseInt(e[1], 10) : 30, o = `${n * 2}daysAgo`, d = `${n + 1}daysAgo`, g = [
|
|
287
398
|
{ name: "sessions" },
|
|
288
399
|
{ name: "totalUsers" },
|
|
289
400
|
{ name: "screenPageViews" },
|
|
@@ -294,38 +405,38 @@ function G(h) {
|
|
|
294
405
|
{ name: "sessionsPerUser" },
|
|
295
406
|
{ name: "screenPageViewsPerSession" }
|
|
296
407
|
];
|
|
297
|
-
let
|
|
408
|
+
let m, w = !0;
|
|
298
409
|
try {
|
|
299
|
-
|
|
410
|
+
m = await l(c, i, {
|
|
300
411
|
dateRanges: [
|
|
301
|
-
{ startDate: a, endDate:
|
|
302
|
-
{ startDate:
|
|
412
|
+
{ startDate: a, endDate: r, name: "current" },
|
|
413
|
+
{ startDate: o, endDate: d, name: "previous" }
|
|
303
414
|
],
|
|
304
415
|
dimensions: [{ name: "date" }],
|
|
305
|
-
metrics:
|
|
416
|
+
metrics: g,
|
|
306
417
|
metricAggregations: ["TOTAL"],
|
|
307
418
|
orderBys: [{ dimension: { dimensionName: "date" } }]
|
|
308
419
|
});
|
|
309
420
|
} catch {
|
|
310
|
-
|
|
311
|
-
dateRanges: [{ startDate: a, endDate:
|
|
421
|
+
w = !1, m = await l(c, i, {
|
|
422
|
+
dateRanges: [{ startDate: a, endDate: r }],
|
|
312
423
|
dimensions: [{ name: "date" }],
|
|
313
|
-
metrics:
|
|
424
|
+
metrics: g,
|
|
314
425
|
metricAggregations: ["TOTAL"],
|
|
315
426
|
orderBys: [{ dimension: { dimensionName: "date" } }]
|
|
316
427
|
});
|
|
317
428
|
}
|
|
318
|
-
return
|
|
429
|
+
return L(m, w);
|
|
319
430
|
})
|
|
320
|
-
),
|
|
431
|
+
), f.get(
|
|
321
432
|
"/realtime",
|
|
322
|
-
|
|
323
|
-
const { accessToken:
|
|
324
|
-
`${
|
|
433
|
+
h(async (t) => {
|
|
434
|
+
const { accessToken: c, propertyId: i } = await u(t), s = await fetch(
|
|
435
|
+
`${x}/properties/${i}:runRealtimeReport`,
|
|
325
436
|
{
|
|
326
437
|
method: "POST",
|
|
327
438
|
headers: {
|
|
328
|
-
Authorization: `Bearer ${
|
|
439
|
+
Authorization: `Bearer ${c}`,
|
|
329
440
|
"Content-Type": "application/json"
|
|
330
441
|
},
|
|
331
442
|
body: JSON.stringify({
|
|
@@ -336,24 +447,24 @@ function G(h) {
|
|
|
336
447
|
})
|
|
337
448
|
}
|
|
338
449
|
);
|
|
339
|
-
if (!
|
|
340
|
-
const
|
|
341
|
-
throw
|
|
450
|
+
if (!s.ok) {
|
|
451
|
+
const n = await s.json().catch(() => ({}));
|
|
452
|
+
throw p({ statusCode: s.status, statusMessage: n?.error?.message || "Realtime API failed" });
|
|
342
453
|
}
|
|
343
|
-
const a = await
|
|
344
|
-
(
|
|
454
|
+
const a = await s.json(), r = (a?.rows || []).reduce(
|
|
455
|
+
(n, o) => n + parseInt(o.metricValues?.[0]?.value || "0", 10),
|
|
345
456
|
0
|
|
346
|
-
),
|
|
347
|
-
page:
|
|
348
|
-
activeUsers: parseInt(
|
|
457
|
+
), e = (a?.rows || []).map((n) => ({
|
|
458
|
+
page: n.dimensionValues?.[0]?.value || "(not set)",
|
|
459
|
+
activeUsers: parseInt(n.metricValues?.[0]?.value || "0", 10)
|
|
349
460
|
}));
|
|
350
|
-
return { activeUsers:
|
|
461
|
+
return { activeUsers: r, activePages: e };
|
|
351
462
|
})
|
|
352
|
-
),
|
|
463
|
+
), f.get(
|
|
353
464
|
"/top-pages",
|
|
354
|
-
|
|
355
|
-
const { accessToken:
|
|
356
|
-
dateRanges: [{ startDate: a, endDate:
|
|
465
|
+
h(async (t) => {
|
|
466
|
+
const { accessToken: c, propertyId: i } = await u(t), s = I(t), a = s.startDate || "30daysAgo", r = s.endDate || "today", e = parseInt(s.limit || "10", 10), n = await l(c, i, {
|
|
467
|
+
dateRanges: [{ startDate: a, endDate: r }],
|
|
357
468
|
dimensions: [{ name: "pagePath" }],
|
|
358
469
|
metrics: [
|
|
359
470
|
{ name: "screenPageViews" },
|
|
@@ -361,25 +472,25 @@ function G(h) {
|
|
|
361
472
|
{ name: "averageSessionDuration" }
|
|
362
473
|
],
|
|
363
474
|
orderBys: [{ metric: { metricName: "screenPageViews" }, desc: !0 }],
|
|
364
|
-
limit:
|
|
475
|
+
limit: e * 2
|
|
365
476
|
// fetch extra to account for duplicates before aggregation
|
|
366
|
-
}),
|
|
367
|
-
for (const
|
|
368
|
-
const
|
|
369
|
-
if (
|
|
370
|
-
|
|
371
|
-
const
|
|
372
|
-
|
|
477
|
+
}), o = b(n, "pagePath"), d = /* @__PURE__ */ new Map();
|
|
478
|
+
for (const m of o.rows) {
|
|
479
|
+
const w = m.pagePath.toLowerCase().replace(/\/+$/, ""), C = d.get(w);
|
|
480
|
+
if (C) {
|
|
481
|
+
C.screenPageViews += m.screenPageViews || 0, C.totalUsers += m.totalUsers || 0;
|
|
482
|
+
const R = C.screenPageViews;
|
|
483
|
+
R > 0 && (C.averageSessionDuration = (C.averageSessionDuration * (R - (m.screenPageViews || 0)) + (m.averageSessionDuration || 0) * (m.screenPageViews || 0)) / R);
|
|
373
484
|
} else
|
|
374
|
-
|
|
485
|
+
d.set(w, { ...m });
|
|
375
486
|
}
|
|
376
|
-
return { rows: [...
|
|
487
|
+
return { rows: [...d.values()].sort((m, w) => (w.screenPageViews || 0) - (m.screenPageViews || 0)).slice(0, e), rowCount: o.rowCount };
|
|
377
488
|
})
|
|
378
|
-
),
|
|
489
|
+
), f.get(
|
|
379
490
|
"/top-sources",
|
|
380
|
-
|
|
381
|
-
const { accessToken:
|
|
382
|
-
dateRanges: [{ startDate: a, endDate:
|
|
491
|
+
h(async (t) => {
|
|
492
|
+
const { accessToken: c, propertyId: i } = await u(t), s = I(t), a = s.startDate || "30daysAgo", r = s.endDate || "today", e = await l(c, i, {
|
|
493
|
+
dateRanges: [{ startDate: a, endDate: r }],
|
|
383
494
|
dimensions: [{ name: "sessionSource" }],
|
|
384
495
|
metrics: [
|
|
385
496
|
{ name: "sessions" },
|
|
@@ -388,13 +499,13 @@ function G(h) {
|
|
|
388
499
|
orderBys: [{ metric: { metricName: "sessions" }, desc: !0 }],
|
|
389
500
|
limit: 10
|
|
390
501
|
});
|
|
391
|
-
return
|
|
502
|
+
return b(e, "sessionSource");
|
|
392
503
|
})
|
|
393
|
-
),
|
|
504
|
+
), f.get(
|
|
394
505
|
"/devices",
|
|
395
|
-
|
|
396
|
-
const { accessToken:
|
|
397
|
-
dateRanges: [{ startDate: a, endDate:
|
|
506
|
+
h(async (t) => {
|
|
507
|
+
const { accessToken: c, propertyId: i } = await u(t), s = I(t), a = s.startDate || "30daysAgo", r = s.endDate || "today", e = await l(c, i, {
|
|
508
|
+
dateRanges: [{ startDate: a, endDate: r }],
|
|
398
509
|
dimensions: [{ name: "deviceCategory" }],
|
|
399
510
|
metrics: [
|
|
400
511
|
{ name: "sessions" },
|
|
@@ -402,13 +513,13 @@ function G(h) {
|
|
|
402
513
|
],
|
|
403
514
|
orderBys: [{ metric: { metricName: "sessions" }, desc: !0 }]
|
|
404
515
|
});
|
|
405
|
-
return
|
|
516
|
+
return b(e, "deviceCategory");
|
|
406
517
|
})
|
|
407
|
-
),
|
|
518
|
+
), f.get(
|
|
408
519
|
"/countries",
|
|
409
|
-
|
|
410
|
-
const { accessToken:
|
|
411
|
-
dateRanges: [{ startDate: a, endDate:
|
|
520
|
+
h(async (t) => {
|
|
521
|
+
const { accessToken: c, propertyId: i } = await u(t), s = I(t), a = s.startDate || "30daysAgo", r = s.endDate || "today", e = await l(c, i, {
|
|
522
|
+
dateRanges: [{ startDate: a, endDate: r }],
|
|
412
523
|
dimensions: [{ name: "country" }],
|
|
413
524
|
metrics: [
|
|
414
525
|
{ name: "sessions" },
|
|
@@ -417,13 +528,13 @@ function G(h) {
|
|
|
417
528
|
orderBys: [{ metric: { metricName: "sessions" }, desc: !0 }],
|
|
418
529
|
limit: 10
|
|
419
530
|
});
|
|
420
|
-
return
|
|
531
|
+
return b(e, "country");
|
|
421
532
|
})
|
|
422
|
-
),
|
|
533
|
+
), f.get(
|
|
423
534
|
"/acquisition/channels",
|
|
424
|
-
|
|
425
|
-
const { accessToken:
|
|
426
|
-
dateRanges: [{ startDate: a, endDate:
|
|
535
|
+
h(async (t) => {
|
|
536
|
+
const { accessToken: c, propertyId: i } = await u(t), s = I(t), a = s.startDate || "30daysAgo", r = s.endDate || "today", e = await l(c, i, {
|
|
537
|
+
dateRanges: [{ startDate: a, endDate: r }],
|
|
427
538
|
dimensions: [{ name: "sessionDefaultChannelGroup" }],
|
|
428
539
|
metrics: [
|
|
429
540
|
{ name: "sessions" },
|
|
@@ -437,13 +548,13 @@ function G(h) {
|
|
|
437
548
|
orderBys: [{ metric: { metricName: "sessions" }, desc: !0 }],
|
|
438
549
|
limit: 15
|
|
439
550
|
});
|
|
440
|
-
return
|
|
551
|
+
return b(e, "sessionDefaultChannelGroup");
|
|
441
552
|
})
|
|
442
|
-
),
|
|
553
|
+
), f.get(
|
|
443
554
|
"/acquisition/source-medium",
|
|
444
|
-
|
|
445
|
-
const { accessToken:
|
|
446
|
-
dateRanges: [{ startDate: a, endDate:
|
|
555
|
+
h(async (t) => {
|
|
556
|
+
const { accessToken: c, propertyId: i } = await u(t), s = I(t), a = s.startDate || "30daysAgo", r = s.endDate || "today", e = await l(c, i, {
|
|
557
|
+
dateRanges: [{ startDate: a, endDate: r }],
|
|
447
558
|
dimensions: [{ name: "sessionSourceMedium" }],
|
|
448
559
|
metrics: [
|
|
449
560
|
{ name: "sessions" },
|
|
@@ -456,13 +567,13 @@ function G(h) {
|
|
|
456
567
|
orderBys: [{ metric: { metricName: "sessions" }, desc: !0 }],
|
|
457
568
|
limit: 20
|
|
458
569
|
});
|
|
459
|
-
return
|
|
570
|
+
return b(e, "sessionSourceMedium");
|
|
460
571
|
})
|
|
461
|
-
),
|
|
572
|
+
), f.get(
|
|
462
573
|
"/acquisition/referrals",
|
|
463
|
-
|
|
464
|
-
const { accessToken:
|
|
465
|
-
dateRanges: [{ startDate: a, endDate:
|
|
574
|
+
h(async (t) => {
|
|
575
|
+
const { accessToken: c, propertyId: i } = await u(t), s = I(t), a = s.startDate || "30daysAgo", r = s.endDate || "today", e = await l(c, i, {
|
|
576
|
+
dateRanges: [{ startDate: a, endDate: r }],
|
|
466
577
|
dimensions: [{ name: "sessionSource" }],
|
|
467
578
|
dimensionFilter: {
|
|
468
579
|
filter: {
|
|
@@ -479,13 +590,13 @@ function G(h) {
|
|
|
479
590
|
orderBys: [{ metric: { metricName: "sessions" }, desc: !0 }],
|
|
480
591
|
limit: 20
|
|
481
592
|
});
|
|
482
|
-
return
|
|
593
|
+
return b(e, "sessionSource");
|
|
483
594
|
})
|
|
484
|
-
),
|
|
595
|
+
), f.get(
|
|
485
596
|
"/acquisition/campaigns",
|
|
486
|
-
|
|
487
|
-
const { accessToken:
|
|
488
|
-
dateRanges: [{ startDate: a, endDate:
|
|
597
|
+
h(async (t) => {
|
|
598
|
+
const { accessToken: c, propertyId: i } = await u(t), s = I(t), a = s.startDate || "30daysAgo", r = s.endDate || "today", e = await l(c, i, {
|
|
599
|
+
dateRanges: [{ startDate: a, endDate: r }],
|
|
489
600
|
dimensions: [{ name: "sessionCampaignName" }],
|
|
490
601
|
dimensionFilter: {
|
|
491
602
|
notExpression: {
|
|
@@ -504,13 +615,13 @@ function G(h) {
|
|
|
504
615
|
orderBys: [{ metric: { metricName: "sessions" }, desc: !0 }],
|
|
505
616
|
limit: 20
|
|
506
617
|
});
|
|
507
|
-
return
|
|
618
|
+
return b(e, "sessionCampaignName");
|
|
508
619
|
})
|
|
509
|
-
),
|
|
620
|
+
), f.get(
|
|
510
621
|
"/content/all-pages",
|
|
511
|
-
|
|
512
|
-
const { accessToken:
|
|
513
|
-
dateRanges: [{ startDate: a, endDate:
|
|
622
|
+
h(async (t) => {
|
|
623
|
+
const { accessToken: c, propertyId: i } = await u(t), s = I(t), a = s.startDate || "30daysAgo", r = s.endDate || "today", e = parseInt(s.limit || "50", 10), n = await l(c, i, {
|
|
624
|
+
dateRanges: [{ startDate: a, endDate: r }],
|
|
514
625
|
dimensions: [{ name: "pagePath" }],
|
|
515
626
|
metrics: [
|
|
516
627
|
{ name: "screenPageViews" },
|
|
@@ -522,15 +633,15 @@ function G(h) {
|
|
|
522
633
|
{ name: "userEngagementDuration" }
|
|
523
634
|
],
|
|
524
635
|
orderBys: [{ metric: { metricName: "screenPageViews" }, desc: !0 }],
|
|
525
|
-
limit:
|
|
636
|
+
limit: e
|
|
526
637
|
});
|
|
527
|
-
return
|
|
638
|
+
return b(n, "pagePath");
|
|
528
639
|
})
|
|
529
|
-
),
|
|
640
|
+
), f.get(
|
|
530
641
|
"/content/landing-pages",
|
|
531
|
-
|
|
532
|
-
const { accessToken:
|
|
533
|
-
dateRanges: [{ startDate: a, endDate:
|
|
642
|
+
h(async (t) => {
|
|
643
|
+
const { accessToken: c, propertyId: i } = await u(t), s = I(t), a = s.startDate || "30daysAgo", r = s.endDate || "today", e = await l(c, i, {
|
|
644
|
+
dateRanges: [{ startDate: a, endDate: r }],
|
|
534
645
|
dimensions: [{ name: "landingPagePlusQueryString" }],
|
|
535
646
|
metrics: [
|
|
536
647
|
{ name: "sessions" },
|
|
@@ -543,13 +654,13 @@ function G(h) {
|
|
|
543
654
|
orderBys: [{ metric: { metricName: "sessions" }, desc: !0 }],
|
|
544
655
|
limit: 30
|
|
545
656
|
});
|
|
546
|
-
return
|
|
657
|
+
return b(e, "landingPagePlusQueryString");
|
|
547
658
|
})
|
|
548
|
-
),
|
|
659
|
+
), f.get(
|
|
549
660
|
"/content/exit-pages",
|
|
550
|
-
|
|
551
|
-
const { accessToken:
|
|
552
|
-
dateRanges: [{ startDate: a, endDate:
|
|
661
|
+
h(async (t) => {
|
|
662
|
+
const { accessToken: c, propertyId: i } = await u(t), s = I(t), a = s.startDate || "30daysAgo", r = s.endDate || "today", e = await l(c, i, {
|
|
663
|
+
dateRanges: [{ startDate: a, endDate: r }],
|
|
553
664
|
dimensions: [{ name: "pagePath" }],
|
|
554
665
|
metrics: [
|
|
555
666
|
{ name: "sessions" },
|
|
@@ -559,60 +670,60 @@ function G(h) {
|
|
|
559
670
|
],
|
|
560
671
|
orderBys: [{ metric: { metricName: "screenPageViews" }, desc: !0 }],
|
|
561
672
|
limit: 20
|
|
562
|
-
}),
|
|
563
|
-
return
|
|
564
|
-
...
|
|
565
|
-
exitRate:
|
|
566
|
-
})),
|
|
673
|
+
}), n = b(e, "pagePath");
|
|
674
|
+
return n.rows = n.rows.map((o) => ({
|
|
675
|
+
...o,
|
|
676
|
+
exitRate: o.bounceRate || 0
|
|
677
|
+
})), n;
|
|
567
678
|
})
|
|
568
|
-
),
|
|
679
|
+
), f.get(
|
|
569
680
|
"/content/search-terms",
|
|
570
|
-
|
|
571
|
-
const { accessToken:
|
|
572
|
-
if (
|
|
681
|
+
h(async (t) => {
|
|
682
|
+
const { accessToken: c, propertyId: i, siteUrl: s } = await u(t), a = I(t), r = a.startDate || "30daysAgo", e = a.endDate || "today";
|
|
683
|
+
if (s)
|
|
573
684
|
try {
|
|
574
|
-
const
|
|
575
|
-
|
|
685
|
+
const d = `${B}/sites/${encodeURIComponent(s)}/searchAnalytics/query`, g = await fetch(
|
|
686
|
+
d,
|
|
576
687
|
{
|
|
577
688
|
method: "POST",
|
|
578
689
|
headers: {
|
|
579
|
-
Authorization: `Bearer ${
|
|
690
|
+
Authorization: `Bearer ${c}`,
|
|
580
691
|
"Content-Type": "application/json"
|
|
581
692
|
},
|
|
582
693
|
body: JSON.stringify({
|
|
583
|
-
startDate:
|
|
584
|
-
endDate:
|
|
694
|
+
startDate: y(r),
|
|
695
|
+
endDate: y(e),
|
|
585
696
|
dimensions: ["query"],
|
|
586
697
|
rowLimit: 30
|
|
587
698
|
})
|
|
588
699
|
}
|
|
589
700
|
);
|
|
590
|
-
if (
|
|
591
|
-
const
|
|
592
|
-
query:
|
|
593
|
-
clicks:
|
|
594
|
-
impressions:
|
|
595
|
-
ctr:
|
|
596
|
-
position:
|
|
701
|
+
if (g.ok) {
|
|
702
|
+
const w = ((await g.json()).rows || []).map((C) => ({
|
|
703
|
+
query: C.keys[0],
|
|
704
|
+
clicks: C.clicks,
|
|
705
|
+
impressions: C.impressions,
|
|
706
|
+
ctr: C.ctr,
|
|
707
|
+
position: C.position
|
|
597
708
|
}));
|
|
598
|
-
if (
|
|
709
|
+
if (w.length > 0)
|
|
599
710
|
return {
|
|
600
|
-
rows:
|
|
601
|
-
rowCount:
|
|
711
|
+
rows: w,
|
|
712
|
+
rowCount: w.length,
|
|
602
713
|
source: "search_console"
|
|
603
714
|
};
|
|
604
715
|
} else {
|
|
605
|
-
const
|
|
606
|
-
console.error(`[GA Module] Search Console API error (${
|
|
716
|
+
const m = await g.text().catch(() => "");
|
|
717
|
+
console.error(`[GA Module] Search Console API error (${g.status}):`, m);
|
|
607
718
|
}
|
|
608
|
-
} catch (
|
|
609
|
-
console.error("[GA Module] Search Console request failed:",
|
|
719
|
+
} catch (d) {
|
|
720
|
+
console.error("[GA Module] Search Console request failed:", d?.message || d);
|
|
610
721
|
}
|
|
611
722
|
else
|
|
612
723
|
console.log("[GA Module] No siteUrl configured, skipping Search Console");
|
|
613
724
|
try {
|
|
614
|
-
const
|
|
615
|
-
dateRanges: [{ startDate:
|
|
725
|
+
const d = await l(c, i, {
|
|
726
|
+
dateRanges: [{ startDate: r, endDate: e }],
|
|
616
727
|
dimensions: [{ name: "sessionGoogleAdsQuery" }],
|
|
617
728
|
metrics: [
|
|
618
729
|
{ name: "sessions" },
|
|
@@ -643,13 +754,13 @@ function G(h) {
|
|
|
643
754
|
},
|
|
644
755
|
orderBys: [{ metric: { metricName: "sessions" }, desc: !0 }],
|
|
645
756
|
limit: 30
|
|
646
|
-
}),
|
|
647
|
-
if (
|
|
648
|
-
return { ...
|
|
757
|
+
}), g = b(d, "sessionGoogleAdsQuery");
|
|
758
|
+
if (g.rows.length > 0)
|
|
759
|
+
return { ...g, source: "google_ads" };
|
|
649
760
|
} catch {
|
|
650
761
|
}
|
|
651
|
-
const
|
|
652
|
-
dateRanges: [{ startDate:
|
|
762
|
+
const n = await l(c, i, {
|
|
763
|
+
dateRanges: [{ startDate: r, endDate: e }],
|
|
653
764
|
dimensions: [{ name: "landingPagePlusQueryString" }],
|
|
654
765
|
metrics: [
|
|
655
766
|
{ name: "sessions" },
|
|
@@ -682,13 +793,13 @@ function G(h) {
|
|
|
682
793
|
orderBys: [{ metric: { metricName: "sessions" }, desc: !0 }],
|
|
683
794
|
limit: 30
|
|
684
795
|
});
|
|
685
|
-
return { ...
|
|
796
|
+
return { ...b(n, "landingPagePlusQueryString"), source: "organic_landing_pages" };
|
|
686
797
|
})
|
|
687
|
-
),
|
|
798
|
+
), f.get(
|
|
688
799
|
"/audience/overview",
|
|
689
|
-
|
|
690
|
-
const { accessToken:
|
|
691
|
-
dateRanges: [{ startDate: a, endDate:
|
|
800
|
+
h(async (t) => {
|
|
801
|
+
const { accessToken: c, propertyId: i } = await u(t), s = I(t), a = s.startDate || "30daysAgo", r = s.endDate || "today", e = await l(c, i, {
|
|
802
|
+
dateRanges: [{ startDate: a, endDate: r }],
|
|
692
803
|
dimensions: [{ name: "newVsReturning" }],
|
|
693
804
|
metrics: [
|
|
694
805
|
{ name: "totalUsers" },
|
|
@@ -699,14 +810,14 @@ function G(h) {
|
|
|
699
810
|
],
|
|
700
811
|
metricAggregations: ["TOTAL"]
|
|
701
812
|
});
|
|
702
|
-
return
|
|
813
|
+
return b(e, "newVsReturning");
|
|
703
814
|
})
|
|
704
|
-
),
|
|
815
|
+
), f.get(
|
|
705
816
|
"/audience/technology",
|
|
706
|
-
|
|
707
|
-
const { accessToken:
|
|
708
|
-
dateRanges: [{ startDate: a, endDate:
|
|
709
|
-
dimensions: [{ name:
|
|
817
|
+
h(async (t) => {
|
|
818
|
+
const { accessToken: c, propertyId: i } = await u(t), s = I(t), a = s.startDate || "30daysAgo", r = s.endDate || "today", e = s.dimension || "browser", o = ["browser", "operatingSystem", "screenResolution"].includes(e) ? e : "browser", d = await l(c, i, {
|
|
819
|
+
dateRanges: [{ startDate: a, endDate: r }],
|
|
820
|
+
dimensions: [{ name: o }],
|
|
710
821
|
metrics: [
|
|
711
822
|
{ name: "totalUsers" },
|
|
712
823
|
{ name: "sessions" },
|
|
@@ -715,13 +826,13 @@ function G(h) {
|
|
|
715
826
|
orderBys: [{ metric: { metricName: "totalUsers" }, desc: !0 }],
|
|
716
827
|
limit: 10
|
|
717
828
|
});
|
|
718
|
-
return
|
|
829
|
+
return b(d, o);
|
|
719
830
|
})
|
|
720
|
-
),
|
|
831
|
+
), f.get(
|
|
721
832
|
"/audience/languages",
|
|
722
|
-
|
|
723
|
-
const { accessToken:
|
|
724
|
-
dateRanges: [{ startDate: a, endDate:
|
|
833
|
+
h(async (t) => {
|
|
834
|
+
const { accessToken: c, propertyId: i } = await u(t), s = I(t), a = s.startDate || "30daysAgo", r = s.endDate || "today", e = await l(c, i, {
|
|
835
|
+
dateRanges: [{ startDate: a, endDate: r }],
|
|
725
836
|
dimensions: [{ name: "language" }],
|
|
726
837
|
metrics: [
|
|
727
838
|
{ name: "totalUsers" },
|
|
@@ -730,13 +841,13 @@ function G(h) {
|
|
|
730
841
|
orderBys: [{ metric: { metricName: "totalUsers" }, desc: !0 }],
|
|
731
842
|
limit: 15
|
|
732
843
|
});
|
|
733
|
-
return
|
|
844
|
+
return b(e, "language");
|
|
734
845
|
})
|
|
735
|
-
),
|
|
846
|
+
), f.get(
|
|
736
847
|
"/audience/hours",
|
|
737
|
-
|
|
738
|
-
const { accessToken:
|
|
739
|
-
dateRanges: [{ startDate: a, endDate:
|
|
848
|
+
h(async (t) => {
|
|
849
|
+
const { accessToken: c, propertyId: i } = await u(t), s = I(t), a = s.startDate || "30daysAgo", r = s.endDate || "today", e = await l(c, i, {
|
|
850
|
+
dateRanges: [{ startDate: a, endDate: r }],
|
|
740
851
|
dimensions: [{ name: "dayOfWeekName" }, { name: "hour" }],
|
|
741
852
|
metrics: [{ name: "sessions" }],
|
|
742
853
|
orderBys: [
|
|
@@ -746,13 +857,13 @@ function G(h) {
|
|
|
746
857
|
limit: 168
|
|
747
858
|
// 7 days × 24 hours
|
|
748
859
|
});
|
|
749
|
-
return
|
|
860
|
+
return $(e, ["dayOfWeekName", "hour"]);
|
|
750
861
|
})
|
|
751
|
-
),
|
|
862
|
+
), f.get(
|
|
752
863
|
"/audience/cities",
|
|
753
|
-
|
|
754
|
-
const { accessToken:
|
|
755
|
-
dateRanges: [{ startDate: a, endDate:
|
|
864
|
+
h(async (t) => {
|
|
865
|
+
const { accessToken: c, propertyId: i } = await u(t), s = I(t), a = s.startDate || "30daysAgo", r = s.endDate || "today", e = await l(c, i, {
|
|
866
|
+
dateRanges: [{ startDate: a, endDate: r }],
|
|
756
867
|
dimensions: [{ name: "city" }, { name: "country" }],
|
|
757
868
|
metrics: [
|
|
758
869
|
{ name: "totalUsers" },
|
|
@@ -769,236 +880,236 @@ function G(h) {
|
|
|
769
880
|
orderBys: [{ metric: { metricName: "totalUsers" }, desc: !0 }],
|
|
770
881
|
limit: 20
|
|
771
882
|
});
|
|
772
|
-
return
|
|
883
|
+
return $(e, ["city", "country"]);
|
|
773
884
|
})
|
|
774
885
|
);
|
|
775
|
-
function
|
|
776
|
-
const
|
|
777
|
-
if (
|
|
778
|
-
const
|
|
779
|
-
return
|
|
886
|
+
function y(t) {
|
|
887
|
+
const c = t.match(/^(\d+)daysAgo$/);
|
|
888
|
+
if (c) {
|
|
889
|
+
const i = /* @__PURE__ */ new Date();
|
|
890
|
+
return i.setDate(i.getDate() - parseInt(c[1], 10)), i.toISOString().slice(0, 10);
|
|
780
891
|
}
|
|
781
|
-
if (
|
|
782
|
-
if (
|
|
783
|
-
const
|
|
784
|
-
return
|
|
892
|
+
if (t === "today") return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
893
|
+
if (t === "yesterday") {
|
|
894
|
+
const i = /* @__PURE__ */ new Date();
|
|
895
|
+
return i.setDate(i.getDate() - 1), i.toISOString().slice(0, 10);
|
|
785
896
|
}
|
|
786
|
-
return
|
|
897
|
+
return t;
|
|
787
898
|
}
|
|
788
|
-
async function
|
|
789
|
-
const
|
|
899
|
+
async function D(t, c, i) {
|
|
900
|
+
const s = `${B}/sites/${encodeURIComponent(c)}/searchAnalytics/query`, a = await fetch(s, {
|
|
790
901
|
method: "POST",
|
|
791
902
|
headers: {
|
|
792
|
-
Authorization: `Bearer ${
|
|
903
|
+
Authorization: `Bearer ${t}`,
|
|
793
904
|
"Content-Type": "application/json"
|
|
794
905
|
},
|
|
795
|
-
body: JSON.stringify(
|
|
906
|
+
body: JSON.stringify(i)
|
|
796
907
|
});
|
|
797
908
|
if (!a.ok) {
|
|
798
|
-
const
|
|
799
|
-
throw
|
|
909
|
+
const r = await a.json().catch(() => ({}));
|
|
910
|
+
throw p({
|
|
800
911
|
statusCode: a.status,
|
|
801
|
-
statusMessage:
|
|
912
|
+
statusMessage: r?.error?.message || "Search Console API request failed"
|
|
802
913
|
});
|
|
803
914
|
}
|
|
804
915
|
return a.json();
|
|
805
916
|
}
|
|
806
|
-
return
|
|
917
|
+
return f.get(
|
|
807
918
|
"/seo/keywords",
|
|
808
|
-
|
|
809
|
-
const { accessToken:
|
|
810
|
-
if (!
|
|
811
|
-
throw
|
|
812
|
-
const
|
|
919
|
+
h(async (t) => {
|
|
920
|
+
const { accessToken: c, siteUrl: i } = await u(t);
|
|
921
|
+
if (!i)
|
|
922
|
+
throw p({ statusCode: 400, statusMessage: "Search Console Site URL is not configured. Add it in module settings." });
|
|
923
|
+
const s = I(t), a = y(s.startDate || "30daysAgo"), r = y(s.endDate || "today"), e = Math.min(parseInt(s.limit) || 50, 100), n = await D(c, i, {
|
|
813
924
|
startDate: a,
|
|
814
|
-
endDate:
|
|
925
|
+
endDate: r,
|
|
815
926
|
dimensions: ["query"],
|
|
816
|
-
rowLimit:
|
|
927
|
+
rowLimit: e
|
|
817
928
|
});
|
|
818
929
|
return {
|
|
819
|
-
rows: (
|
|
820
|
-
query:
|
|
821
|
-
clicks:
|
|
822
|
-
impressions:
|
|
823
|
-
ctr:
|
|
824
|
-
position:
|
|
930
|
+
rows: (n.rows || []).map((o) => ({
|
|
931
|
+
query: o.keys[0],
|
|
932
|
+
clicks: o.clicks,
|
|
933
|
+
impressions: o.impressions,
|
|
934
|
+
ctr: o.ctr,
|
|
935
|
+
position: o.position
|
|
825
936
|
})),
|
|
826
|
-
rowCount:
|
|
937
|
+
rowCount: n.rows?.length || 0
|
|
827
938
|
};
|
|
828
939
|
})
|
|
829
|
-
),
|
|
940
|
+
), f.get(
|
|
830
941
|
"/seo/pages",
|
|
831
|
-
|
|
832
|
-
const { accessToken:
|
|
833
|
-
if (!
|
|
834
|
-
throw
|
|
835
|
-
const
|
|
942
|
+
h(async (t) => {
|
|
943
|
+
const { accessToken: c, siteUrl: i } = await u(t);
|
|
944
|
+
if (!i)
|
|
945
|
+
throw p({ statusCode: 400, statusMessage: "Search Console Site URL is not configured." });
|
|
946
|
+
const s = I(t), a = y(s.startDate || "30daysAgo"), r = y(s.endDate || "today"), e = Math.min(parseInt(s.limit) || 50, 100), n = await D(c, i, {
|
|
836
947
|
startDate: a,
|
|
837
|
-
endDate:
|
|
948
|
+
endDate: r,
|
|
838
949
|
dimensions: ["page"],
|
|
839
|
-
rowLimit:
|
|
950
|
+
rowLimit: e
|
|
840
951
|
});
|
|
841
952
|
return {
|
|
842
|
-
rows: (
|
|
843
|
-
page:
|
|
844
|
-
clicks:
|
|
845
|
-
impressions:
|
|
846
|
-
ctr:
|
|
847
|
-
position:
|
|
953
|
+
rows: (n.rows || []).map((o) => ({
|
|
954
|
+
page: o.keys[0],
|
|
955
|
+
clicks: o.clicks,
|
|
956
|
+
impressions: o.impressions,
|
|
957
|
+
ctr: o.ctr,
|
|
958
|
+
position: o.position
|
|
848
959
|
})),
|
|
849
|
-
rowCount:
|
|
960
|
+
rowCount: n.rows?.length || 0
|
|
850
961
|
};
|
|
851
962
|
})
|
|
852
|
-
),
|
|
963
|
+
), f.get(
|
|
853
964
|
"/seo/trends",
|
|
854
|
-
|
|
855
|
-
const { accessToken:
|
|
856
|
-
if (!
|
|
857
|
-
throw
|
|
858
|
-
const
|
|
965
|
+
h(async (t) => {
|
|
966
|
+
const { accessToken: c, siteUrl: i } = await u(t);
|
|
967
|
+
if (!i)
|
|
968
|
+
throw p({ statusCode: 400, statusMessage: "Search Console Site URL is not configured." });
|
|
969
|
+
const s = I(t), a = y(s.startDate || "30daysAgo"), r = y(s.endDate || "today"), n = ((await D(c, i, {
|
|
859
970
|
startDate: a,
|
|
860
|
-
endDate:
|
|
971
|
+
endDate: r,
|
|
861
972
|
dimensions: ["date"],
|
|
862
973
|
rowLimit: 500
|
|
863
|
-
})).rows || []).map((
|
|
864
|
-
date:
|
|
865
|
-
clicks:
|
|
866
|
-
impressions:
|
|
867
|
-
ctr:
|
|
868
|
-
position:
|
|
869
|
-
})).sort((
|
|
870
|
-
(
|
|
871
|
-
clicks:
|
|
872
|
-
impressions:
|
|
974
|
+
})).rows || []).map((d) => ({
|
|
975
|
+
date: d.keys[0],
|
|
976
|
+
clicks: d.clicks,
|
|
977
|
+
impressions: d.impressions,
|
|
978
|
+
ctr: d.ctr,
|
|
979
|
+
position: d.position
|
|
980
|
+
})).sort((d, g) => d.date.localeCompare(g.date)), o = n.reduce(
|
|
981
|
+
(d, g) => ({
|
|
982
|
+
clicks: d.clicks + g.clicks,
|
|
983
|
+
impressions: d.impressions + g.impressions
|
|
873
984
|
}),
|
|
874
985
|
{ clicks: 0, impressions: 0 }
|
|
875
986
|
);
|
|
876
|
-
return
|
|
987
|
+
return o.ctr = o.impressions > 0 ? o.clicks / o.impressions : 0, o.avgPosition = n.length > 0 ? n.reduce((d, g) => d + g.position, 0) / n.length : 0, { rows: n, totals: o, rowCount: n.length };
|
|
877
988
|
})
|
|
878
|
-
),
|
|
989
|
+
), f.get(
|
|
879
990
|
"/seo/query-pages",
|
|
880
|
-
|
|
881
|
-
const { accessToken:
|
|
882
|
-
if (!
|
|
883
|
-
throw
|
|
884
|
-
const
|
|
991
|
+
h(async (t) => {
|
|
992
|
+
const { accessToken: c, siteUrl: i } = await u(t);
|
|
993
|
+
if (!i)
|
|
994
|
+
throw p({ statusCode: 400, statusMessage: "Search Console Site URL is not configured." });
|
|
995
|
+
const s = I(t), a = y(s.startDate || "30daysAgo"), r = y(s.endDate || "today"), e = await D(c, i, {
|
|
885
996
|
startDate: a,
|
|
886
|
-
endDate:
|
|
997
|
+
endDate: r,
|
|
887
998
|
dimensions: ["query", "page"],
|
|
888
999
|
rowLimit: 100
|
|
889
1000
|
});
|
|
890
1001
|
return {
|
|
891
|
-
rows: (
|
|
892
|
-
query:
|
|
893
|
-
page:
|
|
894
|
-
clicks:
|
|
895
|
-
impressions:
|
|
896
|
-
ctr:
|
|
897
|
-
position:
|
|
1002
|
+
rows: (e.rows || []).map((n) => ({
|
|
1003
|
+
query: n.keys[0],
|
|
1004
|
+
page: n.keys[1],
|
|
1005
|
+
clicks: n.clicks,
|
|
1006
|
+
impressions: n.impressions,
|
|
1007
|
+
ctr: n.ctr,
|
|
1008
|
+
position: n.position
|
|
898
1009
|
})),
|
|
899
|
-
rowCount:
|
|
1010
|
+
rowCount: e.rows?.length || 0
|
|
900
1011
|
};
|
|
901
1012
|
})
|
|
902
|
-
),
|
|
1013
|
+
), f.handler;
|
|
903
1014
|
}
|
|
904
|
-
function
|
|
905
|
-
const
|
|
906
|
-
(
|
|
907
|
-
const
|
|
908
|
-
if (!
|
|
909
|
-
const
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
}),
|
|
1015
|
+
function L(A, P = !0) {
|
|
1016
|
+
const S = (A.metricHeaders || []).map((a) => a.name), u = (A.dimensionHeaders || []).map((a) => a.name).indexOf("date"), l = [];
|
|
1017
|
+
(A.rows || []).forEach((a) => {
|
|
1018
|
+
const r = u >= 0 ? a.dimensionValues[u]?.value : a.dimensionValues[0]?.value;
|
|
1019
|
+
if (!r || r.length < 8) return;
|
|
1020
|
+
const n = { date: `${r.slice(0, 4)}-${r.slice(4, 6)}-${r.slice(6, 8)}` };
|
|
1021
|
+
S.forEach((o, d) => {
|
|
1022
|
+
n[o] = parseFloat(a.metricValues[d]?.value || "0");
|
|
1023
|
+
}), l.push(n);
|
|
913
1024
|
});
|
|
914
|
-
const
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
}) :
|
|
918
|
-
|
|
1025
|
+
const y = {}, D = {};
|
|
1026
|
+
A.totals && A.totals.length >= 2 ? S.forEach((a, r) => {
|
|
1027
|
+
y[a] = parseFloat(A.totals[0]?.metricValues?.[r]?.value || "0"), D[a] = parseFloat(A.totals[1]?.metricValues?.[r]?.value || "0");
|
|
1028
|
+
}) : A.totals && A.totals.length === 1 && S.forEach((a, r) => {
|
|
1029
|
+
y[a] = parseFloat(A.totals[0]?.metricValues?.[r]?.value || "0");
|
|
919
1030
|
});
|
|
920
|
-
const
|
|
921
|
-
|
|
922
|
-
const
|
|
923
|
-
|
|
1031
|
+
const t = {};
|
|
1032
|
+
S.forEach((a) => {
|
|
1033
|
+
const r = y[a] || 0, e = D[a];
|
|
1034
|
+
e !== void 0 && e !== 0 ? t[a] = (r - e) / e * 100 : t[a] = null;
|
|
924
1035
|
});
|
|
925
|
-
const
|
|
926
|
-
for (const a of
|
|
927
|
-
|
|
928
|
-
const
|
|
1036
|
+
const c = /* @__PURE__ */ new Map();
|
|
1037
|
+
for (const a of l)
|
|
1038
|
+
c.has(a.date) || c.set(a.date, a);
|
|
1039
|
+
const i = Array.from(c.values()).sort((a, r) => a.date.localeCompare(r.date)), s = P && A.totals && A.totals.length >= 2 ? i.slice(-Math.ceil(i.length / 2)) : i;
|
|
929
1040
|
return {
|
|
930
|
-
rows:
|
|
931
|
-
totals:
|
|
932
|
-
previousTotals:
|
|
933
|
-
changes:
|
|
934
|
-
rowCount:
|
|
1041
|
+
rows: s,
|
|
1042
|
+
totals: y,
|
|
1043
|
+
previousTotals: D,
|
|
1044
|
+
changes: t,
|
|
1045
|
+
rowCount: s.length
|
|
935
1046
|
};
|
|
936
1047
|
}
|
|
937
|
-
function
|
|
938
|
-
const
|
|
939
|
-
const
|
|
940
|
-
[P]:
|
|
1048
|
+
function b(A, P) {
|
|
1049
|
+
const S = (A.metricHeaders || []).map((u) => u.name), f = (A.rows || []).map((u) => {
|
|
1050
|
+
const l = {
|
|
1051
|
+
[P]: u.dimensionValues[0].value
|
|
941
1052
|
};
|
|
942
|
-
return
|
|
943
|
-
|
|
944
|
-
}),
|
|
1053
|
+
return S.forEach((y, D) => {
|
|
1054
|
+
l[y] = parseFloat(u.metricValues[D].value);
|
|
1055
|
+
}), l;
|
|
945
1056
|
});
|
|
946
|
-
return { rows:
|
|
1057
|
+
return { rows: f, rowCount: A.rowCount || f.length };
|
|
947
1058
|
}
|
|
948
|
-
function
|
|
949
|
-
const
|
|
950
|
-
const
|
|
951
|
-
return P.forEach((
|
|
952
|
-
|
|
953
|
-
}),
|
|
954
|
-
|
|
955
|
-
}),
|
|
1059
|
+
function $(A, P) {
|
|
1060
|
+
const S = (A.metricHeaders || []).map((u) => u.name), f = (A.rows || []).map((u) => {
|
|
1061
|
+
const l = {};
|
|
1062
|
+
return P.forEach((y, D) => {
|
|
1063
|
+
l[y] = u.dimensionValues[D]?.value || "";
|
|
1064
|
+
}), S.forEach((y, D) => {
|
|
1065
|
+
l[y] = parseFloat(u.metricValues[D].value);
|
|
1066
|
+
}), l;
|
|
956
1067
|
});
|
|
957
|
-
return { rows:
|
|
1068
|
+
return { rows: f, rowCount: A.rowCount || f.length };
|
|
958
1069
|
}
|
|
959
|
-
function
|
|
960
|
-
const { decrypt: P } =
|
|
961
|
-
async function
|
|
962
|
-
const { supabase:
|
|
963
|
-
if (
|
|
964
|
-
throw
|
|
965
|
-
const
|
|
966
|
-
if (!
|
|
967
|
-
throw
|
|
968
|
-
const { data:
|
|
969
|
-
let
|
|
970
|
-
if (
|
|
971
|
-
const { data:
|
|
972
|
-
if (
|
|
973
|
-
throw
|
|
974
|
-
|
|
1070
|
+
function Y(A) {
|
|
1071
|
+
const { decrypt: P } = A, S = E();
|
|
1072
|
+
async function f(u) {
|
|
1073
|
+
const { supabase: l, instanceId: y } = u.context.module, { data: D, error: t } = await l.from("project_modules").select("config").eq("id", y).single();
|
|
1074
|
+
if (t || !D?.config)
|
|
1075
|
+
throw p({ statusCode: 500, statusMessage: "Failed to load module config." });
|
|
1076
|
+
const c = D.config, i = c.githubIntegration, s = c.githubRepo, a = c.githubOwner;
|
|
1077
|
+
if (!i || !s || !a)
|
|
1078
|
+
throw p({ statusCode: 400, statusMessage: "No GitHub integration configured for this module." });
|
|
1079
|
+
const { data: r, error: e } = await l.from("integrations").select("config").eq("id", i).single();
|
|
1080
|
+
let n = r?.config;
|
|
1081
|
+
if (e || !n) {
|
|
1082
|
+
const { data: d, error: g } = await l.from("agency_integrations").select("config").eq("id", i).single();
|
|
1083
|
+
if (g || !d?.config)
|
|
1084
|
+
throw p({ statusCode: 500, statusMessage: "Failed to load Github credentials." });
|
|
1085
|
+
n = d.config;
|
|
975
1086
|
}
|
|
976
|
-
return { token: P(
|
|
1087
|
+
return { token: P(n.token), repo: s, owner: a };
|
|
977
1088
|
}
|
|
978
|
-
return
|
|
1089
|
+
return S.post(
|
|
979
1090
|
"/github/deploy",
|
|
980
|
-
|
|
1091
|
+
h(async (u) => {
|
|
981
1092
|
try {
|
|
982
|
-
const { token:
|
|
983
|
-
await fetch(`https://api.github.com/repos/${
|
|
1093
|
+
const { token: l, repo: y, owner: D } = await f(u);
|
|
1094
|
+
await fetch(`https://api.github.com/repos/${D}/${y}/dispatches`, {
|
|
984
1095
|
method: "POST",
|
|
985
1096
|
headers: {
|
|
986
|
-
Authorization: `Bearer ${
|
|
1097
|
+
Authorization: `Bearer ${l}`,
|
|
987
1098
|
Accept: "application/vnd.github+json"
|
|
988
1099
|
},
|
|
989
1100
|
body: JSON.stringify({
|
|
990
1101
|
event_type: "deploy-site"
|
|
991
1102
|
})
|
|
992
1103
|
});
|
|
993
|
-
} catch (
|
|
994
|
-
throw console.error("Error triggering GitHub deployment:",
|
|
1104
|
+
} catch (l) {
|
|
1105
|
+
throw console.error("Error triggering GitHub deployment:", l), p({ statusCode: 500, statusMessage: "Failed to trigger deployment." });
|
|
995
1106
|
}
|
|
996
1107
|
})
|
|
997
|
-
),
|
|
1108
|
+
), S.handler;
|
|
998
1109
|
}
|
|
999
1110
|
export {
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1111
|
+
J as appointments,
|
|
1112
|
+
Y as contentManager,
|
|
1113
|
+
W as googleAnalytics,
|
|
1114
|
+
z as products
|
|
1004
1115
|
};
|