@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
@@ -1,676 +1,222 @@
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
-
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
2
 
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;
3
+ // package.json
4
+ var name = "@justanarthur/payload-www";
5
+
6
+ // src/collections/hooks/populatePublishedAt.ts
7
+ var populatePublishedAt = ({ data, operation, req }) => {
8
+ if (operation === "create" || operation === "update") {
9
+ if (req.data && !req.data.publishedAt) {
10
+ const now = new Date;
11
+ return {
12
+ ...data,
13
+ publishedAt: now
14
+ };
51
15
  }
52
- };
53
- };
54
-
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
16
  }
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);
104
- }
105
- }
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
- }
17
+ return data;
18
+ };
141
19
 
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:`);
20
+ // src/collections/hooks/createRevalidateCollectionGlobalHook.ts
21
+ import { revalidateTag } from "next/cache";
22
+ function createRevalidateCollectionGlobalHook() {
23
+ const afterChangeDeleteHook = async ({ doc, req, ...args }) => {
24
+ const previousDoc = "previousDoc" in args ? args.previousDoc : null, locale = req.locale;
25
+ function revalidate(args2) {
26
+ try {
27
+ revalidateTag(createCollectionCacheKey({ ...args2, locale }), "max");
28
+ } catch (error) {
29
+ const msg = error instanceof Error ? error.message : String(error);
30
+ if (msg.includes("static generation store missing"))
31
+ return;
32
+ console.error(error);
204
33
  }
205
- await fireCollectionTags(payload, typed.id, req);
206
34
  }
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);
35
+ if ("collection" in args) {
36
+ [
37
+ doc && doc._status !== "draft" && doc.slug,
38
+ previousDoc && previousDoc._status === "published" && previousDoc.slug
39
+ ].filter((slug) => slug !== undefined && slug !== false).map((slug) => revalidate({ collectionSlug: args.collection.slug, slug }));
40
+ } else {
41
+ revalidate({ globalSlug: args.global.slug });
212
42
  }
213
43
  return doc;
214
44
  };
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 };
45
+ return { afterChange: afterChangeDeleteHook, afterDelete: afterChangeDeleteHook };
46
+ }
47
+ function createCollectionCacheKey(args) {
48
+ return `${"globalSlug" in args ? args.globalSlug : args.collectionSlug + args.slug}_${args.locale}`;
228
49
  }
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
50
 
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";
51
+ // src/collections/fields/slug.ts
52
+ var slugField = () => ({
53
+ name: "slug",
54
+ type: "text",
55
+ required: true,
56
+ unique: true,
57
+ index: true,
58
+ localized: true,
59
+ admin: {
60
+ position: "sidebar",
61
+ description: "Lowercase, hyphens for words. Use the `_` divider for nesting, e.g. `about_us` → `/about/us`."
62
+ },
63
+ validate: (value) => {
64
+ if (typeof value !== "string")
65
+ return "Slug must be a string";
66
+ if (value !== "" && !/^[a-z0-9_-]+$/.test(value))
67
+ return "Slug must be lowercase, with hyphens (no spaces or special characters).";
68
+ return true;
69
+ }
70
+ });
247
71
 
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
- };
72
+ // src/collections/access/index.ts
73
+ var anyone = () => true;
74
+ var authenticated = ({ req: { user } }) => Boolean(user);
75
+ var authenticatedOrPublished = ({ req: { user } }) => {
76
+ if (user)
77
+ return true;
78
+ return { _status: { equals: "published" } };
312
79
  };
313
80
 
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
- });
81
+ // src/collections/createWWWCollectionGlobal.ts
82
+ function createWWWCollectionGlobal(fields, {
83
+ slug: collectionSlug,
84
+ renderPath,
85
+ isGlobalConfig = false,
86
+ isDraft = true
87
+ }) {
355
88
  return {
356
89
  slug: collectionSlug,
357
- custom: { path: renderPath },
358
- access: {
359
- create: authenticated,
360
- delete: authenticated,
361
- read: authenticatedOrPublished,
362
- update: authenticated
363
- },
364
- fields: baseFields,
365
- hooks: {
366
- afterChange: [afterChange],
367
- afterDelete: [afterDelete]
368
- },
369
- versions: { drafts: { autosave: { interval: 1000 } } }
370
- };
371
- };
372
-
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
- },
415
- {
416
- type: "tabs",
417
- tabs: [
418
- {
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"
430
- }
431
- ]
432
- },
90
+ fields: isGlobalConfig ? fields : [
91
+ slugField(),
433
92
  {
434
93
  name: "publishedAt",
435
94
  type: "date",
436
95
  admin: { position: "sidebar" }
437
- }
96
+ },
97
+ ...fields
438
98
  ],
439
- hooks: {
440
- afterChange: [afterChange],
441
- afterDelete: [afterDelete]
442
- },
443
- versions: { drafts: { autosave: { interval: 1000 } } }
444
- };
445
- };
446
-
447
- // src/core/fields/link.ts
448
- var appearanceOptions = {
449
- default: { label: "Default", value: "default" },
450
- outline: { label: "Outline", value: "outline" }
451
- };
452
- var link = (options = {}) => {
453
- const {
454
- appearances,
455
- disableLabel = false,
456
- relationTo = [PAGES_SLUG],
457
- localized = false,
458
- overrides = {},
459
- extraFields = []
460
- } = options;
461
- const result = {
462
- name: "link",
463
- type: "group",
464
- admin: { hideGutter: true },
465
- fields: [
466
- {
467
- type: "row",
468
- fields: [
469
- {
470
- name: "type",
471
- type: "radio",
472
- admin: { layout: "horizontal", width: "50%" },
473
- defaultValue: "reference",
474
- options: [
475
- { label: "Internal link", value: "reference" },
476
- { label: "Custom URL", value: "custom" }
477
- ]
478
- },
479
- {
480
- name: "newTab",
481
- type: "checkbox",
482
- admin: { style: { alignSelf: "flex-end" }, width: "50%" },
483
- label: "Open in new tab"
484
- }
485
- ]
486
- }
487
- ]
488
- };
489
- const linkTypes = [
490
- {
491
- name: "reference",
492
- type: "relationship",
493
- admin: { condition: (_, siblingData) => siblingData?.type === "reference" },
494
- label: "Document to link to",
495
- relationTo,
496
- required: true,
497
- localized
99
+ custom: { [name]: { path: renderPath } },
100
+ access: {
101
+ create: authenticated,
102
+ delete: authenticated,
103
+ read: isDraft ? authenticatedOrPublished : anyone,
104
+ update: authenticated
498
105
  },
499
- {
500
- name: "url",
501
- type: "text",
502
- admin: { condition: (_, siblingData) => siblingData?.type === "custom" },
503
- label: "Custom URL",
504
- required: true,
505
- localized
506
- }
507
- ];
508
- if (!disableLabel) {
509
- result.fields.push({
510
- type: "row",
511
- fields: [
512
- ...linkTypes,
513
- {
514
- name: "label",
515
- type: "text",
516
- admin: { width: "50%" },
517
- label: "Label",
518
- required: true,
519
- localized
520
- }
521
- ]
522
- });
523
- } else {
524
- result.fields = [...result.fields, ...linkTypes];
525
- }
526
- if (appearances !== false) {
527
- const opts = appearances ? appearances.map((a) => appearanceOptions[a]) : [appearanceOptions.default, appearanceOptions.outline];
528
- result.fields.push({
529
- name: "appearance",
530
- type: "select",
531
- admin: { description: "Choose how the link should be rendered." },
532
- defaultValue: "default",
533
- options: opts
534
- });
535
- }
536
- if (extraFields.length) {
537
- result.fields.push(...extraFields);
538
- }
539
- return { ...result, ...overrides };
540
- };
541
-
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);
106
+ hooks: (() => {
107
+ const { afterChange, afterDelete } = createRevalidateCollectionGlobalHook();
108
+ return {
109
+ afterChange: [afterChange],
110
+ beforeChange: [populatePublishedAt],
111
+ afterDelete: [afterDelete]
112
+ };
113
+ })(),
114
+ ...isDraft && {
115
+ versions: { drafts: { autosave: { interval: 3000 } } }
553
116
  }
554
- return doc;
555
117
  };
556
118
  }
557
119
 
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")]
120
+ // src/render/metadata/query.ts
121
+ import { getPayload } from "payload";
122
+ async function withUnstableCache(keyParts, tags, fn) {
123
+ const { unstable_cache } = await import("next/cache");
124
+ return unstable_cache(fn, keyParts.map(String), { tags })();
125
+ }
126
+ async function queryDoc(args, { config: configPromise }) {
127
+ return withUnstableCache(Object.values(args), [createCollectionCacheKey(args)], async () => {
128
+ if ("globalSlug" in args)
129
+ return queryGlobal({ ...args, config: configPromise });
130
+ else
131
+ return queryDocBySlug({ ...args, config: configPromise });
132
+ });
133
+ }
134
+ async function queryDocBySlug({
135
+ collectionSlug,
136
+ slug,
137
+ slugField: slugField2 = "slug",
138
+ locale,
139
+ draft = false,
140
+ config
141
+ }) {
142
+ return withUnstableCache([collectionSlug, slug, locale, draft], [createCollectionCacheKey({ collectionSlug, slug, locale })], async () => {
143
+ const payload = await getPayload({ config });
144
+ const result = await payload.find({
145
+ collection: collectionSlug,
146
+ draft,
147
+ limit: 1,
148
+ pagination: false,
149
+ overrideAccess: draft,
150
+ where: { [slugField2]: { equals: slug } },
151
+ locale
152
+ });
153
+ return result.docs?.[0] ?? null;
154
+ });
155
+ }
156
+ async function queryGlobal({
157
+ globalSlug,
158
+ locale,
159
+ draft = false,
160
+ config
161
+ }) {
162
+ return withUnstableCache([globalSlug, locale, draft], [createCollectionCacheKey({ globalSlug, locale })], async () => {
163
+ const payload = await getPayload({ config });
164
+ try {
165
+ return await payload.findGlobal({ slug: globalSlug, draft, locale });
166
+ } catch (error) {
167
+ console.warn("[WWW] queryGlobal failed", { globalSlug, locale, error: String(error) });
168
+ return null;
628
169
  }
629
- };
630
- };
631
-
632
- // src/data/collections/previewPath.ts
633
- var collectionPrefixMap = {
634
- posts: "/posts",
635
- pages: ""
636
- };
637
- function generatePreviewPath({
638
- collection,
639
- slug
170
+ });
171
+ }
172
+ async function queryAllDocs({
173
+ collectionSlug,
174
+ slugField: slugField2 = "slug",
175
+ locale,
176
+ config
177
+ }) {
178
+ return withUnstableCache([collectionSlug, slugField2, locale], [createCollectionCacheKey({ collectionSlug, slug: "__all__", locale })], async () => {
179
+ const payload = await getPayload({ config });
180
+ const result = await payload.find({
181
+ collection: collectionSlug,
182
+ draft: false,
183
+ limit: 1000,
184
+ pagination: false,
185
+ overrideAccess: false,
186
+ select: { [slugField2]: true },
187
+ locale
188
+ });
189
+ return result.docs ?? [];
190
+ });
191
+ }
192
+ async function queryAllLocaleSlugs({
193
+ collectionSlug,
194
+ id,
195
+ slugField: slugField2 = "slug",
196
+ config
640
197
  }) {
641
- if (slug === undefined || slug === null)
642
- return null;
643
- const encodedSlug = encodeURIComponent(slug);
644
- const params = new URLSearchParams({
645
- path: `${collectionPrefixMap[collection] ?? ""}/${encodedSlug}`,
646
- previewSecret: process.env.PREVIEW_SECRET || ""
198
+ const payload = await getPayload({ config });
199
+ const doc = await payload.findByID({
200
+ collection: collectionSlug,
201
+ id,
202
+ locale: "all",
203
+ select: { [slugField2]: true }
647
204
  });
648
- return `/next/preview?${params.toString()}`;
205
+ return doc?.[slugField2];
649
206
  }
650
207
 
651
208
  // src/exports/collections.ts
652
- var collections_default = {
653
- createPagesCollection,
654
- createPostsCollection,
655
- createStaticPagesCollection,
656
- createHeaderGlobal,
657
- createFooterGlobal,
658
- generatePreviewPath,
659
- HOME_PAGE_SLUG,
660
- PAGES_SLUG: PAGES_SLUG2,
661
- POSTS_SLUG: POSTS_SLUG2,
662
- STATIC_PAGES_SLUG
209
+ var collections = {
210
+ createWWWCollectionGlobal,
211
+ createRevalidateCollectionGlobalHook,
212
+ createCollectionCacheKey,
213
+ queryDoc
663
214
  };
215
+ var collections_default = collections;
664
216
  export {
665
- generatePreviewPath,
217
+ queryDoc,
666
218
  collections_default as default,
667
- createStaticPagesCollection,
668
- createPostsCollection,
669
- createPagesCollection,
670
- createHeaderGlobal,
671
- createFooterGlobal,
672
- STATIC_PAGES_SLUG,
673
- POSTS_SLUG2 as POSTS_SLUG,
674
- PAGES_SLUG2 as PAGES_SLUG,
675
- HOME_PAGE_SLUG
219
+ createWWWCollectionGlobal,
220
+ createRevalidateCollectionGlobalHook,
221
+ createCollectionCacheKey
676
222
  };