@justanarthur/payload-www 0.3.5 → 1.2.0

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