bsmnt 0.3.2 → 0.4.0
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/helpers/integrate/merge-config.js +1 -1
- package/dist/helpers/integrate/merge-config.js.map +1 -1
- package/dist/helpers/integrate/merge-orchestrator.d.ts.map +1 -1
- package/dist/helpers/integrate/merge-orchestrator.js +5 -5
- package/dist/helpers/integrate/merge-orchestrator.js.map +1 -1
- package/dist/helpers/integrate/sanity/config.d.ts.map +1 -1
- package/dist/helpers/integrate/sanity/config.js +2 -1
- package/dist/helpers/integrate/sanity/config.js.map +1 -1
- package/dist/helpers/integrate/sanity/mergers/sitemap-merger.d.ts +1 -3
- package/dist/helpers/integrate/sanity/mergers/sitemap-merger.d.ts.map +1 -1
- package/dist/helpers/integrate/sanity/mergers/sitemap-merger.js +117 -76
- package/dist/helpers/integrate/sanity/mergers/sitemap-merger.js.map +1 -1
- package/package.json +1 -1
- package/src/helpers/integrate/sanity/files/app/api/blog/[slug]/route.ts +2 -1
- package/src/helpers/integrate/sanity/files/app/api/revalidate/route.ts +4 -1
- package/src/helpers/integrate/sanity/files/app/blog/[slug]/page.tsx +3 -1
- package/src/helpers/integrate/sanity/files/app/layout.tsx +2 -2
- package/src/helpers/integrate/sanity/files/app/sitemap.md/route.ts +29 -18
- package/src/helpers/integrate/sanity/files/lib/integrations/sanity/WEBHOOK-SETUP.md +74 -0
- package/src/helpers/integrate/sanity/files/lib/integrations/sanity/env.ts +4 -2
- package/src/helpers/integrate/sanity/files/lib/integrations/sanity/queries.ts +42 -0
- package/src/helpers/integrate/sanity/files/lib/integrations/sanity/sitemap.ts +90 -0
- package/src/helpers/integrate/sanity/files/lib/utils/metadata.ts +2 -2
- package/src/helpers/integrate/sanity/files/lib/utils/url.ts +23 -0
- package/src/templates/next-default/.env.example +3 -3
- package/src/templates/next-default/app/layout.tsx +2 -2
- package/src/templates/next-default/app/robots.ts +2 -2
- package/src/templates/next-default/app/sitemap.xml/route.ts +51 -0
- package/src/templates/next-default/lib/utils/metadata.ts +2 -2
- package/src/templates/next-default/lib/utils/url.ts +16 -0
- package/src/templates/next-experiments/.env.example +3 -3
- package/src/templates/next-experiments/app/layout.tsx +2 -2
- package/src/templates/next-experiments/app/robots.ts +0 -4
- package/src/templates/next-experiments/lib/utils/metadata.ts +2 -2
- package/src/templates/next-experiments/lib/utils/url.ts +16 -0
- package/src/templates/next-pagebuilder/.biome/plugins/README.md +21 -0
- package/src/templates/next-pagebuilder/.biome/plugins/no-anchor-element.grit +12 -0
- package/src/templates/next-pagebuilder/.biome/plugins/no-relative-parent-imports.grit +10 -0
- package/src/templates/next-pagebuilder/.biome/plugins/no-unnecessary-forwardref.grit +9 -0
- package/src/templates/next-webgl/.env.example +3 -3
- package/src/templates/next-webgl/app/layout.tsx +2 -2
- package/src/templates/next-webgl/app/robots.ts +2 -2
- package/src/templates/next-webgl/app/sitemap.xml/route.ts +51 -0
- package/src/templates/next-webgl/lib/utils/metadata.ts +2 -2
- package/src/templates/next-webgl/lib/utils/url.ts +16 -0
- package/src/helpers/integrate/sanity/files/app/sitemap.ts +0 -61
- package/src/templates/next-default/app/sitemap.ts +0 -16
- package/src/templates/next-experiments/app/sitemap.ts +0 -16
- package/src/templates/next-webgl/app/sitemap.ts +0 -16
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge-config.js","sourceRoot":"","sources":["../../../src/helpers/integrate/merge-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,MAAM,UAAU,GAA+B;IAC9C,MAAM,EAAE;QACP,UAAU,EAAE;YACX,gBAAgB;YAChB,
|
|
1
|
+
{"version":3,"file":"merge-config.js","sourceRoot":"","sources":["../../../src/helpers/integrate/merge-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,MAAM,UAAU,GAA+B;IAC9C,MAAM,EAAE;QACP,UAAU,EAAE;YACX,gBAAgB;YAChB,0BAA0B;YAC1B,uCAAuC;SACvC;QAED,aAAa,EAAE;YACd,yBAAyB;YACzB,4BAA4B;YAC5B,oBAAoB;YACpB,oBAAoB;YACpB,YAAY;YACZ,cAAc;YACd,UAAU;YACV,gBAAgB;YAChB,uBAAuB;YACvB,uBAAuB;YACvB,wCAAwC;YACxC,4BAA4B;YAC5B,UAAU;SACV;KACD;CACD,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW;IACvC,OAAQ,UAAwC,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;AAC/D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACzC,OAAO,GAAG,IAAI,UAAU,CAAC;AAC1B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge-orchestrator.d.ts","sourceRoot":"","sources":["../../../src/helpers/integrate/merge-orchestrator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"merge-orchestrator.d.ts","sourceRoot":"","sources":["../../../src/helpers/integrate/merge-orchestrator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AA4FlE;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACtC,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,GAAG,GACV,OAAO,CAAC,YAAY,CAAC,CA6HvB"}
|
|
@@ -11,7 +11,7 @@ import { mergeSitemap } from "./sanity/mergers/sitemap-merger.js";
|
|
|
11
11
|
const CMS_MERGERS = {
|
|
12
12
|
sanity: {
|
|
13
13
|
"app/layout.tsx": mergeLayout,
|
|
14
|
-
"app/sitemap.ts": (templatePath) => mergeSitemap(templatePath),
|
|
14
|
+
"app/sitemap.xml/route.ts": (templatePath) => mergeSitemap(templatePath),
|
|
15
15
|
"lib/integrations/check-integration.ts": (templatePath) => mergeCheckIntegration(templatePath),
|
|
16
16
|
},
|
|
17
17
|
};
|
|
@@ -142,16 +142,16 @@ export async function injectIntegration(targetDir, cms, spinner) {
|
|
|
142
142
|
}
|
|
143
143
|
continue;
|
|
144
144
|
}
|
|
145
|
-
//
|
|
146
|
-
|
|
145
|
+
// Get the CMS-specific merger function (use base path for lookup)
|
|
146
|
+
const merger = getMerger(cms, mergeFile);
|
|
147
|
+
// Check if integration file exists (skip check if a merger handles it inline)
|
|
148
|
+
if (!merger && !(await fs.pathExists(integrationFile))) {
|
|
147
149
|
results.skipped.push({
|
|
148
150
|
path: transformedPath,
|
|
149
151
|
reason: "Not in integration",
|
|
150
152
|
});
|
|
151
153
|
continue;
|
|
152
154
|
}
|
|
153
|
-
// Get the CMS-specific merger function (use base path for lookup)
|
|
154
|
-
const merger = getMerger(cms, mergeFile);
|
|
155
155
|
if (merger) {
|
|
156
156
|
const result = await merger(templateFile, {
|
|
157
157
|
targetDir,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge-orchestrator.js","sourceRoot":"","sources":["../../../src/helpers/integrate/merge-orchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,UAAU,CAAC;AAE1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8CAA8C,CAAC;AACrF,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAsBlE;;GAEG;AACH,MAAM,WAAW,GAA6C;IAC7D,MAAM,EAAE;QACP,gBAAgB,EAAE,WAAW;QAC7B,
|
|
1
|
+
{"version":3,"file":"merge-orchestrator.js","sourceRoot":"","sources":["../../../src/helpers/integrate/merge-orchestrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../src/helpers/integrate/sanity/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,uBAAuB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,eAAO,MAAM,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../src/helpers/integrate/sanity/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,uBAAuB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,eAAO,MAAM,YAAY,EAAE,uBAsD1B,CAAC"}
|
|
@@ -37,6 +37,7 @@ export const sanityConfig = {
|
|
|
37
37
|
"app/api/blog",
|
|
38
38
|
"app/blog",
|
|
39
39
|
"app/sitemap.md",
|
|
40
|
+
"lib/utils/url.ts",
|
|
40
41
|
"lib/utils/json-ld.tsx",
|
|
41
42
|
"lib/utils/metadata.ts",
|
|
42
43
|
"lib/utils/portable-text-to-markdown.ts",
|
|
@@ -45,7 +46,7 @@ export const sanityConfig = {
|
|
|
45
46
|
],
|
|
46
47
|
mergeFiles: [
|
|
47
48
|
"app/layout.tsx",
|
|
48
|
-
"app/sitemap.ts",
|
|
49
|
+
"app/sitemap.xml/route.ts",
|
|
49
50
|
"lib/integrations/check-integration.ts",
|
|
50
51
|
],
|
|
51
52
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../../src/helpers/integrate/sanity/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,MAAM,CAAC,MAAM,YAAY,GAA4B;IACpD,IAAI,EAAE,QAAQ;IAEd,YAAY,EAAE;QACb,gBAAgB,EAAE,QAAQ;QAC1B,QAAQ,EAAE,QAAQ;QAClB,wBAAwB,EAAE,QAAQ;QAClC,qBAAqB,EAAE,SAAS;QAChC,qBAAqB,EAAE,QAAQ;QAC/B,mBAAmB,EAAE,QAAQ;QAC7B,wBAAwB,EAAE,QAAQ;QAClC,gBAAgB,EAAE,QAAQ;QAC1B,aAAa,EAAE,UAAU;QACzB,MAAM,EAAE,QAAQ;QAChB,qBAAqB,EAAE,QAAQ;KAC/B;IAED,eAAe,EAAE;QAChB,YAAY,EAAE,QAAQ;KACtB;IAED,OAAO,EAAE;QACR,gBAAgB,EACf,wFAAwF;QACzF,gBAAgB,EACf,0LAA0L;QAC3L,MAAM,EAAE,wBAAwB;QAChC,GAAG,EAAE,UAAU;QACf,QAAQ,EAAE,wBAAwB;QAClC,KAAK,EAAE,YAAY;KACnB;IAED,aAAa,EAAE;QACd,yBAAyB;QACzB,4BAA4B;QAC5B,oBAAoB;QACpB,oBAAoB;QACpB,YAAY;QACZ,cAAc;QACd,UAAU;QACV,gBAAgB;QAChB,uBAAuB;QACvB,uBAAuB;QACvB,wCAAwC;QACxC,4BAA4B;QAC5B,UAAU;KACV;IAED,UAAU,EAAE;QACX,gBAAgB;QAChB,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../../src/helpers/integrate/sanity/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,MAAM,CAAC,MAAM,YAAY,GAA4B;IACpD,IAAI,EAAE,QAAQ;IAEd,YAAY,EAAE;QACb,gBAAgB,EAAE,QAAQ;QAC1B,QAAQ,EAAE,QAAQ;QAClB,wBAAwB,EAAE,QAAQ;QAClC,qBAAqB,EAAE,SAAS;QAChC,qBAAqB,EAAE,QAAQ;QAC/B,mBAAmB,EAAE,QAAQ;QAC7B,wBAAwB,EAAE,QAAQ;QAClC,gBAAgB,EAAE,QAAQ;QAC1B,aAAa,EAAE,UAAU;QACzB,MAAM,EAAE,QAAQ;QAChB,qBAAqB,EAAE,QAAQ;KAC/B;IAED,eAAe,EAAE;QAChB,YAAY,EAAE,QAAQ;KACtB;IAED,OAAO,EAAE;QACR,gBAAgB,EACf,wFAAwF;QACzF,gBAAgB,EACf,0LAA0L;QAC3L,MAAM,EAAE,wBAAwB;QAChC,GAAG,EAAE,UAAU;QACf,QAAQ,EAAE,wBAAwB;QAClC,KAAK,EAAE,YAAY;KACnB;IAED,aAAa,EAAE;QACd,yBAAyB;QACzB,4BAA4B;QAC5B,oBAAoB;QACpB,oBAAoB;QACpB,YAAY;QACZ,cAAc;QACd,UAAU;QACV,gBAAgB;QAChB,kBAAkB;QAClB,uBAAuB;QACvB,uBAAuB;QACvB,wCAAwC;QACxC,4BAA4B;QAC5B,UAAU;KACV;IAED,UAAU,EAAE;QACX,gBAAgB;QAChB,0BAA0B;QAC1B,uCAAuC;KACvC;CACD,CAAC"}
|
|
@@ -4,9 +4,7 @@ interface MergeResult {
|
|
|
4
4
|
success?: boolean;
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
* Preserves all existing agnostic code (routes, baseRoutes structure)
|
|
9
|
-
* and injects Sanity-specific fetching logic.
|
|
7
|
+
* Replace the static sitemap.xml route with a Sanity-aware version.
|
|
10
8
|
*/
|
|
11
9
|
export declare function mergeSitemap(templatePath: string): Promise<MergeResult>;
|
|
12
10
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sitemap-merger.d.ts","sourceRoot":"","sources":["../../../../../src/helpers/integrate/sanity/mergers/sitemap-merger.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sitemap-merger.d.ts","sourceRoot":"","sources":["../../../../../src/helpers/integrate/sanity/mergers/sitemap-merger.ts"],"names":[],"mappings":"AAyHA,UAAU,WAAW;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,YAAY,CACjC,YAAY,EAAE,MAAM,GAClB,OAAO,CAAC,WAAW,CAAC,CAatB"}
|
|
@@ -1,92 +1,133 @@
|
|
|
1
1
|
import fs from "fs-extra";
|
|
2
2
|
/**
|
|
3
|
-
* Sanity-
|
|
3
|
+
* Sanity-aware sitemap.xml route.
|
|
4
|
+
* Replaces the static-only sitemap with one that dynamically imports Sanity
|
|
5
|
+
* client/queries to fetch CMS pages and articles when Sanity is configured,
|
|
6
|
+
* falling back to the homepage entry otherwise.
|
|
4
7
|
*/
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
8
|
+
const SANITY_SITEMAP_ROUTE = `import { NextResponse } from "next/server";
|
|
9
|
+
import { isSanityConfigured } from "@/lib/integrations/check-integration";
|
|
10
|
+
import { getBaseUrl } from "@/lib/utils/url";
|
|
11
|
+
|
|
12
|
+
export const dynamic = "force-dynamic";
|
|
13
|
+
|
|
14
|
+
interface SitemapEntry {
|
|
15
|
+
url: string;
|
|
16
|
+
lastModified?: string | null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const createPageEntry = (
|
|
20
|
+
baseUrl: string,
|
|
21
|
+
slug: string | null,
|
|
22
|
+
updatedAt?: string | null
|
|
23
|
+
): SitemapEntry => {
|
|
24
|
+
const path = slug ? \`/\${slug}\` : "";
|
|
25
|
+
return {
|
|
26
|
+
url: \`\${baseUrl}\${path}\`,
|
|
27
|
+
lastModified: updatedAt ?? null,
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const escapeXml = (value: string) =>
|
|
32
|
+
value
|
|
33
|
+
.replaceAll("&", "&")
|
|
34
|
+
.replaceAll("<", "<")
|
|
35
|
+
.replaceAll(">", ">")
|
|
36
|
+
.replaceAll('"', """)
|
|
37
|
+
.replaceAll("'", "'");
|
|
38
|
+
|
|
39
|
+
const renderUrl = (entry: SitemapEntry) => {
|
|
40
|
+
const parts = [" <url>", \` <loc>\${escapeXml(entry.url)}</loc>\`];
|
|
41
|
+
|
|
42
|
+
if (entry.lastModified) {
|
|
43
|
+
parts.push(
|
|
44
|
+
\` <lastmod>\${new Date(entry.lastModified).toISOString()}</lastmod>\`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
parts.push(" </url>");
|
|
49
|
+
|
|
50
|
+
return parts.join("\\n");
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const renderSitemap = (entries: SitemapEntry[]) =>
|
|
54
|
+
[
|
|
55
|
+
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
56
|
+
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
|
|
57
|
+
...entries.map(renderUrl),
|
|
58
|
+
"</urlset>",
|
|
59
|
+
].join("\\n");
|
|
60
|
+
|
|
61
|
+
const getSitemapResponse = (entries: SitemapEntry[]) =>
|
|
62
|
+
new NextResponse(renderSitemap(entries), {
|
|
63
|
+
headers: {
|
|
64
|
+
"Content-Type": "application/xml",
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
export const GET = async () => {
|
|
69
|
+
const baseUrl = getBaseUrl();
|
|
70
|
+
const homepageEntry = createPageEntry(baseUrl, null);
|
|
71
|
+
|
|
72
|
+
if (!isSanityConfigured()) return getSitemapResponse([homepageEntry]);
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
const { client } = await import("@/lib/integrations/sanity/client");
|
|
76
|
+
const {
|
|
77
|
+
SITEMAP_ARTICLES_QUERY,
|
|
78
|
+
SITEMAP_PAGES_QUERY,
|
|
79
|
+
} = await import("@/lib/integrations/sanity/queries");
|
|
80
|
+
|
|
81
|
+
if (!client) return getSitemapResponse([homepageEntry]);
|
|
82
|
+
|
|
83
|
+
type SanityDoc = {
|
|
84
|
+
title?: string;
|
|
85
|
+
slug: { current: string };
|
|
86
|
+
_updatedAt: string;
|
|
87
|
+
noIndex?: boolean;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const [articles, pages] = await Promise.all([
|
|
91
|
+
client.fetch<SanityDoc[]>(SITEMAP_ARTICLES_QUERY),
|
|
92
|
+
client.fetch<SanityDoc[]>(SITEMAP_PAGES_QUERY),
|
|
93
|
+
]);
|
|
94
|
+
|
|
95
|
+
const sitemapEntries: SitemapEntry[] = [homepageEntry];
|
|
96
|
+
|
|
97
|
+
for (const article of articles) {
|
|
98
|
+
if (!article.noIndex) {
|
|
99
|
+
sitemapEntries.push(
|
|
100
|
+
createPageEntry(baseUrl, \`blog/\${article.slug.current}\`, article._updatedAt)
|
|
101
|
+
);
|
|
27
102
|
}
|
|
103
|
+
}
|
|
28
104
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
_updatedAt
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
)) as SanityDocument[]
|
|
36
|
-
|
|
37
|
-
// Add articles to sitemap (exclude noIndex articles)
|
|
38
|
-
const articleEntries: MetadataRoute.Sitemap = articles
|
|
39
|
-
.filter((article: SanityDocument) => !article.metadata?.noIndex)
|
|
40
|
-
.map((article: SanityDocument) => ({
|
|
41
|
-
url: \`\${APP_BASE_URL}/blog/\${article.slug.current}\`,
|
|
42
|
-
lastModified: new Date(article._updatedAt),
|
|
43
|
-
changeFrequency: "weekly" as const,
|
|
44
|
-
priority: 0.7,
|
|
45
|
-
}))
|
|
46
|
-
|
|
47
|
-
return [...baseRoutes, ...articleEntries]
|
|
48
|
-
} catch (error) {
|
|
49
|
-
console.error("Error generating sitemap from Sanity:", error)
|
|
50
|
-
return baseRoutes
|
|
105
|
+
for (const page of pages) {
|
|
106
|
+
if (!page.noIndex) {
|
|
107
|
+
sitemapEntries.push(
|
|
108
|
+
createPageEntry(baseUrl, page.slug.current, page._updatedAt)
|
|
109
|
+
);
|
|
110
|
+
}
|
|
51
111
|
}
|
|
52
|
-
}
|
|
53
112
|
|
|
113
|
+
return getSitemapResponse(sitemapEntries);
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error("Error generating sitemap.xml:", error);
|
|
116
|
+
return getSitemapResponse([homepageEntry]);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
54
119
|
`;
|
|
55
120
|
/**
|
|
56
|
-
*
|
|
57
|
-
* Preserves all existing agnostic code (routes, baseRoutes structure)
|
|
58
|
-
* and injects Sanity-specific fetching logic.
|
|
121
|
+
* Replace the static sitemap.xml route with a Sanity-aware version.
|
|
59
122
|
*/
|
|
60
123
|
export async function mergeSitemap(templatePath) {
|
|
61
|
-
|
|
124
|
+
const content = await fs.readFile(templatePath, "utf-8");
|
|
62
125
|
// Skip if already has Sanity integration
|
|
63
|
-
if (content.includes("isSanityConfigured")
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
// 1. Add Sanity import after existing imports
|
|
67
|
-
const importMatches = [...content.matchAll(/^import .+$/gm)];
|
|
68
|
-
if (importMatches.length > 0) {
|
|
69
|
-
const lastImport = importMatches.at(-1);
|
|
70
|
-
if (lastImport && lastImport.index !== undefined) {
|
|
71
|
-
const insertPos = lastImport.index + lastImport[0].length;
|
|
72
|
-
content =
|
|
73
|
-
content.slice(0, insertPos) +
|
|
74
|
-
"\n" +
|
|
75
|
-
SANITY_IMPORT +
|
|
76
|
-
content.slice(insertPos);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
// 2. Add Sanity fetch logic before the final return statement
|
|
80
|
-
// Find the last "return baseRoutes" or "return [...baseRoutes" pattern
|
|
81
|
-
const returnMatch = content.match(/(\n)([ \t]*)(return\s+(?:baseRoutes|\[\.\.\.baseRoutes))/m);
|
|
82
|
-
if (returnMatch) {
|
|
83
|
-
const returnIndex = content.indexOf(returnMatch[0]);
|
|
84
|
-
content =
|
|
85
|
-
content.slice(0, returnIndex) +
|
|
86
|
-
SANITY_FETCH_LOGIC +
|
|
87
|
-
content.slice(returnIndex);
|
|
126
|
+
if (content.includes("isSanityConfigured") ||
|
|
127
|
+
content.includes("SITEMAP_ARTICLES_QUERY")) {
|
|
128
|
+
return { skipped: true, reason: "Already has Sanity sitemap integration" };
|
|
88
129
|
}
|
|
89
|
-
await fs.writeFile(templatePath,
|
|
130
|
+
await fs.writeFile(templatePath, SANITY_SITEMAP_ROUTE);
|
|
90
131
|
return { success: true };
|
|
91
132
|
}
|
|
92
133
|
//# sourceMappingURL=sitemap-merger.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sitemap-merger.js","sourceRoot":"","sources":["../../../../../src/helpers/integrate/sanity/mergers/sitemap-merger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,UAAU,CAAC;AAE1B
|
|
1
|
+
{"version":3,"file":"sitemap-merger.js","sourceRoot":"","sources":["../../../../../src/helpers/integrate/sanity/mergers/sitemap-merger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,UAAU,CAAC;AAE1B;;;;;GAKG;AACH,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+G5B,CAAC;AAQF;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CACjC,YAAoB;IAEpB,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAEzD,yCAAyC;IACzC,IACC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC;QACtC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EACzC,CAAC;QACF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,wCAAwC,EAAE,CAAC;IAC5E,CAAC;IAED,MAAM,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,oBAAoB,CAAC,CAAC;IACvD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC1B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { NextResponse } from "next/server";
|
|
2
2
|
import { portableTextToMarkdown } from "@/lib/utils/portable-text-to-markdown";
|
|
3
3
|
import { isSanityConfigured } from "@/lib/integrations/check-integration";
|
|
4
|
+
import { getBaseUrl } from "@/lib/utils/url";
|
|
4
5
|
import { ARTICLE_QUERY } from "@/lib/integrations/sanity/queries";
|
|
5
6
|
import { SanityFetch } from "@/lib/integrations/sanity/live";
|
|
6
7
|
import type { Article } from "@/lib/integrations/sanity/sanity.types";
|
|
@@ -16,7 +17,7 @@ export async function GET(
|
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
const slug = rawSlug.slice(0, -3);
|
|
19
|
-
const baseUrl =
|
|
20
|
+
const baseUrl = getBaseUrl();
|
|
20
21
|
|
|
21
22
|
if (!isSanityConfigured()) {
|
|
22
23
|
return new NextResponse("# 404 Not Found\n\nCMS not configured.", {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { revalidateTag } from "next/cache";
|
|
1
|
+
import { revalidatePath, revalidateTag } from "next/cache";
|
|
2
2
|
import { type NextRequest, NextResponse } from "next/server";
|
|
3
3
|
import { parseBody } from "next-sanity/webhook";
|
|
4
4
|
|
|
@@ -25,6 +25,9 @@ export async function POST(request: NextRequest) {
|
|
|
25
25
|
revalidateTag(`${body._type}:${body.slug.current}`, "max");
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
revalidatePath("/sitemap.xml");
|
|
29
|
+
revalidatePath("/sitemap.md");
|
|
30
|
+
|
|
28
31
|
return NextResponse.json({
|
|
29
32
|
status: 200,
|
|
30
33
|
revalidated: true,
|
|
@@ -9,7 +9,9 @@ import { RichText } from "@/lib/integrations/sanity/components/rich-text";
|
|
|
9
9
|
|
|
10
10
|
export async function generateStaticParams() {
|
|
11
11
|
if (!client) return [];
|
|
12
|
-
const articles = await client.fetch
|
|
12
|
+
const articles = await client.fetch<
|
|
13
|
+
Array<{ slug?: { current?: string } }>
|
|
14
|
+
>(ALL_ARTICLES_QUERY);
|
|
13
15
|
|
|
14
16
|
return (articles ?? [])
|
|
15
17
|
.filter((article) => article.slug?.current)
|
|
@@ -9,13 +9,13 @@ import { fontsVariable } from "@/lib/styles/fonts";
|
|
|
9
9
|
import AppData from "@/package.json";
|
|
10
10
|
import "@/lib/styles/css/index.css";
|
|
11
11
|
import { cn } from "@/lib/styles/cn";
|
|
12
|
+
import { getBaseUrl } from "@/lib/utils/url";
|
|
12
13
|
|
|
13
14
|
const APP_NAME = AppData.name;
|
|
14
15
|
const APP_DEFAULT_TITLE = "Basement Starter";
|
|
15
16
|
const APP_TITLE_TEMPLATE = "%s - Basement Starter";
|
|
16
17
|
const APP_DESCRIPTION = AppData.description;
|
|
17
|
-
const APP_BASE_URL =
|
|
18
|
-
process.env.NEXT_PUBLIC_BASE_URL ?? "http://localhost:3000";
|
|
18
|
+
const APP_BASE_URL = getBaseUrl();
|
|
19
19
|
|
|
20
20
|
const geist = Geist({
|
|
21
21
|
subsets: ["latin"],
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { NextResponse } from "next/server";
|
|
2
2
|
import { isSanityConfigured } from "@/lib/integrations/check-integration";
|
|
3
|
+
import { getBaseUrl } from "@/lib/utils/url";
|
|
4
|
+
|
|
5
|
+
export const dynamic = "force-dynamic";
|
|
3
6
|
|
|
4
7
|
export async function GET() {
|
|
5
|
-
const baseUrl =
|
|
8
|
+
const baseUrl = getBaseUrl();
|
|
6
9
|
|
|
7
10
|
if (!isSanityConfigured()) {
|
|
8
11
|
return new NextResponse(
|
|
@@ -14,13 +17,13 @@ export async function GET() {
|
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
try {
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
const { client } = await import("@/lib/integrations/sanity/client");
|
|
21
|
+
const {
|
|
22
|
+
SITEMAP_ARTICLES_QUERY,
|
|
23
|
+
SITEMAP_PAGES_QUERY,
|
|
24
|
+
} = await import("@/lib/integrations/sanity/queries");
|
|
22
25
|
|
|
23
|
-
if (!
|
|
26
|
+
if (!client) {
|
|
24
27
|
return new NextResponse("# Sitemap\n\nUnable to connect to CMS.", {
|
|
25
28
|
status: 503,
|
|
26
29
|
headers: { "Content-Type": "text/markdown; charset=utf-8" },
|
|
@@ -28,18 +31,15 @@ export async function GET() {
|
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
type SanityDoc = {
|
|
31
|
-
title
|
|
34
|
+
title?: string;
|
|
32
35
|
slug: { current: string };
|
|
33
36
|
_updatedAt: string;
|
|
34
37
|
};
|
|
35
38
|
|
|
36
|
-
const articles = await
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
_updatedAt
|
|
41
|
-
}`,
|
|
42
|
-
);
|
|
39
|
+
const [articles, pages] = await Promise.all([
|
|
40
|
+
client.fetch<SanityDoc[]>(SITEMAP_ARTICLES_QUERY),
|
|
41
|
+
client.fetch<SanityDoc[]>(SITEMAP_PAGES_QUERY),
|
|
42
|
+
]);
|
|
43
43
|
|
|
44
44
|
const parts = [
|
|
45
45
|
`# ${new URL(baseUrl).hostname} - Content Sitemap`,
|
|
@@ -52,14 +52,26 @@ export async function GET() {
|
|
|
52
52
|
if (articles.length > 0) {
|
|
53
53
|
parts.push("## Articles", "");
|
|
54
54
|
for (const article of articles) {
|
|
55
|
+
const title = article.title || article.slug.current;
|
|
56
|
+
parts.push(
|
|
57
|
+
`- [${title}](${baseUrl}/blog/${article.slug.current}.md)`,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
parts.push("");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (pages.length > 0) {
|
|
64
|
+
parts.push("## Pages", "");
|
|
65
|
+
for (const page of pages) {
|
|
66
|
+
const title = page.title || page.slug.current;
|
|
55
67
|
parts.push(
|
|
56
|
-
`- [${
|
|
68
|
+
`- [${title}](${baseUrl}/${page.slug.current}.md)`,
|
|
57
69
|
);
|
|
58
70
|
}
|
|
59
71
|
parts.push("");
|
|
60
72
|
}
|
|
61
73
|
|
|
62
|
-
if (articles.length === 0) {
|
|
74
|
+
if (articles.length === 0 && pages.length === 0) {
|
|
63
75
|
parts.push("No content published yet.", "");
|
|
64
76
|
}
|
|
65
77
|
|
|
@@ -69,7 +81,6 @@ export async function GET() {
|
|
|
69
81
|
headers: {
|
|
70
82
|
"Content-Type": "text/markdown; charset=utf-8",
|
|
71
83
|
"X-Content-Type-Options": "nosniff",
|
|
72
|
-
"Cache-Control": "public, s-maxage=3600, stale-while-revalidate=600",
|
|
73
84
|
},
|
|
74
85
|
});
|
|
75
86
|
} catch (error) {
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Sanity Webhook Setup
|
|
2
|
+
|
|
3
|
+
Configure a Sanity webhook to trigger Next.js on-demand revalidation whenever content changes. This keeps pages, sitemap.xml, and sitemap.md in sync with the CMS without redeploying.
|
|
4
|
+
|
|
5
|
+
## 1. Generate a webhook secret
|
|
6
|
+
|
|
7
|
+
Generate a strong random string locally:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
openssl rand -base64 32
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Keep this value — you'll paste it into both the webhook config and your environment variables.
|
|
14
|
+
|
|
15
|
+
## 2. Add the secret to your environment
|
|
16
|
+
|
|
17
|
+
Add to `.env.local` (development) and your production env (Vercel, etc.):
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
SANITY_REVALIDATE_SECRET=<paste-generated-secret-here>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## 3. Create the webhook in Sanity
|
|
24
|
+
|
|
25
|
+
1. Go to [sanity.io/manage](https://sanity.io/manage)
|
|
26
|
+
2. Select your project → **API** → **Webhooks** → **Create webhook**
|
|
27
|
+
3. Fill in the fields below:
|
|
28
|
+
|
|
29
|
+
| Field | Value |
|
|
30
|
+
| --- | --- |
|
|
31
|
+
| **Name** | `Next.js Revalidate` |
|
|
32
|
+
| **Description** | Revalidates pages and sitemap on content changes |
|
|
33
|
+
| **URL** | `https://your-domain.com/api/revalidate` |
|
|
34
|
+
| **Dataset** | `production` (or the dataset you want to revalidate) |
|
|
35
|
+
| **Trigger on** | ✅ Create ✅ Update ✅ Delete |
|
|
36
|
+
| **Projection** | `{ _type, slug }` |
|
|
37
|
+
| **HTTP method** | `POST` |
|
|
38
|
+
| **HTTP Headers** | *(none required)* |
|
|
39
|
+
| **API version** | `2023-05-03` or later |
|
|
40
|
+
| **Include drafts** | ❌ Off (unless you want drafts to trigger revalidation) |
|
|
41
|
+
| **Secret** | Paste the same secret from step 1 |
|
|
42
|
+
|
|
43
|
+
> Update the **Filter** if you add more indexed document types (e.g. `_type in ["page", "article", "project"]`).
|
|
44
|
+
|
|
45
|
+
## 4. Verify the route
|
|
46
|
+
|
|
47
|
+
The webhook handler lives at `app/api/revalidate/route.ts`. It:
|
|
48
|
+
|
|
49
|
+
- Verifies the request signature against `SANITY_REVALIDATE_SECRET`
|
|
50
|
+
- Calls `revalidateTag(_type)` for every page using that document type
|
|
51
|
+
- Calls `revalidateTag(_type:slug)` for the specific document
|
|
52
|
+
- Calls `revalidatePath("/sitemap.xml")` and `revalidatePath("/sitemap.md")`
|
|
53
|
+
|
|
54
|
+
## 5. Test it
|
|
55
|
+
|
|
56
|
+
1. In Sanity Studio, publish a change to any `page` or `article`
|
|
57
|
+
2. Open the webhook in sanity.io/manage → **Recent deliveries**
|
|
58
|
+
3. You should see a `200 OK` response
|
|
59
|
+
|
|
60
|
+
If you see `401 Invalid signature` — the secret in your env doesn't match the webhook secret.
|
|
61
|
+
If you see `400 Bad Request` — the projection is missing `_type`.
|
|
62
|
+
|
|
63
|
+
## Troubleshooting
|
|
64
|
+
|
|
65
|
+
**Changes aren't showing up on the live site**
|
|
66
|
+
- Confirm the webhook delivery returned `200`
|
|
67
|
+
- Confirm `SANITY_REVALIDATE_SECRET` is set in **production** (not just local)
|
|
68
|
+
- Confirm your fetch functions use tags matching `_type` or `_type:slug`
|
|
69
|
+
|
|
70
|
+
**Slug-specific revalidation doesn't fire**
|
|
71
|
+
- Projection must include `slug` — `{ _type }` alone isn't enough
|
|
72
|
+
|
|
73
|
+
**Signature always invalid**
|
|
74
|
+
- Copy the secret fresh from Sanity and re-paste into env — trailing whitespace breaks HMAC verification
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { getBaseUrl } from "@/lib/utils/url";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Sanity Environment Configuration
|
|
3
5
|
*
|
|
@@ -23,7 +25,7 @@ export const projectId =
|
|
|
23
25
|
export const studioUrl =
|
|
24
26
|
process.env.NODE_ENV === "development"
|
|
25
27
|
? "http://localhost:3000/studio"
|
|
26
|
-
: `${
|
|
28
|
+
: `${getBaseUrl()}/studio`;
|
|
27
29
|
|
|
28
30
|
/**
|
|
29
31
|
* Single Sanity API read token used for both browser and server live preview.
|
|
@@ -39,4 +41,4 @@ export const sanityToken =
|
|
|
39
41
|
export const previewURL =
|
|
40
42
|
process.env.NODE_ENV === "development"
|
|
41
43
|
? "http://localhost:3000"
|
|
42
|
-
:
|
|
44
|
+
: getBaseUrl();
|