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