@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.
Files changed (62) hide show
  1. package/README.md +381 -0
  2. package/dist/access.d.ts +11 -0
  3. package/dist/access.js +34 -0
  4. package/dist/blocks.d.ts +24 -0
  5. package/dist/blocks.js +75 -0
  6. package/dist/collections.d.ts +200 -0
  7. package/dist/collections.js +625 -0
  8. package/dist/components.d.ts +6 -0
  9. package/dist/components.js +38 -0
  10. package/dist/config.d.ts +100 -0
  11. package/dist/config.js +914 -0
  12. package/dist/core-access.d.ts +11 -0
  13. package/dist/core-access.js +34 -0
  14. package/dist/core-blocks.d.ts +24 -0
  15. package/dist/core-blocks.js +75 -0
  16. package/dist/core-fields.d.ts +36 -0
  17. package/dist/core-fields.js +134 -0
  18. package/dist/core-utils.d.ts +16 -0
  19. package/dist/core-utils.js +59 -0
  20. package/dist/data-collections.d.ts +200 -0
  21. package/dist/data-collections.js +625 -0
  22. package/dist/data-seed.d.ts +76 -0
  23. package/dist/data-seed.js +212 -0
  24. package/dist/data-test.d.ts +30 -0
  25. package/dist/data-test.js +1018 -0
  26. package/dist/fields.d.ts +36 -0
  27. package/dist/fields.js +134 -0
  28. package/dist/globals.d.ts +48 -0
  29. package/dist/globals.js +228 -0
  30. package/dist/hooks.d.ts +108 -0
  31. package/dist/hooks.js +196 -0
  32. package/dist/imagehash.d.ts +3 -0
  33. package/dist/imagehash.js +24 -0
  34. package/dist/import-map-provider.d.ts +20 -0
  35. package/dist/import-map-provider.js +26 -0
  36. package/dist/index.d.ts +6 -0
  37. package/dist/index.js +38 -0
  38. package/dist/metadata.d.ts +122 -0
  39. package/dist/metadata.js +335 -0
  40. package/dist/pages.d.ts +323 -0
  41. package/dist/pages.js +1016 -0
  42. package/dist/render-components.d.ts +42 -0
  43. package/dist/render-components.js +144 -0
  44. package/dist/render-metadata.d.ts +122 -0
  45. package/dist/render-metadata.js +335 -0
  46. package/dist/render-pages.d.ts +574 -0
  47. package/dist/render-pages.js +1450 -0
  48. package/dist/render-utils.d.ts +158 -0
  49. package/dist/render-utils.js +341 -0
  50. package/dist/seed.d.ts +76 -0
  51. package/dist/seed.js +212 -0
  52. package/dist/server.d.ts +922 -0
  53. package/dist/server.js +2055 -0
  54. package/dist/test.d.ts +30 -0
  55. package/dist/test.js +1018 -0
  56. package/dist/translator.d.ts +2 -0
  57. package/dist/translator.js +24 -0
  58. package/dist/utils.d.ts +16 -0
  59. package/dist/utils.js +59 -0
  60. package/dist/with-www-config.d.ts +100 -0
  61. package/dist/with-www-config.js +914 -0
  62. package/package.json +246 -0
