@justanarthur/payload-www 1.4.2 → 2.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.
package/dist/sitemap.js CHANGED
@@ -1,7 +1,5 @@
1
-
2
-
3
1
  // src/render/pages/createCollectionPageExports.tsx
4
- import"server-only";
2
+ import * as React from "react";
5
3
 
6
4
  // src/render/metadata/slug.ts
7
5
  var SLUG_NESTED_DIVIDER = "_";
@@ -22,135 +20,112 @@ function slugToPath(slug) {
22
20
  }
23
21
 
24
22
  // src/render/metadata/query.ts
23
+ import { createCacheHelpers } from "@pro-laico/payload-revalidate/cache";
24
+ import { tagsFor } from "@pro-laico/payload-revalidate";
25
+ import { cacheLife } from "next/cache";
25
26
  import { getPayload } from "payload";
26
-
27
- // src/collections/hooks/createRevalidateCollectionGlobalHook.ts
28
- import { revalidateTag } from "next/cache";
29
- function createRevalidateCollectionGlobalHook() {
30
- const afterChangeDeleteHook = async ({ doc, req, ...args }) => {
31
- const previousDoc = "previousDoc" in args ? args.previousDoc : null, locale = req.locale;
32
- function revalidate(args2) {
33
- try {
34
- revalidateTag(createCollectionCacheKey({ ...args2, locale }), "max");
35
- } catch (error) {
36
- const msg = error instanceof Error ? error.message : String(error);
37
- if (msg.includes("static generation store missing"))
38
- return;
39
- console.error(error);
40
- }
41
- }
42
- if ("collection" in args) {
43
- [
44
- doc && doc._status !== "draft" && doc.slug,
45
- previousDoc && previousDoc._status === "published" && previousDoc.slug
46
- ].filter((slug) => slug !== undefined && slug !== false).map((slug) => revalidate({ collectionSlug: args.collection.slug, slug }));
47
- } else {
48
- revalidate({ globalSlug: args.global.slug });
49
- }
50
- return doc;
51
- };
52
- return { afterChange: afterChangeDeleteHook, afterDelete: afterChangeDeleteHook };
53
- }
54
- function createCollectionCacheKey(args) {
55
- return `${"globalSlug" in args ? args.globalSlug : args.collectionSlug + args.slug}_${args.locale}`;
27
+ var _helpers = null;
28
+ var _seedPromise = null;
29
+ function seedPayloadCache({ config }) {
30
+ if (_helpers || _seedPromise)
31
+ return;
32
+ _seedPromise = (async () => {
33
+ const payload = await getPayload({ config: await config });
34
+ _helpers = createCacheHelpers(payload);
35
+ })();
56
36
  }
57
-
58
- // src/render/metadata/query.ts
59
- async function withUnstableCache(keyParts, tags, fn) {
60
- const { unstable_cache } = await import("next/cache");
61
- return unstable_cache(fn, keyParts.map(String), { tags })();
37
+ async function requireCacheHelpers() {
38
+ if (_helpers)
39
+ return _helpers;
40
+ if (_seedPromise) {
41
+ await _seedPromise;
42
+ if (_helpers)
43
+ return _helpers;
44
+ }
45
+ throw new Error("[payload-www] seedPayloadCache({ config }) must be called before any query getter. " + "Call it from createCollectionPageExports / createRootLayoutExports factory, or in your root layout.");
62
46
  }
63
- async function queryDoc(args, { config: configPromise }) {
64
- return withUnstableCache(Object.values(args), [createCollectionCacheKey(args)], async () => {
65
- if ("globalSlug" in args)
66
- return queryGlobal({ ...args, config: configPromise });
67
- else
68
- return queryDocBySlug({ ...args, config: configPromise });
47
+ async function queryDocBySlug(args) {
48
+ "use cache";
49
+ cacheLife("weeks");
50
+ const { findDoc } = await requireCacheHelpers();
51
+ const slugField = args.slugField ?? "slug";
52
+ const result = await findDoc(args.collectionSlug, {
53
+ where: { [slugField]: { equals: args.slug } },
54
+ locale: args.locale,
55
+ draft: args.draft ?? false,
56
+ depth: args.depth
69
57
  });
58
+ return result ?? null;
70
59
  }
71
- async function queryDocBySlug({
72
- collectionSlug,
73
- slug,
74
- slugField = "slug",
75
- locale,
76
- draft = false,
77
- config
78
- }) {
79
- return withUnstableCache([collectionSlug, slug, locale, draft], [createCollectionCacheKey({ collectionSlug, slug, locale })], async () => {
80
- const payload = await getPayload({ config });
81
- const result = await payload.find({
82
- collection: collectionSlug,
83
- draft,
84
- limit: 1,
85
- pagination: false,
86
- overrideAccess: draft,
87
- where: { [slugField]: { equals: slug } },
88
- locale
60
+ async function queryGlobal(args) {
61
+ "use cache";
62
+ cacheLife("weeks");
63
+ const { findGlobal } = await requireCacheHelpers();
64
+ try {
65
+ const result = await findGlobal(args.globalSlug, {
66
+ locale: args.locale,
67
+ draft: args.draft ?? false,
68
+ depth: args.depth
89
69
  });
90
- return result.docs?.[0] ?? null;
91
- });
70
+ return result ?? null;
71
+ } catch (error) {
72
+ console.warn("[WWW] queryGlobal failed", { globalSlug: args.globalSlug, locale: args.locale, error: String(error) });
73
+ return null;
74
+ }
92
75
  }
93
- async function queryGlobal({
94
- globalSlug,
95
- locale,
96
- draft = false,
97
- config
98
- }) {
99
- return withUnstableCache([globalSlug, locale, draft], [createCollectionCacheKey({ globalSlug, locale })], async () => {
100
- const payload = await getPayload({ config });
101
- try {
102
- return await payload.findGlobal({ slug: globalSlug, draft, locale });
103
- } catch (error) {
104
- console.warn("[WWW] queryGlobal failed", { globalSlug, locale, error: String(error) });
105
- return null;
106
- }
107
- });
76
+ async function queryAllDocs(args) {
77
+ "use cache";
78
+ cacheLife("weeks");
79
+ const { findIds, findDocByID } = await requireCacheHelpers();
80
+ const collection = args.collectionSlug;
81
+ const { ids } = await findIds(collection, { locale: args.locale });
82
+ if (ids.length === 0)
83
+ return [];
84
+ const docs = await Promise.all(ids.map((id) => findDocByID(collection, id, { locale: args.locale })));
85
+ return docs.filter((d) => d !== null);
108
86
  }
109
- async function queryAllDocs({
110
- collectionSlug,
111
- slugField = "slug",
112
- locale,
113
- config
114
- }) {
115
- return withUnstableCache([collectionSlug, slugField, locale], [createCollectionCacheKey({ collectionSlug, slug: "__all__", locale })], async () => {
116
- const payload = await getPayload({ config });
117
- const result = await payload.find({
118
- collection: collectionSlug,
119
- draft: false,
120
- limit: 1000,
121
- pagination: false,
122
- overrideAccess: false,
123
- select: { [slugField]: true },
124
- locale
125
- });
126
- return result.docs ?? [];
127
- });
87
+ async function queryDoc(args) {
88
+ if ("globalSlug" in args)
89
+ return queryGlobal(args);
90
+ return queryDocBySlug(args);
128
91
  }
129
- async function queryAllLocaleSlugs({
130
- collectionSlug,
131
- id,
132
- slugField = "slug",
133
- config
134
- }) {
135
- const payload = await getPayload({ config });
136
- const doc = await payload.findByID({
137
- collection: collectionSlug,
138
- id,
139
- locale: "all",
140
- select: { [slugField]: true }
92
+ async function queryAllLocaleSlugs(args) {
93
+ "use cache";
94
+ cacheLife("weeks");
95
+ const { findDocByID } = await requireCacheHelpers();
96
+ const slugField = args.slugField ?? "slug";
97
+ const doc = await findDocByID(args.collectionSlug, args.id, { locale: "all", select: { [slugField]: true } });
98
+ const localeMap = doc?.[slugField];
99
+ if (localeMap && typeof localeMap === "object")
100
+ return localeMap;
101
+ return null;
102
+ }
103
+ async function queryDocByID(args) {
104
+ "use cache";
105
+ cacheLife("weeks");
106
+ const { findDocByID } = await requireCacheHelpers();
107
+ return await findDocByID(args.collectionSlug, args.id, {
108
+ locale: args.locale,
109
+ draft: args.draft ?? false,
110
+ depth: args.depth
141
111
  });
142
- return doc?.[slugField];
143
112
  }
144
113
 
145
114
  // src/render/pages/createCollectionPageExports.tsx
146
115
  import { setRequestLocale } from "next-intl/server";
147
116
 
148
117
  // src/render/pages/utils/buildLocalizedPath.ts
118
+ function resolvePagePathPrefix(prefix, locale, routing) {
119
+ if (typeof prefix !== "object")
120
+ return prefix;
121
+ return prefix[locale] ?? prefix[routing.defaultLocale];
122
+ }
149
123
  function buildLocalizedPath(locale, prefix, slug, { routing }) {
150
124
  const path = slugToPath(slug);
125
+ const localePrefix = resolvePagePathPrefix(prefix, locale, routing);
151
126
  return `${routing.localePrefix === "never" ? "" : routing.localePrefix === "always" ? locale : routing.localePrefix === "as-needed" ? locale === routing.defaultLocale ? "" : "/" + locale : (() => {
152
127
  throw new Error("Unsupported locale prefix");
153
- })()}${prefix ? "/" + prefix : ""}${path ? "/" + path : ""}`;
128
+ })()}${localePrefix ? "/" + localePrefix : ""}${path ? "/" + path : ""}`;
154
129
  }
155
130
  function buildLocalizedPaths(localesSlug, pagePathPrefix, { routing }) {
156
131
  const blankIsHome = !localesSlug[routing.defaultLocale];
@@ -226,25 +201,31 @@ async function renderWWWDataModule(data, {
226
201
  import { jsx as jsx2, Fragment } from "react/jsx-runtime";
227
202
  function createCollectionPageExports({
228
203
  slug: collectionSlug = "pages",
229
- config: configPromise,
204
+ _payloadConfig,
230
205
  importMap,
231
206
  routing,
232
207
  slugShape = "single"
233
208
  }, {
234
209
  getServerSideURL,
235
- pagePathPrefix
210
+ pagePathPrefix,
211
+ fallback
236
212
  }) {
213
+ seedPayloadCache({ config: _payloadConfig });
237
214
  const siteUrl = getServerSideURL();
238
215
  async function fetchDoc(locale, slug) {
239
216
  return queryDoc({
240
217
  slug,
241
218
  locale,
242
219
  collectionSlug
243
- }, {
244
- config: configPromise
245
220
  });
246
221
  }
247
- const default_ = async (props) => {
222
+ const default_ = (props) => /* @__PURE__ */ jsx2(React.Suspense, {
223
+ fallback: fallback ?? null,
224
+ children: /* @__PURE__ */ jsx2(CollectionDocument, {
225
+ ...props
226
+ })
227
+ });
228
+ const CollectionDocument = async (props) => {
248
229
  const params = await props.params;
249
230
  const locale = params.locale;
250
231
  if (!routing.locales.includes(locale)) {
@@ -258,22 +239,25 @@ function createCollectionPageExports({
258
239
  const { notFound } = await import("next/navigation");
259
240
  notFound();
260
241
  }
261
- const rendered = renderWWWDataModule(doc, { collectionSlug, config: configPromise, importMap }, { ...props, locale });
242
+ const rendered = renderWWWDataModule(doc, { collectionSlug, config: _payloadConfig, importMap }, { ...props, locale });
262
243
  return /* @__PURE__ */ jsx2(Fragment, {
263
244
  children: rendered
264
245
  });
265
246
  };
266
247
  async function generateMetadata(props) {
267
248
  const params = await props.params;
268
- const locale = params.locale, slug = paramsSlugToSlug(params.slug, slugShape);
249
+ const locale = params.locale;
250
+ if (!routing.locales.includes(locale)) {
251
+ return {};
252
+ }
253
+ const slug = paramsSlugToSlug(params.slug, slugShape);
269
254
  const doc = await fetchDoc(locale, slug);
270
255
  const [localesSlug, siteDefaults] = await Promise.all([
271
256
  doc ? queryAllLocaleSlugs({
272
257
  id: doc.id,
273
- collectionSlug,
274
- config: configPromise
258
+ collectionSlug
275
259
  }) : Promise.resolve({}),
276
- createSiteDefaults({ config: configPromise, locale })
260
+ createSiteDefaults({ config: _payloadConfig, locale })
277
261
  ]);
278
262
  if (!doc)
279
263
  return {};
@@ -290,22 +274,23 @@ function createCollectionPageExports({
290
274
  return { ...meta, alternates };
291
275
  }
292
276
  async function generateStaticParams(props) {
293
- const locale = (await props.params).locale;
294
- const docs = await queryAllDocs({ locale, collectionSlug, config: configPromise });
295
- return docs.filter((doc) => typeof doc.slug === "string" && doc.slug.length > 0).map((doc) => ({ slug: slugToParamsSlug(doc.slug, slugShape) }));
277
+ await props.params;
278
+ const perLocaleEntries = await Promise.all(routing.locales.map(async (locale) => {
279
+ const docs = await queryAllDocs({ locale, collectionSlug });
280
+ return docs.filter((doc) => typeof doc.slug === "string" && doc.slug.length > 0).map((doc) => ({ locale, slug: slugToParamsSlug(doc.slug, slugShape) }));
281
+ }));
282
+ return perLocaleEntries.flat();
296
283
  }
297
284
  async function generateSitemap() {
298
285
  const locale = routing.defaultLocale;
299
286
  const docs = await queryAllDocs({
300
287
  collectionSlug,
301
- locale,
302
- config: configPromise
288
+ locale: routing.defaultLocale
303
289
  });
304
290
  return await Promise.all(docs.map(async (doc) => {
305
291
  const localesSlug = await queryAllLocaleSlugs({
306
292
  id: doc.id,
307
- collectionSlug,
308
- config: configPromise
293
+ collectionSlug
309
294
  }) ?? {};
310
295
  const alternates = buildAlternates(locale, localesSlug, pagePathPrefix, { routing, siteUrl });
311
296
  return {
@@ -316,7 +301,7 @@ function createCollectionPageExports({
316
301
  }));
317
302
  }
318
303
  generateSitemap.getServerSideURL = getServerSideURL;
319
- generateSitemap.pagePathPrefix = pagePathPrefix;
304
+ generateSitemap.pagePathPrefix = resolvePagePathPrefix(pagePathPrefix, routing.defaultLocale, routing);
320
305
  return {
321
306
  default: default_,
322
307
  generateMetadata,
@@ -340,8 +325,9 @@ ${sitemaps.map((url) => ` <sitemap><loc>${url}</loc></sitemap>`).join(`
340
325
  }
341
326
 
342
327
  // src/exports/sitemap.ts
343
- var sitemap_default = { createSitemapFromCollections };
328
+ var sitemap_default = { createSitemapFromCollections, seedPayloadCache };
344
329
  export {
330
+ createSitemapFromCollections,
345
331
  sitemap_default as default,
346
- createSitemapFromCollections
332
+ seedPayloadCache
347
333
  };
@@ -1,2 +1,2 @@
1
1
  import { translator } from "@justanarthur/payload-plugin-translator";
2
- export { translator, translator as default };
2
+ export { translator as default, translator };
@@ -1,9 +1,7 @@
1
-
2
-
3
1
  // src/exports/translator.ts
4
2
  import { translator } from "@justanarthur/payload-plugin-translator";
5
3
  var translator_default = translator;
6
4
  export {
7
- translator,
8
- translator_default as default
5
+ translator_default as default,
6
+ translator
9
7
  };
package/dist/utils.d.ts CHANGED
@@ -11,4 +11,4 @@ declare const utils: {
11
11
  getFromImportMap: typeof getFromImportMap;
12
12
  generateImportName: typeof generateImportName;
13
13
  };
14
- export { getFromImportMap, generateImportName, utils as default };
14
+ export { utils as default, generateImportName, getFromImportMap };
package/dist/utils.js CHANGED
@@ -1,5 +1,3 @@
1
-
2
-
3
1
  // src/render/generateImportName.ts
4
2
  function generateImportName(type, slug) {
5
3
  switch (type) {
@@ -34,7 +32,7 @@ function getFromImportMap(key, importMap) {
34
32
  var utils = { getFromImportMap, generateImportName };
35
33
  var utils_default = utils;
36
34
  export {
37
- getFromImportMap,
35
+ utils_default as default,
38
36
  generateImportName,
39
- utils_default as default
37
+ getFromImportMap
40
38
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@justanarthur/payload-www",
3
3
  "description": "Reusable Payload CMS website template — config builder, collections, globals, blocks, fields, access, hooks, metadata (JSON-LD, hreflang), page renderers, and test helpers.",
4
- "version": "1.4.2",
4
+ "version": "2.0.1",
5
5
  "type": "module",
6
6
  "private": false,
7
7
  "files": [
@@ -113,24 +113,24 @@
113
113
  "prepublishOnly": "bun run clean && bun run build"
114
114
  },
115
115
  "dependencies": {
116
- "@payloadcms/live-preview-react": "3.85.0",
117
- "@payloadcms/plugin-mcp": "3.85.0",
118
- "@payloadcms/richtext-lexical": "3.85.0",
119
- "@payloadcms/next": "3.85.0",
120
- "next": "16.2.6",
121
- "next-intl": "^4.0.0",
116
+ "@payloadcms/live-preview-react": "3.88.0",
117
+ "@payloadcms/plugin-mcp": "3.88.0",
118
+ "@payloadcms/richtext-lexical": "3.88.0",
119
+ "@payloadcms/next": "3.88.0",
120
+ "next": "16.3.4",
121
+ "next-intl": "^4.14.2",
122
122
  "server-only": "0.0.1",
123
123
  "tsx": "^4.19.2"
124
124
  },
125
125
  "devDependencies": {
126
126
  "@types/node": "22.19.9",
127
- "@types/react": "19.2.14",
128
- "@types/react-dom": "19.2.3",
127
+ "@types/react": "19.2.18",
128
+ "@types/react-dom": "19.2.7",
129
129
  "bunup": "^0.16.32",
130
- "payload": "3.85.1",
131
- "react": "19.2.6",
132
- "react-dom": "19.2.6",
133
- "typescript": "5.7.3",
130
+ "payload": "3.88.0",
131
+ "react": "19.2.8",
132
+ "react-dom": "19.2.8",
133
+ "typescript": "^7.0.2",
134
134
  "vitest": "4.0.18"
135
135
  },
136
136
  "peerDependencies": {
@@ -139,12 +139,14 @@
139
139
  "@payloadcms/richtext-lexical": "^3.85.0",
140
140
  "@payloadcms/translations": "^3.85.0",
141
141
  "@payloadcms/ui": "^3.85.0",
142
+ "@pro-laico/core": "^0.5.0",
143
+ "@pro-laico/payload-revalidate": "^0.8.5",
142
144
  "next": "^16.2.6",
143
145
  "next-intl": "^4.0.0",
144
146
  "payload": "^3.85.0",
145
147
  "react": "^19.2.6",
146
148
  "react-dom": "^19.2.6",
147
- "@justanarthur/payload-plugin-seo": "^3.0.0",
149
+ "@justanarthur/payload-plugin-seo": "^4.0.0",
148
150
  "@justanarthur/payload-plugin-translator": "^3.0.0",
149
151
  "@justanarthur/payload-imagehash-plugin": "^3.3.0"
150
152
  },