scribe-cms 0.0.8 → 0.0.10
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/README.md +5 -5
- package/dist/cli/index.cjs +433 -384
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +433 -384
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +643 -512
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +643 -513
- package/dist/index.js.map +1 -1
- package/dist/runtime.cjs +287 -261
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.js +286 -261
- package/dist/runtime.js.map +1 -1
- package/dist/src/config/resolve-config.d.ts.map +1 -1
- package/dist/src/core/builtin-fields.d.ts +8 -8
- package/dist/src/core/builtin-fields.d.ts.map +1 -1
- package/dist/src/core/types.d.ts +11 -4
- package/dist/src/core/types.d.ts.map +1 -1
- package/dist/src/create-project.d.ts.map +1 -1
- package/dist/src/export/build-static-raw-exports.d.ts.map +1 -1
- package/dist/src/i18n/build-url.d.ts +16 -3
- package/dist/src/i18n/build-url.d.ts.map +1 -1
- package/dist/src/i18n/resolve-document.d.ts +3 -2
- package/dist/src/i18n/resolve-document.d.ts.map +1 -1
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/loader/create-loader.d.ts.map +1 -1
- package/dist/src/redirects/build-json-redirects.d.ts +6 -0
- package/dist/src/redirects/build-json-redirects.d.ts.map +1 -0
- package/dist/src/redirects/build-redirects.d.ts +9 -7
- package/dist/src/redirects/build-redirects.d.ts.map +1 -1
- package/dist/src/redirects/load-type-redirects.d.ts +14 -0
- package/dist/src/redirects/load-type-redirects.d.ts.map +1 -0
- package/dist/src/redirects/redirect-schema.d.ts +31 -0
- package/dist/src/redirects/redirect-schema.d.ts.map +1 -0
- package/dist/src/runtime.d.ts +3 -1
- package/dist/src/runtime.d.ts.map +1 -1
- package/dist/src/sitemap/generate-sitemap.d.ts.map +1 -1
- package/dist/src/validate/validate-project.d.ts.map +1 -1
- package/dist/src/validate/validate-redirects.d.ts +4 -0
- package/dist/src/validate/validate-redirects.d.ts.map +1 -0
- package/dist/studio/server.cjs +90 -61
- package/dist/studio/server.cjs.map +1 -1
- package/dist/studio/server.js +90 -61
- package/dist/studio/server.js.map +1 -1
- package/package.json +1 -1
- package/dist/src/core/slug-aliases.d.ts +0 -27
- package/dist/src/core/slug-aliases.d.ts.map +0 -1
- package/dist/src/redirects/translation-index.d.ts +0 -4
- package/dist/src/redirects/translation-index.d.ts.map +0 -1
package/dist/runtime.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import path from 'path';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import fs2 from 'fs';
|
|
4
4
|
import matter from 'gray-matter';
|
|
@@ -11,14 +11,14 @@ var SLUG_PLACEHOLDER = "{slug}";
|
|
|
11
11
|
function isRoutableType(type) {
|
|
12
12
|
return typeof type.path === "string" && type.path.length > 0;
|
|
13
13
|
}
|
|
14
|
-
function assertValidPathTemplate(
|
|
15
|
-
if (!
|
|
16
|
-
throw new Error(`Content type "${typeId}": path must start with / (got "${
|
|
14
|
+
function assertValidPathTemplate(path6, typeId) {
|
|
15
|
+
if (!path6.startsWith("/")) {
|
|
16
|
+
throw new Error(`Content type "${typeId}": path must start with / (got "${path6}")`);
|
|
17
17
|
}
|
|
18
|
-
const count = (
|
|
18
|
+
const count = (path6.match(/\{slug\}/g) ?? []).length;
|
|
19
19
|
if (count !== 1) {
|
|
20
20
|
throw new Error(
|
|
21
|
-
`Content type "${typeId}": path must contain exactly one {slug} (got "${
|
|
21
|
+
`Content type "${typeId}": path must contain exactly one {slug} (got "${path6}")`
|
|
22
22
|
);
|
|
23
23
|
}
|
|
24
24
|
}
|
|
@@ -32,19 +32,69 @@ function pathSuffix(template) {
|
|
|
32
32
|
if (idx === -1) throw new Error(`Invalid path template (missing {slug}): ${template}`);
|
|
33
33
|
return template.slice(idx + SLUG_PLACEHOLDER.length);
|
|
34
34
|
}
|
|
35
|
-
function
|
|
36
|
-
|
|
37
|
-
if (locale === defaultLocale) return relative;
|
|
38
|
-
return `/${locale}${relative}`;
|
|
35
|
+
function resolveDefaultLocaleRouting() {
|
|
36
|
+
return { strategy: "path-prefix", prefixDefaultLocale: false };
|
|
39
37
|
}
|
|
40
|
-
function
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
38
|
+
function splitPathAndSearch(pathname) {
|
|
39
|
+
const q = pathname.indexOf("?");
|
|
40
|
+
if (q === -1) return { pathname, search: "" };
|
|
41
|
+
return { pathname: pathname.slice(0, q), search: pathname.slice(q) };
|
|
42
|
+
}
|
|
43
|
+
function createUrlBuilder(config) {
|
|
44
|
+
const localeRouting = config.localeRouting ?? resolveDefaultLocaleRouting();
|
|
45
|
+
const defaultLocale = config.defaultLocale;
|
|
46
|
+
const prefixedLocales = localeRouting.strategy === "path-prefix" ? localeRouting.prefixDefaultLocale ? [...config.locales] : config.locales.filter((locale) => locale !== defaultLocale) : config.locales.filter((locale) => locale !== defaultLocale);
|
|
47
|
+
function applyLocaleToPath(pathname, locale) {
|
|
48
|
+
if (locale === defaultLocale) {
|
|
49
|
+
if (localeRouting.strategy === "path-prefix" && localeRouting.prefixDefaultLocale) {
|
|
50
|
+
return `/${defaultLocale}${pathname}`;
|
|
51
|
+
}
|
|
52
|
+
return pathname;
|
|
53
|
+
}
|
|
54
|
+
if (localeRouting.strategy === "search-param") {
|
|
55
|
+
const { pathname: base, search } = splitPathAndSearch(pathname);
|
|
56
|
+
const params = new URLSearchParams(search.startsWith("?") ? search.slice(1) : search);
|
|
57
|
+
params.set(localeRouting.param, locale);
|
|
58
|
+
const qs = params.toString();
|
|
59
|
+
return qs ? `${base}?${qs}` : base;
|
|
60
|
+
}
|
|
61
|
+
return `/${locale}${pathname}`;
|
|
62
|
+
}
|
|
63
|
+
function resolvePath(template, slug, locale) {
|
|
64
|
+
const relative = template.replace(SLUG_PLACEHOLDER, slug);
|
|
65
|
+
return applyLocaleToPath(relative, locale);
|
|
66
|
+
}
|
|
67
|
+
function extractSlugFromResolvedPath(template, resolvedPath) {
|
|
68
|
+
let pathname = resolvedPath;
|
|
69
|
+
if (localeRouting.strategy === "search-param") {
|
|
70
|
+
pathname = splitPathAndSearch(resolvedPath).pathname;
|
|
71
|
+
} else if (localeRouting.strategy === "path-prefix") {
|
|
72
|
+
for (const locale of config.locales) {
|
|
73
|
+
if (locale === defaultLocale && !localeRouting.prefixDefaultLocale) continue;
|
|
74
|
+
const prefix2 = `/${locale}`;
|
|
75
|
+
if (pathname === prefix2 || pathname.startsWith(`${prefix2}/`)) {
|
|
76
|
+
pathname = pathname.slice(prefix2.length) || "/";
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const prefix = pathPrefix(template);
|
|
82
|
+
const suffix = pathSuffix(template);
|
|
83
|
+
if (!pathname.startsWith(prefix)) return null;
|
|
84
|
+
if (suffix && !pathname.endsWith(suffix)) return null;
|
|
85
|
+
const slugEnd = suffix ? pathname.length - suffix.length : pathname.length;
|
|
86
|
+
const slug = pathname.slice(prefix.length, slugEnd);
|
|
87
|
+
return slug.length > 0 ? slug : null;
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
defaultLocale,
|
|
91
|
+
locales: config.locales,
|
|
92
|
+
localeRouting,
|
|
93
|
+
prefixedLocales,
|
|
94
|
+
resolvePath,
|
|
95
|
+
extractSlugFromResolvedPath,
|
|
96
|
+
applyLocaleToPath
|
|
97
|
+
};
|
|
48
98
|
}
|
|
49
99
|
|
|
50
100
|
// src/config/resolve-config.ts
|
|
@@ -67,10 +117,17 @@ function resolveConfig(input, baseDir) {
|
|
|
67
117
|
`scribe config: defaultLocale "${defaultLocale}" is not in locales [${raw.locales.join(", ")}]`
|
|
68
118
|
);
|
|
69
119
|
}
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
120
|
+
const localeRouting = raw.localeRouting ?? {
|
|
121
|
+
strategy: "path-prefix",
|
|
122
|
+
prefixDefaultLocale: false
|
|
123
|
+
};
|
|
124
|
+
if (localeRouting.strategy === "search-param" && !localeRouting.param) {
|
|
125
|
+
throw new Error('scribe config: localeRouting search-param requires a "param" name');
|
|
126
|
+
}
|
|
127
|
+
const projectRoot = path.resolve(process.cwd(), raw.rootDir);
|
|
128
|
+
const contentRoot = path.resolve(projectRoot, raw.contentDir ?? "content");
|
|
129
|
+
const storePath = path.resolve(projectRoot, raw.store ?? ".scribe/store.sqlite");
|
|
130
|
+
const assetsPath = raw.assetsDir ? path.resolve(projectRoot, raw.assetsDir) : void 0;
|
|
74
131
|
const seenIds = /* @__PURE__ */ new Set();
|
|
75
132
|
const types = raw.types.map((type) => {
|
|
76
133
|
if (seenIds.has(type.id)) {
|
|
@@ -94,6 +151,7 @@ function resolveConfig(input, baseDir) {
|
|
|
94
151
|
assetsPath,
|
|
95
152
|
locales: [...raw.locales],
|
|
96
153
|
defaultLocale,
|
|
154
|
+
localeRouting,
|
|
97
155
|
localePresets: raw.localePresets,
|
|
98
156
|
translate: raw.translate,
|
|
99
157
|
types
|
|
@@ -193,10 +251,10 @@ function introspectSchema(schema, prefix = []) {
|
|
|
193
251
|
}
|
|
194
252
|
function extractByPaths(data, paths) {
|
|
195
253
|
const out = {};
|
|
196
|
-
for (const
|
|
197
|
-
const value = getAtPath(data,
|
|
254
|
+
for (const path6 of paths) {
|
|
255
|
+
const value = getAtPath(data, path6);
|
|
198
256
|
if (value !== void 0) {
|
|
199
|
-
setAtPath(out,
|
|
257
|
+
setAtPath(out, path6.filter((p) => p !== "*"), value);
|
|
200
258
|
}
|
|
201
259
|
}
|
|
202
260
|
return out;
|
|
@@ -214,13 +272,13 @@ function mergeStructuralOntoLocale(localeData, enData, schema) {
|
|
|
214
272
|
const translatable = pickTranslatable(localeData, schema);
|
|
215
273
|
return deepMerge(structural, translatable);
|
|
216
274
|
}
|
|
217
|
-
function getAtPath(obj,
|
|
275
|
+
function getAtPath(obj, path6) {
|
|
218
276
|
let current = obj;
|
|
219
|
-
for (const segment of
|
|
277
|
+
for (const segment of path6) {
|
|
220
278
|
if (segment === "*") {
|
|
221
279
|
if (!Array.isArray(current)) return void 0;
|
|
222
280
|
return current.map(
|
|
223
|
-
(item) => typeof item === "object" && item !== null ? getAtPath(item,
|
|
281
|
+
(item) => typeof item === "object" && item !== null ? getAtPath(item, path6.slice(path6.indexOf("*") + 1)) : void 0
|
|
224
282
|
);
|
|
225
283
|
}
|
|
226
284
|
if (typeof current !== "object" || current === null || Array.isArray(current)) return void 0;
|
|
@@ -228,13 +286,13 @@ function getAtPath(obj, path5) {
|
|
|
228
286
|
}
|
|
229
287
|
return current;
|
|
230
288
|
}
|
|
231
|
-
function setAtPath(obj,
|
|
232
|
-
if (
|
|
233
|
-
if (
|
|
234
|
-
obj[
|
|
289
|
+
function setAtPath(obj, path6, value) {
|
|
290
|
+
if (path6.length === 0) return;
|
|
291
|
+
if (path6.length === 1) {
|
|
292
|
+
obj[path6[0]] = value;
|
|
235
293
|
return;
|
|
236
294
|
}
|
|
237
|
-
const [head, ...rest] =
|
|
295
|
+
const [head, ...rest] = path6;
|
|
238
296
|
if (!(head in obj) || typeof obj[head] !== "object" || obj[head] === null) {
|
|
239
297
|
obj[head] = {};
|
|
240
298
|
}
|
|
@@ -269,45 +327,23 @@ var SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
|
269
327
|
var slugPatternSchema = z.string().regex(SLUG_PATTERN, "slug must be lowercase-kebab-case");
|
|
270
328
|
var isoDateSchema = z.string().regex(/^\d{4}-\d{2}-\d{2}(T[\d:.Z+-]*)?$/, "Use ISO date YYYY-MM-DD or full ISO 8601");
|
|
271
329
|
var canonicalPathSchema = z.string().regex(/^\//, "canonicalPath must start with /");
|
|
272
|
-
|
|
330
|
+
var DEPRECATED_REDIRECT_FIELDS = [
|
|
331
|
+
[
|
|
332
|
+
"aliases",
|
|
333
|
+
"aliases frontmatter is removed \u2014 add redirects to content/<type>/_redirects.json instead"
|
|
334
|
+
],
|
|
335
|
+
[
|
|
336
|
+
"redirect_to",
|
|
337
|
+
"redirect_to frontmatter is removed \u2014 add redirects to content/<type>/_redirects.json instead"
|
|
338
|
+
]
|
|
339
|
+
];
|
|
340
|
+
function extractBuiltinEnFields(data, _pathTemplate, _enSlug, _defaultLocale) {
|
|
273
341
|
const issues = [];
|
|
274
342
|
const rest = { ...data };
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
let redirectTo;
|
|
280
|
-
if (redirectRaw !== void 0 && redirectRaw !== null && redirectRaw !== "") {
|
|
281
|
-
if (typeof redirectRaw !== "string") {
|
|
282
|
-
issues.push({
|
|
283
|
-
field: "redirect_to",
|
|
284
|
-
message: "redirect_to must be a string path",
|
|
285
|
-
level: "error"
|
|
286
|
-
});
|
|
287
|
-
} else if (!pathTemplate) {
|
|
288
|
-
issues.push({
|
|
289
|
-
field: "redirect_to",
|
|
290
|
-
message: "redirect_to is not allowed on reference-only content types",
|
|
291
|
-
level: "error"
|
|
292
|
-
});
|
|
293
|
-
} else if (!extractSlugFromResolvedPath(pathTemplate, redirectRaw)) {
|
|
294
|
-
issues.push({
|
|
295
|
-
field: "redirect_to",
|
|
296
|
-
message: `redirect_to must match path template "${pathTemplate}" (prefix "${pathPrefix(pathTemplate)}"${pathSuffix(pathTemplate) ? `, suffix "${pathSuffix(pathTemplate)}"` : ""})`,
|
|
297
|
-
level: "error"
|
|
298
|
-
});
|
|
299
|
-
} else {
|
|
300
|
-
redirectTo = redirectRaw;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
const aliases = aliasesResult.success ? aliasesResult.data : [];
|
|
304
|
-
if (!aliasesResult.success) {
|
|
305
|
-
for (const issue of aliasesResult.error.issues) {
|
|
306
|
-
issues.push({
|
|
307
|
-
field: `aliases.${issue.path.join(".")}`,
|
|
308
|
-
message: issue.message,
|
|
309
|
-
level: "error"
|
|
310
|
-
});
|
|
343
|
+
for (const [field, message] of DEPRECATED_REDIRECT_FIELDS) {
|
|
344
|
+
if (rest[field] !== void 0) {
|
|
345
|
+
issues.push({ field, message, level: "error" });
|
|
346
|
+
delete rest[field];
|
|
311
347
|
}
|
|
312
348
|
}
|
|
313
349
|
let publishedAt;
|
|
@@ -369,8 +405,6 @@ function extractBuiltinEnFields(data, pathTemplate, enSlug, defaultLocale) {
|
|
|
369
405
|
}
|
|
370
406
|
return {
|
|
371
407
|
builtin: {
|
|
372
|
-
aliases,
|
|
373
|
-
redirectTo,
|
|
374
408
|
publishedAt,
|
|
375
409
|
updatedAt,
|
|
376
410
|
noindex,
|
|
@@ -386,20 +420,24 @@ function documentLastModified(doc) {
|
|
|
386
420
|
const date = new Date(raw);
|
|
387
421
|
return Number.isNaN(date.getTime()) ? void 0 : date.toISOString();
|
|
388
422
|
}
|
|
389
|
-
function resolveCanonicalPathname(type, doc, defaultLocale) {
|
|
423
|
+
function resolveCanonicalPathname(type, doc, defaultLocale, localeRouting) {
|
|
424
|
+
const urlBuilder = createUrlBuilder({
|
|
425
|
+
locales: [defaultLocale, ...doc.locale !== defaultLocale ? [doc.locale] : []],
|
|
426
|
+
defaultLocale,
|
|
427
|
+
localeRouting: localeRouting ?? { strategy: "path-prefix", prefixDefaultLocale: false }
|
|
428
|
+
});
|
|
390
429
|
if (doc.canonicalPathOverride) {
|
|
391
|
-
|
|
392
|
-
return `/${doc.locale}${doc.canonicalPathOverride}`;
|
|
430
|
+
return urlBuilder.applyLocaleToPath(doc.canonicalPathOverride, doc.locale);
|
|
393
431
|
}
|
|
394
432
|
if (!type.path) return `/${doc.slug}`;
|
|
395
|
-
return resolvePath(type.path, doc.slug, doc.locale
|
|
433
|
+
return urlBuilder.resolvePath(type.path, doc.slug, doc.locale);
|
|
396
434
|
}
|
|
397
|
-
function mergeBuiltinsIntoFrontmatter(frontmatter, doc, type, defaultLocale) {
|
|
435
|
+
function mergeBuiltinsIntoFrontmatter(frontmatter, doc, type, defaultLocale, localeRouting) {
|
|
398
436
|
const out = { ...frontmatter };
|
|
399
437
|
if (doc.publishedAt !== void 0) out.publishedAt = doc.publishedAt;
|
|
400
438
|
if (doc.updatedAt !== void 0) out.updatedAt = doc.updatedAt;
|
|
401
439
|
out.noindex = doc.noindex;
|
|
402
|
-
out.canonicalPath = resolveCanonicalPathname(type, doc, defaultLocale);
|
|
440
|
+
out.canonicalPath = resolveCanonicalPathname(type, doc, defaultLocale, localeRouting);
|
|
403
441
|
return out;
|
|
404
442
|
}
|
|
405
443
|
function seoFieldsFromEn(enDoc) {
|
|
@@ -407,8 +445,7 @@ function seoFieldsFromEn(enDoc) {
|
|
|
407
445
|
publishedAt: enDoc.publishedAt,
|
|
408
446
|
updatedAt: enDoc.updatedAt,
|
|
409
447
|
noindex: enDoc.noindex,
|
|
410
|
-
canonicalPathOverride: enDoc.canonicalPathOverride
|
|
411
|
-
redirectTo: enDoc.redirectTo
|
|
448
|
+
canonicalPathOverride: enDoc.canonicalPathOverride
|
|
412
449
|
};
|
|
413
450
|
}
|
|
414
451
|
var SCHEMA_VERSION = 4;
|
|
@@ -467,7 +504,7 @@ function resolveStorePath(config) {
|
|
|
467
504
|
function openStore(config, mode = "readwrite") {
|
|
468
505
|
const storePath = resolveStorePath(config);
|
|
469
506
|
if (mode === "readwrite") {
|
|
470
|
-
fs2.mkdirSync(
|
|
507
|
+
fs2.mkdirSync(path.dirname(storePath), { recursive: true });
|
|
471
508
|
}
|
|
472
509
|
const db = new Database(storePath, { readonly: mode === "readonly" });
|
|
473
510
|
if (mode === "readwrite") {
|
|
@@ -531,10 +568,10 @@ function isPostFile(name) {
|
|
|
531
568
|
}
|
|
532
569
|
function listEnFiles(contentDir) {
|
|
533
570
|
if (!fs2.existsSync(contentDir)) return [];
|
|
534
|
-
return fs2.readdirSync(contentDir).filter(isPostFile).map((f) =>
|
|
571
|
+
return fs2.readdirSync(contentDir).filter(isPostFile).map((f) => path.join(contentDir, f));
|
|
535
572
|
}
|
|
536
573
|
function slugFromPath(filePath) {
|
|
537
|
-
return
|
|
574
|
+
return path.basename(filePath).replace(/\.(md|mdx)$/, "");
|
|
538
575
|
}
|
|
539
576
|
function parseEnMdx(filePath, config, type) {
|
|
540
577
|
const raw = fs2.readFileSync(filePath, "utf8");
|
|
@@ -580,7 +617,8 @@ function parseEnMdx(filePath, config, type) {
|
|
|
580
617
|
locale: config.defaultLocale
|
|
581
618
|
},
|
|
582
619
|
type,
|
|
583
|
-
config.defaultLocale
|
|
620
|
+
config.defaultLocale,
|
|
621
|
+
config.localeRouting
|
|
584
622
|
);
|
|
585
623
|
const crossIssues = type.crossValidate?.(result.data, {
|
|
586
624
|
locale: config.defaultLocale,
|
|
@@ -594,8 +632,6 @@ function parseEnMdx(filePath, config, type) {
|
|
|
594
632
|
slug,
|
|
595
633
|
enSlug: slug,
|
|
596
634
|
locale: config.defaultLocale,
|
|
597
|
-
aliases: builtin.aliases,
|
|
598
|
-
redirectTo: builtin.redirectTo,
|
|
599
635
|
publishedAt: builtin.publishedAt,
|
|
600
636
|
updatedAt: builtin.updatedAt,
|
|
601
637
|
noindex: builtin.noindex,
|
|
@@ -606,7 +642,7 @@ function parseEnMdx(filePath, config, type) {
|
|
|
606
642
|
};
|
|
607
643
|
return { document, issues };
|
|
608
644
|
}
|
|
609
|
-
function buildDocumentFromTranslation(row, enDoc, type) {
|
|
645
|
+
function buildDocumentFromTranslation(row, enDoc, type, config) {
|
|
610
646
|
const localeFm = JSON.parse(row.frontmatter_json);
|
|
611
647
|
const merged = mergeStructuralOntoLocale(localeFm, enDoc.frontmatter, type.schema);
|
|
612
648
|
const seo = seoFieldsFromEn(enDoc);
|
|
@@ -614,14 +650,13 @@ function buildDocumentFromTranslation(row, enDoc, type) {
|
|
|
614
650
|
merged,
|
|
615
651
|
{ ...seo, slug: row.slug, locale: row.locale },
|
|
616
652
|
type,
|
|
617
|
-
|
|
653
|
+
config.defaultLocale,
|
|
654
|
+
config.localeRouting
|
|
618
655
|
);
|
|
619
656
|
return {
|
|
620
657
|
slug: row.slug,
|
|
621
658
|
enSlug: row.en_slug,
|
|
622
659
|
locale: row.locale,
|
|
623
|
-
aliases: [],
|
|
624
|
-
redirectTo: seo.redirectTo,
|
|
625
660
|
publishedAt: seo.publishedAt,
|
|
626
661
|
updatedAt: seo.updatedAt,
|
|
627
662
|
noindex: seo.noindex,
|
|
@@ -635,7 +670,7 @@ function createContentLoader(config, type) {
|
|
|
635
670
|
let cached = null;
|
|
636
671
|
let signature = "";
|
|
637
672
|
let lastCheck = 0;
|
|
638
|
-
const contentDir =
|
|
673
|
+
const contentDir = path.join(
|
|
639
674
|
/* turbopackIgnore: true */
|
|
640
675
|
config.rootDir,
|
|
641
676
|
type.contentDir
|
|
@@ -699,7 +734,7 @@ function createContentLoader(config, type) {
|
|
|
699
734
|
for (const row of rowsByLocale.get(locale) ?? []) {
|
|
700
735
|
const enDoc = englishBySlug.get(row.en_slug);
|
|
701
736
|
if (!enDoc) continue;
|
|
702
|
-
const doc = buildDocumentFromTranslation(row, enDoc, type);
|
|
737
|
+
const doc = buildDocumentFromTranslation(row, enDoc, type, config);
|
|
703
738
|
bySlug.set(doc.slug, doc);
|
|
704
739
|
byEnSlug.set(row.en_slug, doc);
|
|
705
740
|
}
|
|
@@ -725,72 +760,18 @@ function createContentLoader(config, type) {
|
|
|
725
760
|
return cached;
|
|
726
761
|
};
|
|
727
762
|
}
|
|
728
|
-
function readEnDocument(config, type, enSlug) {
|
|
729
|
-
const contentDir = path3.join(
|
|
730
|
-
/* turbopackIgnore: true */
|
|
731
|
-
config.rootDir,
|
|
732
|
-
type.contentDir
|
|
733
|
-
);
|
|
734
|
-
for (const ext of [".mdx", ".md"]) {
|
|
735
|
-
const filePath = path3.join(contentDir, `${enSlug}${ext}`);
|
|
736
|
-
if (!fs2.existsSync(filePath)) continue;
|
|
737
|
-
const { document } = parseEnMdx(filePath, config, type);
|
|
738
|
-
return document;
|
|
739
|
-
}
|
|
740
|
-
return null;
|
|
741
|
-
}
|
|
742
763
|
|
|
743
764
|
// src/i18n/resolve-document.ts
|
|
744
|
-
function
|
|
745
|
-
const
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
}
|
|
750
|
-
return null;
|
|
751
|
-
}
|
|
752
|
-
function enCanonicalDoc(doc, allDocs, defaultLocale) {
|
|
753
|
-
if (doc.locale === defaultLocale) return doc;
|
|
754
|
-
return allDocs.get(defaultLocale)?.bySlug.get(doc.enSlug) ?? doc;
|
|
755
|
-
}
|
|
756
|
-
function redirectPathForDocument(doc, locale, defaultLocale, allDocs, type) {
|
|
757
|
-
if (!type.path) return void 0;
|
|
758
|
-
const enDoc = enCanonicalDoc(doc, allDocs, defaultLocale);
|
|
759
|
-
if (!enDoc.redirectTo) return void 0;
|
|
760
|
-
const targetEnSlug = extractSlugFromResolvedPath(type.path, enDoc.redirectTo);
|
|
761
|
-
if (!targetEnSlug) return void 0;
|
|
762
|
-
const targetEnDoc = allDocs.get(defaultLocale)?.bySlug.get(targetEnSlug);
|
|
763
|
-
const targetSlug = targetEnDoc ? getSlugForLocale(targetEnDoc, defaultLocale, locale, allDocs, defaultLocale) ?? targetEnSlug : targetEnSlug;
|
|
764
|
-
return resolvePath(type.path, targetSlug, locale, defaultLocale);
|
|
765
|
-
}
|
|
766
|
-
function withRedirectTo(result, locale, defaultLocale, allDocs, type) {
|
|
767
|
-
if (result.shouldRedirectTo || !result.document) return result;
|
|
768
|
-
const redirect = redirectPathForDocument(result.document, locale, defaultLocale, allDocs, type);
|
|
769
|
-
if (!redirect) return result;
|
|
770
|
-
return {
|
|
771
|
-
document: null,
|
|
772
|
-
actualLocale: result.actualLocale,
|
|
773
|
-
shouldRedirectTo: redirect
|
|
774
|
-
};
|
|
775
|
-
}
|
|
776
|
-
function resolveLocalizedDocument(slug, locale, defaultLocale, allDocs, type) {
|
|
765
|
+
function resolveLocalizedDocument(slug, locale, defaultLocale, allDocs, type, localeRouting) {
|
|
766
|
+
const urlBuilder = createUrlBuilder({
|
|
767
|
+
locales: [defaultLocale, locale],
|
|
768
|
+
defaultLocale,
|
|
769
|
+
localeRouting: localeRouting ?? { strategy: "path-prefix", prefixDefaultLocale: false }
|
|
770
|
+
});
|
|
777
771
|
const idx = allDocs.get(locale);
|
|
778
772
|
const direct = idx?.bySlug.get(slug);
|
|
779
773
|
if (direct) {
|
|
780
|
-
return
|
|
781
|
-
}
|
|
782
|
-
const aliasDoc = findEnDocByAlias(slug, allDocs, defaultLocale);
|
|
783
|
-
if (aliasDoc && type.path) {
|
|
784
|
-
const canonicalSlug = aliasDoc.slug;
|
|
785
|
-
const localizedSlug = getSlugForLocale(aliasDoc, defaultLocale, locale, allDocs, defaultLocale);
|
|
786
|
-
const targetSlug = localizedSlug ?? canonicalSlug;
|
|
787
|
-
if (targetSlug !== slug) {
|
|
788
|
-
return {
|
|
789
|
-
document: null,
|
|
790
|
-
actualLocale: locale,
|
|
791
|
-
shouldRedirectTo: resolvePath(type.path, targetSlug, locale, defaultLocale)
|
|
792
|
-
};
|
|
793
|
-
}
|
|
774
|
+
return { document: direct, actualLocale: locale };
|
|
794
775
|
}
|
|
795
776
|
for (const [docLocale, docIdx] of allDocs) {
|
|
796
777
|
const found = docIdx.bySlug.get(slug);
|
|
@@ -803,17 +784,11 @@ function resolveLocalizedDocument(slug, locale, defaultLocale, allDocs, type) {
|
|
|
803
784
|
return {
|
|
804
785
|
document: null,
|
|
805
786
|
actualLocale: locale,
|
|
806
|
-
shouldRedirectTo: resolvePath(type.path, correctSlug, locale
|
|
787
|
+
shouldRedirectTo: urlBuilder.resolvePath(type.path, correctSlug, locale)
|
|
807
788
|
};
|
|
808
789
|
}
|
|
809
790
|
if (docLocale === defaultLocale) {
|
|
810
|
-
return
|
|
811
|
-
{ document: found, actualLocale: defaultLocale },
|
|
812
|
-
locale,
|
|
813
|
-
defaultLocale,
|
|
814
|
-
allDocs,
|
|
815
|
-
type
|
|
816
|
-
);
|
|
791
|
+
return { document: found, actualLocale: defaultLocale };
|
|
817
792
|
}
|
|
818
793
|
if (!type.path) {
|
|
819
794
|
return { document: null, actualLocale: locale };
|
|
@@ -821,39 +796,21 @@ function resolveLocalizedDocument(slug, locale, defaultLocale, allDocs, type) {
|
|
|
821
796
|
return {
|
|
822
797
|
document: null,
|
|
823
798
|
actualLocale: locale,
|
|
824
|
-
shouldRedirectTo: resolvePath(type.path, found.enSlug, locale
|
|
799
|
+
shouldRedirectTo: urlBuilder.resolvePath(type.path, found.enSlug, locale)
|
|
825
800
|
};
|
|
826
801
|
}
|
|
827
802
|
if (locale !== defaultLocale) {
|
|
828
803
|
const enDoc = allDocs.get(defaultLocale)?.bySlug.get(slug);
|
|
829
804
|
if (enDoc && type.indexFallback === "en") {
|
|
830
|
-
return
|
|
831
|
-
{ document: enDoc, actualLocale: defaultLocale },
|
|
832
|
-
locale,
|
|
833
|
-
defaultLocale,
|
|
834
|
-
allDocs,
|
|
835
|
-
type
|
|
836
|
-
);
|
|
805
|
+
return { document: enDoc, actualLocale: defaultLocale };
|
|
837
806
|
}
|
|
838
807
|
const byEn = idx?.byEnSlug.get(slug);
|
|
839
808
|
if (byEn) {
|
|
840
|
-
return
|
|
841
|
-
{ document: byEn, actualLocale: locale },
|
|
842
|
-
locale,
|
|
843
|
-
defaultLocale,
|
|
844
|
-
allDocs,
|
|
845
|
-
type
|
|
846
|
-
);
|
|
809
|
+
return { document: byEn, actualLocale: locale };
|
|
847
810
|
}
|
|
848
811
|
const fallback = allDocs.get(defaultLocale)?.bySlug.get(slug);
|
|
849
812
|
if (fallback && type.indexFallback === "en") {
|
|
850
|
-
return
|
|
851
|
-
{ document: fallback, actualLocale: defaultLocale },
|
|
852
|
-
locale,
|
|
853
|
-
defaultLocale,
|
|
854
|
-
allDocs,
|
|
855
|
-
type
|
|
856
|
-
);
|
|
813
|
+
return { document: fallback, actualLocale: defaultLocale };
|
|
857
814
|
}
|
|
858
815
|
}
|
|
859
816
|
return { document: null, actualLocale: locale };
|
|
@@ -895,6 +852,7 @@ function buildRuntime(config, type, getRuntime) {
|
|
|
895
852
|
}
|
|
896
853
|
return type.path;
|
|
897
854
|
}
|
|
855
|
+
const urlBuilder = createUrlBuilder(config);
|
|
898
856
|
const runtime = {
|
|
899
857
|
id: type.id,
|
|
900
858
|
config: type,
|
|
@@ -910,15 +868,21 @@ function buildRuntime(config, type, getRuntime) {
|
|
|
910
868
|
return load().get(locale)?.bySlug.get(slug) ?? null;
|
|
911
869
|
},
|
|
912
870
|
resolve(slug, locale) {
|
|
913
|
-
const result = resolveLocalizedDocument(
|
|
871
|
+
const result = resolveLocalizedDocument(
|
|
872
|
+
slug,
|
|
873
|
+
locale,
|
|
874
|
+
config.defaultLocale,
|
|
875
|
+
load(),
|
|
876
|
+
type,
|
|
877
|
+
config.localeRouting
|
|
878
|
+
);
|
|
914
879
|
if (result.document && type.path) {
|
|
915
880
|
return {
|
|
916
881
|
...result,
|
|
917
|
-
canonicalPath: resolvePath(
|
|
882
|
+
canonicalPath: urlBuilder.resolvePath(
|
|
918
883
|
type.path,
|
|
919
884
|
result.document.slug,
|
|
920
|
-
result.actualLocale
|
|
921
|
-
config.defaultLocale
|
|
885
|
+
result.actualLocale
|
|
922
886
|
)
|
|
923
887
|
};
|
|
924
888
|
}
|
|
@@ -942,10 +906,9 @@ function buildRuntime(config, type, getRuntime) {
|
|
|
942
906
|
alternates(doc) {
|
|
943
907
|
const pathTemplate = assertRoutable("alternates");
|
|
944
908
|
const out = {
|
|
945
|
-
[config.defaultLocale]: resolvePath(
|
|
909
|
+
[config.defaultLocale]: urlBuilder.resolvePath(
|
|
946
910
|
pathTemplate,
|
|
947
911
|
doc.enSlug,
|
|
948
|
-
config.defaultLocale,
|
|
949
912
|
config.defaultLocale
|
|
950
913
|
)
|
|
951
914
|
};
|
|
@@ -954,7 +917,7 @@ function buildRuntime(config, type, getRuntime) {
|
|
|
954
917
|
if (locale === config.defaultLocale) continue;
|
|
955
918
|
const translated = all.get(locale)?.byEnSlug.get(doc.enSlug);
|
|
956
919
|
if (translated) {
|
|
957
|
-
out[locale] = resolvePath(pathTemplate, translated.slug, locale
|
|
920
|
+
out[locale] = urlBuilder.resolvePath(pathTemplate, translated.slug, locale);
|
|
958
921
|
}
|
|
959
922
|
}
|
|
960
923
|
return out;
|
|
@@ -969,7 +932,7 @@ function buildRuntime(config, type, getRuntime) {
|
|
|
969
932
|
},
|
|
970
933
|
url(slug, locale) {
|
|
971
934
|
const pathTemplate = assertRoutable("url");
|
|
972
|
-
return resolvePath(pathTemplate, slug, locale
|
|
935
|
+
return urlBuilder.resolvePath(pathTemplate, slug, locale);
|
|
973
936
|
},
|
|
974
937
|
related(doc, fieldName, locale) {
|
|
975
938
|
const meta = relationFields.get(fieldName);
|
|
@@ -1031,87 +994,150 @@ function createProject(config) {
|
|
|
1031
994
|
}
|
|
1032
995
|
};
|
|
1033
996
|
}
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
997
|
+
var redirectFromSchema = z.union([
|
|
998
|
+
slugPatternSchema,
|
|
999
|
+
z.array(slugPatternSchema).min(1).max(20)
|
|
1000
|
+
]);
|
|
1001
|
+
var typeRedirectEntrySchema = z.object({
|
|
1002
|
+
from: redirectFromSchema,
|
|
1003
|
+
toSlug: slugPatternSchema.optional(),
|
|
1004
|
+
toType: z.string().min(1).optional(),
|
|
1005
|
+
toUrl: z.string().min(1).optional(),
|
|
1006
|
+
permanent: z.boolean().optional()
|
|
1007
|
+
}).superRefine((entry, ctx) => {
|
|
1008
|
+
const hasToSlug = entry.toSlug !== void 0;
|
|
1009
|
+
const hasToUrl = entry.toUrl !== void 0;
|
|
1010
|
+
const hasToType = entry.toType !== void 0;
|
|
1011
|
+
const targetCount = Number(hasToSlug) + Number(hasToUrl);
|
|
1012
|
+
if (targetCount !== 1) {
|
|
1013
|
+
ctx.addIssue({
|
|
1014
|
+
code: "custom",
|
|
1015
|
+
message: "Each redirect must specify exactly one of toSlug/toType+toSlug or toUrl",
|
|
1016
|
+
path: ["toSlug"]
|
|
1017
|
+
});
|
|
1018
|
+
return;
|
|
1019
|
+
}
|
|
1020
|
+
if (hasToUrl && hasToType) {
|
|
1021
|
+
ctx.addIssue({
|
|
1022
|
+
code: "custom",
|
|
1023
|
+
message: "toUrl cannot be combined with toType",
|
|
1024
|
+
path: ["toUrl"]
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
if (hasToType && !hasToSlug) {
|
|
1028
|
+
ctx.addIssue({
|
|
1029
|
+
code: "custom",
|
|
1030
|
+
message: "Cross-type redirects require both toType and toSlug",
|
|
1031
|
+
path: ["toSlug"]
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
});
|
|
1035
|
+
var typeRedirectsFileSchema = z.object({
|
|
1036
|
+
redirects: z.array(typeRedirectEntrySchema).max(500)
|
|
1037
|
+
});
|
|
1038
|
+
function normalizeRedirectFrom(from) {
|
|
1039
|
+
return Array.isArray(from) ? from : [from];
|
|
1040
|
+
}
|
|
1041
|
+
function parseRedirectEntry(entry) {
|
|
1042
|
+
const fromSlugs = normalizeRedirectFrom(entry.from);
|
|
1043
|
+
if (entry.toUrl !== void 0) {
|
|
1044
|
+
return {
|
|
1045
|
+
fromSlugs,
|
|
1046
|
+
kind: "anywhere",
|
|
1047
|
+
toUrl: entry.toUrl,
|
|
1048
|
+
permanent: entry.permanent ?? true
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
if (entry.toType !== void 0) {
|
|
1052
|
+
return {
|
|
1053
|
+
fromSlugs,
|
|
1054
|
+
kind: "cross-type",
|
|
1055
|
+
toType: entry.toType,
|
|
1056
|
+
toSlug: entry.toSlug,
|
|
1057
|
+
permanent: entry.permanent ?? true
|
|
1058
|
+
};
|
|
1059
|
+
}
|
|
1060
|
+
return {
|
|
1061
|
+
fromSlugs,
|
|
1062
|
+
kind: "same-type",
|
|
1063
|
+
toSlug: entry.toSlug,
|
|
1064
|
+
permanent: entry.permanent ?? true
|
|
1065
|
+
};
|
|
1038
1066
|
}
|
|
1039
1067
|
|
|
1040
|
-
// src/
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
const
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1068
|
+
// src/redirects/load-type-redirects.ts
|
|
1069
|
+
var TYPE_REDIRECTS_FILENAME = "_redirects.json";
|
|
1070
|
+
function redirectsFilePath(config, type) {
|
|
1071
|
+
return path.join(config.rootDir, type.contentDir, TYPE_REDIRECTS_FILENAME);
|
|
1072
|
+
}
|
|
1073
|
+
function loadTypeRedirectsFile(config, type) {
|
|
1074
|
+
const filePath = redirectsFilePath(config, type);
|
|
1075
|
+
if (!fs2.existsSync(filePath)) return null;
|
|
1076
|
+
let raw;
|
|
1077
|
+
try {
|
|
1078
|
+
raw = JSON.parse(fs2.readFileSync(filePath, "utf8"));
|
|
1079
|
+
} catch (error) {
|
|
1080
|
+
throw new Error(
|
|
1081
|
+
`${type.id}: failed to parse ${TYPE_REDIRECTS_FILENAME}: ${error instanceof Error ? error.message : String(error)}`
|
|
1082
|
+
);
|
|
1083
|
+
}
|
|
1084
|
+
const parsed = typeRedirectsFileSchema.safeParse(raw);
|
|
1085
|
+
if (!parsed.success) {
|
|
1086
|
+
const details = parsed.error.issues.map((issue) => `${issue.path.join(".") || "root"}: ${issue.message}`).join("; ");
|
|
1087
|
+
throw new Error(`${type.id}: invalid ${TYPE_REDIRECTS_FILENAME}: ${details}`);
|
|
1050
1088
|
}
|
|
1089
|
+
return {
|
|
1090
|
+
contentTypeId: type.id,
|
|
1091
|
+
contentDir: type.contentDir,
|
|
1092
|
+
filePath,
|
|
1093
|
+
entries: parsed.data.redirects.map(parseRedirectEntry)
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1096
|
+
function loadAllTypeRedirects(config) {
|
|
1097
|
+
const out = [];
|
|
1051
1098
|
for (const type of config.types) {
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
});
|
|
1076
|
-
continue;
|
|
1077
|
-
}
|
|
1078
|
-
const existing = aliasToTarget.get(alias);
|
|
1079
|
-
if (existing) {
|
|
1080
|
-
issues.push({
|
|
1081
|
-
contentTypeId: type.id,
|
|
1082
|
-
enSlug,
|
|
1083
|
-
field: "aliases",
|
|
1084
|
-
message: `Alias "${alias}" is already claimed by ${existing.contentTypeId}/${existing.canonicalSlug}`,
|
|
1085
|
-
level: "error"
|
|
1086
|
-
});
|
|
1087
|
-
continue;
|
|
1088
|
-
}
|
|
1089
|
-
aliasToTarget.set(alias, {
|
|
1090
|
-
contentTypeId: type.id,
|
|
1091
|
-
canonicalSlug: enSlug,
|
|
1092
|
-
path: type.path
|
|
1093
|
-
});
|
|
1094
|
-
allAliasSlugs.add(alias);
|
|
1099
|
+
const loaded = loadTypeRedirectsFile(config, type);
|
|
1100
|
+
if (loaded) out.push(loaded);
|
|
1101
|
+
}
|
|
1102
|
+
return out;
|
|
1103
|
+
}
|
|
1104
|
+
function collectRedirectSourceSlugs(loaded) {
|
|
1105
|
+
const slugs = /* @__PURE__ */ new Set();
|
|
1106
|
+
for (const file of loaded) {
|
|
1107
|
+
for (const entry of file.entries) {
|
|
1108
|
+
for (const from of entry.fromSlugs) {
|
|
1109
|
+
slugs.add(from);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
return slugs;
|
|
1114
|
+
}
|
|
1115
|
+
function collectOutboundRedirectSourcesByType(loaded) {
|
|
1116
|
+
const out = /* @__PURE__ */ new Map();
|
|
1117
|
+
for (const file of loaded) {
|
|
1118
|
+
const set = out.get(file.contentTypeId) ?? /* @__PURE__ */ new Set();
|
|
1119
|
+
for (const entry of file.entries) {
|
|
1120
|
+
for (const from of entry.fromSlugs) {
|
|
1121
|
+
set.add(from);
|
|
1095
1122
|
}
|
|
1096
1123
|
}
|
|
1124
|
+
out.set(file.contentTypeId, set);
|
|
1097
1125
|
}
|
|
1098
|
-
return
|
|
1126
|
+
return out;
|
|
1099
1127
|
}
|
|
1100
1128
|
|
|
1101
1129
|
// src/redirects/build-redirects.ts
|
|
1102
1130
|
function getRedirectSourceSlugs(project) {
|
|
1103
|
-
const
|
|
1104
|
-
const
|
|
1131
|
+
const loaded = loadAllTypeRedirects(project.config);
|
|
1132
|
+
const aliasSlugs = collectRedirectSourceSlugs(loaded);
|
|
1133
|
+
const outboundByType = collectOutboundRedirectSourcesByType(loaded);
|
|
1105
1134
|
for (const type of project.config.types) {
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
const doc = readEnDocument(project.config, type, enSlug);
|
|
1109
|
-
if (doc?.redirectTo) outbound.add(enSlug);
|
|
1135
|
+
if (!outboundByType.has(type.id)) {
|
|
1136
|
+
outboundByType.set(type.id, /* @__PURE__ */ new Set());
|
|
1110
1137
|
}
|
|
1111
|
-
outboundByType.set(type.id, outbound);
|
|
1112
1138
|
}
|
|
1113
1139
|
return {
|
|
1114
|
-
aliasSlugs
|
|
1140
|
+
aliasSlugs,
|
|
1115
1141
|
outboundByType
|
|
1116
1142
|
};
|
|
1117
1143
|
}
|
|
@@ -1119,13 +1145,12 @@ function getRedirectSourceSlugs(project) {
|
|
|
1119
1145
|
// src/sitemap/join-base-url.ts
|
|
1120
1146
|
function joinBaseUrl(baseUrl, pathname) {
|
|
1121
1147
|
const origin = baseUrl.replace(/\/$/, "");
|
|
1122
|
-
const
|
|
1123
|
-
return `${origin}${
|
|
1148
|
+
const path6 = pathname.startsWith("/") ? pathname : `/${pathname}`;
|
|
1149
|
+
return `${origin}${path6}`;
|
|
1124
1150
|
}
|
|
1125
1151
|
|
|
1126
1152
|
// src/sitemap/generate-sitemap.ts
|
|
1127
1153
|
function shouldIncludeEnDoc(enDoc, enSlug, redirectSources, contentTypeId, excludeNoindex) {
|
|
1128
|
-
if (enDoc.redirectTo) return false;
|
|
1129
1154
|
if (redirectSources.aliasSlugs.has(enSlug)) return false;
|
|
1130
1155
|
const outbound = redirectSources.outboundByType.get(contentTypeId);
|
|
1131
1156
|
if (outbound?.has(enSlug)) return false;
|
|
@@ -1223,6 +1248,6 @@ function createScribe(input) {
|
|
|
1223
1248
|
return scribe;
|
|
1224
1249
|
}
|
|
1225
1250
|
|
|
1226
|
-
export { createScribe, isRoutableType };
|
|
1251
|
+
export { createScribe, createUrlBuilder, isRoutableType };
|
|
1227
1252
|
//# sourceMappingURL=runtime.js.map
|
|
1228
1253
|
//# sourceMappingURL=runtime.js.map
|