package/dist/config.js ADDED
@@ -0,0 +1,914 @@
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/core/access/index.ts
19
+ var anyone = () => true;
20
+ var authenticated = ({ req: { user } }) => Boolean(user);
21
+ var authenticatedOrPublished = ({ req: { user } }) => {
22
+ if (user)
23
+ return true;
24
+ return { _status: { equals: "published" } };
25
+ };
26
+
27
+ // src/render/_locale.ts
28
+ function prefixFor(locale, defaultLocale, mode) {
29
+ if (mode === "never")
30
+ return "";
31
+ if (mode === "as-needed" && locale === defaultLocale)
32
+ return "";
33
+ return `/${locale}`;
34
+ }
35
+ function resolveLocale(req) {
36
+ if (!req || typeof req !== "object")
37
+ return "";
38
+ const r = req;
39
+ if (typeof r.locale === "string" && r.locale.length > 0)
40
+ return r.locale;
41
+ const fallback = r.payload?.config?.localization?.defaultLocale;
42
+ if (typeof fallback === "string" && fallback.length > 0)
43
+ return fallback;
44
+ return "";
45
+ }
46
+ function allLocales(req) {
47
+ if (!req || typeof req !== "object")
48
+ return [];
49
+ const r = req;
50
+ const list = r.payload?.config?.localization?.locales;
51
+ if (!Array.isArray(list) || list.length === 0)
52
+ return [];
53
+ const out = [];
54
+ for (const entry of list) {
55
+ if (typeof entry === "string" && entry.length > 0) {
56
+ out.push(entry);
57
+ } else if (entry && typeof entry === "object" && "code" in entry) {
58
+ const code = entry.code;
59
+ if (typeof code === "string" && code.length > 0)
60
+ out.push(code);
61
+ }
62
+ }
63
+ return out;
64
+ }
65
+
66
+ // src/render/hooks/_shared.ts
67
+ var cachePromise = null;
68
+ function nextCacheImport() {
69
+ return cachePromise ??= import("next/cache");
70
+ }
71
+ function shouldSkipRevalidate(context) {
72
+ return Boolean(context?.disableRevalidate);
73
+ }
74
+ async function safeRevalidatePath(payload, path) {
75
+ try {
76
+ const { revalidatePath } = await nextCacheImport();
77
+ revalidatePath(path);
78
+ } catch (error) {
79
+ payload.logger.error(`revalidatePath("${path}") failed: ${String(error)}`);
80
+ }
81
+ }
82
+ async function safeRevalidateTag(payload, tag, profile = "max") {
83
+ try {
84
+ const { revalidateTag } = await nextCacheImport();
85
+ revalidateTag(tag, profile);
86
+ } catch (error) {
87
+ payload.logger.error(`revalidateTag("${tag}") failed: ${String(error)}`);
88
+ }
89
+ }
90
+
91
+ // src/render/hooks/revalidateCollection.ts
92
+ function createRevalidateCollectionHook(options) {
93
+ const {
94
+ collectionSlug,
95
+ urlPathPrefix = "",
96
+ sitemapTag,
97
+ localePrefix: modeOption,
98
+ defaultLocale: defaultLocaleOption,
99
+ pathMode = "url"
100
+ } = options;
101
+ const resolvedSitemapTag = sitemapTag === false ? false : sitemapTag ?? `${collectionSlug}-sitemap`;
102
+ const resolveDefaults = (req) => {
103
+ const mode = modeOption ?? "always";
104
+ const defaultLocale = defaultLocaleOption ?? req?.payload?.config?.localization?.defaultLocale ?? "";
105
+ return { mode, defaultLocale };
106
+ };
107
+ const localesToFanOut = (req) => {
108
+ const all = allLocales(req);
109
+ if (all.length > 0)
110
+ return all;
111
+ const single = resolveLocale(req);
112
+ return single ? [single] : [];
113
+ };
114
+ const collectionPath = (slug, locale, mode, defaultLocale) => {
115
+ const prefix = prefixFor(locale, defaultLocale, mode);
116
+ if (!slug)
117
+ return `${prefix}${urlPathPrefix}` || "/";
118
+ return `${prefix}${urlPathPrefix}/${slug}`;
119
+ };
120
+ const fanOutPaths = async (payload, req, slug, label) => {
121
+ const { mode, defaultLocale } = resolveDefaults(req);
122
+ const locales = localesToFanOut(req);
123
+ for (const locale of locales) {
124
+ const path = collectionPath(slug, locale, mode, defaultLocale);
125
+ payload.logger.info?.(`${label} ${path}`);
126
+ await safeRevalidatePath(payload, path);
127
+ }
128
+ };
129
+ const fireCollectionTags = async (payload, docId, req) => {
130
+ if (typeof docId === "string" || typeof docId === "number") {
131
+ await safeRevalidateTag(payload, `collection_${collectionSlug}_${docId}`);
132
+ }
133
+ if (resolvedSitemapTag !== false) {
134
+ await safeRevalidateTag(payload, resolvedSitemapTag);
135
+ }
136
+ };
137
+ const afterChange = async ({ doc, previousDoc, req }) => {
138
+ if (shouldSkipRevalidate(req.context))
139
+ return doc;
140
+ const { payload } = req;
141
+ const typed = doc;
142
+ const prev = previousDoc;
143
+ const isPublished = typed._status === "published";
144
+ const wasPublished = prev?._status === "published";
145
+ const prevSlugIsString = typeof prev?.slug === "string";
146
+ const slugChanged = prevSlugIsString && prev?.slug !== typed.slug;
147
+ if (isPublished) {
148
+ if (pathMode !== "tag-only") {
149
+ await fanOutPaths(payload, req, typed.slug, `Revalidating ${collectionSlug} at path:`);
150
+ }
151
+ await fireCollectionTags(payload, typed.id, req);
152
+ }
153
+ if (wasPublished && (!isPublished || slugChanged)) {
154
+ if (pathMode !== "tag-only") {
155
+ await fanOutPaths(payload, req, prev?.slug, `Revalidating old ${collectionSlug} at path:`);
156
+ }
157
+ await fireCollectionTags(payload, typed.id, req);
158
+ }
159
+ return doc;
160
+ };
161
+ const afterDelete = async ({ doc, req }) => {
162
+ if (shouldSkipRevalidate(req.context))
163
+ return doc ?? null;
164
+ const { payload } = req;
165
+ const typed = doc;
166
+ if (pathMode !== "tag-only") {
167
+ await fanOutPaths(payload, req, typed?.slug, `Revalidating deleted ${collectionSlug} at path:`);
168
+ }
169
+ await fireCollectionTags(payload, typed?.id, req);
170
+ return doc ?? null;
171
+ };
172
+ return { afterChange, afterDelete };
173
+ }
174
+ var createRevalidatePageHooks = (opts = {}) => createRevalidateCollectionHook({
175
+ collectionSlug: "pages",
176
+ urlPathPrefix: "",
177
+ ...opts
178
+ });
179
+
180
+ // src/config/constants.ts
181
+ var PAGES_RENDER_PATH = "@justanarthur/payload-www/render-pages#PagesPage";
182
+ var POSTS_RENDER_PATH = "@justanarthur/payload-www/render-pages#PostsPage";
183
+ var HEADER_RENDER_PATH = "@justanarthur/payload-www/render-pages#HeaderPage";
184
+ var FOOTER_RENDER_PATH = "@justanarthur/payload-www/render-pages#FooterPage";
185
+ var LIVE_PREVIEW_LISTENER_PATH = "@justanarthur/payload-www/render-components#LivePreviewListener";
186
+ var PAGES_SLUG = "pages";
187
+ var POSTS_SLUG = "posts";
188
+ var STATIC_PAGES_SLUG = "staticPages";
189
+
190
+ // src/data/collections/Pages/index.ts
191
+ var HOME_PAGE_SLUG = "";
192
+ var PAGES_SLUG2 = PAGES_SLUG;
193
+ var createPagesCollection = (blocks, options = {}) => {
194
+ const {
195
+ renderPath = PAGES_RENDER_PATH,
196
+ slug: collectionSlug = PAGES_SLUG2,
197
+ localePrefix,
198
+ defaultLocale
199
+ } = options;
200
+ const slugField = {
201
+ name: "slug",
202
+ type: "text",
203
+ required: true,
204
+ unique: true,
205
+ index: true,
206
+ admin: { position: "sidebar" },
207
+ validate: (value) => {
208
+ if (typeof value !== "string")
209
+ return "Slug must be a string";
210
+ if (value !== "" && !/^[a-z0-9-]+$/.test(value)) {
211
+ return "Slug must be lowercase, with hyphens (no spaces or special characters)";
212
+ }
213
+ return true;
214
+ }
215
+ };
216
+ const baseFields = [
217
+ {
218
+ name: "title",
219
+ type: "text",
220
+ required: true,
221
+ localized: true
222
+ },
223
+ {
224
+ type: "tabs",
225
+ tabs: [
226
+ {
227
+ fields: [
228
+ {
229
+ name: "blocks",
230
+ type: "blocks",
231
+ blocks,
232
+ required: true,
233
+ admin: { initCollapsed: true }
234
+ }
235
+ ],
236
+ label: "Content"
237
+ }
238
+ ]
239
+ },
240
+ {
241
+ name: "publishedAt",
242
+ type: "date",
243
+ admin: { position: "sidebar" }
244
+ },
245
+ slugField
246
+ ];
247
+ const { afterChange: revalidateAfterChange, afterDelete: revalidateAfterDelete } = createRevalidateCollectionHook({
248
+ collectionSlug,
249
+ urlPathPrefix: "",
250
+ localePrefix,
251
+ defaultLocale
252
+ });
253
+ return {
254
+ slug: collectionSlug,
255
+ custom: { path: renderPath },
256
+ access: {
257
+ create: authenticated,
258
+ delete: authenticated,
259
+ read: authenticatedOrPublished,
260
+ update: authenticated
261
+ },
262
+ fields: baseFields,
263
+ hooks: {
264
+ afterChange: [revalidateAfterChange],
265
+ afterDelete: [revalidateAfterDelete]
266
+ },
267
+ versions: { drafts: { autosave: { interval: 1000 } } }
268
+ };
269
+ };
270
+
271
+ // src/data/collections/Posts/index.ts
272
+ var POSTS_SLUG2 = "posts";
273
+ var createPostsCollection = (options = {}) => {
274
+ const {
275
+ renderPath = POSTS_RENDER_PATH,
276
+ slug: collectionSlug = POSTS_SLUG2,
277
+ localePrefix,
278
+ defaultLocale
279
+ } = options;
280
+ const slugField = {
281
+ name: "slug",
282
+ type: "text",
283
+ required: true,
284
+ unique: true,
285
+ index: true,
286
+ admin: { position: "sidebar" }
287
+ };
288
+ const baseFields = [
289
+ {
290
+ name: "title",
291
+ type: "text",
292
+ required: true,
293
+ localized: true
294
+ },
295
+ {
296
+ name: "excerpt",
297
+ type: "text",
298
+ required: false,
299
+ localized: true
300
+ },
301
+ {
302
+ name: "content",
303
+ type: "richText",
304
+ required: false,
305
+ localized: true
306
+ },
307
+ {
308
+ name: "publishedAt",
309
+ type: "date",
310
+ admin: { position: "sidebar" }
311
+ },
312
+ slugField
313
+ ];
314
+ const { afterChange, afterDelete } = createRevalidateCollectionHook({
315
+ collectionSlug,
316
+ urlPathPrefix: "/posts",
317
+ localePrefix,
318
+ defaultLocale
319
+ });
320
+ return {
321
+ slug: collectionSlug,
322
+ custom: { path: renderPath },
323
+ access: {
324
+ create: authenticated,
325
+ delete: authenticated,
326
+ read: authenticatedOrPublished,
327
+ update: authenticated
328
+ },
329
+ fields: baseFields,
330
+ hooks: {
331
+ afterChange: [afterChange],
332
+ afterDelete: [afterDelete]
333
+ },
334
+ versions: { drafts: { autosave: { interval: 1000 } } }
335
+ };
336
+ };
337
+
338
+ // src/data/collections/StaticPages/index.ts
339
+ var createStaticPagesCollection = (blocks) => {
340
+ const { afterChange, afterDelete } = createRevalidateCollectionHook({
341
+ collectionSlug: STATIC_PAGES_SLUG,
342
+ pathMode: "tag-only",
343
+ sitemapTag: "static-pages"
344
+ });
345
+ return {
346
+ slug: STATIC_PAGES_SLUG,
347
+ dbName: "sp",
348
+ admin: { group: "System", useAsTitle: "title" },
349
+ access: {
350
+ create: authenticated,
351
+ delete: authenticated,
352
+ read: authenticatedOrPublished,
353
+ update: authenticated
354
+ },
355
+ fields: [
356
+ {
357
+ name: "kind",
358
+ type: "select",
359
+ required: true,
360
+ unique: true,
361
+ index: true,
362
+ options: [
363
+ { label: "Not found (404)", value: "not-found" },
364
+ { label: "Server error (500)", value: "server-error" },
365
+ { label: "Search empty", value: "search-empty" },
366
+ { label: "Offline", value: "offline" }
367
+ ],
368
+ admin: {
369
+ position: "sidebar",
370
+ description: "Which system page this row powers. One row per kind."
371
+ }
372
+ },
373
+ {
374
+ name: "title",
375
+ type: "text",
376
+ required: true,
377
+ localized: true,
378
+ admin: { description: "Admin-only label. Not rendered." }
379
+ },
380
+ {
381
+ type: "tabs",
382
+ tabs: [
383
+ {
384
+ fields: [
385
+ {
386
+ name: "blocks",
387
+ type: "blocks",
388
+ localized: true,
389
+ blocks,
390
+ admin: { initCollapsed: true },
391
+ dbName: "b"
392
+ }
393
+ ],
394
+ label: "Content"
395
+ }
396
+ ]
397
+ },
398
+ {
399
+ name: "publishedAt",
400
+ type: "date",
401
+ admin: { position: "sidebar" }
402
+ }
403
+ ],
404
+ hooks: {
405
+ afterChange: [afterChange],
406
+ afterDelete: [afterDelete]
407
+ },
408
+ versions: { drafts: { autosave: { interval: 1000 } } }
409
+ };
410
+ };
411
+
412
+ // src/core/fields/link.ts
413
+ var appearanceOptions = {
414
+ default: { label: "Default", value: "default" },
415
+ outline: { label: "Outline", value: "outline" }
416
+ };
417
+ var link = (options = {}) => {
418
+ const {
419
+ appearances,
420
+ disableLabel = false,
421
+ relationTo = [PAGES_SLUG],
422
+ localized = false,
423
+ overrides = {}
424
+ } = options;
425
+ const result = {
426
+ name: "link",
427
+ type: "group",
428
+ admin: { hideGutter: true },
429
+ fields: [
430
+ {
431
+ type: "row",
432
+ fields: [
433
+ {
434
+ name: "type",
435
+ type: "radio",
436
+ admin: { layout: "horizontal", width: "50%" },
437
+ defaultValue: "reference",
438
+ options: [
439
+ { label: "Internal link", value: "reference" },
440
+ { label: "Custom URL", value: "custom" }
441
+ ]
442
+ },
443
+ {
444
+ name: "newTab",
445
+ type: "checkbox",
446
+ admin: { style: { alignSelf: "flex-end" }, width: "50%" },
447
+ label: "Open in new tab"
448
+ }
449
+ ]
450
+ }
451
+ ]
452
+ };
453
+ const linkTypes = [
454
+ {
455
+ name: "reference",
456
+ type: "relationship",
457
+ admin: { condition: (_, siblingData) => siblingData?.type === "reference" },
458
+ label: "Document to link to",
459
+ relationTo,
460
+ required: true,
461
+ localized
462
+ },
463
+ {
464
+ name: "url",
465
+ type: "text",
466
+ admin: { condition: (_, siblingData) => siblingData?.type === "custom" },
467
+ label: "Custom URL",
468
+ required: true,
469
+ localized
470
+ }
471
+ ];
472
+ if (!disableLabel) {
473
+ result.fields.push({
474
+ type: "row",
475
+ fields: [
476
+ ...linkTypes,
477
+ {
478
+ name: "label",
479
+ type: "text",
480
+ admin: { width: "50%" },
481
+ label: "Label",
482
+ required: true,
483
+ localized
484
+ }
485
+ ]
486
+ });
487
+ } else {
488
+ result.fields = [...result.fields, ...linkTypes];
489
+ }
490
+ if (appearances !== false) {
491
+ const opts = appearances ? appearances.map((a) => appearanceOptions[a]) : [appearanceOptions.default, appearanceOptions.outline];
492
+ result.fields.push({
493
+ name: "appearance",
494
+ type: "select",
495
+ admin: { description: "Choose how the link should be rendered." },
496
+ defaultValue: "default",
497
+ options: opts
498
+ });
499
+ }
500
+ return { ...result, ...overrides };
501
+ };
502
+
503
+ // src/render/hooks/revalidateGlobal.ts
504
+ function createRevalidateGlobalHook(slug) {
505
+ return async ({ doc, req: { payload, context, locale } }) => {
506
+ if (shouldSkipRevalidate(context))
507
+ return doc;
508
+ const tags = [`global_${slug}`, `global_${slug}_${locale}`];
509
+ payload.logger.info?.(`Revalidating global: ${tags.join(", ")}`);
510
+ for (const tag of tags) {
511
+ await safeRevalidateTag(payload, tag);
512
+ }
513
+ return doc;
514
+ };
515
+ }
516
+
517
+ // src/data/collections/globals/Header/config.ts
518
+ var createHeaderGlobal = (options = {}) => {
519
+ const { renderPath = HEADER_RENDER_PATH, linkRelationTo = [PAGES_SLUG] } = options;
520
+ const navColumnBlock = {
521
+ slug: "navColumn",
522
+ fields: [
523
+ { name: "title", type: "text", required: true, localized: true },
524
+ { name: "links", type: "array", fields: [link({ appearances: false, localized: true, relationTo: linkRelationTo })] }
525
+ ]
526
+ };
527
+ const navItemBlock = {
528
+ slug: "navItem",
529
+ fields: [link({ appearances: false, localized: true, relationTo: linkRelationTo })]
530
+ };
531
+ return {
532
+ slug: "header",
533
+ custom: { path: renderPath },
534
+ access: { read: () => true },
535
+ fields: [
536
+ {
537
+ name: "nav",
538
+ type: "blocks",
539
+ required: true,
540
+ blocks: [navColumnBlock, navItemBlock]
541
+ }
542
+ ],
543
+ hooks: {
544
+ afterChange: [createRevalidateGlobalHook("header")]
545
+ }
546
+ };
547
+ };
548
+
549
+ // src/data/collections/globals/Footer/config.ts
550
+ var createFooterGlobal = (options = {}) => {
551
+ const { renderPath = FOOTER_RENDER_PATH, linkRelationTo = [PAGES_SLUG] } = options;
552
+ const navColumnBlock = {
553
+ slug: "navColumn",
554
+ fields: [
555
+ { name: "title", type: "text", required: true, localized: true },
556
+ { name: "links", type: "array", fields: [link({ appearances: false, localized: true, relationTo: linkRelationTo })] }
557
+ ]
558
+ };
559
+ const navItemBlock = {
560
+ slug: "navItem",
561
+ fields: [link({ appearances: false, localized: true, relationTo: linkRelationTo })]
562
+ };
563
+ return {
564
+ slug: "footer",
565
+ custom: { path: renderPath },
566
+ access: { read: () => true },
567
+ fields: [
568
+ {
569
+ name: "nav",
570
+ type: "blocks",
571
+ required: true,
572
+ blocks: [navColumnBlock, navItemBlock]
573
+ }
574
+ ],
575
+ hooks: {
576
+ afterChange: [createRevalidateGlobalHook("footer")]
577
+ }
578
+ };
579
+ };
580
+
581
+ // src/config/createWWWConfig.ts
582
+ import openAIResolver from "@justanarthur/payload-plugin-translator/resolvers/openAI";
583
+
584
+ // src/render/preview/createPreviewHandler.ts
585
+ function createPreviewHandler(options) {
586
+ const { getServerSideURL: _getServerSideURL, secret, enableDraftMode = true } = options;
587
+ return async function GET(req) {
588
+ const { draftMode } = await import("next/headers");
589
+ const { redirect } = await import("next/navigation");
590
+ const url = new URL(req.url);
591
+ const path = url.searchParams.get("path") ?? "/";
592
+ const previewSecret = url.searchParams.get("previewSecret");
593
+ if (!previewSecret || previewSecret !== secret) {
594
+ return new Response("Invalid preview secret", { status: 401 });
595
+ }
596
+ if (enableDraftMode) {
597
+ (await draftMode()).enable();
598
+ }
599
+ redirect(path);
600
+ return new Response(null, { status: 204 });
601
+ };
602
+ }
603
+ // src/render/metadata/hreflang.ts
604
+ async function buildHreflangAlternates({
605
+ siteUrl,
606
+ locale,
607
+ urlPrefix,
608
+ storedSlug,
609
+ queryAllLocaleSlugs,
610
+ nested,
611
+ homeSlug,
612
+ defaultLocale,
613
+ locales,
614
+ localePrefix = "always"
615
+ }) {
616
+ const allLocaleSlugs = await queryAllLocaleSlugs(storedSlug, locale);
617
+ const languages = {};
618
+ const urlFor = (l, slug) => {
619
+ const trimmedPrefix = urlPrefix.replace(/^\/|\/$/g, "");
620
+ const prefixSegment = trimmedPrefix ? `/${trimmedPrefix}` : "";
621
+ const urlPath = slug === homeSlug ? "/" : nested ? "/" + slug.replaceAll("_", "/") : "/" + slug;
622
+ const localeSegment = localePrefix === "never" ? "" : localePrefix === "as-needed" && l === defaultLocale ? "" : `/${l}`;
623
+ return `${siteUrl}${localeSegment}${prefixSegment}${urlPath}`;
624
+ };
625
+ for (const l of locales) {
626
+ const slugForLocale = allLocaleSlugs?.[l];
627
+ if (!slugForLocale)
628
+ continue;
629
+ languages[l] = urlFor(l, slugForLocale);
630
+ }
631
+ if (allLocaleSlugs?.[defaultLocale]) {
632
+ languages["x-default"] = urlFor(defaultLocale, allLocaleSlugs[defaultLocale]);
633
+ }
634
+ return languages;
635
+ }
636
+
637
+ // src/render/metadata/query.ts
638
+ import { getPayload } from "payload";
639
+ import { cache } from "react";
640
+
641
+ // src/core/utils/getFromImportMap.ts
642
+ function getFromImportMap(key, importMap) {
643
+ return importMap[key.includes("#") ? key : key + "#default"];
644
+ }
645
+
646
+ // src/render/metadata/query.ts
647
+ var queryDocBySlug = cache(async function queryDocBySlug2({
648
+ collectionSlug,
649
+ slug,
650
+ slugField = "slug",
651
+ locale,
652
+ draft = false,
653
+ config
654
+ }) {
655
+ const payload = await getPayload({ config });
656
+ const result = await payload.find({
657
+ collection: collectionSlug,
658
+ draft,
659
+ limit: 1,
660
+ pagination: false,
661
+ overrideAccess: draft,
662
+ where: { [slugField]: { equals: slug } },
663
+ locale
664
+ });
665
+ return result.docs?.[0] ?? null;
666
+ });
667
+ var queryAllDocs = cache(async function queryAllDocs2({
668
+ collectionSlug,
669
+ slugField = "slug",
670
+ locale,
671
+ config
672
+ }) {
673
+ const payload = await getPayload({ config });
674
+ const result = await payload.find({
675
+ collection: collectionSlug,
676
+ draft: false,
677
+ limit: 1000,
678
+ pagination: false,
679
+ overrideAccess: false,
680
+ select: { [slugField]: true },
681
+ locale
682
+ });
683
+ return result.docs ?? [];
684
+ });
685
+ var queryAllLocaleSlugs = cache(async function queryAllLocaleSlugs2({
686
+ collectionSlug,
687
+ slug,
688
+ slugField = "slug",
689
+ locale,
690
+ config
691
+ }) {
692
+ const payload = await getPayload({ config });
693
+ const result = await payload.find({
694
+ collection: collectionSlug,
695
+ draft: false,
696
+ limit: 1,
697
+ pagination: false,
698
+ overrideAccess: false,
699
+ locale,
700
+ where: { [slugField]: { equals: slug } },
701
+ select: { [slugField]: true }
702
+ });
703
+ const doc = result.docs?.[0];
704
+ if (!doc)
705
+ return;
706
+ const fieldValue = doc?.[slugField];
707
+ if (fieldValue && typeof fieldValue === "object") {
708
+ return fieldValue;
709
+ }
710
+ const resolved = await config;
711
+ const rawLocales = Array.isArray(resolved?.localization?.localeCodes) ? resolved.localization.localeCodes : resolved?.localization?.locales?.map((l) => l.code) ?? [];
712
+ const out = {};
713
+ for (const l of rawLocales)
714
+ out[l] = String(fieldValue ?? slug);
715
+ return out;
716
+ });
717
+ var queryGlobal = cache(async function queryGlobal2({
718
+ globalSlug,
719
+ locale,
720
+ depth = 0,
721
+ draft = false,
722
+ config
723
+ }) {
724
+ const payload = await getPayload({ config });
725
+ try {
726
+ const global = await payload.findGlobal({
727
+ slug: globalSlug,
728
+ depth,
729
+ draft,
730
+ locale
731
+ });
732
+ return global;
733
+ } catch {
734
+ return null;
735
+ }
736
+ });
737
+ function getRenderModuleExports(exportName, collection, importMap) {
738
+ const path = collection?.custom?.path;
739
+ if (!path)
740
+ return;
741
+ const mod = getFromImportMap(path, importMap);
742
+ return mod?.[exportName];
743
+ }
744
+
745
+ // src/render/sitemap/createSitemapFile.ts
746
+ function createSitemapFile(options) {
747
+ const { collections } = options;
748
+ return async function sitemap() {
749
+ const cfg = await options.config;
750
+ const allLocales2 = Array.isArray(cfg.localization?.locales) ? cfg.localization.locales.map((l) => typeof l === "string" ? l : l.code) : [cfg.localization?.defaultLocale ?? "en"];
751
+ const defaultLocale = cfg.localization?.defaultLocale ?? allLocales2[0];
752
+ const activeLocales = Array.isArray(options.locales) && options.locales.length > 0 ? options.locales.filter((l) => allLocales2.includes(l)) : allLocales2;
753
+ const entries = [];
754
+ const seen = new Set;
755
+ for (const collectionSlug of collections) {
756
+ const collectionDefaults = options.perCollection?.[collectionSlug] ?? {};
757
+ const urlPrefix = (options.urlPrefixes?.[collectionSlug] ?? "").replace(/\/$/, "");
758
+ const siteUrl = options.getServerSideURL().replace(/\/$/, "");
759
+ for (const locale of activeLocales) {
760
+ const docs = await queryAllDocs({
761
+ collectionSlug,
762
+ slugField: "slug",
763
+ locale,
764
+ config: options.config
765
+ });
766
+ for (const doc of docs) {
767
+ const storedSlug = doc.slug;
768
+ if (typeof storedSlug !== "string" || storedSlug === "")
769
+ continue;
770
+ const dedupeKey = `${collectionSlug}:${locale}:${storedSlug}`;
771
+ if (seen.has(dedupeKey))
772
+ continue;
773
+ seen.add(dedupeKey);
774
+ const url = `${siteUrl}${prefixFor(locale, defaultLocale, options.localePrefix ?? "always")}${urlPrefix}/${storedSlug}`;
775
+ const languages = await buildHreflangAlternates({
776
+ siteUrl,
777
+ locale,
778
+ urlPrefix,
779
+ storedSlug,
780
+ nested: false,
781
+ homeSlug: "",
782
+ defaultLocale,
783
+ locales: activeLocales,
784
+ localePrefix: options.localePrefix,
785
+ queryAllLocaleSlugs: async (s, l) => {
786
+ const result = await queryAllLocaleSlugs({
787
+ collectionSlug,
788
+ slug: s,
789
+ slugField: "slug",
790
+ locale: l,
791
+ config: options.config
792
+ });
793
+ return result ?? undefined;
794
+ }
795
+ });
796
+ entries.push({
797
+ url,
798
+ lastModified: doc.updatedAt ? new Date(doc.updatedAt) : undefined,
799
+ changeFrequency: collectionDefaults.changefreq ?? "weekly",
800
+ priority: collectionDefaults.priority ?? 0.5,
801
+ alternates: { languages }
802
+ });
803
+ }
804
+ }
805
+ }
806
+ return entries;
807
+ };
808
+ }
809
+ // src/config/createWWWConfig.ts
810
+ function createWWWConfig(options) {
811
+ const { locales, routing, blocks, linkRelationTo, registerPosts = true, defaultPlugins } = options;
812
+ const defaultLocale = routing?.defaultLocale ?? locales[0] ?? "";
813
+ const localePrefixMode = (() => {
814
+ const raw = routing?.localePrefix;
815
+ if (typeof raw === "string")
816
+ return raw;
817
+ return raw?.mode ?? "always";
818
+ })();
819
+ if (locales.length === 0) {
820
+ throw new Error("createWWWConfig: `locales` must contain at least one entry.");
821
+ }
822
+ const buildPagesCollection = () => createPagesCollection(blocks, {
823
+ localePrefix: localePrefixMode,
824
+ defaultLocale
825
+ });
826
+ const buildPostsCollection = () => createPostsCollection({
827
+ localePrefix: localePrefixMode,
828
+ defaultLocale
829
+ });
830
+ const buildStaticPagesCollection = () => createStaticPagesCollection(blocks);
831
+ const buildHeaderGlobal = () => createHeaderGlobal({ linkRelationTo });
832
+ const buildFooterGlobal = () => createFooterGlobal({ linkRelationTo });
833
+ async function withWWWConfig(config) {
834
+ const baseDefaults = [
835
+ buildPagesCollection(),
836
+ buildStaticPagesCollection()
837
+ ];
838
+ if (registerPosts)
839
+ baseDefaults.push(buildPostsCollection());
840
+ const defaultCollections = baseDefaults;
841
+ const collections = typeof config.collections === "function" ? config.collections({ defaultCollections }) : [...defaultCollections, ...config.collections || []];
842
+ const defaultGlobals = [buildHeaderGlobal(), buildFooterGlobal()];
843
+ const globals = typeof config.globals === "function" ? config.globals({ defaultGlobals }) : [...defaultGlobals, ...config.globals || []];
844
+ const renderDependencies = {
845
+ [PAGES_RENDER_PATH]: { path: PAGES_RENDER_PATH, type: "component" },
846
+ [POSTS_RENDER_PATH]: { path: POSTS_RENDER_PATH, type: "component" },
847
+ [HEADER_RENDER_PATH]: { path: HEADER_RENDER_PATH, type: "component" },
848
+ [FOOTER_RENDER_PATH]: { path: FOOTER_RENDER_PATH, type: "component" },
849
+ [LIVE_PREVIEW_LISTENER_PATH]: {
850
+ path: LIVE_PREVIEW_LISTENER_PATH,
851
+ type: "component"
852
+ }
853
+ };
854
+ for (const { slug, admin } of blocks) {
855
+ const path = admin?.custom?.path;
856
+ if (typeof path === "string" && slug)
857
+ renderDependencies[slug] = { path, type: "component" };
858
+ }
859
+ for (const entry of [...collections, ...globals]) {
860
+ const path = entry.custom?.path;
861
+ if (typeof path === "string")
862
+ renderDependencies[path] = { path, type: "component" };
863
+ }
864
+ const [
865
+ { seoPlugin },
866
+ { imageHashPlugin },
867
+ { translator }
868
+ ] = await Promise.all([
869
+ import("@justanarthur/payload-plugin-seo"),
870
+ import("@justanarthur/payload-imagehash-plugin"),
871
+ import("@justanarthur/payload-plugin-translator")
872
+ ]);
873
+ const defaultPluginList = [
874
+ seoPlugin({
875
+ collections: ["pages", "posts", "static-pages"],
876
+ autoGenerate: { mode: "onCreate", deriveFrom: "allScalars" }
877
+ }),
878
+ imageHashPlugin({ algorithm: "lqip-modern" }),
879
+ translator({
880
+ collections: ["pages", "posts", "static-pages"],
881
+ globals: ["header", "footer"],
882
+ resolvers: [
883
+ openAIResolver({
884
+ apiKey: process.env.OPENAI_API_KEY,
885
+ chunkLength: 31,
886
+ model: "gpt-5-mini"
887
+ })
888
+ ]
889
+ })
890
+ ];
891
+ const mergedPlugins = defaultPlugins ? defaultPlugins(defaultPluginList) : defaultPluginList;
892
+ return {
893
+ ...config,
894
+ collections,
895
+ globals,
896
+ plugins: mergedPlugins,
897
+ admin: {
898
+ ...config.admin ?? {},
899
+ dependencies: {
900
+ ...renderDependencies,
901
+ ...config.admin?.dependencies ?? {}
902
+ }
903
+ }
904
+ };
905
+ }
906
+ return { withWWWConfig };
907
+ }
908
+
909
+ // src/exports/config.ts
910
+ var config_default = createWWWConfig;
911
+ export {
912
+ config_default as default,
913
+ createWWWConfig
914
+ };