@justanarthur/payload-www 0.3.4 → 1.0.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.
Files changed (62) hide show
  1. package/README.md +317 -307
  2. package/dist/access.d.ts +2 -2
  3. package/dist/access.js +6 -30
  4. package/dist/blocks.d.ts +0 -10
  5. package/dist/blocks.js +8 -33
  6. package/dist/collections.d.ts +33 -225
  7. package/dist/collections.js +186 -661
  8. package/dist/config.d.ts +19 -105
  9. package/dist/config.js +263 -868
  10. package/dist/fields.d.ts +4 -46
  11. package/dist/fields.js +183 -73
  12. package/dist/imagehash.js +0 -15
  13. package/dist/import-map-provider.d.ts +0 -16
  14. package/dist/import-map-provider.js +0 -15
  15. package/dist/metadata.d.ts +24 -89
  16. package/dist/metadata.js +123 -258
  17. package/dist/pages.d.ts +37 -319
  18. package/dist/pages.js +355 -973
  19. package/dist/render-pages.d.ts +69 -564
  20. package/dist/render-pages.js +476 -1502
  21. package/dist/sitemap.d.ts +10 -0
  22. package/dist/sitemap.js +324 -0
  23. package/dist/translator.js +0 -15
  24. package/dist/utils.d.ts +4 -12
  25. package/dist/utils.js +10 -56
  26. package/package.json +75 -178
  27. package/dist/components.d.ts +0 -6
  28. package/dist/components.js +0 -39
  29. package/dist/core-access.d.ts +0 -11
  30. package/dist/core-access.js +0 -44
  31. package/dist/core-blocks.d.ts +0 -24
  32. package/dist/core-blocks.js +0 -89
  33. package/dist/core-fields.d.ts +0 -73
  34. package/dist/core-fields.js +0 -181
  35. package/dist/core-utils.d.ts +0 -16
  36. package/dist/core-utils.js +0 -73
  37. package/dist/data-collections.d.ts +0 -229
  38. package/dist/data-collections.js +0 -697
  39. package/dist/data-seed.d.ts +0 -76
  40. package/dist/data-seed.js +0 -212
  41. package/dist/data-test.d.ts +0 -30
  42. package/dist/data-test.js +0 -1134
  43. package/dist/globals.d.ts +0 -69
  44. package/dist/globals.js +0 -259
  45. package/dist/hooks.d.ts +0 -108
  46. package/dist/hooks.js +0 -228
  47. package/dist/index.d.ts +0 -6
  48. package/dist/index.js +0 -39
  49. package/dist/render-components.d.ts +0 -42
  50. package/dist/render-components.js +0 -154
  51. package/dist/render-metadata.d.ts +0 -122
  52. package/dist/render-metadata.js +0 -393
  53. package/dist/render-utils.d.ts +0 -166
  54. package/dist/render-utils.js +0 -401
  55. package/dist/seed.d.ts +0 -76
  56. package/dist/seed.js +0 -212
  57. package/dist/server.d.ts +0 -980
  58. package/dist/server.js +0 -2265
  59. package/dist/test.d.ts +0 -30
  60. package/dist/test.js +0 -1134
  61. package/dist/with-www-config.d.ts +0 -108
  62. package/dist/with-www-config.js +0 -1030
