@justanarthur/payload-www 0.1.1
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 +381 -0
- package/dist/access.d.ts +11 -0
- package/dist/access.js +34 -0
- package/dist/blocks.d.ts +24 -0
- package/dist/blocks.js +75 -0
- package/dist/collections.d.ts +200 -0
- package/dist/collections.js +625 -0
- package/dist/components.d.ts +6 -0
- package/dist/components.js +38 -0
- package/dist/config.d.ts +100 -0
- package/dist/config.js +914 -0
- package/dist/core-access.d.ts +11 -0
- package/dist/core-access.js +34 -0
- package/dist/core-blocks.d.ts +24 -0
- package/dist/core-blocks.js +75 -0
- package/dist/core-fields.d.ts +36 -0
- package/dist/core-fields.js +134 -0
- package/dist/core-utils.d.ts +16 -0
- package/dist/core-utils.js +59 -0
- package/dist/data-collections.d.ts +200 -0
- package/dist/data-collections.js +625 -0
- package/dist/data-seed.d.ts +76 -0
- package/dist/data-seed.js +212 -0
- package/dist/data-test.d.ts +30 -0
- package/dist/data-test.js +1018 -0
- package/dist/fields.d.ts +36 -0
- package/dist/fields.js +134 -0
- package/dist/globals.d.ts +48 -0
- package/dist/globals.js +228 -0
- package/dist/hooks.d.ts +108 -0
- package/dist/hooks.js +196 -0
- package/dist/imagehash.d.ts +3 -0
- package/dist/imagehash.js +24 -0
- package/dist/import-map-provider.d.ts +20 -0
- package/dist/import-map-provider.js +26 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +38 -0
- package/dist/metadata.d.ts +122 -0
- package/dist/metadata.js +335 -0
- package/dist/pages.d.ts +323 -0
- package/dist/pages.js +1016 -0
- package/dist/render-components.d.ts +42 -0
- package/dist/render-components.js +144 -0
- package/dist/render-metadata.d.ts +122 -0
- package/dist/render-metadata.js +335 -0
- package/dist/render-pages.d.ts +574 -0
- package/dist/render-pages.js +1450 -0
- package/dist/render-utils.d.ts +158 -0
- package/dist/render-utils.js +341 -0
- package/dist/seed.d.ts +76 -0
- package/dist/seed.js +212 -0
- package/dist/server.d.ts +922 -0
- package/dist/server.js +2055 -0
- package/dist/test.d.ts +30 -0
- package/dist/test.js +1018 -0
- package/dist/translator.d.ts +2 -0
- package/dist/translator.js +24 -0
- package/dist/utils.d.ts +16 -0
- package/dist/utils.js +59 -0
- package/dist/with-www-config.d.ts +100 -0
- package/dist/with-www-config.js +914 -0
- package/package.json +246 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
type CreatePreviewHandlerOptions = {
|
|
2
|
+
/** Resolves the host's site URL (used to construct preview links if
|
|
3
|
+
* the host navigates back to the canonical site). */
|
|
4
|
+
getServerSideURL: () => string;
|
|
5
|
+
/**
|
|
6
|
+
* Secret token the host configures in `process.env.PREVIEW_SECRET`.
|
|
7
|
+
* The handler validates `?previewSecret=...` against this value and
|
|
8
|
+
* 401s on mismatch.
|
|
9
|
+
*/
|
|
10
|
+
secret: string;
|
|
11
|
+
/**
|
|
12
|
+
* Whether to enable draft mode on a valid preview. Hosts that use
|
|
13
|
+
* their own preview mechanism can pass `false`.
|
|
14
|
+
* Default: `true`.
|
|
15
|
+
*/
|
|
16
|
+
enableDraftMode?: boolean;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Build a Next.js `GET` route handler for the host's
|
|
20
|
+
* `app/(payload)/next/preview/route.ts`. Validates the preview secret
|
|
21
|
+
* from the query string, enables draft mode if configured, and
|
|
22
|
+
* redirects to the `?path=...` value.
|
|
23
|
+
*
|
|
24
|
+
* Usage:
|
|
25
|
+
*
|
|
26
|
+
* // app/(payload)/next/preview/route.ts
|
|
27
|
+
* import { createPreviewHandler } from '@justanarthur/payload-www/render-utils'
|
|
28
|
+
* import { getServerSideURL } from '@/utilities/getURL'
|
|
29
|
+
* const GET = createPreviewHandler({
|
|
30
|
+
* getServerSideURL,
|
|
31
|
+
* secret: process.env.PREVIEW_SECRET || ''
|
|
32
|
+
* })
|
|
33
|
+
*/
|
|
34
|
+
declare function createPreviewHandler(options: CreatePreviewHandlerOptions): (req: Request) => Promise<Response>;
|
|
35
|
+
import { MetadataRoute } from "next";
|
|
36
|
+
type CreateSitemapFileOptions = {
|
|
37
|
+
/**
|
|
38
|
+
* Collection slugs whose docs should appear in the sitemap. Each
|
|
39
|
+
* collection must have a `slug` field on its documents. The lib
|
|
40
|
+
* emits a single unified sitemap at `/sitemap.xml` listing every
|
|
41
|
+
* doc from every configured collection across every active locale.
|
|
42
|
+
*/
|
|
43
|
+
collections: string[];
|
|
44
|
+
/**
|
|
45
|
+
* The Payload config promise. The factory resolves it at request
|
|
46
|
+
* time.
|
|
47
|
+
*/
|
|
48
|
+
config: Promise<any>;
|
|
49
|
+
/**
|
|
50
|
+
* The host's site URL — used to build absolute URLs.
|
|
51
|
+
*/
|
|
52
|
+
getServerSideURL: () => string;
|
|
53
|
+
/**
|
|
54
|
+
* Locale prefix mode. Mirrors next-intl's `localePrefix` so the
|
|
55
|
+
* sitemap URLs match the host's actual route shape:
|
|
56
|
+
*
|
|
57
|
+
* - `'always'`: every URL is prefixed with `/{locale}/…`
|
|
58
|
+
* (e.g. `/en/about`, `/uk/about`). The default.
|
|
59
|
+
* - `'as-needed'`: the default locale renders without a prefix
|
|
60
|
+
* (e.g. `/about`), other locales are prefixed (`/uk/about`).
|
|
61
|
+
* - `'never'`: no locale prefix (only useful for single-locale
|
|
62
|
+
* sites or hosts that don't expose locales in the URL).
|
|
63
|
+
*
|
|
64
|
+
* The default locale is read from `config.localization.defaultLocale`
|
|
65
|
+
* — the same single source of truth that next-intl and the rest of
|
|
66
|
+
* the lib use.
|
|
67
|
+
*/
|
|
68
|
+
localePrefix?: "always" | "as-needed" | "never";
|
|
69
|
+
/**
|
|
70
|
+
* Optional filter for which locales to include in the sitemap.
|
|
71
|
+
* Defaults to every locale declared in `config.localization.locales`.
|
|
72
|
+
*/
|
|
73
|
+
locales?: string[];
|
|
74
|
+
/**
|
|
75
|
+
* Optional URL path prefix per collection. The Pages collection
|
|
76
|
+
* lives at the root (`/about`) so it doesn't need a prefix, but
|
|
77
|
+
* collections mounted under a sub-route (e.g. a posts collection
|
|
78
|
+
* under `/posts/[...slug]`) need their URLs prefixed with `/posts`
|
|
79
|
+
* so the sitemap entries match the actual route.
|
|
80
|
+
*
|
|
81
|
+
* Defaults to `''` (no prefix). Pass a value like `'/posts'`
|
|
82
|
+
* (leading slash, no trailing slash) for a sub-routed collection.
|
|
83
|
+
*/
|
|
84
|
+
urlPrefixes?: Record<string, string>;
|
|
85
|
+
/**
|
|
86
|
+
* Optional priority / changeFrequency overrides per collection.
|
|
87
|
+
*/
|
|
88
|
+
perCollection?: Record<string, {
|
|
89
|
+
priority?: number;
|
|
90
|
+
changefreq?: "always" | "hourly" | "daily" | "weekly" | "monthly" | "yearly" | "never";
|
|
91
|
+
}>;
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* A Next.js sitemap function for the host's
|
|
95
|
+
* `app/(frontend)/sitemap.ts`. Returns the typed
|
|
96
|
+
* `MetadataRoute.Sitemap` array — Next.js handles XML serialization.
|
|
97
|
+
*
|
|
98
|
+
* Usage — single unified sitemap:
|
|
99
|
+
*
|
|
100
|
+
* // app/(frontend)/sitemap.ts
|
|
101
|
+
* import { createSitemapFile } from '@justanarthur/payload-www/render-utils'
|
|
102
|
+
* import configPromise from '@payload-config'
|
|
103
|
+
* import { getServerSideURL } from '@/utilities/getURL'
|
|
104
|
+
*
|
|
105
|
+
* createSitemapFile({
|
|
106
|
+
* collections: ['pages', 'posts'],
|
|
107
|
+
* config: configPromise,
|
|
108
|
+
* getServerSideURL,
|
|
109
|
+
* localePrefix: 'as-needed',
|
|
110
|
+
* urlPrefixes: { posts: '/posts' }
|
|
111
|
+
* })
|
|
112
|
+
*
|
|
113
|
+
* The lib resolves the sitemap at request time, queries every
|
|
114
|
+
* configured collection across every active locale, and emits one
|
|
115
|
+
* unified `<urlset>` with full `alternates.languages` hreflang blocks
|
|
116
|
+
* per URL. Google accepts up to 50,000 URLs per file.
|
|
117
|
+
*/
|
|
118
|
+
type SitemapFunction = () => Promise<MetadataRoute.Sitemap>;
|
|
119
|
+
declare function createSitemapFile(options: CreateSitemapFileOptions): SitemapFunction;
|
|
120
|
+
import { ReactElement } from "react";
|
|
121
|
+
/**
|
|
122
|
+
* Hreflang alternate URLs as a `lang → url` map. Always includes an
|
|
123
|
+
* `'x-default'` entry pointing at the default locale's URL.
|
|
124
|
+
*/
|
|
125
|
+
type HreflangAlternates = Record<string, string>;
|
|
126
|
+
type LocaleSwitcherProps = {
|
|
127
|
+
/**
|
|
128
|
+
* The currently-active locale (the one being rendered). The
|
|
129
|
+
* switcher marks the corresponding link with `aria-current="true"`.
|
|
130
|
+
*/
|
|
131
|
+
currentLocale: string;
|
|
132
|
+
/**
|
|
133
|
+
* The hreflang alternates map as returned by the lib's metadata
|
|
134
|
+
* pipeline. Keys are locale codes; values are absolute URLs. An
|
|
135
|
+
* `'x-default'` entry is also expected.
|
|
136
|
+
*/
|
|
137
|
+
hreflangAlternates: HreflangAlternates;
|
|
138
|
+
/**
|
|
139
|
+
* Optional human-readable labels per locale. When missing, the
|
|
140
|
+
* switcher falls back to uppercased locale codes.
|
|
141
|
+
*/
|
|
142
|
+
labels?: Record<string, string>;
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Render a list of links to the same page in every other locale.
|
|
146
|
+
* The component is server-renderable (no `'use client'`) and emits
|
|
147
|
+
* a single `<nav>` element with one `<a>` per locale plus an
|
|
148
|
+
* `x-default` fallback. The lib's `<PageShowcase>` mounts it as a
|
|
149
|
+
* child of the sidebar; hosts can also drop it elsewhere on the
|
|
150
|
+
* page.
|
|
151
|
+
*/
|
|
152
|
+
declare function LocaleSwitcher({ currentLocale, hreflangAlternates, labels }: LocaleSwitcherProps): ReactElement;
|
|
153
|
+
declare const _default: {
|
|
154
|
+
createPreviewHandler: typeof createPreviewHandler;
|
|
155
|
+
createSitemapFile: typeof createSitemapFile;
|
|
156
|
+
LocaleSwitcher: typeof LocaleSwitcher;
|
|
157
|
+
};
|
|
158
|
+
export { _default as default, createSitemapFile, createPreviewHandler, SitemapFunction, LocaleSwitcherProps, LocaleSwitcher, CreateSitemapFileOptions, CreatePreviewHandlerOptions };
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __returnValue = (v) => v;
|
|
4
|
+
function __exportSetter(name, newValue) {
|
|
5
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
6
|
+
}
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, {
|
|
10
|
+
get: all[name],
|
|
11
|
+
enumerable: true,
|
|
12
|
+
configurable: true,
|
|
13
|
+
set: __exportSetter.bind(all, name)
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
17
|
+
|
|
18
|
+
// src/render/components/LocaleSwitcher.tsx
|
|
19
|
+
var exports_LocaleSwitcher = {};
|
|
20
|
+
__export(exports_LocaleSwitcher, {
|
|
21
|
+
LocaleSwitcher: () => LocaleSwitcher
|
|
22
|
+
});
|
|
23
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
24
|
+
function LocaleSwitcher({
|
|
25
|
+
currentLocale,
|
|
26
|
+
hreflangAlternates,
|
|
27
|
+
labels
|
|
28
|
+
}) {
|
|
29
|
+
const locales = Object.keys(hreflangAlternates).filter((k) => k !== "x-default");
|
|
30
|
+
return /* @__PURE__ */ jsx("nav", {
|
|
31
|
+
"aria-label": "Language",
|
|
32
|
+
className: "locale-switcher",
|
|
33
|
+
children: /* @__PURE__ */ jsxs("ul", {
|
|
34
|
+
className: "flex flex-wrap gap-2 list-none p-0 m-0",
|
|
35
|
+
children: [
|
|
36
|
+
locales.map((locale) => {
|
|
37
|
+
const href = hreflangAlternates[locale];
|
|
38
|
+
if (!href)
|
|
39
|
+
return null;
|
|
40
|
+
const isCurrent = locale === currentLocale;
|
|
41
|
+
return /* @__PURE__ */ jsx("li", {
|
|
42
|
+
children: /* @__PURE__ */ jsx("a", {
|
|
43
|
+
href,
|
|
44
|
+
"aria-current": isCurrent ? "true" : undefined,
|
|
45
|
+
hrefLang: locale,
|
|
46
|
+
className: "locale-switcher__link",
|
|
47
|
+
"data-locale": locale,
|
|
48
|
+
children: labels?.[locale] ?? locale.toUpperCase()
|
|
49
|
+
})
|
|
50
|
+
}, locale);
|
|
51
|
+
}),
|
|
52
|
+
hreflangAlternates["x-default"] ? /* @__PURE__ */ jsx("li", {
|
|
53
|
+
children: /* @__PURE__ */ jsx("a", {
|
|
54
|
+
href: hreflangAlternates["x-default"],
|
|
55
|
+
hrefLang: "x-default",
|
|
56
|
+
className: "locale-switcher__link",
|
|
57
|
+
"data-locale": "x-default",
|
|
58
|
+
children: labels?.["x-default"] ?? "Default"
|
|
59
|
+
})
|
|
60
|
+
}, "x-default") : null
|
|
61
|
+
]
|
|
62
|
+
})
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
var init_LocaleSwitcher = () => {};
|
|
66
|
+
|
|
67
|
+
// src/render/preview/createPreviewHandler.ts
|
|
68
|
+
function createPreviewHandler(options) {
|
|
69
|
+
const { getServerSideURL: _getServerSideURL, secret, enableDraftMode = true } = options;
|
|
70
|
+
return async function GET(req) {
|
|
71
|
+
const { draftMode } = await import("next/headers");
|
|
72
|
+
const { redirect } = await import("next/navigation");
|
|
73
|
+
const url = new URL(req.url);
|
|
74
|
+
const path = url.searchParams.get("path") ?? "/";
|
|
75
|
+
const previewSecret = url.searchParams.get("previewSecret");
|
|
76
|
+
if (!previewSecret || previewSecret !== secret) {
|
|
77
|
+
return new Response("Invalid preview secret", { status: 401 });
|
|
78
|
+
}
|
|
79
|
+
if (enableDraftMode) {
|
|
80
|
+
(await draftMode()).enable();
|
|
81
|
+
}
|
|
82
|
+
redirect(path);
|
|
83
|
+
return new Response(null, { status: 204 });
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// src/render/_locale.ts
|
|
88
|
+
function prefixFor(locale, defaultLocale, mode) {
|
|
89
|
+
if (mode === "never")
|
|
90
|
+
return "";
|
|
91
|
+
if (mode === "as-needed" && locale === defaultLocale)
|
|
92
|
+
return "";
|
|
93
|
+
return `/${locale}`;
|
|
94
|
+
}
|
|
95
|
+
function resolveLocale(req) {
|
|
96
|
+
if (!req || typeof req !== "object")
|
|
97
|
+
return "";
|
|
98
|
+
const r = req;
|
|
99
|
+
if (typeof r.locale === "string" && r.locale.length > 0)
|
|
100
|
+
return r.locale;
|
|
101
|
+
const fallback = r.payload?.config?.localization?.defaultLocale;
|
|
102
|
+
if (typeof fallback === "string" && fallback.length > 0)
|
|
103
|
+
return fallback;
|
|
104
|
+
return "";
|
|
105
|
+
}
|
|
106
|
+
function allLocales(req) {
|
|
107
|
+
if (!req || typeof req !== "object")
|
|
108
|
+
return [];
|
|
109
|
+
const r = req;
|
|
110
|
+
const list = r.payload?.config?.localization?.locales;
|
|
111
|
+
if (!Array.isArray(list) || list.length === 0)
|
|
112
|
+
return [];
|
|
113
|
+
const out = [];
|
|
114
|
+
for (const entry of list) {
|
|
115
|
+
if (typeof entry === "string" && entry.length > 0) {
|
|
116
|
+
out.push(entry);
|
|
117
|
+
} else if (entry && typeof entry === "object" && "code" in entry) {
|
|
118
|
+
const code = entry.code;
|
|
119
|
+
if (typeof code === "string" && code.length > 0)
|
|
120
|
+
out.push(code);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return out;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// src/render/metadata/hreflang.ts
|
|
127
|
+
async function buildHreflangAlternates({
|
|
128
|
+
siteUrl,
|
|
129
|
+
locale,
|
|
130
|
+
urlPrefix,
|
|
131
|
+
storedSlug,
|
|
132
|
+
queryAllLocaleSlugs,
|
|
133
|
+
nested,
|
|
134
|
+
homeSlug,
|
|
135
|
+
defaultLocale,
|
|
136
|
+
locales,
|
|
137
|
+
localePrefix = "always"
|
|
138
|
+
}) {
|
|
139
|
+
const allLocaleSlugs = await queryAllLocaleSlugs(storedSlug, locale);
|
|
140
|
+
const languages = {};
|
|
141
|
+
const urlFor = (l, slug) => {
|
|
142
|
+
const trimmedPrefix = urlPrefix.replace(/^\/|\/$/g, "");
|
|
143
|
+
const prefixSegment = trimmedPrefix ? `/${trimmedPrefix}` : "";
|
|
144
|
+
const urlPath = slug === homeSlug ? "/" : nested ? "/" + slug.replaceAll("_", "/") : "/" + slug;
|
|
145
|
+
const localeSegment = localePrefix === "never" ? "" : localePrefix === "as-needed" && l === defaultLocale ? "" : `/${l}`;
|
|
146
|
+
return `${siteUrl}${localeSegment}${prefixSegment}${urlPath}`;
|
|
147
|
+
};
|
|
148
|
+
for (const l of locales) {
|
|
149
|
+
const slugForLocale = allLocaleSlugs?.[l];
|
|
150
|
+
if (!slugForLocale)
|
|
151
|
+
continue;
|
|
152
|
+
languages[l] = urlFor(l, slugForLocale);
|
|
153
|
+
}
|
|
154
|
+
if (allLocaleSlugs?.[defaultLocale]) {
|
|
155
|
+
languages["x-default"] = urlFor(defaultLocale, allLocaleSlugs[defaultLocale]);
|
|
156
|
+
}
|
|
157
|
+
return languages;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// src/render/metadata/query.ts
|
|
161
|
+
import { getPayload } from "payload";
|
|
162
|
+
import { cache } from "react";
|
|
163
|
+
|
|
164
|
+
// src/core/utils/getFromImportMap.ts
|
|
165
|
+
function getFromImportMap(key, importMap) {
|
|
166
|
+
return importMap[key.includes("#") ? key : key + "#default"];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// src/render/metadata/query.ts
|
|
170
|
+
var queryDocBySlug = cache(async function queryDocBySlug2({
|
|
171
|
+
collectionSlug,
|
|
172
|
+
slug,
|
|
173
|
+
slugField = "slug",
|
|
174
|
+
locale,
|
|
175
|
+
draft = false,
|
|
176
|
+
config
|
|
177
|
+
}) {
|
|
178
|
+
const payload = await getPayload({ config });
|
|
179
|
+
const result = await payload.find({
|
|
180
|
+
collection: collectionSlug,
|
|
181
|
+
draft,
|
|
182
|
+
limit: 1,
|
|
183
|
+
pagination: false,
|
|
184
|
+
overrideAccess: draft,
|
|
185
|
+
where: { [slugField]: { equals: slug } },
|
|
186
|
+
locale
|
|
187
|
+
});
|
|
188
|
+
return result.docs?.[0] ?? null;
|
|
189
|
+
});
|
|
190
|
+
var queryAllDocs = cache(async function queryAllDocs2({
|
|
191
|
+
collectionSlug,
|
|
192
|
+
slugField = "slug",
|
|
193
|
+
locale,
|
|
194
|
+
config
|
|
195
|
+
}) {
|
|
196
|
+
const payload = await getPayload({ config });
|
|
197
|
+
const result = await payload.find({
|
|
198
|
+
collection: collectionSlug,
|
|
199
|
+
draft: false,
|
|
200
|
+
limit: 1000,
|
|
201
|
+
pagination: false,
|
|
202
|
+
overrideAccess: false,
|
|
203
|
+
select: { [slugField]: true },
|
|
204
|
+
locale
|
|
205
|
+
});
|
|
206
|
+
return result.docs ?? [];
|
|
207
|
+
});
|
|
208
|
+
var queryAllLocaleSlugs = cache(async function queryAllLocaleSlugs2({
|
|
209
|
+
collectionSlug,
|
|
210
|
+
slug,
|
|
211
|
+
slugField = "slug",
|
|
212
|
+
locale,
|
|
213
|
+
config
|
|
214
|
+
}) {
|
|
215
|
+
const payload = await getPayload({ config });
|
|
216
|
+
const result = await payload.find({
|
|
217
|
+
collection: collectionSlug,
|
|
218
|
+
draft: false,
|
|
219
|
+
limit: 1,
|
|
220
|
+
pagination: false,
|
|
221
|
+
overrideAccess: false,
|
|
222
|
+
locale,
|
|
223
|
+
where: { [slugField]: { equals: slug } },
|
|
224
|
+
select: { [slugField]: true }
|
|
225
|
+
});
|
|
226
|
+
const doc = result.docs?.[0];
|
|
227
|
+
if (!doc)
|
|
228
|
+
return;
|
|
229
|
+
const fieldValue = doc?.[slugField];
|
|
230
|
+
if (fieldValue && typeof fieldValue === "object") {
|
|
231
|
+
return fieldValue;
|
|
232
|
+
}
|
|
233
|
+
const resolved = await config;
|
|
234
|
+
const rawLocales = Array.isArray(resolved?.localization?.localeCodes) ? resolved.localization.localeCodes : resolved?.localization?.locales?.map((l) => l.code) ?? [];
|
|
235
|
+
const out = {};
|
|
236
|
+
for (const l of rawLocales)
|
|
237
|
+
out[l] = String(fieldValue ?? slug);
|
|
238
|
+
return out;
|
|
239
|
+
});
|
|
240
|
+
var queryGlobal = cache(async function queryGlobal2({
|
|
241
|
+
globalSlug,
|
|
242
|
+
locale,
|
|
243
|
+
depth = 0,
|
|
244
|
+
draft = false,
|
|
245
|
+
config
|
|
246
|
+
}) {
|
|
247
|
+
const payload = await getPayload({ config });
|
|
248
|
+
try {
|
|
249
|
+
const global = await payload.findGlobal({
|
|
250
|
+
slug: globalSlug,
|
|
251
|
+
depth,
|
|
252
|
+
draft,
|
|
253
|
+
locale
|
|
254
|
+
});
|
|
255
|
+
return global;
|
|
256
|
+
} catch {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
function getRenderModuleExports(exportName, collection, importMap) {
|
|
261
|
+
const path = collection?.custom?.path;
|
|
262
|
+
if (!path)
|
|
263
|
+
return;
|
|
264
|
+
const mod = getFromImportMap(path, importMap);
|
|
265
|
+
return mod?.[exportName];
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// src/render/sitemap/createSitemapFile.ts
|
|
269
|
+
function createSitemapFile(options) {
|
|
270
|
+
const { collections } = options;
|
|
271
|
+
return async function sitemap() {
|
|
272
|
+
const cfg = await options.config;
|
|
273
|
+
const allLocales2 = Array.isArray(cfg.localization?.locales) ? cfg.localization.locales.map((l) => typeof l === "string" ? l : l.code) : [cfg.localization?.defaultLocale ?? "en"];
|
|
274
|
+
const defaultLocale = cfg.localization?.defaultLocale ?? allLocales2[0];
|
|
275
|
+
const activeLocales = Array.isArray(options.locales) && options.locales.length > 0 ? options.locales.filter((l) => allLocales2.includes(l)) : allLocales2;
|
|
276
|
+
const entries = [];
|
|
277
|
+
const seen = new Set;
|
|
278
|
+
for (const collectionSlug of collections) {
|
|
279
|
+
const collectionDefaults = options.perCollection?.[collectionSlug] ?? {};
|
|
280
|
+
const urlPrefix = (options.urlPrefixes?.[collectionSlug] ?? "").replace(/\/$/, "");
|
|
281
|
+
const siteUrl = options.getServerSideURL().replace(/\/$/, "");
|
|
282
|
+
for (const locale of activeLocales) {
|
|
283
|
+
const docs = await queryAllDocs({
|
|
284
|
+
collectionSlug,
|
|
285
|
+
slugField: "slug",
|
|
286
|
+
locale,
|
|
287
|
+
config: options.config
|
|
288
|
+
});
|
|
289
|
+
for (const doc of docs) {
|
|
290
|
+
const storedSlug = doc.slug;
|
|
291
|
+
if (typeof storedSlug !== "string" || storedSlug === "")
|
|
292
|
+
continue;
|
|
293
|
+
const dedupeKey = `${collectionSlug}:${locale}:${storedSlug}`;
|
|
294
|
+
if (seen.has(dedupeKey))
|
|
295
|
+
continue;
|
|
296
|
+
seen.add(dedupeKey);
|
|
297
|
+
const url = `${siteUrl}${prefixFor(locale, defaultLocale, options.localePrefix ?? "always")}${urlPrefix}/${storedSlug}`;
|
|
298
|
+
const languages = await buildHreflangAlternates({
|
|
299
|
+
siteUrl,
|
|
300
|
+
locale,
|
|
301
|
+
urlPrefix,
|
|
302
|
+
storedSlug,
|
|
303
|
+
nested: false,
|
|
304
|
+
homeSlug: "",
|
|
305
|
+
defaultLocale,
|
|
306
|
+
locales: activeLocales,
|
|
307
|
+
localePrefix: options.localePrefix,
|
|
308
|
+
queryAllLocaleSlugs: async (s, l) => {
|
|
309
|
+
const result = await queryAllLocaleSlugs({
|
|
310
|
+
collectionSlug,
|
|
311
|
+
slug: s,
|
|
312
|
+
slugField: "slug",
|
|
313
|
+
locale: l,
|
|
314
|
+
config: options.config
|
|
315
|
+
});
|
|
316
|
+
return result ?? undefined;
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
entries.push({
|
|
320
|
+
url,
|
|
321
|
+
lastModified: doc.updatedAt ? new Date(doc.updatedAt) : undefined,
|
|
322
|
+
changeFrequency: collectionDefaults.changefreq ?? "weekly",
|
|
323
|
+
priority: collectionDefaults.priority ?? 0.5,
|
|
324
|
+
alternates: { languages }
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return entries;
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// src/exports/render-utils.ts
|
|
334
|
+
init_LocaleSwitcher();
|
|
335
|
+
var render_utils_default = { createPreviewHandler, createSitemapFile, LocaleSwitcher };
|
|
336
|
+
export {
|
|
337
|
+
render_utils_default as default,
|
|
338
|
+
createSitemapFile,
|
|
339
|
+
createPreviewHandler,
|
|
340
|
+
LocaleSwitcher
|
|
341
|
+
};
|
package/dist/seed.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Payload } from "payload";
|
|
2
|
+
type SeedPageInput = {
|
|
3
|
+
slug: string;
|
|
4
|
+
title: Record<string, string>;
|
|
5
|
+
meta?: Record<string, {
|
|
6
|
+
title?: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
}>;
|
|
9
|
+
blocks?: Array<Record<string, unknown>>;
|
|
10
|
+
status?: "draft" | "published";
|
|
11
|
+
publishedAt?: string;
|
|
12
|
+
};
|
|
13
|
+
type SeedPostInput = {
|
|
14
|
+
slug: string;
|
|
15
|
+
title: Record<string, string>;
|
|
16
|
+
excerpt?: Record<string, string>;
|
|
17
|
+
content?: Record<string, unknown>;
|
|
18
|
+
status?: "draft" | "published";
|
|
19
|
+
publishedAt?: string;
|
|
20
|
+
};
|
|
21
|
+
type SeedUserInput = {
|
|
22
|
+
email: string;
|
|
23
|
+
password?: string;
|
|
24
|
+
name?: string;
|
|
25
|
+
};
|
|
26
|
+
type SeedCategoryInput = {
|
|
27
|
+
title: string;
|
|
28
|
+
slug?: string;
|
|
29
|
+
};
|
|
30
|
+
type CreateBaseSeedOptions = {
|
|
31
|
+
defaultLocale?: string;
|
|
32
|
+
locales?: string[];
|
|
33
|
+
users?: SeedUserInput[];
|
|
34
|
+
categories?: SeedCategoryInput[];
|
|
35
|
+
pages?: SeedPageInput[];
|
|
36
|
+
posts?: SeedPostInput[];
|
|
37
|
+
dryRun?: boolean;
|
|
38
|
+
};
|
|
39
|
+
type CreateBaseSeedResult = {
|
|
40
|
+
users: Array<{
|
|
41
|
+
id: string | number;
|
|
42
|
+
email: string;
|
|
43
|
+
}>;
|
|
44
|
+
categories: Array<{
|
|
45
|
+
id: string | number;
|
|
46
|
+
title: string;
|
|
47
|
+
slug: string;
|
|
48
|
+
}>;
|
|
49
|
+
pages: Array<{
|
|
50
|
+
id: string | number;
|
|
51
|
+
slug: string;
|
|
52
|
+
locale: string;
|
|
53
|
+
}>;
|
|
54
|
+
posts: Array<{
|
|
55
|
+
id: string | number;
|
|
56
|
+
slug: string;
|
|
57
|
+
locale: string;
|
|
58
|
+
}>;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Idempotent seeder for the lib's collections. Re-running on the
|
|
62
|
+
* same database is a no-op for users (matched by email) and
|
|
63
|
+
* categories (matched by title); pages and posts are matched by
|
|
64
|
+
* slug and re-created if missing.
|
|
65
|
+
*
|
|
66
|
+
* Pages and posts are created once per slug — localized values are
|
|
67
|
+
* stored in a single doc per slug. Tests assert the alternate
|
|
68
|
+
* resolution by querying `locale: 'all'`.
|
|
69
|
+
*
|
|
70
|
+
* Throws on:
|
|
71
|
+
* - any block slug in a Page's `layout` that doesn't exist on the
|
|
72
|
+
* Pages collection's `blocks` field
|
|
73
|
+
* - a block without a `blockType`
|
|
74
|
+
*/
|
|
75
|
+
declare function createBaseSeed(payload: Payload, options?: CreateBaseSeedOptions): Promise<CreateBaseSeedResult>;
|
|
76
|
+
export { createBaseSeed as default, createBaseSeed, SeedUserInput, SeedPostInput, SeedPageInput, SeedCategoryInput, CreateBaseSeedResult, CreateBaseSeedOptions };
|