@justanarthur/payload-www 1.4.1 → 2.0.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.
package/dist/sitemap.js CHANGED
@@ -1,8 +1,3 @@
1
-
2
-
3
- // src/render/pages/createCollectionPageExports.tsx
4
- import"server-only";
5
-
6
1
  // src/render/metadata/slug.ts
7
2
  var SLUG_NESTED_DIVIDER = "_";
8
3
  function paramsSlugToSlug(slug, _shape) {
@@ -22,142 +17,118 @@ function slugToPath(slug) {
22
17
  }
23
18
 
24
19
  // src/render/metadata/query.ts
20
+ import { createCacheHelpers } from "@pro-laico/payload-revalidate/cache";
21
+ import { tagsFor } from "@pro-laico/payload-revalidate";
22
+ import { cacheLife } from "next/cache";
25
23
  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}`;
24
+ var _helpers = null;
25
+ var _seedPromise = null;
26
+ function seedPayloadCache({ config }) {
27
+ if (_helpers || _seedPromise)
28
+ return;
29
+ _seedPromise = (async () => {
30
+ const payload = await getPayload({ config: await config });
31
+ _helpers = createCacheHelpers(payload);
32
+ })();
56
33
  }
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 })();
34
+ async function requireCacheHelpers() {
35
+ if (_helpers)
36
+ return _helpers;
37
+ if (_seedPromise) {
38
+ await _seedPromise;
39
+ if (_helpers)
40
+ return _helpers;
41
+ }
42
+ 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
43
  }
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 });
44
+ async function queryDocBySlug(args) {
45
+ "use cache";
46
+ cacheLife("weeks");
47
+ const { findDoc } = await requireCacheHelpers();
48
+ const slugField = args.slugField ?? "slug";
49
+ const result = await findDoc(args.collectionSlug, {
50
+ where: { [slugField]: { equals: args.slug } },
51
+ locale: args.locale,
52
+ draft: args.draft ?? false,
53
+ depth: args.depth
69
54
  });
55
+ return result ?? null;
70
56
  }
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
57
+ async function queryGlobal(args) {
58
+ "use cache";
59
+ cacheLife("weeks");
60
+ const { findGlobal } = await requireCacheHelpers();
61
+ try {
62
+ const result = await findGlobal(args.globalSlug, {
63
+ locale: args.locale,
64
+ draft: args.draft ?? false,
65
+ depth: args.depth
89
66
  });
90
- return result.docs?.[0] ?? null;
91
- });
67
+ return result ?? null;
68
+ } catch (error) {
69
+ console.warn("[WWW] queryGlobal failed", { globalSlug: args.globalSlug, locale: args.locale, error: String(error) });
70
+ return null;
71
+ }
92
72
  }
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
- });
73
+ async function queryAllDocs(args) {
74
+ "use cache";
75
+ cacheLife("weeks");
76
+ const { findIds, findDocByID } = await requireCacheHelpers();
77
+ const collection = args.collectionSlug;
78
+ const { ids } = await findIds(collection, { locale: args.locale });
79
+ if (ids.length === 0)
80
+ return [];
81
+ const docs = await Promise.all(ids.map((id) => findDocByID(collection, id, { locale: args.locale })));
82
+ return docs.filter((d) => d !== null);
108
83
  }
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
- });
84
+ async function queryDoc(args) {
85
+ if ("globalSlug" in args)
86
+ return queryGlobal(args);
87
+ return queryDocBySlug(args);
128
88
  }
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 }
89
+ async function queryAllLocaleSlugs(args) {
90
+ "use cache";
91
+ cacheLife("weeks");
92
+ const { findDocByID } = await requireCacheHelpers();
93
+ const slugField = args.slugField ?? "slug";
94
+ const doc = await findDocByID(args.collectionSlug, args.id, { locale: "all", select: { [slugField]: true } });
95
+ const localeMap = doc?.[slugField];
96
+ if (localeMap && typeof localeMap === "object")
97
+ return localeMap;
98
+ return null;
99
+ }
100
+ async function queryDocByID(args) {
101
+ "use cache";
102
+ cacheLife("weeks");
103
+ const { findDocByID } = await requireCacheHelpers();
104
+ return await findDocByID(args.collectionSlug, args.id, {
105
+ locale: args.locale,
106
+ draft: args.draft ?? false,
107
+ depth: args.depth
141
108
  });
142
- return doc?.[slugField];
143
109
  }
144
110
 
145
111
  // src/render/pages/createCollectionPageExports.tsx
146
112
  import { setRequestLocale } from "next-intl/server";
147
113
 
148
114
  // src/render/pages/utils/buildLocalizedPath.ts
115
+ function resolvePagePathPrefix(prefix, locale, routing) {
116
+ if (typeof prefix !== "object")
117
+ return prefix;
118
+ return prefix[locale] ?? prefix[routing.defaultLocale];
119
+ }
149
120
  function buildLocalizedPath(locale, prefix, slug, { routing }) {
150
121
  const path = slugToPath(slug);
122
+ const localePrefix = resolvePagePathPrefix(prefix, locale, routing);
151
123
  return `${routing.localePrefix === "never" ? "" : routing.localePrefix === "always" ? locale : routing.localePrefix === "as-needed" ? locale === routing.defaultLocale ? "" : "/" + locale : (() => {
152
124
  throw new Error("Unsupported locale prefix");
153
- })()}${prefix ? "/" + prefix : ""}${path ? "/" + path : ""}`;
125
+ })()}${localePrefix ? "/" + localePrefix : ""}${path ? "/" + path : ""}`;
154
126
  }
