Google analytics integration.
Sentry.io integration. Vince integration. Region-scoped consent (denied-by-default in EU/EEA/UK/CH, granted elsewhere, DPDP-friendly notice)
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Generates dist/client/sitemap.xml after `vite build`.
|
||||
*
|
||||
* Static routes are listed explicitly; journal essay slugs are parsed from
|
||||
* src/data/catalog.ts so they stay in sync with the source of truth.
|
||||
* Dynamic product/collection pages are intentionally excluded for now —
|
||||
* they duplicate shop.mozimo.in content and churn constantly.
|
||||
*
|
||||
* Origin: SITE_ORIGIN env (default https://mozimo.in).
|
||||
*/
|
||||
import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
||||
import { join, dirname } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const root = join(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const origin = (process.env.SITE_ORIGIN ?? "https://mozimo.in").replace(
|
||||
/\/+$/,
|
||||
"",
|
||||
);
|
||||
|
||||
const STATIC_ROUTES = [
|
||||
{ path: "/", priority: 1.0, changefreq: "weekly" },
|
||||
{ path: "/chocolate", priority: 0.9, changefreq: "weekly" },
|
||||
{ path: "/gifting", priority: 0.9, changefreq: "weekly" },
|
||||
{ path: "/experiences", priority: 0.7, changefreq: "monthly" },
|
||||
{ path: "/bespoke", priority: 0.8, changefreq: "monthly" },
|
||||
{ path: "/contact", priority: 0.5, changefreq: "yearly" },
|
||||
{ path: "/our-world", priority: 0.6, changefreq: "monthly" },
|
||||
{ path: "/journal", priority: 0.6, changefreq: "monthly" },
|
||||
{ path: "/privacy", priority: 0.2, changefreq: "yearly" },
|
||||
];
|
||||
|
||||
// journal essay slugs live in src/data/catalog.ts (the essays block)
|
||||
const catalogSrc = readFileSync(join(root, "src/data/catalog.ts"), "utf8");
|
||||
const slugs = [...catalogSrc.matchAll(/^\s{4}slug:\s*"([^"]+)"/gm)].map(
|
||||
(m) => m[1],
|
||||
);
|
||||
|
||||
const today = new Date().toISOString().slice(0, 10);
|
||||
|
||||
const urls = [
|
||||
...STATIC_ROUTES,
|
||||
...slugs.map((slug) => ({
|
||||
path: `/journal/${slug}`,
|
||||
priority: 0.5,
|
||||
changefreq: "yearly",
|
||||
})),
|
||||
];
|
||||
|
||||
const xml = [
|
||||
'<?xml version="1.0" encoding="UTF-8"?>',
|
||||
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
|
||||
...urls.map(({ path, priority, changefreq }) =>
|
||||
[
|
||||
" <url>",
|
||||
` <loc>${origin}${path === "/" ? "/" : path}</loc>`,
|
||||
` <lastmod>${today}</lastmod>`,
|
||||
changefreq ? ` <changefreq>${changefreq}</changefreq>` : null,
|
||||
priority !== undefined ? ` <priority>${priority}</priority>` : null,
|
||||
" </url>",
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join("\n"),
|
||||
),
|
||||
"</urlset>",
|
||||
"",
|
||||
].join("\n");
|
||||
|
||||
const outDir = join(root, "dist/client");
|
||||
mkdirSync(outDir, { recursive: true });
|
||||
writeFileSync(join(outDir, "sitemap.xml"), xml, "utf8");
|
||||
console.log(
|
||||
`[sitemap] ${urls.length} URLs → dist/client/sitemap.xml (origin ${origin})`,
|
||||
);
|
||||
+38
-16
@@ -518,19 +518,29 @@ async function main() {
|
||||
// one-off migration: gifting tab CTAs must keep users on mozimo.in,
|
||||
// never bounce them out to the shopify domain
|
||||
if (name === "gifting_tabs") {
|
||||
const all = await authed(`/api/collections/${name}/records?perPage=100`);
|
||||
const all = await authed(
|
||||
`/api/collections/${name}/records?perPage=100`,
|
||||
);
|
||||
for (const rec of all.body.items ?? []) {
|
||||
const url = rec.cta_url ?? "";
|
||||
if (url.startsWith("https://shop.mozimo.in/")) {
|
||||
const internal = url.replace("https://shop.mozimo.in", "");
|
||||
const patched = await authed(`/api/collections/${name}/records/${rec.id}`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify({ cta_url: internal }),
|
||||
});
|
||||
const patched = await authed(
|
||||
`/api/collections/${name}/records/${rec.id}`,
|
||||
{
|
||||
method: "PATCH",
|
||||
body: JSON.stringify({ cta_url: internal }),
|
||||
},
|
||||
);
|
||||
if (patched.ok) {
|
||||
console.log(`[pb-seed] migrated cta_url for "${rec.name}" -> ${internal}`);
|
||||
console.log(
|
||||
`[pb-seed] migrated cta_url for "${rec.name}" -> ${internal}`,
|
||||
);
|
||||
} else {
|
||||
console.warn(`[pb-seed] cta migration failed for "${rec.name}":`, patched.status);
|
||||
console.warn(
|
||||
`[pb-seed] cta migration failed for "${rec.name}":`,
|
||||
patched.status,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -539,26 +549,34 @@ async function main() {
|
||||
// migration: fill section copy that arrived after the record was seeded
|
||||
// (only empty fields — anything edited in the admin is never overwritten)
|
||||
if (name === "gifting_page") {
|
||||
const rec = (await authed(`/api/collections/${name}/records?perPage=1`)).body.items?.[0];
|
||||
const rec = (await authed(`/api/collections/${name}/records?perPage=1`))
|
||||
.body.items?.[0];
|
||||
if (rec) {
|
||||
const patch = {};
|
||||
for (const [k, v] of Object.entries(SEEDS[name][0] ?? {})) {
|
||||
if (k !== "sort" && !rec[k]) patch[k] = v;
|
||||
}
|
||||
if (Object.keys(patch).length) {
|
||||
const patched = await authed(`/api/collections/${name}/records/${rec.id}`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify(patch),
|
||||
});
|
||||
const patched = await authed(
|
||||
`/api/collections/${name}/records/${rec.id}`,
|
||||
{
|
||||
method: "PATCH",
|
||||
body: JSON.stringify(patch),
|
||||
},
|
||||
);
|
||||
if (patched.ok)
|
||||
console.log(`[pb-seed] gifting_page: filled ${Object.keys(patch).length} empty field(s)`);
|
||||
console.log(
|
||||
`[pb-seed] gifting_page: filled ${Object.keys(patch).length} empty field(s)`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// migration: make sure editorial rows/settings that shipped later exist
|
||||
if (name === "collection_rows") {
|
||||
const all = (await authed(`/api/collections/${name}/records?perPage=100`)).body.items ?? [];
|
||||
const all =
|
||||
(await authed(`/api/collections/${name}/records?perPage=100`)).body
|
||||
.items ?? [];
|
||||
for (const row of COLLECTION_ROWS) {
|
||||
if (!all.some((r) => r.shopify_handle === row.shopify_handle)) {
|
||||
const inserted = await authed(`/api/collections/${name}/records`, {
|
||||
@@ -566,12 +584,16 @@ async function main() {
|
||||
body: JSON.stringify(row),
|
||||
});
|
||||
if (inserted.ok)
|
||||
console.log(`[pb-seed] collection_rows: added missing row "${row.name_override}"`);
|
||||
console.log(
|
||||
`[pb-seed] collection_rows: added missing row "${row.name_override}"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (name === "site_settings") {
|
||||
const all = (await authed(`/api/collections/${name}/records?perPage=100`)).body.items ?? [];
|
||||
const all =
|
||||
(await authed(`/api/collections/${name}/records?perPage=100`)).body
|
||||
.items ?? [];
|
||||
for (const setting of SITE_SETTINGS) {
|
||||
if (!all.some((r) => r.key === setting.key)) {
|
||||
const inserted = await authed(`/api/collections/${name}/records`, {
|
||||
|
||||
Reference in New Issue
Block a user