dh-remixer-sdk 0.0.37 → 0.0.38-ce1e2d3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dh-remixer-sdk",
3
- "version": "0.0.37",
3
+ "version": "0.0.38-ce1e2d3",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "templates",
@@ -10,6 +10,7 @@ import {
10
10
  populateRoutesFromHtml,
11
11
  } from "./populate-sitemap.mjs";
12
12
  import { buildSitemapXml } from "./build-sitemap-xml.mjs";
13
+ import { writeRobotsTxt } from "./robots-txt.mjs";
13
14
  import { writeHelmetFile } from "./fs-utils.mjs";
14
15
  import {
15
16
  ROOT_ROUTE,
@@ -82,16 +83,7 @@ async function main() {
82
83
  );
83
84
  console.log("[created] sitemap.xml");
84
85
 
85
- await fs.writeFile(
86
- path.join(REMIXER_BUILD_DIR, "robots.txt"),
87
- `User-agent: *
88
- Allow: /
89
-
90
- Sitemap: https://${TARGET_DOMAIN}/sitemap.xml
91
- `,
92
- "utf8",
93
- );
94
- console.log("[created] robots.txt");
86
+ await writeRobotsTxt(REMIXER_BUILD_DIR, TARGET_DOMAIN);
95
87
 
96
88
  await prerenderer.removeBootstrapBackup();
97
89
 
@@ -0,0 +1,39 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+
4
+ // The robots.txt every forked template shipped before robots.txt became
5
+ // AI-editable. Sites carrying it verbatim never had it customised, so it is
6
+ // replaced with the indexable default rather than preserved.
7
+ const LEGACY_TEMPLATE_DEFAULT = "User-agent: *\nDisallow: /";
8
+
9
+ export function resolveRobotsTxt(existing, targetDomain) {
10
+ const sitemapLine = `Sitemap: https://${targetDomain}/sitemap.xml`;
11
+
12
+ if (typeof existing !== "string") {
13
+ return `User-agent: *\nAllow: /\n\n${sitemapLine}\n`;
14
+ }
15
+
16
+ const normalised = existing.replace(/\r\n/g, "\n");
17
+
18
+ if (normalised.trim() === LEGACY_TEMPLATE_DEFAULT) {
19
+ return `User-agent: *\nAllow: /\n\n${sitemapLine}\n`;
20
+ }
21
+
22
+ if (/^[ \t]*Sitemap:/im.test(normalised)) {
23
+ return normalised;
24
+ }
25
+
26
+ return `${normalised.replace(/\s*$/, "")}\n\n${sitemapLine}\n`;
27
+ }
28
+
29
+ export async function writeRobotsTxt(buildDir, targetDomain) {
30
+ const robotsPath = path.join(buildDir, "robots.txt");
31
+ const existing = await fs.readFile(robotsPath, "utf8").catch(() => null);
32
+
33
+ await fs.writeFile(
34
+ robotsPath,
35
+ resolveRobotsTxt(existing, targetDomain),
36
+ "utf8",
37
+ );
38
+ console.log("[created] robots.txt");
39
+ }
@@ -0,0 +1,41 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { resolveRobotsTxt } from "./robots-txt.mjs";
4
+
5
+ const DOMAIN = "domain.com";
6
+ const SITEMAP = "Sitemap: https://domain.com/sitemap.xml";
7
+
8
+ test("writes the indexable default when the build has no robots.txt", () => {
9
+ const out = resolveRobotsTxt(null, DOMAIN);
10
+ assert.equal(out, `User-agent: *\nAllow: /\n\n${SITEMAP}\n`);
11
+ });
12
+
13
+ test("replaces the untouched legacy template default", () => {
14
+ const out = resolveRobotsTxt("User-agent: *\nDisallow: /", DOMAIN);
15
+ assert.equal(out, `User-agent: *\nAllow: /\n\n${SITEMAP}\n`);
16
+ });
17
+
18
+ test("replaces the legacy default regardless of line endings or trailing space", () => {
19
+ const out = resolveRobotsTxt("User-agent: *\r\nDisallow: /\r\n\r\n", DOMAIN);
20
+ assert.equal(out, `User-agent: *\nAllow: /\n\n${SITEMAP}\n`);
21
+ });
22
+
23
+ test("preserves an AI-authored robots.txt and appends the sitemap", () => {
24
+ const authored = "User-agent: *\nDisallow: /admin/\nAllow: /";
25
+ const out = resolveRobotsTxt(authored, DOMAIN);
26
+ assert.equal(out, `${authored}\n\n${SITEMAP}\n`);
27
+ });
28
+
29
+ test("preserves an AI-authored Disallow: / that is not the legacy default", () => {
30
+ const authored = "User-agent: Googlebot\nDisallow: /";
31
+ const out = resolveRobotsTxt(authored, DOMAIN);
32
+ assert.match(out, /^User-agent: Googlebot\nDisallow: \/$/m);
33
+ assert.doesNotMatch(out, /Allow: \//);
34
+ });
35
+
36
+ test("does not duplicate an existing Sitemap directive", () => {
37
+ const authored = `User-agent: *\nAllow: /\n\nSitemap: https://other.example/sitemap.xml\n`;
38
+ const out = resolveRobotsTxt(authored, DOMAIN);
39
+ assert.equal(out, authored);
40
+ assert.equal(out.match(/Sitemap:/g).length, 1);
41
+ });
@@ -3,7 +3,6 @@
3
3
  "index.tsx",
4
4
  "filemap.json",
5
5
  "public/.htaccess",
6
- "public/robots.txt",
7
6
  ".gitignore",
8
7
  "lib/supabase.ts",
9
8
  "tsconfig.json",
@@ -6,7 +6,6 @@
6
6
  "filemap.json": "filemap.json",
7
7
  "tsconfig.json": "tsconfig.json",
8
8
  "vite.config.ts": "vite.config.ts",
9
- "robots.txt": "public/robots.txt",
10
9
  ".htaccess": "public/.htaccess",
11
10
  "context/LanguageContext.tsx": "context/LanguageContext.tsx",
12
11
  "remixer.ts": "lib/remixer.ts",
@@ -1,2 +0,0 @@
1
- User-agent: *
2
- Disallow: /