155
127
  function buildLocalizedPaths(localesSlug, pagePathPrefix, { routing }) {
156
- if (!localesSlug[routing.defaultLocale])
157
- return {};
128
+ const blankIsHome = !localesSlug[routing.defaultLocale];
158
129
  return routing.locales.reduce((paths, locale) => {
159
130
  const slug = localesSlug[locale];
160
- if (!slug)
131
+ if (!slug && !blankIsHome)
161
132
  return paths;
162
133
  paths[locale] = buildLocalizedPath(locale, pagePathPrefix, slug, { routing });
163
134
  return paths;
@@ -227,7 +198,7 @@ async function renderWWWDataModule(data, {
227
198
  import { jsx as jsx2, Fragment } from "react/jsx-runtime";
228
199
  function createCollectionPageExports({
229
200
  slug: collectionSlug = "pages",
230
- config: configPromise,
201
+ _payloadConfig,
231
202
  importMap,
232
203
  routing,
233
204
  slugShape = "single"
@@ -235,14 +206,13 @@ function createCollectionPageExports({
235
206
  getServerSideURL,
236
207
  pagePathPrefix
237
208
  }) {
209
+ seedPayloadCache({ config: _payloadConfig });
238
210
  const siteUrl = getServerSideURL();
239
211
  async function fetchDoc(locale, slug) {
240
212
  return queryDoc({
241
213
  slug,
242
214
  locale,
243
215
  collectionSlug
244
- }, {
245
- config: configPromise
246
216
  });
247
217
  }
248
218
  const default_ = async (props) => {
@@ -259,22 +229,25 @@ function createCollectionPageExports({
259
229
  const { notFound } = await import("next/navigation");
260
230
  notFound();
261
231
  }
262
- const rendered = renderWWWDataModule(doc, { collectionSlug, config: configPromise, importMap }, { ...props, locale });
232
+ const rendered = renderWWWDataModule(doc, { collectionSlug, config: _payloadConfig, importMap }, { ...props, locale });
263
233
  return /* @__PURE__ */ jsx2(Fragment, {
264
234
  children: rendered
265
235
  });
266
236
  };
267
237
  async function generateMetadata(props) {
268
238
  const params = await props.params;
269
- const locale = params.locale, slug = paramsSlugToSlug(params.slug, slugShape);
239
+ const locale = params.locale;
240
+ if (!routing.locales.includes(locale)) {
241
+ return {};
242
+ }
243
+ const slug = paramsSlugToSlug(params.slug, slugShape);
270
244
  const doc = await fetchDoc(locale, slug);
271
245
  const [localesSlug, siteDefaults] = await Promise.all([
272
246
  doc ? queryAllLocaleSlugs({
273
247
  id: doc.id,
274
- collectionSlug,
275
- config: configPromise
248
+ collectionSlug
276
249
  }) : Promise.resolve({}),
277
- createSiteDefaults({ config: configPromise, locale })
250
+ createSiteDefaults({ config: _payloadConfig, locale })
278
251
  ]);
279
252
  if (!doc)
280
253
  return {};
@@ -291,22 +264,23 @@ function createCollectionPageExports({
291
264
  return { ...meta, alternates };
292
265
  }
293
266
  async function generateStaticParams(props) {
294
- const locale = (await props.params).locale;
295
- const docs = await queryAllDocs({ locale, collectionSlug, config: configPromise });
296
- return docs.filter((doc) => typeof doc.slug === "string" && doc.slug.length > 0).map((doc) => ({ slug: slugToParamsSlug(doc.slug, slugShape) }));
267
+ await props.params;
268
+ const perLocaleEntries = await Promise.all(routing.locales.map(async (locale) => {
269
+ const docs = await queryAllDocs({ locale, collectionSlug });
270
+ return docs.filter((doc) => typeof doc.slug === "string" && doc.slug.length > 0).map((doc) => ({ locale, slug: slugToParamsSlug(doc.slug, slugShape) }));
271
+ }));
272
+ return perLocaleEntries.flat();
297
273
  }
298
274
  async function generateSitemap() {
299
275
  const locale = routing.defaultLocale;
300
276
  const docs = await queryAllDocs({
301
277
  collectionSlug,
302
- locale,
303
- config: configPromise
278
+ locale: routing.defaultLocale
304
279
  });
305
280
  return await Promise.all(docs.map(async (doc) => {
306
281
  const localesSlug = await queryAllLocaleSlugs({
307
282
  id: doc.id,
308
- collectionSlug,
309
- config: configPromise
283
+ collectionSlug
310
284
  }) ?? {};
311
285
  const alternates = buildAlternates(locale, localesSlug, pagePathPrefix, { routing, siteUrl });
312
286
  return {
@@ -317,7 +291,7 @@ function createCollectionPageExports({
317
291
  }));
318
292
  }
319
293
  generateSitemap.getServerSideURL = getServerSideURL;
320
- generateSitemap.pagePathPrefix = pagePathPrefix;
294
+ generateSitemap.pagePathPrefix = resolvePagePathPrefix(pagePathPrefix, routing.defaultLocale, routing);
321
295
  return {
322
296
  default: default_,
323
297
  generateMetadata,
@@ -341,8 +315,9 @@ ${sitemaps.map((url) => ` <sitemap><loc>${url}</loc></sitemap>`).join(`
341
315
  }
342
316
 
343
317
  // src/exports/sitemap.ts
344
- var sitemap_default = { createSitemapFromCollections };
318
+ var sitemap_default = { createSitemapFromCollections, seedPayloadCache };
345
319
  export {
320
+ createSitemapFromCollections,
346
321
  sitemap_default as default,
347
- createSitemapFromCollections
322
+ seedPayloadCache
348
323
  };
@@ -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.1",
4
+ "version": "2.0.0",
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
  },