@mohasinac/appkit 2.7.4 → 2.7.5
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/_internal/server/features/seo/index.d.ts +8 -0
- package/dist/_internal/server/features/seo/index.js +4 -0
- package/dist/_internal/server/features/seo/manifest.d.ts +7 -0
- package/dist/_internal/server/features/seo/manifest.js +48 -0
- package/dist/_internal/server/features/seo/og.d.ts +11 -0
- package/dist/_internal/server/features/seo/og.js +52 -0
- package/dist/_internal/server/features/seo/robots.d.ts +5 -0
- package/dist/_internal/server/features/seo/robots.js +30 -0
- package/dist/_internal/server/features/seo/sitemap.d.ts +5 -0
- package/dist/_internal/server/features/seo/sitemap.js +254 -0
- package/dist/configs/next.js +5 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { buildRobots } from "./robots";
|
|
2
|
+
export type { RobotsOptions } from "./robots";
|
|
3
|
+
export { buildManifest } from "./manifest";
|
|
4
|
+
export type { ManifestOptions } from "./manifest";
|
|
5
|
+
export { buildSitemap } from "./sitemap";
|
|
6
|
+
export type { SitemapOptions } from "./sitemap";
|
|
7
|
+
export { buildDefaultOgImage, DEFAULT_OG_SIZE } from "./og";
|
|
8
|
+
export type { DefaultOgOptions } from "./og";
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ROUTES } from "../../../../next/routing/route-map";
|
|
2
|
+
export function buildManifest({ name, shortName, description }) {
|
|
3
|
+
return {
|
|
4
|
+
name,
|
|
5
|
+
short_name: shortName,
|
|
6
|
+
description,
|
|
7
|
+
start_url: "/",
|
|
8
|
+
display: "standalone",
|
|
9
|
+
orientation: "portrait",
|
|
10
|
+
background_color: "#ffffff",
|
|
11
|
+
theme_color: "#3570fc",
|
|
12
|
+
categories: ["shopping", "marketplace", "business"],
|
|
13
|
+
lang: "en",
|
|
14
|
+
dir: "ltr",
|
|
15
|
+
prefer_related_applications: false,
|
|
16
|
+
icons: [
|
|
17
|
+
{
|
|
18
|
+
src: "/favicon.svg",
|
|
19
|
+
sizes: "any",
|
|
20
|
+
type: "image/svg+xml",
|
|
21
|
+
purpose: "any maskable",
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
screenshots: [],
|
|
25
|
+
shortcuts: [
|
|
26
|
+
{
|
|
27
|
+
name: "Browse Products",
|
|
28
|
+
url: String(ROUTES.PUBLIC.PRODUCTS),
|
|
29
|
+
description: "Browse the latest products",
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: "Live Auctions",
|
|
33
|
+
url: String(ROUTES.PUBLIC.AUCTIONS),
|
|
34
|
+
description: "Join live auction bidding",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "Categories",
|
|
38
|
+
url: String(ROUTES.PUBLIC.CATEGORIES),
|
|
39
|
+
description: "Explore product categories",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "Stores",
|
|
43
|
+
url: String(ROUTES.PUBLIC.STORES),
|
|
44
|
+
description: "Browse seller storefronts",
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ImageResponse } from "next/og";
|
|
2
|
+
export declare const DEFAULT_OG_SIZE: {
|
|
3
|
+
width: number;
|
|
4
|
+
height: number;
|
|
5
|
+
};
|
|
6
|
+
export interface DefaultOgOptions {
|
|
7
|
+
siteName: string;
|
|
8
|
+
tagline?: string;
|
|
9
|
+
domain?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function buildDefaultOgImage({ siteName, tagline, domain }: DefaultOgOptions): ImageResponse;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ImageResponse } from "next/og";
|
|
3
|
+
export const DEFAULT_OG_SIZE = { width: 1200, height: 630 };
|
|
4
|
+
export function buildDefaultOgImage({ siteName, tagline, domain }) {
|
|
5
|
+
const subtitle = tagline ?? "Shop, Bid & Sell — India's Multi-Seller Marketplace";
|
|
6
|
+
return new ImageResponse(_jsxs("div", { style: {
|
|
7
|
+
width: "100%",
|
|
8
|
+
height: "100%",
|
|
9
|
+
display: "flex",
|
|
10
|
+
flexDirection: "column",
|
|
11
|
+
alignItems: "center",
|
|
12
|
+
justifyContent: "center",
|
|
13
|
+
background: "linear-gradient(135deg, #3570fc 0%, #65c408 50%, #e91e8c 100%)",
|
|
14
|
+
fontFamily: "sans-serif",
|
|
15
|
+
position: "relative",
|
|
16
|
+
overflow: "hidden",
|
|
17
|
+
}, children: [_jsx("div", { style: {
|
|
18
|
+
position: "absolute",
|
|
19
|
+
inset: 0,
|
|
20
|
+
opacity: 0.07,
|
|
21
|
+
backgroundImage: "radial-gradient(circle at 25% 25%, white 1px, transparent 0), radial-gradient(circle at 75% 75%, white 1px, transparent 0)",
|
|
22
|
+
backgroundSize: "48px 48px",
|
|
23
|
+
} }), _jsx("div", { style: {
|
|
24
|
+
display: "flex",
|
|
25
|
+
alignItems: "center",
|
|
26
|
+
justifyContent: "center",
|
|
27
|
+
width: 120,
|
|
28
|
+
height: 120,
|
|
29
|
+
borderRadius: 24,
|
|
30
|
+
background: "rgba(255,255,255,0.15)",
|
|
31
|
+
marginBottom: 32,
|
|
32
|
+
fontSize: 64,
|
|
33
|
+
}, children: "\uD83D\uDECD\uFE0F" }), _jsx("div", { style: {
|
|
34
|
+
fontSize: 80,
|
|
35
|
+
fontWeight: 800,
|
|
36
|
+
color: "white",
|
|
37
|
+
letterSpacing: "-2px",
|
|
38
|
+
marginBottom: 16,
|
|
39
|
+
textShadow: "0 4px 24px rgba(0,0,0,0.3)",
|
|
40
|
+
}, children: siteName }), _jsx("div", { style: {
|
|
41
|
+
fontSize: 32,
|
|
42
|
+
color: "rgba(255,255,255,0.85)",
|
|
43
|
+
fontWeight: 400,
|
|
44
|
+
letterSpacing: "0.5px",
|
|
45
|
+
}, children: subtitle }), domain && (_jsx("div", { style: {
|
|
46
|
+
position: "absolute",
|
|
47
|
+
bottom: 36,
|
|
48
|
+
fontSize: 22,
|
|
49
|
+
color: "rgba(255,255,255,0.6)",
|
|
50
|
+
letterSpacing: "1px",
|
|
51
|
+
}, children: domain }))] }), { ...DEFAULT_OG_SIZE });
|
|
52
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export function buildRobots({ siteUrl }) {
|
|
2
|
+
return {
|
|
3
|
+
rules: [
|
|
4
|
+
{
|
|
5
|
+
userAgent: "*",
|
|
6
|
+
allow: "/",
|
|
7
|
+
disallow: [
|
|
8
|
+
"/admin/",
|
|
9
|
+
"/api/",
|
|
10
|
+
"/seller/",
|
|
11
|
+
"/user/",
|
|
12
|
+
"/auth/",
|
|
13
|
+
"/checkout/",
|
|
14
|
+
"/cart/",
|
|
15
|
+
"/demo/",
|
|
16
|
+
"/track/",
|
|
17
|
+
"/unauthorized/",
|
|
18
|
+
"/_next/",
|
|
19
|
+
"/profile/*/edit",
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
userAgent: ["GPTBot", "ChatGPT-User", "Google-Extended", "CCBot"],
|
|
24
|
+
disallow: "/",
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
sitemap: `${siteUrl}/sitemap.xml`,
|
|
28
|
+
host: siteUrl,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { getAdminDb } from "../../../../providers/db-firebase";
|
|
2
|
+
import { ROUTES } from "../../../../next/routing/route-map";
|
|
3
|
+
import { PRODUCT_COLLECTION } from "../../../..";
|
|
4
|
+
import { EVENTS_COLLECTION, EVENT_FIELDS } from "../../../../features/events";
|
|
5
|
+
import { BLOG_POSTS_COLLECTION, BLOG_POST_FIELDS } from "../../../../features/blog";
|
|
6
|
+
import { CATEGORIES_COLLECTION, CATEGORY_FIELDS } from "../../../../features/categories";
|
|
7
|
+
import { STORE_COLLECTION, STORE_FIELDS } from "../../../../features/stores";
|
|
8
|
+
import { SCAMMER_COLLECTION } from "../../../../features/scams/schemas/firestore";
|
|
9
|
+
import { serverLogger } from "../../../../monitoring/server-logger";
|
|
10
|
+
// Product field strings — matches consumer field-names.ts
|
|
11
|
+
const PRODUCT_STATUS = "status";
|
|
12
|
+
const PRODUCT_STATUS_PUBLISHED = "published";
|
|
13
|
+
const PRODUCT_SLUG = "slug";
|
|
14
|
+
const PRODUCT_UPDATED_AT = "updatedAt";
|
|
15
|
+
function staticPages(baseUrl) {
|
|
16
|
+
const page = (path, changeFreq, priority) => ({ url: `${baseUrl}${path}`, lastModified: new Date(), changeFrequency: changeFreq, priority });
|
|
17
|
+
return [
|
|
18
|
+
page(String(ROUTES.HOME), "daily", 1.0),
|
|
19
|
+
page(String(ROUTES.PUBLIC.PRODUCTS), "hourly", 0.9),
|
|
20
|
+
page(String(ROUTES.PUBLIC.AUCTIONS), "hourly", 0.9),
|
|
21
|
+
page(String(ROUTES.PUBLIC.CATEGORIES), "weekly", 0.8),
|
|
22
|
+
page(String(ROUTES.PUBLIC.BLOG), "daily", 0.7),
|
|
23
|
+
page(String(ROUTES.PUBLIC.EVENTS), "daily", 0.7),
|
|
24
|
+
page(String(ROUTES.PUBLIC.SELLERS), "weekly", 0.6),
|
|
25
|
+
page(String(ROUTES.PUBLIC.ABOUT), "monthly", 0.5),
|
|
26
|
+
page(String(ROUTES.PUBLIC.CONTACT), "monthly", 0.5),
|
|
27
|
+
page(String(ROUTES.PUBLIC.FAQS), "monthly", 0.4),
|
|
28
|
+
page(String(ROUTES.PUBLIC.TERMS), "yearly", 0.3),
|
|
29
|
+
page(String(ROUTES.PUBLIC.PRIVACY), "yearly", 0.3),
|
|
30
|
+
page(String(ROUTES.PUBLIC.SECURITY), "yearly", 0.4),
|
|
31
|
+
page(String(ROUTES.PUBLIC.HELP), "monthly", 0.4),
|
|
32
|
+
page(String(ROUTES.PUBLIC.STORES), "weekly", 0.7),
|
|
33
|
+
page(String(ROUTES.PUBLIC.PROMOTIONS), "daily", 0.6),
|
|
34
|
+
page(String(ROUTES.PUBLIC.REVIEWS), "daily", 0.5),
|
|
35
|
+
page(String(ROUTES.PUBLIC.SELLER_GUIDE), "monthly", 0.5),
|
|
36
|
+
page(String(ROUTES.PUBLIC.COOKIE_POLICY), "yearly", 0.2),
|
|
37
|
+
page(String(ROUTES.PUBLIC.REFUND_POLICY), "yearly", 0.3),
|
|
38
|
+
page(String(ROUTES.PUBLIC.SHIPPING_POLICY), "yearly", 0.3),
|
|
39
|
+
page(String(ROUTES.PUBLIC.PRE_ORDERS), "daily", 0.7),
|
|
40
|
+
page(String(ROUTES.PUBLIC.FEES), "monthly", 0.4),
|
|
41
|
+
page(String(ROUTES.PUBLIC.HOW_AUCTIONS_WORK), "monthly", 0.4),
|
|
42
|
+
page(String(ROUTES.PUBLIC.HOW_PRE_ORDERS_WORK), "monthly", 0.4),
|
|
43
|
+
page(String(ROUTES.PUBLIC.HOW_OFFERS_WORK), "monthly", 0.4),
|
|
44
|
+
page(String(ROUTES.PUBLIC.HOW_CHECKOUT_WORKS), "monthly", 0.4),
|
|
45
|
+
page(String(ROUTES.PUBLIC.HOW_ORDERS_WORK), "monthly", 0.4),
|
|
46
|
+
page(String(ROUTES.PUBLIC.HOW_REVIEWS_WORK), "monthly", 0.4),
|
|
47
|
+
page(String(ROUTES.PUBLIC.HOW_PAYOUTS_WORK), "monthly", 0.4),
|
|
48
|
+
page(String(ROUTES.PUBLIC.SCAMS), "daily", 0.8),
|
|
49
|
+
page(String(ROUTES.PUBLIC.SCAM_TYPES), "monthly", 0.7),
|
|
50
|
+
page(String(ROUTES.PUBLIC.SCAM_REPORT), "monthly", 0.6),
|
|
51
|
+
page(String(ROUTES.PUBLIC.SCAM_FAQS), "weekly", 0.7),
|
|
52
|
+
];
|
|
53
|
+
}
|
|
54
|
+
async function fetchProductUrls(baseUrl) {
|
|
55
|
+
try {
|
|
56
|
+
const db = getAdminDb();
|
|
57
|
+
const snap = await db
|
|
58
|
+
.collection(PRODUCT_COLLECTION)
|
|
59
|
+
.where(PRODUCT_STATUS, "==", PRODUCT_STATUS_PUBLISHED)
|
|
60
|
+
.where("listingType", "==", "standard")
|
|
61
|
+
.select(PRODUCT_SLUG, PRODUCT_UPDATED_AT)
|
|
62
|
+
.limit(5000)
|
|
63
|
+
.get();
|
|
64
|
+
return snap.docs.map((doc) => {
|
|
65
|
+
const data = doc.data();
|
|
66
|
+
const slug = data[PRODUCT_SLUG] ?? doc.id;
|
|
67
|
+
return {
|
|
68
|
+
url: `${baseUrl}${ROUTES.PUBLIC.PRODUCT_DETAIL(slug)}`,
|
|
69
|
+
lastModified: data[PRODUCT_UPDATED_AT]?.toDate?.() ?? new Date(),
|
|
70
|
+
changeFrequency: "daily",
|
|
71
|
+
priority: 0.8,
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
serverLogger.warn("sitemap: failed to fetch product URLs", { error: err });
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async function fetchAuctionUrls(baseUrl) {
|
|
81
|
+
try {
|
|
82
|
+
const db = getAdminDb();
|
|
83
|
+
const snap = await db
|
|
84
|
+
.collection(PRODUCT_COLLECTION)
|
|
85
|
+
.where(PRODUCT_STATUS, "==", PRODUCT_STATUS_PUBLISHED)
|
|
86
|
+
.where("listingType", "==", "auction")
|
|
87
|
+
.select(PRODUCT_SLUG, PRODUCT_UPDATED_AT)
|
|
88
|
+
.limit(2000)
|
|
89
|
+
.get();
|
|
90
|
+
return snap.docs.map((doc) => {
|
|
91
|
+
const data = doc.data();
|
|
92
|
+
const slug = data[PRODUCT_SLUG] ?? doc.id;
|
|
93
|
+
return {
|
|
94
|
+
url: `${baseUrl}${ROUTES.PUBLIC.AUCTION_DETAIL(slug)}`,
|
|
95
|
+
lastModified: data[PRODUCT_UPDATED_AT]?.toDate?.() ?? new Date(),
|
|
96
|
+
changeFrequency: "daily",
|
|
97
|
+
priority: 0.8,
|
|
98
|
+
};
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
serverLogger.warn("sitemap: failed to fetch auction URLs", { error: err });
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async function fetchEventUrls(baseUrl) {
|
|
107
|
+
try {
|
|
108
|
+
const db = getAdminDb();
|
|
109
|
+
const snap = await db
|
|
110
|
+
.collection(EVENTS_COLLECTION)
|
|
111
|
+
.where(EVENT_FIELDS.STATUS, "==", EVENT_FIELDS.STATUS_VALUES.ACTIVE)
|
|
112
|
+
.select(EVENT_FIELDS.UPDATED_AT)
|
|
113
|
+
.limit(500)
|
|
114
|
+
.get();
|
|
115
|
+
return snap.docs.map((doc) => {
|
|
116
|
+
const data = doc.data();
|
|
117
|
+
return {
|
|
118
|
+
url: `${baseUrl}${ROUTES.PUBLIC.EVENT_DETAIL(doc.id)}`,
|
|
119
|
+
lastModified: data[EVENT_FIELDS.UPDATED_AT]?.toDate?.() ?? new Date(),
|
|
120
|
+
changeFrequency: "daily",
|
|
121
|
+
priority: 0.7,
|
|
122
|
+
};
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
serverLogger.warn("sitemap: failed to fetch event URLs", { error: err });
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async function fetchCategoryUrls(baseUrl) {
|
|
131
|
+
try {
|
|
132
|
+
const db = getAdminDb();
|
|
133
|
+
const snap = await db
|
|
134
|
+
.collection(CATEGORIES_COLLECTION)
|
|
135
|
+
.where(CATEGORY_FIELDS.IS_ACTIVE, "==", true)
|
|
136
|
+
.select(CATEGORY_FIELDS.SLUG, CATEGORY_FIELDS.UPDATED_AT)
|
|
137
|
+
.limit(500)
|
|
138
|
+
.get();
|
|
139
|
+
return snap.docs.map((doc) => {
|
|
140
|
+
const data = doc.data();
|
|
141
|
+
const slug = data[CATEGORY_FIELDS.SLUG] ?? doc.id;
|
|
142
|
+
return {
|
|
143
|
+
url: `${baseUrl}/categories/${slug}`,
|
|
144
|
+
lastModified: data[CATEGORY_FIELDS.UPDATED_AT]?.toDate?.() ?? new Date(),
|
|
145
|
+
changeFrequency: "weekly",
|
|
146
|
+
priority: 0.7,
|
|
147
|
+
};
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
serverLogger.warn("sitemap: failed to fetch category URLs", { error: err });
|
|
152
|
+
return [];
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async function fetchBlogPostUrls(baseUrl) {
|
|
156
|
+
try {
|
|
157
|
+
const db = getAdminDb();
|
|
158
|
+
const snap = await db
|
|
159
|
+
.collection(BLOG_POSTS_COLLECTION)
|
|
160
|
+
.where(BLOG_POST_FIELDS.STATUS, "==", BLOG_POST_FIELDS.STATUS_VALUES.PUBLISHED)
|
|
161
|
+
.select(BLOG_POST_FIELDS.SLUG, BLOG_POST_FIELDS.PUBLISHED_AT, BLOG_POST_FIELDS.UPDATED_AT)
|
|
162
|
+
.limit(1000)
|
|
163
|
+
.get();
|
|
164
|
+
return snap.docs.map((doc) => {
|
|
165
|
+
const data = doc.data();
|
|
166
|
+
const slug = data[BLOG_POST_FIELDS.SLUG] ?? doc.id;
|
|
167
|
+
const lastModified = data[BLOG_POST_FIELDS.UPDATED_AT]?.toDate?.() ??
|
|
168
|
+
data[BLOG_POST_FIELDS.PUBLISHED_AT]?.toDate?.() ??
|
|
169
|
+
new Date();
|
|
170
|
+
return {
|
|
171
|
+
url: `${baseUrl}${ROUTES.BLOG.ARTICLE(slug)}`,
|
|
172
|
+
lastModified,
|
|
173
|
+
changeFrequency: "weekly",
|
|
174
|
+
priority: 0.7,
|
|
175
|
+
};
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
catch (err) {
|
|
179
|
+
serverLogger.warn("sitemap: failed to fetch blog post URLs", { error: err });
|
|
180
|
+
return [];
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
async function fetchStoreUrls(baseUrl) {
|
|
184
|
+
try {
|
|
185
|
+
const db = getAdminDb();
|
|
186
|
+
const snap = await db
|
|
187
|
+
.collection(STORE_COLLECTION)
|
|
188
|
+
.where(STORE_FIELDS.STATUS, "==", STORE_FIELDS.STATUS_VALUES.ACTIVE)
|
|
189
|
+
.where(STORE_FIELDS.IS_PUBLIC, "==", true)
|
|
190
|
+
.select(STORE_FIELDS.STORE_SLUG, STORE_FIELDS.UPDATED_AT)
|
|
191
|
+
.limit(1000)
|
|
192
|
+
.get();
|
|
193
|
+
return snap.docs.map((doc) => {
|
|
194
|
+
const data = doc.data();
|
|
195
|
+
const slug = data[STORE_FIELDS.STORE_SLUG] ?? doc.id;
|
|
196
|
+
return {
|
|
197
|
+
url: `${baseUrl}${ROUTES.PUBLIC.STORE_DETAIL(slug)}`,
|
|
198
|
+
lastModified: data[STORE_FIELDS.UPDATED_AT]?.toDate?.() ?? new Date(),
|
|
199
|
+
changeFrequency: "weekly",
|
|
200
|
+
priority: 0.6,
|
|
201
|
+
};
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
serverLogger.warn("sitemap: failed to fetch store URLs", { error: err });
|
|
206
|
+
return [];
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
async function fetchScammerUrls(baseUrl) {
|
|
210
|
+
try {
|
|
211
|
+
const db = getAdminDb();
|
|
212
|
+
const snap = await db
|
|
213
|
+
.collection(SCAMMER_COLLECTION)
|
|
214
|
+
.where("status", "==", "verified")
|
|
215
|
+
.select("seo", "updatedAt")
|
|
216
|
+
.limit(2000)
|
|
217
|
+
.get();
|
|
218
|
+
return snap.docs.map((doc) => {
|
|
219
|
+
const data = doc.data();
|
|
220
|
+
const slug = data.seo?.slug ?? doc.id;
|
|
221
|
+
return {
|
|
222
|
+
url: `${baseUrl}${ROUTES.PUBLIC.SCAM_DETAIL(slug)}`,
|
|
223
|
+
lastModified: data.updatedAt?.toDate?.() ?? new Date(),
|
|
224
|
+
changeFrequency: "weekly",
|
|
225
|
+
priority: 0.7,
|
|
226
|
+
};
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
catch (err) {
|
|
230
|
+
serverLogger.warn("sitemap: failed to fetch scammer URLs", { error: err });
|
|
231
|
+
return [];
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
export async function buildSitemap({ baseUrl }) {
|
|
235
|
+
const [productUrls, categoryUrls, eventUrls, blogUrls, auctionUrls, storeUrls, scammerUrls] = await Promise.all([
|
|
236
|
+
fetchProductUrls(baseUrl),
|
|
237
|
+
fetchCategoryUrls(baseUrl),
|
|
238
|
+
fetchEventUrls(baseUrl),
|
|
239
|
+
fetchBlogPostUrls(baseUrl),
|
|
240
|
+
fetchAuctionUrls(baseUrl),
|
|
241
|
+
fetchStoreUrls(baseUrl),
|
|
242
|
+
fetchScammerUrls(baseUrl),
|
|
243
|
+
]);
|
|
244
|
+
return [
|
|
245
|
+
...staticPages(baseUrl),
|
|
246
|
+
...categoryUrls,
|
|
247
|
+
...blogUrls,
|
|
248
|
+
...productUrls,
|
|
249
|
+
...auctionUrls,
|
|
250
|
+
...eventUrls,
|
|
251
|
+
...storeUrls,
|
|
252
|
+
...scammerUrls,
|
|
253
|
+
];
|
|
254
|
+
}
|
package/dist/configs/next.js
CHANGED
|
@@ -108,6 +108,11 @@ export function defineNextConfig(override = {}) {
|
|
|
108
108
|
"./node_modules/duplexify/**",
|
|
109
109
|
"./node_modules/uuid/**",
|
|
110
110
|
"./node_modules/lodash.camelcase/**",
|
|
111
|
+
// gaxios transitive deps missing from Vercel tracer (dynamic require, not statically analysed)
|
|
112
|
+
"./node_modules/is-stream/**",
|
|
113
|
+
"./node_modules/extend/**",
|
|
114
|
+
"./node_modules/https-proxy-agent/**",
|
|
115
|
+
"./node_modules/agent-base/**",
|
|
111
116
|
],
|
|
112
117
|
};
|
|
113
118
|
const mergedOutputFileTracingIncludes = {
|
package/dist/server.d.ts
CHANGED
|
@@ -483,3 +483,5 @@ export { getStoreCapabilities, storeHasCapability, } from "./_internal/server/fe
|
|
|
483
483
|
export { isSoftBanned, getBanSummary } from "./features/auth/server/checkSoftBan";
|
|
484
484
|
export type { UserSoftBan } from "./features/auth/schemas/firestore";
|
|
485
485
|
export type { BannedAction } from "./features/auth/permissions/constants";
|
|
486
|
+
export { buildSitemap, buildRobots, buildManifest, buildDefaultOgImage, DEFAULT_OG_SIZE } from "./_internal/server/features/seo";
|
|
487
|
+
export type { SitemapOptions, RobotsOptions, ManifestOptions, DefaultOgOptions } from "./_internal/server/features/seo";
|
package/dist/server.js
CHANGED
|
@@ -1356,3 +1356,5 @@ export { getServerPermissions, checkPermission, checkAnyPermission, makeAdminSec
|
|
|
1356
1356
|
export { getStoreCapabilities, storeHasCapability, } from "./_internal/server/features/auth/capabilities";
|
|
1357
1357
|
// ── Soft ban helpers ──────────────────────────────────────────────────────────
|
|
1358
1358
|
export { isSoftBanned, getBanSummary } from "./features/auth/server/checkSoftBan";
|
|
1359
|
+
// -- SEO builders (sitemap / robots / manifest / og-image) --
|
|
1360
|
+
export { buildSitemap, buildRobots, buildManifest, buildDefaultOgImage, DEFAULT_OG_SIZE } from "./_internal/server/features/seo";
|