package/dist/server.js DELETED
@@ -1,2265 +0,0 @@
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/PageShowcase.tsx
19
- var exports_PageShowcase = {};
20
- __export(exports_PageShowcase, {
21
- PageShowcase: () => PageShowcase
22
- });
23
- import * as React from "react";
24
- import { jsx as jsx5, jsxs } from "react/jsx-runtime";
25
- function PageShowcase({
26
- children,
27
- metadata,
28
- jsonLd,
29
- localeSwitcher,
30
- metadataHeading = "Page metadata",
31
- jsonLdHeading = "JSON-LD"
32
- }) {
33
- console.log("[WWW] render/components:PageShowcase jsonLdEntries=", jsonLd.length, "hasOg=", Boolean(metadata.openGraph), "hasTwitter=", Boolean(metadata.twitter), "canonical=", metadata.alternates?.canonical);
34
- const og = metadata.openGraph;
35
- const twitter = metadata.twitter;
36
- const rows = [
37
- ["Title", resolveTitle(metadata.title)],
38
- ["Description", metadata.description],
39
- ["Canonical", metadata.alternates?.canonical],
40
- [
41
- "Languages",
42
- metadata.alternates?.languages ? Object.entries(metadata.alternates.languages).map(([locale, url]) => `${locale}: ${url}`).join(`
43
- `) : undefined
44
- ],
45
- ["Open Graph title", og?.title],
46
- ["Open Graph description", og?.description],
47
- ["Open Graph type", og?.type],
48
- ["Open Graph url", og?.url],
49
- ["Open Graph site name", og?.siteName],
50
- ["Twitter card", twitter?.card],
51
- ["Twitter title", twitter?.title],
52
- ["Twitter description", twitter?.description],
53
- ["Twitter site", twitter?.site],
54
- ["Twitter creator", twitter?.creator]
55
- ];
56
- return /* @__PURE__ */ jsxs("div", {
57
- className: "page-showcase grid gap-8 lg:grid-cols-[1fr_320px]",
58
- children: [
59
- /* @__PURE__ */ jsx5("main", {
60
- className: "page-showcase__main",
61
- children
62
- }),
63
- /* @__PURE__ */ jsxs("aside", {
64
- className: "page-showcase__sidebar flex flex-col gap-6 text-sm",
65
- children: [
66
- /* @__PURE__ */ jsxs("section", {
67
- className: "page-showcase__locale",
68
- children: [
69
- /* @__PURE__ */ jsx5("h2", {
70
- className: "m-0 mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground",
71
- children: "Language"
72
- }),
73
- localeSwitcher
74
- ]
75
- }),
76
- /* @__PURE__ */ jsxs("section", {
77
- className: "page-showcase__metadata",
78
- children: [
79
- /* @__PURE__ */ jsx5("h2", {
80
- className: "m-0 mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground",
81
- children: metadataHeading
82
- }),
83
- /* @__PURE__ */ jsx5("dl", {
84
- className: "m-0 grid grid-cols-[max-content_1fr] gap-x-3 gap-y-1.5",
85
- children: rows.filter(([, value]) => value !== undefined && value !== "").map(([label, value]) => /* @__PURE__ */ jsxs(React.Fragment, {
86
- children: [
87
- /* @__PURE__ */ jsx5("dt", {
88
- className: "font-medium text-muted-foreground",
89
- children: label
90
- }),
91
- /* @__PURE__ */ jsx5("dd", {
92
- className: "m-0 whitespace-pre-wrap break-words font-mono text-xs",
93
- children: value
94
- })
95
- ]
96
- }, label))
97
- })
98
- ]
99
- }),
100
- jsonLd.length > 0 ? /* @__PURE__ */ jsxs("section", {
101
- className: "page-showcase__jsonld",
102
- children: [
103
- /* @__PURE__ */ jsx5("h2", {
104
- className: "m-0 mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground",
105
- children: jsonLdHeading
106
- }),
107
- jsonLd.map(({ id, schema }) => /* @__PURE__ */ jsxs("details", {
108
- className: "mb-2 rounded border border-border bg-muted/30 p-2",
109
- children: [
110
- /* @__PURE__ */ jsx5("summary", {
111
- className: "cursor-pointer font-mono text-xs",
112
- children: id
113
- }),
114
- /* @__PURE__ */ jsx5("pre", {
115
- className: "mt-2 overflow-x-auto whitespace-pre-wrap break-words font-mono text-[10px] leading-snug",
116
- children: JSON.stringify(schema, null, 2)
117
- })
118
- ]
119
- }, id))
120
- ]
121
- }) : null
122
- ]
123
- })
124
- ]
125
- });
126
- }
127
- function resolveTitle(title) {
128
- if (!title)
129
- return;
130
- if (typeof title === "string")
131
- return title;
132
- if (title === null)
133
- return;
134
- const t = title;
135
- return t.absolute ?? t.template ?? t.default;
136
- }
137
- var init_PageShowcase = () => {};
138
-
139
- // src/render/components/LocaleSwitcher.tsx
140
- var exports_LocaleSwitcher = {};
141
- __export(exports_LocaleSwitcher, {
142
- LocaleSwitcher: () => LocaleSwitcher
143
- });
144
- import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
145
- function LocaleSwitcher({
146
- currentLocale,
147
- hreflangAlternates,
148
- labels
149
- }) {
150
- const locales = Object.keys(hreflangAlternates).filter((k) => k !== "x-default");
151
- console.log("[WWW] render/components:LocaleSwitcher currentLocale=", currentLocale, "locales=", JSON.stringify(locales), "hasXDefault=", Boolean(hreflangAlternates["x-default"]));
152
- return /* @__PURE__ */ jsx6("nav", {
153
- "aria-label": "Language",
154
- className: "locale-switcher",
155
- children: /* @__PURE__ */ jsxs2("ul", {
156
- className: "flex flex-wrap gap-2 list-none p-0 m-0",
157
- children: [
158
- locales.map((locale) => {
159
- const href = hreflangAlternates[locale];
160
- if (!href)
161
- return null;
162
- const isCurrent = locale === currentLocale;
163
- return /* @__PURE__ */ jsx6("li", {
164
- children: /* @__PURE__ */ jsx6("a", {
165
- href,
166
- "aria-current": isCurrent ? "true" : undefined,
167
- hrefLang: locale,
168
- className: "locale-switcher__link",
169
- "data-locale": locale,
170
- children: labels?.[locale] ?? locale.toUpperCase()
171
- })
172
- }, locale);
173
- }),
174
- hreflangAlternates["x-default"] ? /* @__PURE__ */ jsx6("li", {
175
- children: /* @__PURE__ */ jsx6("a", {
176
- href: hreflangAlternates["x-default"],
177
- hrefLang: "x-default",
178
- className: "locale-switcher__link",
179
- "data-locale": "x-default",
180
- children: labels?.["x-default"] ?? "Default"
181
- })
182
- }, "x-default") : null
183
- ]
184
- })
185
- });
186
- }
187
- var init_LocaleSwitcher = () => {};
188
-
189
- // src/core/access/index.ts
190
- var anyone = () => {
191
- console.log("[WWW] core/access:anyone -> true");
192
- return true;
193
- };
194
- var authenticated = ({ req: { user } }) => {
195
- const result = Boolean(user);
196
- console.log("[WWW] core/access:authenticated ->", result);
197
- return result;
198
- };
199
- var authenticatedOrPublished = ({ req: { user } }) => {
200
- if (user) {
201
- console.log("[WWW] core/access:authenticatedOrPublished -> true (authenticated)");
202
- return true;
203
- }
204
- console.log('[WWW] core/access:authenticatedOrPublished -> { _status: { equals: "published" } }');
205
- return { _status: { equals: "published" } };
206
- };
207
-
208
- // src/core/fields/slug.ts
209
- var FLAT_PATTERN = /^[a-z0-9-]+$/;
210
- var NESTED_PATTERN = /^[a-z0-9_-]+$/;
211
- var slugField = (options = {}) => {
212
- const { name = "slug", nested = false, localized = true } = options;
213
- const pattern = nested ? NESTED_PATTERN : FLAT_PATTERN;
214
- const invalidMessage = nested ? "Slug must be lowercase, with hyphens or the `_` nesting divider (no spaces or other special characters)" : "Slug must be lowercase, with hyphens (no spaces or special characters)";
215
- console.log("[WWW] core/fields:slugField options=", JSON.stringify({ name, nested, localized }));
216
- return {
217
- name,
218
- type: "text",
219
- required: true,
220
- unique: true,
221
- index: true,
222
- localized,
223
- admin: {
224
- position: "sidebar",
225
- ...nested ? { description: "Lowercase, hyphens for words. Use the `_` divider for nesting, e.g. `about_us` → `/about/us`." } : {}
226
- },
227
- validate: (value) => {
228
- if (typeof value !== "string")
229
- return "Slug must be a string";
230
- if (value !== "" && !pattern.test(value)) {
231
- console.warn("[WWW] core/fields:slugField invalid slug value=", JSON.stringify(value));
232
- return invalidMessage;
233
- }
234
- return true;
235
- }
236
- };
237
- };
238
-
239
- // src/render/_locale.ts
240
- function prefixFor(locale, defaultLocale, mode) {
241
- let result;
242
- if (mode === "never")
243
- result = "";
244
- else if (mode === "as-needed" && locale === defaultLocale)
245
- result = "";
246
- else
247
- result = `/${locale}`;
248
- console.log("[WWW] render/_locale:prefixFor locale=", locale, "default=", defaultLocale, "mode=", mode, "->", JSON.stringify(result));
249
- return result;
250
- }
251
- function resolveLocale(req) {
252
- if (!req || typeof req !== "object") {
253
- console.log('[WWW] render/_locale:resolveLocale -> "" (no req)');
254
- return "";
255
- }
256
- const r = req;
257
- if (typeof r.locale === "string" && r.locale.length > 0) {
258
- console.log("[WWW] render/_locale:resolveLocale ->", r.locale, "(from req.locale)");
259
- return r.locale;
260
- }
261
- const fallback = r.payload?.config?.localization?.defaultLocale;
262
- if (typeof fallback === "string" && fallback.length > 0) {
263
- console.log("[WWW] render/_locale:resolveLocale ->", fallback, "(from config.localization.defaultLocale)");
264
- return fallback;
265
- }
266
- console.log('[WWW] render/_locale:resolveLocale -> "" (no locale anywhere)');
267
- return "";
268
- }
269
- function allLocales(req) {
270
- if (!req || typeof req !== "object") {
271
- console.log("[WWW] render/_locale:allLocales -> [] (no req)");
272
- return [];
273
- }
274
- const r = req;
275
- const list = r.payload?.config?.localization?.locales;
276
- if (!Array.isArray(list) || list.length === 0) {
277
- console.log("[WWW] render/_locale:allLocales -> [] (no locales declared)");
278
- return [];
279
- }
280
- const out = [];
281
- for (const entry of list) {
282
- if (typeof entry === "string" && entry.length > 0) {
283
- out.push(entry);
284
- } else if (entry && typeof entry === "object" && "code" in entry) {
285
- const code = entry.code;
286
- if (typeof code === "string" && code.length > 0)
287
- out.push(code);
288
- }
289
- }
290
- console.log("[WWW] render/_locale:allLocales ->", JSON.stringify(out));
291
- return out;
292
- }
293
-
294
- // src/render/hooks/_shared.ts
295
- var cachePromise = null;
296
- function nextCacheImport() {
297
- return cachePromise ??= import("next/cache");
298
- }
299
- function shouldSkipRevalidate(context) {
300
- const skip = Boolean(context?.disableRevalidate);
301
- if (skip)
302
- console.log("[WWW] render/hooks:_shared:shouldSkipRevalidate -> skip");
303
- return skip;
304
- }
305
- async function safeRevalidatePath(payload, path) {
306
- console.log("[WWW] render/hooks:_shared:safeRevalidatePath path=", path);
307
- try {
308
- const { revalidatePath } = await nextCacheImport();
309
- revalidatePath(path);
310
- } catch (error) {
311
- console.error("[WWW] render/hooks:_shared:safeRevalidatePath failed path=", path, "err=", String(error));
312
- payload.logger.error(`revalidatePath("${path}") failed: ${String(error)}`);
313
- }
314
- }
315
- async function safeRevalidateTag(payload, tag, profile = "max") {
316
- console.log("[WWW] render/hooks:_shared:safeRevalidateTag tag=", tag, "profile=", profile);
317
- try {
318
- const { revalidateTag } = await nextCacheImport();
319
- revalidateTag(tag, profile);
320
- } catch (error) {
321
- console.error("[WWW] render/hooks:_shared:safeRevalidateTag failed tag=", tag, "err=", String(error));
322
- payload.logger.error(`revalidateTag("${tag}") failed: ${String(error)}`);
323
- }
324
- }
325
-
326
- // src/render/hooks/revalidateCollection.ts
327
- function createRevalidateCollectionHook(options) {
328
- const {
329
- collectionSlug,
330
- urlPathPrefix = "",
331
- sitemapTag,
332
- localePrefix: modeOption,
333
- defaultLocale: defaultLocaleOption,
334
- pathMode = "url"
335
- } = options;
336
- const resolvedSitemapTag = sitemapTag === false ? false : sitemapTag ?? `${collectionSlug}-sitemap`;
337
- console.log("[WWW] render/hooks:createRevalidateCollectionHook collectionSlug=", collectionSlug, "urlPathPrefix=", urlPathPrefix, "sitemapTag=", resolvedSitemapTag, "pathMode=", pathMode);
338
- const resolveDefaults = (req) => {
339
- const mode = modeOption ?? "always";
340
- const defaultLocale = defaultLocaleOption ?? req?.payload?.config?.localization?.defaultLocale ?? "";
341
- return { mode, defaultLocale };
342
- };
343
- const localesToFanOut = (req) => {
344
- const all = allLocales(req);
345
- if (all.length > 0)
346
- return all;
347
- const single = resolveLocale(req);
348
- return single ? [single] : [];
349
- };
350
- const collectionPath = (slug, locale, mode, defaultLocale) => {
351
- const prefix = prefixFor(locale, defaultLocale, mode);
352
- if (!slug)
353
- return `${prefix}${urlPathPrefix}` || "/";
354
- return `${prefix}${urlPathPrefix}/${slug}`;
355
- };
356
- const fanOutPaths = async (payload, req, slug, label) => {
357
- const { mode, defaultLocale } = resolveDefaults(req);
358
- const locales = localesToFanOut(req);
359
- for (const locale of locales) {
360
- const path = collectionPath(slug, locale, mode, defaultLocale);
361
- payload.logger.info?.(`${label} ${path}`);
362
- await safeRevalidatePath(payload, path);
363
- }
364
- };
365
- const fireCollectionTags = async (payload, docId, req) => {
366
- console.log("[WWW] render/hooks:fireCollectionTags collectionSlug=", collectionSlug, "docId=", docId);
367
- if (typeof docId === "string" || typeof docId === "number") {
368
- await safeRevalidateTag(payload, `collection_${collectionSlug}_${docId}`);
369
- }
370
- if (resolvedSitemapTag !== false) {
371
- await safeRevalidateTag(payload, resolvedSitemapTag);
372
- }
373
- };
374
- const afterChange = async ({ doc, previousDoc, req }) => {
375
- if (shouldSkipRevalidate(req.context))
376
- return doc;
377
- const { payload } = req;
378
- const typed = doc;
379
- const prev = previousDoc;
380
- console.log("[WWW] render/hooks:afterChange collectionSlug=", collectionSlug, "id=", typed.id, "slug=", typed.slug, "prevSlug=", prev?.slug);
381
- const isPublished = typed._status === "published";
382
- const wasPublished = prev?._status === "published";
383
- const prevSlugIsString = typeof prev?.slug === "string";
384
- const slugChanged = prevSlugIsString && prev?.slug !== typed.slug;
385
- if (isPublished) {
386
- if (pathMode !== "tag-only") {
387
- await fanOutPaths(payload, req, typed.slug, `Revalidating ${collectionSlug} at path:`);
388
- }
389
- await fireCollectionTags(payload, typed.id, req);
390
- }
391
- if (wasPublished && (!isPublished || slugChanged)) {
392
- if (pathMode !== "tag-only") {
393
- await fanOutPaths(payload, req, prev?.slug, `Revalidating old ${collectionSlug} at path:`);
394
- }
395
- await fireCollectionTags(payload, typed.id, req);
396
- }
397
- return doc;
398
- };
399
- const afterDelete = async ({ doc, req }) => {
400
- if (shouldSkipRevalidate(req.context))
401
- return doc ?? null;
402
- const { payload } = req;
403
- const typed = doc;
404
- console.log("[WWW] render/hooks:afterDelete collectionSlug=", collectionSlug, "id=", typed?.id, "slug=", typed?.slug);
405
- if (pathMode !== "tag-only") {
406
- await fanOutPaths(payload, req, typed?.slug, `Revalidating deleted ${collectionSlug} at path:`);
407
- }
408
- await fireCollectionTags(payload, typed?.id, req);
409
- return doc ?? null;
410
- };
411
- return { afterChange, afterDelete };
412
- }
413
- var createRevalidatePageHooks = (opts = {}) => {
414
- console.log("[WWW] render/hooks:createRevalidatePageHooks (deprecated alias) opts=", JSON.stringify(opts));
415
- return createRevalidateCollectionHook({
416
- collectionSlug: "pages",
417
- urlPathPrefix: "",
418
- ...opts
419
- });
420
- };
421
-
422
- // src/config/constants.ts
423
- var PAGES_RENDER_PATH = "@justanarthur/payload-www/render-pages#PagesPage";
424
- var POSTS_RENDER_PATH = "@justanarthur/payload-www/render-pages#PostsPage";
425
- var HEADER_RENDER_PATH = "@justanarthur/payload-www/render-pages#HeaderPage";
426
- var FOOTER_RENDER_PATH = "@justanarthur/payload-www/render-pages#FooterPage";
427
- var LIVE_PREVIEW_LISTENER_PATH = "@justanarthur/payload-www/render-components#LivePreviewListener";
428
- var PAGES_SLUG = "pages";
429
- var POSTS_SLUG = "posts";
430
- var STATIC_PAGES_SLUG = "staticPages";
431
-
432
- // src/data/collections/Pages/index.ts
433
- var HOME_PAGE_SLUG = "";
434
- var PAGES_SLUG2 = PAGES_SLUG;
435
- var createPagesCollection = (blocks, options = {}) => {
436
- const {
437
- renderPath = PAGES_RENDER_PATH,
438
- slug: collectionSlug = PAGES_SLUG2,
439
- localePrefix,
440
- defaultLocale,
441
- nested = false
442
- } = options;
443
- const baseFields = [
444
- {
445
- name: "title",
446
- type: "text",
447
- required: true,
448
- localized: true
449
- },
450
- {
451
- type: "tabs",
452
- tabs: [
453
- {
454
- fields: [
455
- {
456
- name: "blocks",
457
- type: "blocks",
458
- blocks,
459
- required: true,
460
- admin: { initCollapsed: true }
461
- }
462
- ],
463
- label: "Content"
464
- }
465
- ]
466
- },
467
- {
468
- name: "publishedAt",
469
- type: "date",
470
- admin: { position: "sidebar" }
471
- },
472
- slugField({ nested })
473
- ];
474
- const { afterChange: revalidateAfterChange, afterDelete: revalidateAfterDelete } = createRevalidateCollectionHook({
475
- collectionSlug,
476
- urlPathPrefix: "",
477
- localePrefix,
478
- defaultLocale
479
- });
480
- return {
481
- slug: collectionSlug,
482
- custom: { path: renderPath },
483
- access: {
484
- create: authenticated,
485
- delete: authenticated,
486
- read: authenticatedOrPublished,
487
- update: authenticated
488
- },
489
- fields: baseFields,
490
- hooks: {
491
- afterChange: [revalidateAfterChange],
492
- afterDelete: [revalidateAfterDelete]
493
- },
494
- versions: { drafts: { autosave: { interval: 1000 } } }
495
- };
496
- };
497
-
498
- // src/data/collections/Posts/index.ts
499
- var POSTS_SLUG2 = "posts";
500
- var createPostsCollection = (options = {}) => {
501
- const {
502
- renderPath = POSTS_RENDER_PATH,
503
- slug: collectionSlug = POSTS_SLUG2,
504
- localePrefix,
505
- defaultLocale
506
- } = options;
507
- const baseFields = [
508
- {
509
- name: "title",
510
- type: "text",
511
- required: true,
512
- localized: true
513
- },
514
- {
515
- name: "excerpt",
516
- type: "text",
517
- required: false,
518
- localized: true
519
- },
520
- {
521
- name: "content",
522
- type: "richText",
523
- required: false,
524
- localized: true
525
- },
526
- {
527
- name: "publishedAt",
528
- type: "date",
529
- admin: { position: "sidebar" }
530
- },
531
- slugField()
532
- ];
533
- const { afterChange, afterDelete } = createRevalidateCollectionHook({
534
- collectionSlug,
535
- urlPathPrefix: "/posts",
536
- localePrefix,
537
- defaultLocale
538
- });
539
- return {
540
- slug: collectionSlug,
541
- custom: { path: renderPath },
542
- access: {
543
- create: authenticated,
544
- delete: authenticated,
545
- read: authenticatedOrPublished,
546
- update: authenticated
547
- },
548
- fields: baseFields,
549
- hooks: {
550
- afterChange: [afterChange],
551
- afterDelete: [afterDelete]
552
- },
553
- versions: { drafts: { autosave: { interval: 1000 } } }
554
- };
555
- };
556
-
557
- // src/data/collections/StaticPages/index.ts
558
- var createStaticPagesCollection = (blocks) => {
559
- const { afterChange, afterDelete } = createRevalidateCollectionHook({
560
- collectionSlug: STATIC_PAGES_SLUG,
561
- pathMode: "tag-only",
562
- sitemapTag: "static-pages"
563
- });
564
- return {
565
- slug: STATIC_PAGES_SLUG,
566
- dbName: "sp",
567
- admin: { group: "System", useAsTitle: "title" },
568
- access: {
569
- create: authenticated,
570
- delete: authenticated,
571
- read: authenticatedOrPublished,
572
- update: authenticated
573
- },
574
- fields: [
575
- {
576
- name: "kind",
577
- type: "select",
578
- required: true,
579
- unique: true,
580
- index: true,
581
- options: [
582
- { label: "Not found (404)", value: "not-found" },
583
- { label: "Server error (500)", value: "server-error" },
584
- { label: "Search empty", value: "search-empty" },
585
- { label: "Offline", value: "offline" }
586
- ],
587
- admin: {
588
- position: "sidebar",
589
- description: "Which system page this row powers. One row per kind."
590
- }
591
- },
592
- {
593
- name: "title",
594
- type: "text",
595
- required: true,
596
- localized: true,
597
- admin: { description: "Admin-only label. Not rendered." }
598
- },
599
- {
600
- type: "tabs",
601
- tabs: [
602
- {
603
- fields: [
604
- {
605
- name: "blocks",
606
- type: "blocks",
607
- localized: true,
608
- blocks,
609
- admin: { initCollapsed: true },
610
- dbName: "b"
611
- }
612
- ],
613
- label: "Content"
614
- }
615
- ]
616
- },
617
- {
618
- name: "publishedAt",
619
- type: "date",
620
- admin: { position: "sidebar" }
621
- }
622
- ],
623
- hooks: {
624
- afterChange: [afterChange],
625
- afterDelete: [afterDelete]
626
- },
627
- versions: { drafts: { autosave: { interval: 1000 } } }
628
- };
629
- };
630
-
631
- // src/core/fields/link.ts
632
- var appearanceOptions = {
633
- default: { label: "Default", value: "default" },
634
- outline: { label: "Outline", value: "outline" }
635
- };
636
- var link = (options = {}) => {
637
- const {
638
- appearances,
639
- disableLabel = false,
640
- relationTo = [PAGES_SLUG],
641
- localized = false,
642
- overrides = {},
643
- extraFields = []
644
- } = options;
645
- console.log("[WWW] core/fields:link options=", JSON.stringify({
646
- appearances: appearances === false ? false : appearances ?? "default-set",
647
- disableLabel,
648
- relationTo,
649
- localized,
650
- extraFieldsCount: extraFields.length
651
- }));
652
- const result = {
653
- name: "link",
654
- type: "group",
655
- admin: { hideGutter: true },
656
- fields: [
657
- {
658
- type: "row",
659
- fields: [
660
- {
661
- name: "type",
662
- type: "radio",
663
- admin: { layout: "horizontal", width: "50%" },
664
- defaultValue: "reference",
665
- options: [
666
- { label: "Internal link", value: "reference" },
667
- { label: "Custom URL", value: "custom" }
668
- ]
669
- },
670
- {
671
- name: "newTab",
672
- type: "checkbox",
673
- admin: { style: { alignSelf: "flex-end" }, width: "50%" },
674
- label: "Open in new tab"
675
- }
676
- ]
677
- }
678
- ]
679
- };
680
- const linkTypes = [
681
- {
682
- name: "reference",
683
- type: "relationship",
684
- admin: { condition: (_, siblingData) => siblingData?.type === "reference" },
685
- label: "Document to link to",
686
- relationTo,
687
- required: true,
688
- localized
689
- },
690
- {
691
- name: "url",
692
- type: "text",
693
- admin: { condition: (_, siblingData) => siblingData?.type === "custom" },
694
- label: "Custom URL",
695
- required: true,
696
- localized
697
- }
698
- ];
699
- if (!disableLabel) {
700
- result.fields.push({
701
- type: "row",
702
- fields: [
703
- ...linkTypes,
704
- {
705
- name: "label",
706
- type: "text",
707
- admin: { width: "50%" },
708
- label: "Label",
709
- required: true,
710
- localized
711
- }
712
- ]
713
- });
714
- } else {
715
- result.fields = [...result.fields, ...linkTypes];
716
- }
717
- if (appearances !== false) {
718
- const opts = appearances ? appearances.map((a) => appearanceOptions[a]) : [appearanceOptions.default, appearanceOptions.outline];
719
- result.fields.push({
720
- name: "appearance",
721
- type: "select",
722
- admin: { description: "Choose how the link should be rendered." },
723
- defaultValue: "default",
724
- options: opts
725
- });
726
- }
727
- if (extraFields.length) {
728
- result.fields.push(...extraFields);
729
- }
730
- console.log("[WWW] core/fields:link built fieldsCount=", result.fields.length);
731
- return { ...result, ...overrides };
732
- };
733
-
734
- // src/render/hooks/revalidateGlobal.ts
735
- function createRevalidateGlobalHook(slug) {
736
- console.log("[WWW] render/hooks:createRevalidateGlobalHook slug=", slug);
737
- return async ({ doc, req: { payload, context, locale } }) => {
738
- if (shouldSkipRevalidate(context))
739
- return doc;
740
- const tags = [`global_${slug}`, `global_${slug}_${locale}`];
741
- console.log("[WWW] render/hooks:revalidateGlobal slug=", slug, "locale=", locale, "tags=", JSON.stringify(tags));
742
- payload.logger.info?.(`Revalidating global: ${tags.join(", ")}`);
743
- for (const tag of tags) {
744
- await safeRevalidateTag(payload, tag);
745
- }
746
- return doc;
747
- };
748
- }
749
-
750
- // src/data/collections/globals/Header/config.ts
751
- var createHeaderGlobal = (options = {}) => {
752
- const {
753
- renderPath = HEADER_RENDER_PATH,
754
- linkRelationTo = [PAGES_SLUG],
755
- navColumnLinkFields = [],
756
- navItemLinkFields = []
757
- } = options;
758
- const navColumnBlock = {
759
- slug: "navColumn",
760
- fields: [
761
- { name: "title", type: "text", required: true, localized: true },
762
- { name: "links", type: "array", fields: [link({ appearances: false, localized: true, relationTo: linkRelationTo, extraFields: navColumnLinkFields })] }
763
- ]
764
- };
765
- const navItemBlock = {
766
- slug: "navItem",
767
- fields: [link({ appearances: false, localized: true, relationTo: linkRelationTo, extraFields: navItemLinkFields })]
768
- };
769
- return {
770
- slug: "header",
771
- custom: { path: renderPath },
772
- access: { read: () => true },
773
- fields: [
774
- {
775
- name: "nav",
776
- type: "blocks",
777
- required: true,
778
- blocks: [navColumnBlock, navItemBlock]
779
- }
780
- ],
781
- hooks: {
782
- afterChange: [createRevalidateGlobalHook("header")]
783
- }
784
- };
785
- };
786
-
787
- // src/data/collections/globals/Footer/config.ts
788
- var createFooterGlobal = (options = {}) => {
789
- const {
790
- renderPath = FOOTER_RENDER_PATH,
791
- linkRelationTo = [PAGES_SLUG],
792
- navColumnLinkFields = [],
793
- navItemLinkFields = []
794
- } = options;
795
- const navColumnBlock = {
796
- slug: "navColumn",
797
- fields: [
798
- { name: "title", type: "text", required: true, localized: true },
799
- { name: "links", type: "array", fields: [link({ appearances: false, localized: true, relationTo: linkRelationTo, extraFields: navColumnLinkFields })] }
800
- ]
801
- };
802
- const navItemBlock = {
803
- slug: "navItem",
804
- fields: [link({ appearances: false, localized: true, relationTo: linkRelationTo, extraFields: navItemLinkFields })]
805
- };
806
- return {
807
- slug: "footer",
808
- custom: { path: renderPath },
809
- access: { read: () => true },
810
- fields: [
811
- {
812
- name: "nav",
813
- type: "blocks",
814
- required: true,
815
- blocks: [navColumnBlock, navItemBlock]
816
- }
817
- ],
818
- hooks: {
819
- afterChange: [createRevalidateGlobalHook("footer")]
820
- }
821
- };
822
- };
823
-
824
- // src/config/createWWWConfig.ts
825
- import openAIResolver from "@justanarthur/payload-plugin-translator/resolvers/openAI";
826
-
827
- // src/render/preview/createPreviewHandler.ts
828
- function createPreviewHandler(options) {
829
- const { getServerSideURL: _getServerSideURL, secret, enableDraftMode = true } = options;
830
- return async function GET(req) {
831
- const { draftMode } = await import("next/headers");
832
- const { redirect } = await import("next/navigation");
833
- const url = new URL(req.url);
834
- const path = url.searchParams.get("path") ?? "/";
835
- const previewSecret = url.searchParams.get("previewSecret");
836
- console.log("[WWW] render/preview:createPreviewHandler:GET path=", path, "hasSecret=", Boolean(previewSecret), "enableDraftMode=", enableDraftMode);
837
- if (!previewSecret || previewSecret !== secret) {
838
- console.warn("[WWW] render/preview:createPreviewHandler:GET invalid preview secret (401)");
839
- return new Response("Invalid preview secret", { status: 401 });
840
- }
841
- if (enableDraftMode) {
842
- (await draftMode()).enable();
843
- console.log("[WWW] render/preview:createPreviewHandler:GET draftMode enabled");
844
- }
845
- redirect(path);
846
- return new Response(null, { status: 204 });
847
- };
848
- }
849
- // src/render/metadata/hreflang.ts
850
- async function buildHreflangAlternates({
851
- siteUrl,
852
- locale,
853
- urlPrefix,
854
- storedSlug,
855
- queryAllLocaleSlugs,
856
- nested,
857
- homeSlug,
858
- defaultLocale,
859
- locales,
860
- localePrefix = "always"
861
- }) {
862
- const allLocaleSlugs = await queryAllLocaleSlugs(storedSlug, locale);
863
- console.log("[WWW] render/metadata:buildHreflangAlternates storedSlug=", storedSlug, "locale=", locale, "allLocaleSlugs=", JSON.stringify(allLocaleSlugs));
864
- const languages = {};
865
- const urlFor = (l, slug) => {
866
- const trimmedPrefix = urlPrefix.replace(/^\/|\/$/g, "");
867
- const prefixSegment = trimmedPrefix ? `/${trimmedPrefix}` : "";
868
- const urlPath = slug === homeSlug ? "/" : nested ? "/" + slug.replaceAll("_", "/") : "/" + slug;
869
- const localeSegment = localePrefix === "never" ? "" : localePrefix === "as-needed" && l === defaultLocale ? "" : `/${l}`;
870
- return `${siteUrl}${localeSegment}${prefixSegment}${urlPath}`;
871
- };
872
- for (const l of locales) {
873
- const slugForLocale = allLocaleSlugs?.[l];
874
- if (!slugForLocale)
875
- continue;
876
- languages[l] = urlFor(l, slugForLocale);
877
- }
878
- if (allLocaleSlugs?.[defaultLocale]) {
879
- languages["x-default"] = urlFor(defaultLocale, allLocaleSlugs[defaultLocale]);
880
- }
881
- console.log("[WWW] render/metadata:buildHreflangAlternates ->", JSON.stringify(languages));
882
- return languages;
883
- }
884
-
885
- // src/render/metadata/query.ts
886
- import { getPayload } from "payload";
887
- import { cache } from "react";
888
-
889
- // src/core/utils/getFromImportMap.ts
890
- function getFromImportMap(key, importMap) {
891
- const resolvedKey = key.includes("#") ? key : key + "#default";
892
- const value = importMap[resolvedKey];
893
- console.log("[WWW] core/utils:getFromImportMap key=", key, "resolved=", resolvedKey, "hit=", Boolean(value));
894
- return value;
895
- }
896
-
897
- // src/render/metadata/query.ts
898
- var queryDocBySlug = cache(async function queryDocBySlug2({
899
- collectionSlug,
900
- slug,
901
- slugField: slugField2 = "slug",
902
- locale,
903
- draft = false,
904
- config
905
- }) {
906
- console.log("[WWW] render/metadata:queryDocBySlug collection=", collectionSlug, "slug=", slug, "slugField=", slugField2, "locale=", locale, "draft=", draft);
907
- const payload = await getPayload({ config });
908
- const result = await payload.find({
909
- collection: collectionSlug,
910
- draft,
911
- limit: 1,
912
- pagination: false,
913
- overrideAccess: draft,
914
- where: { [slugField2]: { equals: slug } },
915
- locale
916
- });
917
- const doc = result.docs?.[0] ?? null;
918
- console.log("[WWW] render/metadata:queryDocBySlug ->", doc ? "hit" : "miss");
919
- return doc;
920
- });
921
- var queryAllDocs = cache(async function queryAllDocs2({
922
- collectionSlug,
923
- slugField: slugField2 = "slug",
924
- locale,
925
- config
926
- }) {
927
- console.log("[WWW] render/metadata:queryAllDocs collection=", collectionSlug, "locale=", locale);
928
- const payload = await getPayload({ config });
929
- const result = await payload.find({
930
- collection: collectionSlug,
931
- draft: false,
932
- limit: 1000,
933
- pagination: false,
934
- overrideAccess: false,
935
- select: { [slugField2]: true },
936
- locale
937
- });
938
- const docs = result.docs ?? [];
939
- console.log("[WWW] render/metadata:queryAllDocs -> count=", docs.length);
940
- return docs;
941
- });
942
- var queryAllLocaleSlugs = cache(async function queryAllLocaleSlugs2({
943
- collectionSlug,
944
- slug,
945
- slugField: slugField2 = "slug",
946
- locale,
947
- config
948
- }) {
949
- console.log("[WWW] render/metadata:queryAllLocaleSlugs collection=", collectionSlug, "slug=", slug, "locale=", locale);
950
- const payload = await getPayload({ config });
951
- const result = await payload.find({
952
- collection: collectionSlug,
953
- draft: false,
954
- limit: 1,
955
- pagination: false,
956
- overrideAccess: false,
957
- locale,
958
- where: { [slugField2]: { equals: slug } },
959
- select: { [slugField2]: true }
960
- });
961
- const doc = result.docs?.[0];
962
- if (!doc) {
963
- console.log("[WWW] render/metadata:queryAllLocaleSlugs -> undefined (no doc)");
964
- return;
965
- }
966
- let fieldValue = doc[slugField2];
967
- if (doc.id != null) {
968
- const allLocales2 = await payload.findByID({
969
- collection: collectionSlug,
970
- id: doc.id,
971
- locale: "all",
972
- draft: false,
973
- overrideAccess: false,
974
- select: { [slugField2]: true }
975
- }).catch(() => null);
976
- if (allLocales2)
977
- fieldValue = allLocales2[slugField2];
978
- }
979
- if (fieldValue && typeof fieldValue === "object") {
980
- console.log("[WWW] render/metadata:queryAllLocaleSlugs -> localized map=", JSON.stringify(fieldValue));
981
- return fieldValue;
982
- }
983
- const resolved = await config;
984
- const rawLocales = Array.isArray(resolved?.localization?.localeCodes) ? resolved.localization.localeCodes : resolved?.localization?.locales?.map((l) => l.code) ?? [];
985
- const out = {};
986
- for (const l of rawLocales)
987
- out[l] = String(fieldValue ?? slug);
988
- console.log("[WWW] render/metadata:queryAllLocaleSlugs -> flat-fanout locales=", rawLocales.length, "slug=", JSON.stringify(fieldValue ?? slug));
989
- return out;
990
- });
991
- var queryGlobal = cache(async function queryGlobal2({
992
- globalSlug,
993
- locale,
994
- depth = 0,
995
- draft = false,
996
- config
997
- }) {
998
- console.log("[WWW] render/metadata:queryGlobal global=", globalSlug, "locale=", locale, "depth=", depth, "draft=", draft);
999
- const payload = await getPayload({ config });
1000
- try {
1001
- const global = await payload.findGlobal({
1002
- slug: globalSlug,
1003
- depth,
1004
- draft,
1005
- locale
1006
- });
1007
- console.log("[WWW] render/metadata:queryGlobal -> hit");
1008
- return global;
1009
- } catch (error) {
1010
- console.warn("[WWW] render/metadata:queryGlobal failed for slug=", globalSlug, "err=", String(error));
1011
- return null;
1012
- }
1013
- });
1014
- function getRenderModuleExports(exportName, collection, importMap) {
1015
- const path = collection?.custom?.path;
1016
- if (!path) {
1017
- console.log("[WWW] render/metadata:getRenderModuleExports no custom.path exportName=", exportName);
1018
- return;
1019
- }
1020
- const mod = getFromImportMap(path, importMap);
1021
- const value = mod?.[exportName];
1022
- console.log("[WWW] render/metadata:getRenderModuleExports exportName=", exportName, "path=", path, "hit=", Boolean(value));
1023
- return value;
1024
- }
1025
-
1026
- // src/render/sitemap/createSitemapFile.ts
1027
- function createSitemapFile(options) {
1028
- const { collections } = options;
1029
- return async function sitemap() {
1030
- console.log("[WWW] render/sitemap:createSitemapFile:sitemap collections=", JSON.stringify(options.collections), "localePrefix=", options.localePrefix ?? "always");
1031
- const cfg = await options.config;
1032
- const allLocales2 = Array.isArray(cfg.localization?.locales) ? cfg.localization.locales.map((l) => typeof l === "string" ? l : l.code) : [cfg.localization?.defaultLocale ?? "en"];
1033
- const defaultLocale = cfg.localization?.defaultLocale ?? allLocales2[0];
1034
- const activeLocales = Array.isArray(options.locales) && options.locales.length > 0 ? options.locales.filter((l) => allLocales2.includes(l)) : allLocales2;
1035
- console.log("[WWW] render/sitemap:createSitemapFile:sitemap allLocales=", JSON.stringify(allLocales2), "default=", defaultLocale, "active=", JSON.stringify(activeLocales));
1036
- const entries = [];
1037
- const seen = new Set;
1038
- for (const collectionSlug of collections) {
1039
- const collectionDefaults = options.perCollection?.[collectionSlug] ?? {};
1040
- const urlPrefix = (options.urlPrefixes?.[collectionSlug] ?? "").replace(/\/$/, "");
1041
- const siteUrl = options.getServerSideURL().replace(/\/$/, "");
1042
- const isNested = options.nested?.[collectionSlug] ?? false;
1043
- for (const locale of activeLocales) {
1044
- const docs = await queryAllDocs({
1045
- collectionSlug,
1046
- slugField: "slug",
1047
- locale,
1048
- config: options.config
1049
- });
1050
- for (const doc of docs) {
1051
- const storedSlug = doc.slug;
1052
- if (typeof storedSlug !== "string" || storedSlug === "")
1053
- continue;
1054
- const dedupeKey = `${collectionSlug}:${locale}:${storedSlug}`;
1055
- if (seen.has(dedupeKey))
1056
- continue;
1057
- seen.add(dedupeKey);
1058
- const slugPath = isNested ? storedSlug.replaceAll("_", "/") : storedSlug;
1059
- const url = `${siteUrl}${prefixFor(locale, defaultLocale, options.localePrefix ?? "always")}${urlPrefix}/${slugPath}`;
1060
- const languages = await buildHreflangAlternates({
1061
- siteUrl,
1062
- locale,
1063
- urlPrefix,
1064
- storedSlug,
1065
- nested: isNested,
1066
- homeSlug: "",
1067
- defaultLocale,
1068
- locales: activeLocales,
1069
- localePrefix: options.localePrefix,
1070
- queryAllLocaleSlugs: async (s, l) => {
1071
- const result = await queryAllLocaleSlugs({
1072
- collectionSlug,
1073
- slug: s,
1074
- slugField: "slug",
1075
- locale: l,
1076
- config: options.config
1077
- });
1078
- return result ?? undefined;
1079
- }
1080
- });
1081
- entries.push({
1082
- url,
1083
- lastModified: doc.updatedAt ? new Date(doc.updatedAt) : undefined,
1084
- changeFrequency: collectionDefaults.changefreq ?? "weekly",
1085
- priority: collectionDefaults.priority ?? 0.5,
1086
- alternates: { languages }
1087
- });
1088
- }
1089
- }
1090
- }
1091
- console.log("[WWW] render/sitemap:createSitemapFile:sitemap -> entries=", entries.length);
1092
- return entries;
1093
- };
1094
- }
1095
- // src/config/createWWWConfig.ts
1096
- function createWWWConfig(options) {
1097
- const { locales, routing, blocks, linkRelationTo, registerPosts = true, nested = false, defaultPlugins } = options;
1098
- const defaultLocale = routing?.defaultLocale ?? locales[0] ?? "";
1099
- const localePrefixMode = (() => {
1100
- const raw = routing?.localePrefix;
1101
- if (typeof raw === "string")
1102
- return raw;
1103
- return raw?.mode ?? "always";
1104
- })();
1105
- if (locales.length === 0) {
1106
- throw new Error("createWWWConfig: `locales` must contain at least one entry.");
1107
- }
1108
- const buildPagesCollection = () => createPagesCollection(blocks, {
1109
- localePrefix: localePrefixMode,
1110
- defaultLocale,
1111
- nested
1112
- });
1113
- const buildPostsCollection = () => createPostsCollection({
1114
- localePrefix: localePrefixMode,
1115
- defaultLocale
1116
- });
1117
- const buildStaticPagesCollection = () => createStaticPagesCollection(blocks);
1118
- const buildHeaderGlobal = () => createHeaderGlobal({ linkRelationTo });
1119
- const buildFooterGlobal = () => createFooterGlobal({ linkRelationTo });
1120
- async function withWWWConfig(config) {
1121
- const baseDefaults = [
1122
- buildPagesCollection(),
1123
- buildStaticPagesCollection()
1124
- ];
1125
- if (registerPosts)
1126
- baseDefaults.push(buildPostsCollection());
1127
- const defaultCollections = baseDefaults;
1128
- const collections = typeof config.collections === "function" ? config.collections({ defaultCollections }) : [...defaultCollections, ...config.collections || []];
1129
- const defaultGlobals = [buildHeaderGlobal(), buildFooterGlobal()];
1130
- const globals = typeof config.globals === "function" ? config.globals({ defaultGlobals }) : [...defaultGlobals, ...config.globals || []];
1131
- const renderDependencies = {
1132
- [PAGES_RENDER_PATH]: { path: PAGES_RENDER_PATH, type: "component" },
1133
- [POSTS_RENDER_PATH]: { path: POSTS_RENDER_PATH, type: "component" },
1134
- [HEADER_RENDER_PATH]: { path: HEADER_RENDER_PATH, type: "component" },
1135
- [FOOTER_RENDER_PATH]: { path: FOOTER_RENDER_PATH, type: "component" },
1136
- [LIVE_PREVIEW_LISTENER_PATH]: {
1137
- path: LIVE_PREVIEW_LISTENER_PATH,
1138
- type: "component"
1139
- }
1140
- };
1141
- for (const { slug, custom, admin } of blocks) {
1142
- const path = custom?.path ?? admin?.custom?.path;
1143
- if (typeof path === "string" && slug)
1144
- renderDependencies[slug] = { path, type: "component" };
1145
- }
1146
- for (const entry of [...collections, ...globals]) {
1147
- const path = entry.custom?.path;
1148
- if (typeof path === "string")
1149
- renderDependencies[path] = { path, type: "component" };
1150
- }
1151
- const [
1152
- { seoPlugin },
1153
- { imageHashPlugin },
1154
- { translator }
1155
- ] = await Promise.all([
1156
- import("@justanarthur/payload-plugin-seo"),
1157
- import("@justanarthur/payload-imagehash-plugin"),
1158
- import("@justanarthur/payload-plugin-translator")
1159
- ]);
1160
- const defaultPluginList = [
1161
- seoPlugin({
1162
- collections: ["pages", "posts", "static-pages"],
1163
- autoGenerate: { mode: "onCreate", deriveFrom: "allScalars" }
1164
- }),
1165
- imageHashPlugin({ algorithm: "lqip-modern" }),
1166
- translator({
1167
- collections: ["pages", "posts", "static-pages"],
1168
- globals: ["header", "footer"],
1169
- resolvers: [
1170
- openAIResolver({
1171
- apiKey: process.env.OPENAI_API_KEY,
1172
- chunkLength: 31,
1173
- model: "gpt-5-mini"
1174
- })
1175
- ]
1176
- })
1177
- ];
1178
- const mergedPlugins = defaultPlugins ? defaultPlugins(defaultPluginList) : defaultPluginList;
1179
- return {
1180
- ...config,
1181
- collections,
1182
- globals,
1183
- plugins: mergedPlugins,
1184
- admin: {
1185
- ...config.admin ?? {},
1186
- dependencies: {
1187
- ...renderDependencies,
1188
- ...config.admin?.dependencies ?? {}
1189
- }
1190
- }
1191
- };
1192
- }
1193
- return { withWWWConfig };
1194
- }
1195
-
1196
- // src/core/fields/linkGroup.ts
1197
- var linkGroup = (options = {}) => {
1198
- console.log("[WWW] core/fields:linkGroup relationTo=", JSON.stringify(options.relationTo ?? "link-default"), "extraFields=", options.extraFields?.length ?? 0);
1199
- return {
1200
- name: "links",
1201
- type: "array",
1202
- fields: [link(options)],
1203
- admin: { initCollapsed: true }
1204
- };
1205
- };
1206
-
1207
- // src/core/utils/generateImportName.ts
1208
- function generateImportName(type, slug) {
1209
- switch (type) {
1210
- case "block": {
1211
- const name = `Block${slug.replace(/(^\w|-\w)/g, (m) => m.replace("-", "").toUpperCase())}#default`;
1212
- console.log("[WWW] core/utils:generateImportName type=block slug=", slug, "->", name);
1213
- return name;
1214
- }
1215
- case "page": {
1216
- const name = `Page${slug.replace(/(^\w|-\w)/g, (m) => m.replace("-", "").toUpperCase())}#default`;
1217
- console.log("[WWW] core/utils:generateImportName type=page slug=", slug, "->", name);
1218
- return name;
1219
- }
1220
- default:
1221
- console.error("[WWW] core/utils:generateImportName unknown type:", type);
1222
- throw new Error(`Unknown type: ${type}`);
1223
- }
1224
- }
1225
-
1226
- // src/render/utils/renderCollectionModule.tsx
1227
- import { jsx } from "react/jsx-runtime";
1228
- function renderCollectionModule(collection = [], slug, importMap, props) {
1229
- const renderPath = collection?.find((c) => c.slug === slug)?.custom?.path;
1230
- if (!renderPath) {
1231
- console.log("[WWW] render/utils:renderCollectionModule no custom.path slug=", slug);
1232
- return null;
1233
- }
1234
- const CollectionRenderModule = getFromImportMap(renderPath, importMap);
1235
- if (!CollectionRenderModule) {
1236
- console.error("[WWW] render/utils:renderCollectionModule not found slug=", slug, "path=", renderPath);
1237
- if (false) {}
1238
- return null;
1239
- }
1240
- console.log("[WWW] render/utils:renderCollectionModule rendering slug=", slug, "path=", renderPath);
1241
- return /* @__PURE__ */ jsx(CollectionRenderModule, {
1242
- importMap,
1243
- ...props
1244
- });
1245
- }
1246
-
1247
- // src/render/utils/renderGlobalModule.tsx
1248
- import { jsx as jsx2 } from "react/jsx-runtime";
1249
- function renderGlobalModule(globals = [], slug, importMap, props) {
1250
- const renderPath = globals?.find((g) => g.slug === slug)?.custom?.path;
1251
- if (!renderPath) {
1252
- console.log("[WWW] render/utils:renderGlobalModule no custom.path slug=", slug);
1253
- return null;
1254
- }
1255
- const GlobalRenderModule = getFromImportMap(renderPath, importMap);
1256
- if (!GlobalRenderModule) {
1257
- console.error("[WWW] render/utils:renderGlobalModule not found slug=", slug, "path=", renderPath);
1258
- if (false) {}
1259
- return null;
1260
- }
1261
- console.log("[WWW] render/utils:renderGlobalModule rendering slug=", slug, "path=", renderPath);
1262
- return /* @__PURE__ */ jsx2(GlobalRenderModule, {
1263
- importMap,
1264
- ...props
1265
- });
1266
- }
1267
-
1268
- // src/render/utils/getCachedGlobal.ts
1269
- import { unstable_cache } from "next/cache";
1270
- var getCachedGlobal = (config, slug, depth = 0) => {
1271
- console.log("[WWW] render/utils:getCachedGlobal slug=", slug, "depth=", depth);
1272
- return unstable_cache(async () => queryGlobal({
1273
- globalSlug: slug,
1274
- locale: "__ALL__",
1275
- depth,
1276
- config
1277
- }), [slug], { tags: [`global_${slug}`] });
1278
- };
1279
-
1280
- // src/render/metadata/jsonld.ts
1281
- function getImageUrl(doc, siteUrl) {
1282
- const img = doc?.meta?.image ?? doc?.heroImage ?? doc?.image;
1283
- if (!img)
1284
- return null;
1285
- if (typeof img === "string")
1286
- return img;
1287
- if (img?.url)
1288
- return img.url.startsWith("http") ? img.url : `${siteUrl}${img.url}`;
1289
- return null;
1290
- }
1291
- function getImageUrlWithLog(doc, siteUrl) {
1292
- const result = getImageUrl(doc, siteUrl);
1293
- console.log("[WWW] render/metadata:jsonld:getImageUrl ->", result);
1294
- return result;
1295
- }
1296
- function resolveLocalizedField(value, locale) {
1297
- if (value == null)
1298
- return "";
1299
- if (typeof value === "string") {
1300
- if (!value.startsWith("{"))
1301
- return value;
1302
- try {
1303
- const parsed = JSON.parse(value);
1304
- return resolveLocalizedField(parsed, locale);
1305
- } catch {
1306
- return value;
1307
- }
1308
- }
1309
- if (typeof value !== "object")
1310
- return "";
1311
- const obj = value;
1312
- if (typeof obj[locale] === "string" && obj[locale].length > 0) {
1313
- return obj[locale];
1314
- }
1315
- return Object.values(obj).filter((v) => typeof v === "string" && v.length > 0).join(" / ");
1316
- }
1317
- function resolveLocalizedFieldWithLog(value, locale) {
1318
- const result = resolveLocalizedField(value, locale);
1319
- if (value && typeof value === "object") {
1320
- console.log("[WWW] render/metadata:jsonld:resolveLocalizedField locale=", locale, "->", JSON.stringify(result));
1321
- }
1322
- return result;
1323
- }
1324
- function buildArticleLd({
1325
- doc,
1326
- url,
1327
- locale,
1328
- siteUrl,
1329
- type = "BlogPosting",
1330
- publisherName,
1331
- publisherLogo
1332
- }) {
1333
- const name = publisherName ?? new URL(siteUrl).hostname;
1334
- console.log("[WWW] render/metadata:buildArticleLd url=", url, "locale=", locale, "type=", type, "publisherName=", name);
1335
- const ld = {
1336
- "@context": "https://schema.org",
1337
- "@type": type,
1338
- "@id": `${url}#article`,
1339
- headline: resolveLocalizedFieldWithLog(doc.title, locale),
1340
- description: resolveLocalizedFieldWithLog(doc.meta?.description ?? doc.description ?? doc.excerpt, locale),
1341
- inLanguage: locale,
1342
- url,
1343
- dateModified: doc.updatedAt ? new Date(doc.updatedAt).toISOString() : undefined
1344
- };
1345
- const datePublished = doc.publishedAt ?? doc.createdAt;
1346
- if (datePublished)
1347
- ld.datePublished = new Date(datePublished).toISOString();
1348
- const imgUrl = getImageUrlWithLog(doc, siteUrl);
1349
- if (imgUrl)
1350
- ld.image = imgUrl;
1351
- ld.author = { "@type": "Organization", name, url: siteUrl };
1352
- const publisher = { "@type": "Organization", name };
1353
- if (publisherLogo !== undefined) {
1354
- if (publisherLogo !== null)
1355
- publisher.logo = { "@type": "ImageObject", url: publisherLogo };
1356
- }
1357
- ld.publisher = publisher;
1358
- return ld;
1359
- }
1360
- function buildBreadcrumbsLd({
1361
- items,
1362
- currentUrl
1363
- }) {
1364
- console.log("[WWW] render/metadata:buildBreadcrumbsLd items=", items.length, "currentUrl=", currentUrl);
1365
- return {
1366
- "@context": "https://schema.org",
1367
- "@type": "BreadcrumbList",
1368
- itemListElement: items.map((item, index) => ({
1369
- "@type": "ListItem",
1370
- position: index + 1,
1371
- name: item.label,
1372
- item: index === items.length - 1 ? currentUrl : item.url
1373
- }))
1374
- };
1375
- }
1376
- function buildOrganizationLd({
1377
- siteUrl,
1378
- name,
1379
- logo,
1380
- sameAs
1381
- }) {
1382
- console.log("[WWW] render/metadata:buildOrganizationLd siteUrl=", siteUrl, "name=", name, "logo?", Boolean(logo), "sameAs?", Boolean(sameAs));
1383
- const org = {
1384
- "@context": "https://schema.org",
1385
- "@type": "Organization",
1386
- "@id": `${siteUrl}#organization`,
1387
- url: siteUrl,
1388
- ...name && { name },
1389
- ...logo && { logo: { "@type": "ImageObject", url: logo } },
1390
- ...sameAs && sameAs.length > 0 && { sameAs }
1391
- };
1392
- return org;
1393
- }
1394
-
1395
- // src/render/metadata/slug.ts
1396
- var SLUG_NESTED_DIVIDER = "_";
1397
- function segmentsToStoredSlug(segments, nested) {
1398
- if (!Array.isArray(segments)) {
1399
- console.log("[WWW] render/metadata:segmentsToStoredSlug string passthrough:", JSON.stringify(segments));
1400
- return segments;
1401
- }
1402
- const result = nested ? segments.join(SLUG_NESTED_DIVIDER) : segments[0] ?? "";
1403
- console.log("[WWW] render/metadata:segmentsToStoredSlug nested=", nested, "segments=", JSON.stringify(segments), "->", result);
1404
- return result;
1405
- }
1406
- function segmentsToUrlPath(segments, nested) {
1407
- let result;
1408
- if (!Array.isArray(segments))
1409
- result = "/" + segments;
1410
- else if (nested)
1411
- result = "/" + segments.join("/");
1412
- else
1413
- result = "/" + (segments[0] ?? "");
1414
- console.log("[WWW] render/metadata:segmentsToUrlPath nested=", nested, "segments=", JSON.stringify(segments), "->", result);
1415
- return result;
1416
- }
1417
- function storedSlugToSegments(storedSlug, nested) {
1418
- const result = nested ? storedSlug.split(SLUG_NESTED_DIVIDER) : storedSlug;
1419
- console.log("[WWW] render/metadata:storedSlugToSegments nested=", nested, "storedSlug=", storedSlug, "->", JSON.stringify(result));
1420
- return result;
1421
- }
1422
- function buildCanonicalUrl({
1423
- siteUrl,
1424
- locale,
1425
- urlPrefix,
1426
- urlPath
1427
- }) {
1428
- const trimmedPrefix = urlPrefix.replace(/^\/|\/$/g, "");
1429
- const prefixSegment = trimmedPrefix ? `/${trimmedPrefix}` : "";
1430
- const result = `${siteUrl}/${locale}${prefixSegment}${urlPath}`;
1431
- console.log("[WWW] render/metadata:buildCanonicalUrl siteUrl=", siteUrl, "locale=", locale, "urlPrefix=", urlPrefix, "urlPath=", urlPath, "->", result);
1432
- return result;
1433
- }
1434
- function getUrlPath(segments, nested, homeSlug) {
1435
- const urlPath = segmentsToUrlPath(segments, nested);
1436
- if (nested && !Array.isArray(segments)) {
1437
- if (segments === homeSlug)
1438
- return "/";
1439
- } else if (nested && Array.isArray(segments)) {
1440
- const stored = segments.join(SLUG_NESTED_DIVIDER);
1441
- if (stored === homeSlug)
1442
- return "/";
1443
- }
1444
- return urlPath;
1445
- }
1446
-
1447
- // src/render/blocks/renderBlocks.tsx
1448
- import { jsx as jsx3, Fragment } from "react/jsx-runtime";
1449
- var RenderBlocks = ({
1450
- blocks,
1451
- blockProps,
1452
- config,
1453
- importMap,
1454
- locale,
1455
- searchParams
1456
- }) => {
1457
- if (!blocks || !Array.isArray(blocks) || blocks.length === 0) {
1458
- console.log("[WWW] render/blocks:RenderBlocks no blocks (locale=", locale, ")");
1459
- return null;
1460
- }
1461
- console.log("[WWW] render/blocks:RenderBlocks rendering count=", blocks.length, "locale=", locale);
1462
- const rendered = [];
1463
- for (let i = 0;i < blocks.length; i++) {
1464
- const block = blocks[i];
1465
- const { blockType } = block;
1466
- const importMapPath = config.admin?.dependencies?.[blockType]?.path ?? generateImportName("block", blockType);
1467
- const Block = getFromImportMap(importMapPath, importMap);
1468
- if (!Block) {
1469
- console.warn(`[WWW] render/blocks:RenderBlocks no block for type=${blockType} importMapPath=${importMapPath} (locale=${locale})`);
1470
- continue;
1471
- }
1472
- console.log("[WWW] render/blocks:RenderBlocks [", i, "] blockType=", blockType, "importMapPath=", importMapPath);
1473
- rendered.push(/* @__PURE__ */ jsx3(Block, {
1474
- index: i,
1475
- ...blockProps,
1476
- ...block,
1477
- locale,
1478
- searchParams
1479
- }, i));
1480
- }
1481
- return /* @__PURE__ */ jsx3(Fragment, {
1482
- children: rendered
1483
- });
1484
- };
1485
-
1486
- // src/data/seed/createBaseSeed.ts
1487
- var simpleRichText = (text) => ({
1488
- root: {
1489
- type: "root",
1490
- format: "",
1491
- indent: 0,
1492
- version: 1,
1493
- direction: "ltr",
1494
- children: [
1495
- {
1496
- type: "paragraph",
1497
- format: "",
1498
- indent: 0,
1499
- version: 1,
1500
- direction: "ltr",
1501
- textFormat: 0,
1502
- children: [
1503
- { mode: "normal", text, type: "text", style: "", detail: 0, format: 0, version: 1 }
1504
- ]
1505
- }
1506
- ]
1507
- }
1508
- });
1509
- async function createBaseSeed(payload, options = {}) {
1510
- const localization = payload.config.localization;
1511
- const defaultLocale = options.defaultLocale ?? (typeof localization === "object" && localization ? typeof localization.defaultLocale === "string" ? localization.defaultLocale : "en" : "en");
1512
- const configLocales = typeof localization === "object" && localization ? (localization.locales ?? []).map((l) => typeof l === "string" ? l : l.code) : [];
1513
- const locales = options.locales ?? (configLocales.length > 0 ? configLocales : [defaultLocale]);
1514
- const result = { users: [], categories: [], pages: [], posts: [] };
1515
- const pagesCollection = payload.collections["pages"];
1516
- if (!pagesCollection) {
1517
- throw new Error("createBaseSeed: no `pages` collection registered with this payload instance");
1518
- }
1519
- const findBlocksField = (fields) => {
1520
- for (const f of fields) {
1521
- if (f.name === "blocks" && Array.isArray(f.blocks))
1522
- return f;
1523
- if (Array.isArray(f.fields)) {
1524
- const found = findBlocksField(f.fields);
1525
- if (found)
1526
- return found;
1527
- }
1528
- if (Array.isArray(f.tabs)) {
1529
- for (const t of f.tabs) {
1530
- if (Array.isArray(t.fields)) {
1531
- const found = findBlocksField(t.fields);
1532
- if (found)
1533
- return found;
1534
- }
1535
- }
1536
- }
1537
- }
1538
- return;
1539
- };
1540
- const layoutField = findBlocksField(pagesCollection.config.fields);
1541
- const validBlockSlugs = new Set((layoutField?.blocks ?? []).map((b) => b.slug));
1542
- for (const page of options.pages ?? []) {
1543
- for (const block of page.blocks ?? []) {
1544
- const slug = block.blockType;
1545
- if (!slug) {
1546
- throw new Error(`createBaseSeed: page "${page.slug}" has a block without blockType`);
1547
- }
1548
- if (!validBlockSlugs.has(slug)) {
1549
- throw new Error(`createBaseSeed: page "${page.slug}" references unknown block slug "${slug}". Allowed: ${[...validBlockSlugs].join(", ")}`);
1550
- }
1551
- }
1552
- }
1553
- if (options.dryRun)
1554
- return result;
1555
- for (const user of options.users ?? [{ email: "dev@payloadcms.com", password: "test", name: "Dev User" }]) {
1556
- const existing = await payload.find({
1557
- collection: "users",
1558
- where: { email: { equals: user.email } },
1559
- limit: 1,
1560
- overrideAccess: true
1561
- });
1562
- let id;
1563
- if (existing.docs.length > 0) {
1564
- id = existing.docs[0].id;
1565
- } else {
1566
- const created = await payload.create({
1567
- collection: "users",
1568
- data: { email: user.email, password: user.password ?? "test", name: user.name ?? "" },
1569
- overrideAccess: true
1570
- });
1571
- id = created.id;
1572
- }
1573
- result.users.push({ id, email: user.email });
1574
- }
1575
- for (const cat of options.categories ?? []) {
1576
- const slug = cat.slug ?? cat.title.toLowerCase().replace(/\s+/g, "-");
1577
- const existing = await payload.find({
1578
- collection: "categories",
1579
- where: { title: { equals: cat.title } },
1580
- limit: 1,
1581
- overrideAccess: true
1582
- });
1583
- let id;
1584
- if (existing.docs.length > 0) {
1585
- id = existing.docs[0].id;
1586
- } else {
1587
- const created = await payload.create({
1588
- collection: "categories",
1589
- data: { title: cat.title, slug },
1590
- overrideAccess: true
1591
- });
1592
- id = created.id;
1593
- }
1594
- result.categories.push({ id, title: cat.title, slug });
1595
- }
1596
- for (const page of options.pages ?? []) {
1597
- const existing = await payload.find({
1598
- collection: "pages",
1599
- where: { slug: { equals: page.slug } },
1600
- limit: 1,
1601
- overrideAccess: true
1602
- });
1603
- const data = {
1604
- slug: page.slug,
1605
- title: { ...page.title },
1606
- blocks: page.blocks ?? [],
1607
- publishedAt: page.publishedAt ?? new Date().toISOString(),
1608
- _status: page.status === "draft" ? "draft" : "published"
1609
- };
1610
- if (page.meta)
1611
- data.meta = { ...page.meta };
1612
- let id;
1613
- if (existing.docs.length === 0) {
1614
- const created = await payload.create({
1615
- collection: "pages",
1616
- data,
1617
- overrideAccess: true,
1618
- draft: page.status === "draft"
1619
- });
1620
- id = created.id;
1621
- } else {
1622
- id = existing.docs[0].id;
1623
- await payload.update({
1624
- collection: "pages",
1625
- id,
1626
- data,
1627
- overrideAccess: true,
1628
- draft: page.status === "draft"
1629
- });
1630
- }
1631
- for (const locale of locales)
1632
- result.pages.push({ id, slug: page.slug, locale });
1633
- }
1634
- for (const post of options.posts ?? []) {
1635
- const existing = await payload.find({
1636
- collection: "posts",
1637
- where: { slug: { equals: post.slug } },
1638
- limit: 1,
1639
- overrideAccess: true
1640
- });
1641
- const data = {
1642
- slug: post.slug,
1643
- title: { ...post.title },
1644
- ...post.excerpt ? { excerpt: { ...post.excerpt } } : {},
1645
- content: post.content ?? simpleRichText("Hello world"),
1646
- publishedAt: post.publishedAt ?? new Date().toISOString(),
1647
- authors: result.users.length > 0 ? [result.users[0].id] : [],
1648
- _status: post.status === "draft" ? "draft" : "published"
1649
- };
1650
- let id;
1651
- if (existing.docs.length === 0) {
1652
- const created = await payload.create({
1653
- collection: "posts",
1654
- data,
1655
- overrideAccess: true,
1656
- draft: post.status === "draft"
1657
- });
1658
- id = created.id;
1659
- } else {
1660
- id = existing.docs[0].id;
1661
- await payload.update({
1662
- collection: "posts",
1663
- id,
1664
- data,
1665
- overrideAccess: true,
1666
- draft: post.status === "draft"
1667
- });
1668
- }
1669
- for (const locale of locales)
1670
- result.posts.push({ id, slug: post.slug, locale });
1671
- }
1672
- return result;
1673
- }
1674
-
1675
- // src/data/test/createTestPayload.ts
1676
- import { sqliteAdapter } from "@payloadcms/db-sqlite";
1677
- import { flattenAllFields, getPayload as getPayload2, inMemoryKVAdapter } from "payload";
1678
- import path from "node:path";
1679
- import { fileURLToPath } from "node:url";
1680
- async function createTestPayload(options = {}) {
1681
- const filename = fileURLToPath(import.meta.url);
1682
- const dirname = path.dirname(filename);
1683
- const databaseFile = options.databaseFile ?? path.join(dirname, `.test-${Date.now()}-${Math.random().toString(36).slice(2)}.db`);
1684
- const locales = options.locales ?? ["en", "uk"];
1685
- const defaultLocale = locales[0] ?? "en";
1686
- const blocks = options.blocks ?? [];
1687
- const { withWWWConfig } = createWWWConfig({ locales: [...locales], blocks });
1688
- const config = await withWWWConfig({
1689
- admin: { user: "users" },
1690
- blocks: [],
1691
- collections: [
1692
- {
1693
- slug: "posts",
1694
- access: { read: () => true },
1695
- fields: [{ name: "title", type: "text" }]
1696
- }
1697
- ],
1698
- globals: [],
1699
- db: sqliteAdapter({
1700
- client: { url: `file:${databaseFile}` },
1701
- push: false
1702
- }),
1703
- secret: "test-secret-do-not-use-in-prod",
1704
- sharp: (await import("sharp")).default,
1705
- editor: {},
1706
- localization: { locales: [...locales], defaultLocale },
1707
- kv: inMemoryKVAdapter(),
1708
- typescript: { outputFile: "./payload-types.ts" }
1709
- });
1710
- const registered = new Set([
1711
- ...(config.collections ?? []).map((c) => c.slug),
1712
- ...(config.globals ?? []).map((g) => g.slug)
1713
- ]);
1714
- const findMissing = (fields) => {
1715
- const out = [];
1716
- const walk = (f) => {
1717
- if (Array.isArray(f)) {
1718
- for (const child of f)
1719
- walk(child);
1720
- return;
1721
- }
1722
- if (f.relationTo) {
1723
- const rels = Array.isArray(f.relationTo) ? f.relationTo : [f.relationTo];
1724
- for (const r of rels) {
1725
- if (typeof r === "string" && !registered.has(r))
1726
- out.push(r);
1727
- }
1728
- }
1729
- if (Array.isArray(f.fields))
1730
- walk(f.fields);
1731
- };
1732
- for (const f of fields)
1733
- walk(f);
1734
- return out;
1735
- };
1736
- for (const c of config.collections ?? []) {
1737
- const missing = findMissing(c.fields ?? []);
1738
- if (missing.length)
1739
- console.log("collection", c.slug, "missing relations:", missing);
1740
- }
1741
- for (const g of config.globals ?? []) {
1742
- const missing = findMissing(g.fields ?? []);
1743
- if (missing.length)
1744
- console.log("global", g.slug, "missing relations:", missing);
1745
- }
1746
- for (const c of config.collections ?? []) {
1747
- if (c.fields) {
1748
- c.flattenedFields = flattenAllFields({ fields: c.fields });
1749
- }
1750
- if (c.upload === undefined)
1751
- c.upload = false;
1752
- c.sanitizedIndexes = c.sanitizedIndexes ?? [];
1753
- c.polymorphicJoins = c.polymorphicJoins ?? [];
1754
- if (options.overridePagesVersions && c.slug === "pages") {
1755
- c.versions = false;
1756
- }
1757
- }
1758
- for (const g of config.globals ?? []) {
1759
- if (g.fields) {
1760
- g.flattenedFields = flattenAllFields({ fields: g.fields });
1761
- }
1762
- g.sanitizedIndexes = g.sanitizedIndexes ?? [];
1763
- }
1764
- const payload = await getPayload2({ config });
1765
- let destroyed = false;
1766
- const destroy = async () => {
1767
- if (destroyed)
1768
- return;
1769
- destroyed = true;
1770
- try {
1771
- await payload.destroy();
1772
- } catch {}
1773
- };
1774
- return { payload, databaseFile, destroy };
1775
- }
1776
-
1777
- // src/render/pages/createCollectionPageExports.tsx
1778
- import"server-only";
1779
- import { Suspense } from "react";
1780
- import { RichText } from "@payloadcms/richtext-lexical/react";
1781
-
1782
- // src/render/pages/PagesPage.tsx
1783
- import { jsx as jsx4, Fragment as Fragment2 } from "react/jsx-runtime";
1784
- async function PagesPage({ doc, ...props }) {
1785
- if (!doc) {
1786
- console.log("[WWW] render/pages:PagesPage no doc");
1787
- return /* @__PURE__ */ jsx4(Fragment2, {});
1788
- }
1789
- const blocks = doc.blocks ?? [];
1790
- console.log("[WWW] render/pages:PagesPage blocks=", blocks.length, "locale=", props.locale);
1791
- return /* @__PURE__ */ jsx4(Fragment2, {
1792
- children: /* @__PURE__ */ jsx4(RenderBlocks, {
1793
- blocks,
1794
- ...props
1795
- })
1796
- });
1797
- }
1798
-
1799
- // src/render/pages/createCollectionPageExports.tsx
1800
- import { jsx as jsx7, jsxs as jsxs3, Fragment as Fragment4 } from "react/jsx-runtime";
1801
- var HOME_SLUG = "";
1802
- function createCollectionPageExports({
1803
- slug = "pages",
1804
- config: configPromise,
1805
- routing,
1806
- importMap: importMapArg,
1807
- renderPath,
1808
- nested = false
1809
- }, deps, options = {}) {
1810
- const importMap = importMapArg ?? {};
1811
- const { jsonLd: jsonLdOption = true, changefreq = "weekly", priority = 0.5, websiteName } = options;
1812
- const {
1813
- getServerSideURL,
1814
- generateMeta,
1815
- metadataType: metadataTypeOverride,
1816
- showcase: showcaseOption,
1817
- homeExtras
1818
- } = deps;
1819
- const showcaseEnabled = showcaseOption?.enabled === true;
1820
- const { metadataHeading, jsonLdHeading } = showcaseOption ?? {};
1821
- const locales = routing.locales;
1822
- const defaultLocale = routing.defaultLocale;
1823
- const metadataType = metadataTypeOverride ?? (slug === POSTS_SLUG ? "article" : "website");
1824
- const defaultRenderPath = slug === POSTS_SLUG ? POSTS_RENDER_PATH : PAGES_RENDER_PATH;
1825
- const localePrefixMode = typeof routing.localePrefix === "string" ? routing.localePrefix : routing.localePrefix?.mode ?? "always";
1826
- const buildLocalePath = (locale, storedSlug) => {
1827
- const urlPath = getUrlPath(storedSlugToSegments(storedSlug, nested), nested, HOME_SLUG);
1828
- let result;
1829
- if (localePrefixMode === "never")
1830
- result = urlPath;
1831
- else if (localePrefixMode === "as-needed" && locale === defaultLocale)
1832
- result = urlPath;
1833
- else
1834
- result = `/${locale}${urlPath}`;
1835
- console.log("[WWW] render/pages:createCollectionPageExports:buildLocalePath locale=", locale, "storedSlug=", storedSlug, "->", result);
1836
- return result;
1837
- };
1838
- async function fetchDoc(locale, storedSlug, draft = false) {
1839
- return queryDocBySlug({
1840
- collectionSlug: slug,
1841
- slug: storedSlug,
1842
- locale,
1843
- draft,
1844
- config: configPromise
1845
- });
1846
- }
1847
- async function resolveHreflangAlternates(locale, storedSlug) {
1848
- const siteUrl = getServerSideURL();
1849
- const urlPath = buildLocalePath(locale, storedSlug);
1850
- const canonical = `${siteUrl}${urlPath}`;
1851
- const languages = await buildHreflangAlternates({
1852
- siteUrl,
1853
- locale,
1854
- urlPrefix: "",
1855
- storedSlug,
1856
- nested,
1857
- homeSlug: HOME_SLUG,
1858
- defaultLocale,
1859
- locales,
1860
- localePrefix: localePrefixMode,
1861
- queryAllLocaleSlugs: (s, l) => queryAllLocaleSlugs({ collectionSlug: slug, slug: s, slugField: "slug", locale: l, config: configPromise })
1862
- });
1863
- const alternates = {};
1864
- for (const [key, url] of Object.entries(languages)) {
1865
- alternates[key] = url;
1866
- }
1867
- console.log("[WWW] render/pages:createCollectionPageExports:resolveHreflangAlternates canonical=", canonical, "alts=", JSON.stringify(alternates));
1868
- return { alternates, canonical };
1869
- }
1870
- const default_ = async (props) => {
1871
- const { slug: rawSlugSegments, locale: incomingLocale } = await props.params ?? {};
1872
- const slugSegments = Array.isArray(rawSlugSegments) ? rawSlugSegments : [];
1873
- const locale = typeof incomingLocale === "string" ? incomingLocale : defaultLocale;
1874
- console.log("[WWW] render/pages:createCollectionPageExports:default_ collectionSlug=", slug, "locale=", locale, "segments=", JSON.stringify(slugSegments), "showcase=", showcaseEnabled);
1875
- if (!locales.includes(locale)) {
1876
- console.error(`[WWW] render/pages:createCollectionPageExports:default_ notFound invalid-locale collection=${slug} locale=${locale} segments=${JSON.stringify(slugSegments)}`);
1877
- const { notFound } = await import("next/navigation");
1878
- notFound();
1879
- }
1880
- const { setRequestLocale } = await import("next-intl/server");
1881
- setRequestLocale(locale);
1882
- const { draftMode } = await import("next/headers");
1883
- const { isEnabled: draft } = await draftMode();
1884
- console.log("[WWW] render/pages:createCollectionPageExports:default_ draftMode=", draft);
1885
- const storedSlug = segmentsToStoredSlug(slugSegments, nested);
1886
- const doc = await fetchDoc(locale, storedSlug, draft);
1887
- if (!doc) {
1888
- console.error(`[WWW] render/pages:createCollectionPageExports:default_ notFound no-doc collection=${slug} locale=${locale} storedSlug="${storedSlug}" segments=${JSON.stringify(slugSegments)} draft=${draft}`);
1889
- const { notFound } = await import("next/navigation");
1890
- notFound();
1891
- }
1892
- const cfg = await configPromise;
1893
- const collectionCustomPath = cfg.collections.find((c) => c.slug === slug)?.custom?.path;
1894
- const effectivePath = renderPath ?? collectionCustomPath ?? defaultRenderPath;
1895
- console.log("[WWW] render/pages:createCollectionPageExports:default_ effectivePath=", effectivePath);
1896
- const render = effectivePath === PAGES_RENDER_PATH ? /* @__PURE__ */ jsx7(PagesPage, {
1897
- doc,
1898
- importMap,
1899
- config: cfg,
1900
- locale
1901
- }) : effectivePath === POSTS_RENDER_PATH ? doc ? await renderPostBody(doc, locale) : null : renderCollectionModule(cfg.collections, slug, importMap, {
1902
- ...props,
1903
- config: cfg,
1904
- locale,
1905
- searchParams: props.searchParams,
1906
- doc
1907
- });
1908
- const jsonLdNodes = doc ? await generateJsonLd(slugSegments, doc, locale) : [];
1909
- const { alternates: hreflangAlternates, canonical } = await resolveHreflangAlternates(locale, storedSlug);
1910
- const inner = /* @__PURE__ */ jsxs3(Fragment4, {
1911
- children: [
1912
- jsonLdNodes.map(({ id, schema }) => /* @__PURE__ */ jsx7("script", {
1913
- type: "application/ld+json",
1914
- dangerouslySetInnerHTML: { __html: JSON.stringify(schema) }
1915
- }, id)),
1916
- render,
1917
- draft ? (() => {
1918
- const ResolvedListener = importMap?.[LIVE_PREVIEW_LISTENER_PATH];
1919
- if (!ResolvedListener)
1920
- return null;
1921
- return /* @__PURE__ */ jsx7(Suspense, {
1922
- fallback: null,
1923
- children: /* @__PURE__ */ jsx7(ResolvedListener, {})
1924
- });
1925
- })() : null,
1926
- storedSlug === HOME_SLUG && homeExtras ? await homeExtras({ locale, doc }) : null
1927
- ]
1928
- });
1929
- if (!showcaseEnabled || !doc)
1930
- return inner;
1931
- const { PageShowcase: PageShowcase2 } = await Promise.resolve().then(() => (init_PageShowcase(), exports_PageShowcase));
1932
- const { LocaleSwitcher: LocaleSwitcher2 } = await Promise.resolve().then(() => (init_LocaleSwitcher(), exports_LocaleSwitcher));
1933
- const meta = await generateMeta({
1934
- doc,
1935
- url: canonical,
1936
- type: metadataType,
1937
- locale
1938
- });
1939
- return /* @__PURE__ */ jsx7(PageShowcase2, {
1940
- metadata: meta,
1941
- metadataHeading,
1942
- jsonLdHeading,
1943
- jsonLd: jsonLdNodes,
1944
- localeSwitcher: /* @__PURE__ */ jsx7(LocaleSwitcher2, {
1945
- currentLocale: locale,
1946
- hreflangAlternates,
1947
- labels: routing.labels
1948
- }),
1949
- children: inner
1950
- });
1951
- };
1952
- async function generateMetadata(props) {
1953
- const cfg = await configPromise;
1954
- const { slug: rawSlugSegments, locale: incomingLocale } = await props.params ?? {};
1955
- const slugSegments = Array.isArray(rawSlugSegments) ? rawSlugSegments : [];
1956
- const locale = typeof incomingLocale === "string" ? incomingLocale : defaultLocale;
1957
- console.log("[WWW] render/pages:createCollectionPageExports:generateMetadata collectionSlug=", slug, "locale=", locale, "segments=", JSON.stringify(slugSegments));
1958
- if (!locales.includes(locale)) {
1959
- console.log("[WWW] render/pages:createCollectionPageExports:generateMetadata invalid locale -> not found meta");
1960
- return { title: "Not found", robots: { index: false, follow: false } };
1961
- }
1962
- const storedSlug = segmentsToStoredSlug(slugSegments, nested);
1963
- const doc = await fetchDoc(locale, storedSlug);
1964
- if (!doc) {
1965
- console.log("[WWW] render/pages:createCollectionPageExports:generateMetadata no doc -> not found meta");
1966
- return { title: "Not found", robots: { index: false, follow: false } };
1967
- }
1968
- const collection = cfg.collections.find((c) => c.slug === slug);
1969
- if (!collection) {
1970
- console.warn("[WWW] render/pages:createCollectionPageExports:generateMetadata collection not in config slug=", slug);
1971
- return {};
1972
- }
1973
- const { canonical, alternates } = await resolveHreflangAlternates(locale, storedSlug);
1974
- const meta = await generateMeta({
1975
- doc,
1976
- url: canonical,
1977
- type: metadataType,
1978
- locale
1979
- });
1980
- meta.alternates = {
1981
- canonical,
1982
- languages: Object.keys(alternates).length ? alternates : undefined
1983
- };
1984
- return meta;
1985
- }
1986
- async function generateJsonLd(slugSegments, doc, locale) {
1987
- if (jsonLdOption === false || !doc)
1988
- return [];
1989
- const siteUrl = getServerSideURL();
1990
- const storedSlug = segmentsToStoredSlug(slugSegments, nested);
1991
- const urlPath = buildLocalePath(locale, storedSlug);
1992
- const canonical = `${siteUrl}${urlPath}`;
1993
- const entries = Array.isArray(jsonLdOption) ? jsonLdOption : metadataType === "article" ? [{ type: "article" }] : [{ type: "website" }];
1994
- console.log("[WWW] render/pages:createCollectionPageExports:generateJsonLd collection=", slug, "locale=", locale, "entries=", entries.map((e) => e.type).join(","));
1995
- const outputs = [];
1996
- for (const entry of entries) {
1997
- const id = entry.id ?? `jsonld-${entry.type}-${outputs.length}`;
1998
- let schema = null;
1999
- switch (entry.type) {
2000
- case "article": {
2001
- const articleOpts = {
2002
- doc,
2003
- url: canonical,
2004
- locale,
2005
- siteUrl,
2006
- type: entry.schemaType ?? "BlogPosting"
2007
- };
2008
- if (entry.publisherName !== undefined)
2009
- articleOpts.publisherName = entry.publisherName;
2010
- if (entry.publisherLogo !== undefined)
2011
- articleOpts.publisherLogo = entry.publisherLogo;
2012
- schema = buildArticleLd(articleOpts);
2013
- break;
2014
- }
2015
- case "website": {
2016
- schema = {
2017
- "@context": "https://schema.org",
2018
- "@type": "WebSite",
2019
- "@id": `${siteUrl}#website`,
2020
- url: siteUrl,
2021
- name: entry.name ?? websiteName ?? new URL(siteUrl).hostname,
2022
- ...entry.alternateName ? { alternateName: entry.alternateName } : {},
2023
- inLanguage: locale
2024
- };
2025
- break;
2026
- }
2027
- case "organization": {
2028
- schema = buildOrganizationLd({
2029
- siteUrl,
2030
- name: entry.name,
2031
- logo: entry.logo,
2032
- sameAs: entry.sameAs
2033
- });
2034
- break;
2035
- }
2036
- case "breadcrumbs": {
2037
- let items = entry.items ?? [];
2038
- if (!items.length && entry.buildItems)
2039
- items = entry.buildItems(doc, canonical);
2040
- if (items.length > 0)
2041
- schema = buildBreadcrumbsLd({ items, currentUrl: canonical });
2042
- break;
2043
- }
2044
- case "custom": {
2045
- schema = entry.build({ doc, url: canonical, locale, siteUrl });
2046
- break;
2047
- }
2048
- }
2049
- if (schema)
2050
- outputs.push({ id, schema });
2051
- }
2052
- return outputs;
2053
- }
2054
- async function generateStaticParams() {
2055
- console.log("[WWW] render/pages:createCollectionPageExports:generateStaticParams collection=", slug, "locales=", JSON.stringify(locales));
2056
- const params = [];
2057
- for (const locale of locales) {
2058
- const docs = await queryAllDocs({ collectionSlug: slug, slugField: "slug", locale, config: configPromise });
2059
- for (const doc of docs) {
2060
- const slugVal = doc.slug;
2061
- if (typeof slugVal !== "string" || slugVal === "")
2062
- continue;
2063
- const segments = storedSlugToSegments(slugVal, nested);
2064
- params.push({ slug: Array.isArray(segments) ? segments : [segments], locale });
2065
- }
2066
- }
2067
- console.log("[WWW] render/pages:createCollectionPageExports:generateStaticParams -> count=", params.length);
2068
- return params;
2069
- }
2070
- async function generateSitemap() {
2071
- console.log("[WWW] render/pages:createCollectionPageExports:generateSitemap collection=", slug, "locales=", JSON.stringify(locales));
2072
- const docs = await queryAllDocs({
2073
- collectionSlug: slug,
2074
- slugField: "slug",
2075
- locale: defaultLocale,
2076
- config: configPromise
2077
- });
2078
- const siteUrl = getServerSideURL().replace(/\/$/, "");
2079
- const urls = [];
2080
- for (const doc of docs) {
2081
- const slugVal = doc.slug;
2082
- if (typeof slugVal !== "string" || slugVal === "")
2083
- continue;
2084
- for (const locale of locales) {
2085
- const urlPath = buildLocalePath(locale, slugVal);
2086
- const updatedAt = doc.updatedAt;
2087
- const lastmod = typeof updatedAt === "string" ? new Date(updatedAt).toISOString() : undefined;
2088
- urls.push({ url: `${siteUrl}${urlPath}`, lastModified: lastmod, changeFrequency: changefreq, priority });
2089
- }
2090
- }
2091
- console.log("[WWW] render/pages:createCollectionPageExports:generateSitemap -> urls=", urls.length);
2092
- return urls;
2093
- }
2094
- return {
2095
- default: default_,
2096
- generateMetadata,
2097
- generateStaticParams,
2098
- generateSitemap,
2099
- generateJsonLd
2100
- };
2101
- }
2102
- function addCollectionsToSitemap(exports) {
2103
- async function buildSitemap() {
2104
- const all = await Promise.all(exports.map((e) => e.generateSitemap()));
2105
- return all.flat();
2106
- }
2107
- return { default: buildSitemap, generateSitemap: buildSitemap };
2108
- }
2109
- async function renderPostBody(doc, locale) {
2110
- const typedDoc = doc;
2111
- const title = typedDoc.title ?? "";
2112
- const excerpt = typedDoc.excerpt ?? null;
2113
- const content = typedDoc.content;
2114
- return /* @__PURE__ */ jsxs3("article", {
2115
- className: "posts-page prose prose-neutral dark:prose-invert mx-auto max-w-3xl py-10",
2116
- children: [
2117
- /* @__PURE__ */ jsxs3("header", {
2118
- className: "posts-page__header not-prose mb-8",
2119
- children: [
2120
- /* @__PURE__ */ jsx7("h1", {
2121
- className: "posts-page__title text-4xl font-semibold tracking-tight",
2122
- children: title
2123
- }),
2124
- excerpt ? /* @__PURE__ */ jsx7("p", {
2125
- className: "posts-page__excerpt mt-3 text-lg text-muted-foreground",
2126
- children: excerpt
2127
- }) : null
2128
- ]
2129
- }),
2130
- content ? /* @__PURE__ */ jsx7("div", {
2131
- className: "posts-page__content",
2132
- children: /* @__PURE__ */ jsx7(RichText, {
2133
- data: content
2134
- })
2135
- }) : null
2136
- ]
2137
- });
2138
- }
2139
-
2140
- // src/render/pages/createStaticPageExports.tsx
2141
- import"server-only";
2142
- import { jsx as jsx8 } from "react/jsx-runtime";
2143
- function createStaticPageExports({
2144
- kind = "not-found",
2145
- config: configPromise,
2146
- importMap: importMapArg
2147
- }) {
2148
- const importMap = importMapArg ?? {};
2149
- let dbgRenderCount = 0;
2150
- const default_ = async () => {
2151
- const { getLocale } = await import("next-intl/server");
2152
- const locale = await getLocale();
2153
- console.log("[WWW] render/pages:createStaticPageExports:default_ kind=", kind, "locale=", locale);
2154
- dbgRenderCount++;
2155
- {
2156
- let reqUrl = "?";
2157
- try {
2158
- const { headers } = await import("next/headers");
2159
- const h = await headers();
2160
- reqUrl = h.get("x-invoke-path") || h.get("x-matched-path") || h.get("x-next-url") || h.get("next-url") || h.get("referer") || "?";
2161
- } catch {}
2162
- console.error(`[WWW-DBG static-render #${dbgRenderCount}] kind=${kind} locale=${locale} url=${reqUrl}`);
2163
- if (dbgRenderCount <= 5) {
2164
- console.error(`[WWW-DBG static-render #${dbgRenderCount}] stack:
2165
- ` + (new Error("static-render").stack?.split(`
2166
- `).slice(2, 12).join(`
2167
- `) ?? ""));
2168
- }
2169
- }
2170
- const doc = await queryDocBySlug({
2171
- collectionSlug: STATIC_PAGES_SLUG,
2172
- slug: kind,
2173
- slugField: "kind",
2174
- locale,
2175
- config: configPromise
2176
- });
2177
- if (!doc) {
2178
- console.warn("[createStaticPageExports] !doc: STATIC_PAGES_SLUG=", STATIC_PAGES_SLUG, "slug:" + kind);
2179
- return /* @__PURE__ */ jsx8("section", {
2180
- children: /* @__PURE__ */ jsx8("h1", {
2181
- children: "404"
2182
- })
2183
- });
2184
- }
2185
- const cfg = await configPromise;
2186
- console.log("[WWW] render/pages:createStaticPageExports:default_ -> rendering via PagesPage kind=", kind, "locale=", locale);
2187
- return /* @__PURE__ */ jsx8(PagesPage, {
2188
- doc,
2189
- locale,
2190
- importMap,
2191
- config: cfg
2192
- });
2193
- };
2194
- return { default: default_ };
2195
- }
2196
-
2197
- // src/data/collections/previewPath.ts
2198
- var collectionPrefixMap = {
2199
- posts: "/posts",
2200
- pages: ""
2201
- };
2202
- function generatePreviewPath({
2203
- collection,
2204
- slug
2205
- }) {
2206
- if (slug === undefined || slug === null)
2207
- return null;
2208
- const encodedSlug = encodeURIComponent(slug);
2209
- const params = new URLSearchParams({
2210
- path: `${collectionPrefixMap[collection] ?? ""}/${encodedSlug}`,
2211
- previewSecret: process.env.PREVIEW_SECRET || ""
2212
- });
2213
- return `/next/preview?${params.toString()}`;
2214
- }
2215
-
2216
- // src/exports/server.ts
2217
- var server_default = createWWWConfig;
2218
- export {
2219
- storedSlugToSegments,
2220
- segmentsToUrlPath,
2221
- segmentsToStoredSlug,
2222
- renderGlobalModule,
2223
- renderCollectionModule,
2224
- queryGlobal,
2225
- queryDocBySlug,
2226
- queryAllLocaleSlugs,
2227
- queryAllDocs,
2228
- linkGroup,
2229
- link,
2230
- getUrlPath,
2231
- getRenderModuleExports,
2232
- getFromImportMap,
2233
- getCachedGlobal,
2234
- generatePreviewPath,
2235
- generateImportName,
2236
- server_default as default,
2237
- createWWWConfig,
2238
- createTestPayload,
2239
- createStaticPagesCollection,
2240
- createStaticPageExports,
2241
- createRevalidatePageHooks,
2242
- createRevalidateGlobalHook,
2243
- createRevalidateCollectionHook,
2244
- createPostsCollection,
2245
- createPagesCollection,
2246
- createHeaderGlobal,
2247
- createFooterGlobal,
2248
- createCollectionPageExports,
2249
- createBaseSeed,
2250
- buildOrganizationLd,
2251
- buildHreflangAlternates,
2252
- buildCanonicalUrl,
2253
- buildBreadcrumbsLd,
2254
- buildArticleLd,
2255
- authenticatedOrPublished,
2256
- authenticated,
2257
- appearanceOptions,
2258
- anyone,
2259
- addCollectionsToSitemap,
2260
- STATIC_PAGES_SLUG,
2261
- RenderBlocks,
2262
- POSTS_SLUG2 as POSTS_SLUG,
2263
- PAGES_SLUG2 as PAGES_SLUG,
2264
- HOME_PAGE_SLUG
2265
- };