@websolutespa/bom-next 3.0.2 → 4.0.0-next.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/CHANGELOG.md +37 -7
- package/README.md +28 -0
- package/dist/_virtual/{_rolldown/runtime.js → rolldown_runtime.js} +7 -4
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +17 -6
- package/dist/client/client.js.map +1 -1
- package/dist/client/extra.d.ts +3 -3
- package/dist/client/extra.d.ts.map +1 -1
- package/dist/client/extra.js +10 -5
- package/dist/client/extra.js.map +1 -1
- package/dist/client/label.d.ts +3 -3
- package/dist/client/label.d.ts.map +1 -1
- package/dist/client/label.js +10 -5
- package/dist/client/label.js.map +1 -1
- package/dist/client/layout.d.ts +3 -3
- package/dist/client/layout.d.ts.map +1 -1
- package/dist/client/layout.js +10 -5
- package/dist/client/layout.js.map +1 -1
- package/dist/client/local.collection.d.ts.map +1 -1
- package/dist/client/local.collection.js +4 -2
- package/dist/client/local.collection.js.map +1 -1
- package/dist/client/metadata.d.ts +3 -3
- package/dist/client/metadata.d.ts.map +1 -1
- package/dist/client/metadata.js +48 -40
- package/dist/client/metadata.js.map +1 -1
- package/dist/client/page.d.ts +3 -3
- package/dist/client/page.d.ts.map +1 -1
- package/dist/client/page.js +10 -5
- package/dist/client/page.js.map +1 -1
- package/dist/client/useApi.d.ts +7 -7
- package/dist/client/useApi.d.ts.map +1 -1
- package/dist/client/useApi.js +2 -1
- package/dist/client/useApi.js.map +1 -1
- package/dist/client/useCollectionApi.d.ts +6 -6
- package/dist/client/useCollectionApi.d.ts.map +1 -1
- package/dist/client/useCollectionApi.js +4 -2
- package/dist/client/useCollectionApi.js.map +1 -1
- package/dist/client/useExtra.d.ts.map +1 -1
- package/dist/client/useExtra.js +5 -2
- package/dist/client/useExtra.js.map +1 -1
- package/dist/client/useHttp.d.ts.map +1 -1
- package/dist/client/useHttp.js +9 -6
- package/dist/client/useHttp.js.map +1 -1
- package/dist/client/useLabel.d.ts.map +1 -1
- package/dist/client/useLabel.js +5 -2
- package/dist/client/useLabel.js.map +1 -1
- package/dist/client/useLayout.d.ts.map +1 -1
- package/dist/client/useLayout.js +5 -2
- package/dist/client/useLayout.js.map +1 -1
- package/dist/client/useLink.d.ts.map +1 -1
- package/dist/client/useLink.js +7 -3
- package/dist/client/useLink.js.map +1 -1
- package/dist/client/useMetaData.d.ts.map +1 -1
- package/dist/client/useMetaData.js +5 -2
- package/dist/client/useMetaData.js.map +1 -1
- package/dist/client/usePage.d.ts.map +1 -1
- package/dist/client/usePage.js +5 -2
- package/dist/client/usePage.js.map +1 -1
- package/dist/client/useUser.d.ts.map +1 -1
- package/dist/client/useUser.js +5 -2
- package/dist/client/useUser.js.map +1 -1
- package/dist/client/user.d.ts.map +1 -1
- package/dist/client/user.js +17 -11
- package/dist/client/user.js.map +1 -1
- package/dist/exports/client.js +2 -1
- package/dist/exports/instrumentation.js +2 -1
- package/dist/exports/proxy.js +2 -1
- package/dist/exports/server.d.ts +5 -4
- package/dist/exports/server.js +7 -5
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -2
- package/dist/instrumentation/client.d.ts.map +1 -1
- package/dist/instrumentation/client.js +2 -1
- package/dist/instrumentation/client.js.map +1 -1
- package/dist/instrumentation/sentry/capture.requestError.js +4 -1
- package/dist/instrumentation/sentry/capture.requestError.js.map +1 -1
- package/dist/instrumentation/sentry/capture.routerTransitionStart.js +2 -1
- package/dist/instrumentation/sentry/capture.routerTransitionStart.js.map +1 -1
- package/dist/instrumentation/sentry/config.client.js +10 -2
- package/dist/instrumentation/sentry/config.client.js.map +1 -0
- package/dist/instrumentation/sentry/config.edge.js +10 -2
- package/dist/instrumentation/sentry/config.edge.js.map +1 -0
- package/dist/instrumentation/sentry/config.server.js +10 -2
- package/dist/instrumentation/sentry/config.server.js.map +1 -0
- package/dist/instrumentation/server.d.ts.map +1 -1
- package/dist/instrumentation/server.js +8 -5
- package/dist/instrumentation/server.js.map +1 -1
- package/dist/instrumentation/types.d.ts.map +1 -1
- package/dist/lib/breadcrumb.d.ts.map +1 -1
- package/dist/lib/breadcrumb.js +6 -1
- package/dist/lib/breadcrumb.js.map +1 -1
- package/dist/lib/const.d.ts +14 -2
- package/dist/lib/const.d.ts.map +1 -1
- package/dist/lib/const.js +24 -2
- package/dist/lib/const.js.map +1 -1
- package/dist/lib/http.d.ts +9 -0
- package/dist/lib/http.d.ts.map +1 -1
- package/dist/lib/http.js +27 -4
- package/dist/lib/http.js.map +1 -1
- package/dist/lib/label.d.ts.map +1 -1
- package/dist/lib/label.js +4 -3
- package/dist/lib/label.js.map +1 -1
- package/dist/lib/layout.defaults.d.ts.map +1 -1
- package/dist/lib/layout.defaults.js +1 -1
- package/dist/lib/layout.defaults.js.map +1 -1
- package/dist/lib/link.d.ts.map +1 -1
- package/dist/lib/link.js +2 -1
- package/dist/lib/link.js.map +1 -1
- package/dist/lib/meta-data.d.ts.map +1 -1
- package/dist/lib/open-graph.d.ts.map +1 -1
- package/dist/lib/pagination.d.ts.map +1 -1
- package/dist/lib/pagination.js +4 -2
- package/dist/lib/pagination.js.map +1 -1
- package/dist/lib/route.d.ts.map +1 -1
- package/dist/lib/route.js +9 -3
- package/dist/lib/route.js.map +1 -1
- package/dist/lib/store.d.ts.map +1 -1
- package/dist/lib/store.js +31 -31
- package/dist/lib/store.js.map +1 -1
- package/dist/lib/structured-data.d.ts.map +1 -1
- package/dist/lib/twitter-card.d.ts.map +1 -1
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +3 -2
- package/dist/lib/utils.js.map +1 -1
- package/dist/mock.d.ts.map +1 -1
- package/dist/node_modules/@selderee/plugin-htmlparser2/lib/hp2-builder.js +3 -2
- package/dist/node_modules/@selderee/plugin-htmlparser2/lib/hp2-builder.js.map +1 -1
- package/dist/node_modules/deepmerge/dist/cjs.js +17 -9
- package/dist/node_modules/deepmerge/dist/cjs.js.map +1 -1
- package/dist/node_modules/dom-serializer/lib/esm/foreignNames.js +2 -2
- package/dist/node_modules/dom-serializer/lib/esm/foreignNames.js.map +1 -1
- package/dist/node_modules/dom-serializer/lib/esm/index.js +10 -15
- package/dist/node_modules/dom-serializer/lib/esm/index.js.map +1 -1
- package/dist/node_modules/domelementtype/lib/esm/index.js +12 -12
- package/dist/node_modules/domelementtype/lib/esm/index.js.map +1 -1
- package/dist/node_modules/domhandler/lib/esm/index.js +4 -3
- package/dist/node_modules/domhandler/lib/esm/index.js.map +1 -1
- package/dist/node_modules/domhandler/lib/esm/node.js +8 -7
- package/dist/node_modules/domhandler/lib/esm/node.js.map +1 -1
- package/dist/node_modules/entities/lib/esm/decode.js +33 -32
- package/dist/node_modules/entities/lib/esm/decode.js.map +1 -1
- package/dist/node_modules/entities/lib/esm/decode_codepoint.js +5 -5
- package/dist/node_modules/entities/lib/esm/decode_codepoint.js.map +1 -1
- package/dist/node_modules/entities/lib/esm/escape.js +14 -6
- package/dist/node_modules/entities/lib/esm/escape.js.map +1 -1
- package/dist/node_modules/entities/lib/esm/generated/decode-data-html.js +2 -2
- package/dist/node_modules/entities/lib/esm/generated/decode-data-html.js.map +1 -1
- package/dist/node_modules/entities/lib/esm/generated/decode-data-xml.js +2 -2
- package/dist/node_modules/entities/lib/esm/generated/decode-data-xml.js.map +1 -1
- package/dist/node_modules/html-to-text/lib/html-to-text.js +45 -33
- package/dist/node_modules/html-to-text/lib/html-to-text.js.map +1 -1
- package/dist/node_modules/html-to-text/node_modules/htmlparser2/lib/esm/Parser.js +25 -25
- package/dist/node_modules/html-to-text/node_modules/htmlparser2/lib/esm/Parser.js.map +1 -1
- package/dist/node_modules/html-to-text/node_modules/htmlparser2/lib/esm/Tokenizer.js +76 -73
- package/dist/node_modules/html-to-text/node_modules/htmlparser2/lib/esm/Tokenizer.js.map +1 -1
- package/dist/node_modules/html-to-text/node_modules/htmlparser2/lib/esm/index.js +4 -3
- package/dist/node_modules/html-to-text/node_modules/htmlparser2/lib/esm/index.js.map +1 -1
- package/dist/node_modules/leac/lib/leac.js +72 -72
- package/dist/node_modules/leac/lib/leac.js.map +1 -1
- package/dist/node_modules/parseley/lib/parseley.js +37 -33
- package/dist/node_modules/parseley/lib/parseley.js.map +1 -1
- package/dist/node_modules/peberminta/lib/core.js +4 -4
- package/dist/node_modules/peberminta/lib/core.js.map +1 -1
- package/dist/node_modules/selderee/lib/selderee.js +16 -10
- package/dist/node_modules/selderee/lib/selderee.js.map +1 -1
- package/dist/proxy/protected-route.d.ts.map +1 -1
- package/dist/proxy/protected-route.js +11 -6
- package/dist/proxy/protected-route.js.map +1 -1
- package/dist/proxy/proxy.d.ts +5 -4
- package/dist/proxy/proxy.d.ts.map +1 -1
- package/dist/proxy/proxy.js +26 -6
- package/dist/proxy/proxy.js.map +1 -1
- package/dist/proxy/route-auto-detection.d.ts.map +1 -1
- package/dist/proxy/route-auto-detection.js +26 -14
- package/dist/proxy/route-auto-detection.js.map +1 -1
- package/dist/proxy/route-proxy.d.ts.map +1 -1
- package/dist/proxy/route-proxy.js +22 -5
- package/dist/proxy/route-proxy.js.map +1 -1
- package/dist/server/context.d.ts +31 -15
- package/dist/server/context.d.ts.map +1 -1
- package/dist/server/context.js +156 -69
- package/dist/server/context.js.map +1 -1
- package/dist/server/handlers/auth.handler.d.ts.map +1 -1
- package/dist/server/handlers/auth.handler.js +4 -2
- package/dist/server/handlers/auth.handler.js.map +1 -1
- package/dist/server/handlers/captions.handler.d.ts.map +1 -1
- package/dist/server/handlers/captions.handler.js +4 -2
- package/dist/server/handlers/captions.handler.js.map +1 -1
- package/dist/server/handlers/collection.handler.d.ts.map +1 -1
- package/dist/server/handlers/collection.handler.js +2 -1
- package/dist/server/handlers/collection.handler.js.map +1 -1
- package/dist/server/handlers/error-response.js +6 -2
- package/dist/server/handlers/error-response.js.map +1 -1
- package/dist/server/handlers/index.handler.d.ts.map +1 -1
- package/dist/server/handlers/index.handler.js +2 -1
- package/dist/server/handlers/index.handler.js.map +1 -1
- package/dist/server/handlers/preview.handler.d.ts.map +1 -1
- package/dist/server/handlers/preview.handler.js +6 -3
- package/dist/server/handlers/preview.handler.js.map +1 -1
- package/dist/server/handlers/registry.handler.d.ts.map +1 -1
- package/dist/server/handlers/registry.handler.js +14 -9
- package/dist/server/handlers/registry.handler.js.map +1 -1
- package/dist/server/handlers/route.handler.d.ts.map +1 -1
- package/dist/server/handlers/route.handler.js +12 -3
- package/dist/server/handlers/route.handler.js.map +1 -1
- package/dist/server/handlers/sitemap.handler.d.ts.map +1 -1
- package/dist/server/handlers/sitemap.handler.js +12 -9
- package/dist/server/handlers/sitemap.handler.js.map +1 -1
- package/dist/server/handlers/static-params.handler.d.ts.map +1 -1
- package/dist/server/handlers/static-params.handler.js +13 -8
- package/dist/server/handlers/static-params.handler.js.map +1 -1
- package/dist/server/handlers/vars.handler.d.ts.map +1 -1
- package/dist/server/handlers/vars.handler.js +5 -4
- package/dist/server/handlers/vars.handler.js.map +1 -1
- package/dist/server/helpers.d.ts +50 -0
- package/dist/server/helpers.d.ts.map +1 -0
- package/dist/server/helpers.js +60 -0
- package/dist/server/helpers.js.map +1 -0
- package/dist/server/layout.js +69 -34
- package/dist/server/layout.js.map +1 -1
- package/dist/server/lazy.d.ts +1 -0
- package/dist/server/lazy.d.ts.map +1 -1
- package/dist/server/lazy.js +3 -2
- package/dist/server/lazy.js.map +1 -1
- package/dist/server/local-api.d.ts.map +1 -1
- package/dist/server/local-api.js +12 -6
- package/dist/server/local-api.js.map +1 -1
- package/dist/server/metadata.d.ts +8 -5
- package/dist/server/metadata.d.ts.map +1 -1
- package/dist/server/metadata.js +21 -7
- package/dist/server/metadata.js.map +1 -1
- package/dist/server/mixer-payload.d.ts +1 -1
- package/dist/server/mixer-payload.d.ts.map +1 -1
- package/dist/server/mixer.d.ts +48 -6
- package/dist/server/mixer.d.ts.map +1 -1
- package/dist/server/mixer.js +235 -68
- package/dist/server/mixer.js.map +1 -1
- package/dist/server/page.d.ts +21 -5
- package/dist/server/page.d.ts.map +1 -1
- package/dist/server/page.js +74 -15
- package/dist/server/page.js.map +1 -1
- package/dist/server/utils.d.ts.map +1 -1
- package/dist/server/utils.js +4 -2
- package/dist/server/utils.js.map +1 -1
- package/dist/server/utmz.d.ts.map +1 -1
- package/dist/server/utmz.js +1 -1
- package/dist/server/utmz.js.map +1 -1
- package/dist/types.d.ts +79 -8
- package/dist/types.d.ts.map +1 -1
- package/package.json +16 -15
- package/src/exports/server.ts +1 -0
- package/src/lib/const.ts +15 -0
- package/src/lib/http.ts +15 -4
- package/src/proxy/proxy.ts +11 -4
- package/src/server/context.test.ts +467 -0
- package/src/server/context.ts +237 -78
- package/src/server/context.type-test.ts +106 -0
- package/src/server/helpers.ts +58 -0
- package/src/server/layout.ts +45 -39
- package/src/server/lazy.ts +1 -1
- package/src/server/metadata.ts +15 -7
- package/src/server/mixer.ts +57 -9
- package/src/server/page.ts +62 -17
- package/src/types.ts +109 -7
package/src/server/metadata.ts
CHANGED
|
@@ -1,22 +1,30 @@
|
|
|
1
1
|
import type { ResolvingMetadata } from 'next';
|
|
2
2
|
import type { CollectionSlug, SanitizedConfig } from 'payload';
|
|
3
|
-
import type { PageParams } from '../types';
|
|
3
|
+
import type { LayoutOption, PageContextOptions, PageParams, PageSelect } from '../types';
|
|
4
4
|
import { createPageContext } from './context';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Returns a generateMetadata function for a given page collection slug.
|
|
8
|
-
*
|
|
8
|
+
*
|
|
9
|
+
* It uses the same defaults as `createPageContext`, so the page read is
|
|
10
|
+
* memoized and shared with the page component within the same request.
|
|
11
|
+
* Pass the same options used by the page (depth, select, headers…) to hit that cache.
|
|
9
12
|
*/
|
|
10
|
-
export function getMetadata<TSlug extends CollectionSlug
|
|
13
|
+
export function getMetadata<TSlug extends CollectionSlug, TSelect extends PageSelect<TSlug> = undefined>(
|
|
14
|
+
slug: TSlug,
|
|
15
|
+
config: Promise<SanitizedConfig>,
|
|
16
|
+
options?: Omit<PageContextOptions<TSlug, TSelect, LayoutOption>, 'config'>
|
|
17
|
+
) {
|
|
11
18
|
return async function generateMetadata(
|
|
12
19
|
props: Readonly<{ params: Promise<PageParams>; }>,
|
|
13
|
-
|
|
20
|
+
_parent: ResolvingMetadata
|
|
14
21
|
) {
|
|
15
22
|
const { market, locale, id } = await props.params;
|
|
16
|
-
const { page } = await createPageContext(market, locale, slug, id, config);
|
|
23
|
+
const { page } = await createPageContext<TSlug, TSelect, LayoutOption>(market, locale, slug, id, { ...options, config });
|
|
24
|
+
const doc = page as { title?: string; abstract?: string; meta?: { title?: string; description?: string } } | undefined;
|
|
17
25
|
return {
|
|
18
|
-
title:
|
|
19
|
-
description:
|
|
26
|
+
title: doc?.meta?.title || doc?.title,
|
|
27
|
+
description: doc?.meta?.description || doc?.abstract,
|
|
20
28
|
};
|
|
21
29
|
};
|
|
22
30
|
}
|
package/src/server/mixer.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { collectRoutes, defaultLocale, defaultMarket, ICategory, ILocale, IMarket, IMedia, IRoute, isDevelopment, isObject } from '@websolutespa/bom-core';
|
|
2
2
|
import type { Config, User } from '@websolutespa/payload-plugin-bowl';
|
|
3
3
|
import { InMemoryCache } from '@websolutespa/payload-plugin-bowl';
|
|
4
|
+
import { draftMode, headers as getHeaders } from 'next/headers';
|
|
4
5
|
import { NextRequest } from 'next/server';
|
|
5
6
|
import { BasePayload, getPayload as getPayload_, SanitizedConfig, TypedFallbackLocale, TypedLocale } from 'payload';
|
|
6
7
|
import { cache } from 'react';
|
|
7
8
|
import { guest } from '../lib/const';
|
|
8
|
-
import type { BaseOptions, IContext, MixerContext, ReadonlyHeaders } from '../types';
|
|
9
|
+
import type { BaseOptions, DraftOption, IContext, MixerContext, ReadOptions, ReadonlyHeaders } from '../types';
|
|
9
10
|
import type { MixerPayload } from './mixer-payload';
|
|
10
11
|
|
|
11
12
|
// !!! todo check when to use in memory cache
|
|
@@ -269,11 +270,28 @@ export async function getMixerContext({
|
|
|
269
270
|
return context;
|
|
270
271
|
}
|
|
271
272
|
|
|
273
|
+
/**
|
|
274
|
+
* Resolves a draft option to a boolean.
|
|
275
|
+
* `'auto'` reads Next's `draftMode()`; outside a request scope (build, scripts) it resolves to false.
|
|
276
|
+
*/
|
|
277
|
+
export async function resolveDraft(draft: DraftOption = 'auto'): Promise<boolean> {
|
|
278
|
+
if (typeof draft === 'boolean') {
|
|
279
|
+
return draft;
|
|
280
|
+
}
|
|
281
|
+
try {
|
|
282
|
+
return (await draftMode()).isEnabled;
|
|
283
|
+
} catch {
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
272
288
|
/**
|
|
273
289
|
* Runtime (request-time) payload accessor.
|
|
274
290
|
*
|
|
275
291
|
* By default, operates as the guest user for static generation. For auth:
|
|
276
292
|
* call getHeaders() directly in your page/route/layout, then pass it here.
|
|
293
|
+
* In draft mode the request headers are read automatically, so drafts are
|
|
294
|
+
* read as the authenticated user rather than the guest.
|
|
277
295
|
*
|
|
278
296
|
* Example:
|
|
279
297
|
* const headers = await getHeaders();
|
|
@@ -282,13 +300,23 @@ export async function getMixerContext({
|
|
|
282
300
|
export async function getPayload({
|
|
283
301
|
config,
|
|
284
302
|
headers,
|
|
303
|
+
draft = false,
|
|
285
304
|
}: {
|
|
286
305
|
config: Promise<SanitizedConfig>;
|
|
287
306
|
headers?: ReadonlyHeaders;
|
|
307
|
+
draft?: boolean;
|
|
288
308
|
}) {
|
|
289
309
|
const payload = await getPayload_({ config });
|
|
290
310
|
await setContext({ payload: payload as MixerPayload });
|
|
291
311
|
|
|
312
|
+
if (!headers && draft) {
|
|
313
|
+
try {
|
|
314
|
+
headers = await getHeaders() as ReadonlyHeaders;
|
|
315
|
+
} catch {
|
|
316
|
+
// outside a request scope: keep the guest user
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
292
320
|
let user: User & Config['user'] = guest;
|
|
293
321
|
if (headers) {
|
|
294
322
|
try {
|
|
@@ -296,17 +324,15 @@ export async function getPayload({
|
|
|
296
324
|
if (auth.user) {
|
|
297
325
|
user = auth.user as typeof user;
|
|
298
326
|
}
|
|
299
|
-
// console.log('getPayload', user, token);
|
|
300
327
|
} catch (error) {
|
|
301
328
|
console.log('getPayload.error', error);
|
|
302
329
|
}
|
|
303
330
|
}
|
|
304
331
|
|
|
305
|
-
const draft = false;
|
|
306
|
-
|
|
307
332
|
return {
|
|
308
333
|
payload: payload as MixerPayload,
|
|
309
334
|
user,
|
|
335
|
+
draft,
|
|
310
336
|
getContext: (market: string, locale: string) => getMixerContext({ payload, market, locale, user, draft }),
|
|
311
337
|
};
|
|
312
338
|
}
|
|
@@ -326,21 +352,43 @@ export function getAuthHeaders(token: { value: string } | undefined): Headers {
|
|
|
326
352
|
}
|
|
327
353
|
|
|
328
354
|
/**
|
|
329
|
-
* Produces the
|
|
355
|
+
* Produces the read options shared across payload.find / findByID / findGlobal calls.
|
|
330
356
|
* For payload.find, add pagination: false and limit: 10000 at the call site.
|
|
331
|
-
*
|
|
357
|
+
* `select`, `populate` and `joins` are only included when provided.
|
|
332
358
|
*/
|
|
333
|
-
export function
|
|
359
|
+
export function buildReadOptions({
|
|
360
|
+
user,
|
|
361
|
+
locale,
|
|
362
|
+
draft = false,
|
|
363
|
+
depth,
|
|
364
|
+
select,
|
|
365
|
+
populate,
|
|
366
|
+
joins,
|
|
367
|
+
}: ReadOptions & {
|
|
368
|
+
user: any;
|
|
369
|
+
locale: string;
|
|
370
|
+
}) {
|
|
334
371
|
return {
|
|
335
372
|
locale: locale as TypedLocale,
|
|
336
373
|
fallbackLocale: defaultLocale as TypedFallbackLocale,
|
|
337
|
-
draft
|
|
338
|
-
depth
|
|
374
|
+
draft,
|
|
375
|
+
depth,
|
|
339
376
|
user,
|
|
340
377
|
overrideAccess: false,
|
|
378
|
+
...(select !== undefined ? { select } : {}),
|
|
379
|
+
...(populate !== undefined ? { populate } : {}),
|
|
380
|
+
// joins are collection specific: typed by the caller's options, untyped here
|
|
381
|
+
...(joins !== undefined ? { joins } as {} : {}),
|
|
341
382
|
};
|
|
342
383
|
}
|
|
343
384
|
|
|
385
|
+
/**
|
|
386
|
+
* @deprecated Use `buildReadOptions({ user, locale, draft, depth })`.
|
|
387
|
+
* Kept for backward compatibility: reads at depth 0.
|
|
388
|
+
*/
|
|
389
|
+
export function buildBaseOptions(user: any, locale: string, draft?: boolean) {
|
|
390
|
+
return buildReadOptions({ user, locale, draft, depth: 0 });
|
|
391
|
+
}
|
|
344
392
|
|
|
345
393
|
/**
|
|
346
394
|
* Payload proxy example
|
package/src/server/page.ts
CHANGED
|
@@ -1,13 +1,50 @@
|
|
|
1
|
-
'
|
|
1
|
+
import 'server-only';
|
|
2
2
|
|
|
3
3
|
import { getCategorySegments, ICategorized, ICategory, IRoute, IRouteLink } from '@websolutespa/bom-core';
|
|
4
4
|
import type { User } from '@websolutespa/payload-plugin-bowl';
|
|
5
|
-
import type { CollectionSlug } from 'payload';
|
|
5
|
+
import type { CollectionSlug, SelectType } from 'payload';
|
|
6
6
|
import { buildBreadcrumb } from '../lib/breadcrumb';
|
|
7
|
-
import type { MixerContext, TypedPage } from '../types';
|
|
8
|
-
import {
|
|
7
|
+
import type { MixerContext, PageEnvelopeField, PageSelect, ReadOptions, TypedPage } from '../types';
|
|
8
|
+
import { buildReadOptions } from './mixer';
|
|
9
9
|
import type { MixerPayload } from './mixer-payload';
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Fields `getPage` needs to build the envelope (href, alternates, breadcrumb,
|
|
13
|
+
* segments) and that templates rely on (meta, template). They are always
|
|
14
|
+
* kept, whatever `select` the caller passes.
|
|
15
|
+
*/
|
|
16
|
+
export const PAGE_ENVELOPE_FIELDS = ['id', 'slug', 'title', 'category', 'markets', 'meta', 'template'] as const satisfies readonly PageEnvelopeField[];
|
|
17
|
+
|
|
18
|
+
function isExcludeSelect(select: SelectType): boolean {
|
|
19
|
+
return Object.values(select).some(value =>
|
|
20
|
+
value === false || (typeof value === 'object' && value !== null && isExcludeSelect(value as SelectType))
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Merges the envelope fields into a Payload select.
|
|
26
|
+
* - include mode (`true` values): envelope keys are added.
|
|
27
|
+
* - exclude mode (`false` values): envelope keys are removed from the exclusion list.
|
|
28
|
+
*/
|
|
29
|
+
export function withEnvelopeSelect<T extends SelectType | undefined>(select: T): T {
|
|
30
|
+
if (!select || Object.keys(select).length === 0) {
|
|
31
|
+
return select;
|
|
32
|
+
}
|
|
33
|
+
const merged: Record<string, unknown> = { ...select };
|
|
34
|
+
if (isExcludeSelect(select)) {
|
|
35
|
+
for (const key of PAGE_ENVELOPE_FIELDS) {
|
|
36
|
+
delete merged[key];
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
for (const key of PAGE_ENVELOPE_FIELDS) {
|
|
40
|
+
if (merged[key] === undefined) {
|
|
41
|
+
merged[key] = true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return merged as T;
|
|
46
|
+
}
|
|
47
|
+
|
|
11
48
|
/**
|
|
12
49
|
* Fetches a single page document by ID using Payload local API and assembles
|
|
13
50
|
* the IPage envelope (routes, alternates, breadcrumb, parentRoute).
|
|
@@ -16,8 +53,12 @@ import type { MixerPayload } from './mixer-payload';
|
|
|
16
53
|
* - routes/alternates : mixerContext.routes filtered by schema+id
|
|
17
54
|
* - segments : getCategorySegments() from bom-core (pure)
|
|
18
55
|
* - breadcrumb : findRouteOfCategory() from bom-core + mixerContext.currentRoutes
|
|
56
|
+
*
|
|
57
|
+
* Returns undefined when the document is not found; any other error is logged and rethrown.
|
|
58
|
+
* The last argument accepts read options (depth, draft, select, populate, joins);
|
|
59
|
+
* a boolean is still accepted as the legacy `draftMode` flag (depth 0).
|
|
19
60
|
*/
|
|
20
|
-
export async function getPage<TSlug extends CollectionSlug>(
|
|
61
|
+
export async function getPage<TSlug extends CollectionSlug, TSelect extends PageSelect<TSlug> = undefined>(
|
|
21
62
|
slug: TSlug,
|
|
22
63
|
id: string,
|
|
23
64
|
market: string,
|
|
@@ -25,19 +66,22 @@ export async function getPage<TSlug extends CollectionSlug>(
|
|
|
25
66
|
payload: MixerPayload,
|
|
26
67
|
user: User,
|
|
27
68
|
mixerContext: MixerContext,
|
|
28
|
-
|
|
29
|
-
): Promise<TypedPage<TSlug> | undefined> {
|
|
69
|
+
readOptions?: ReadOptions | boolean
|
|
70
|
+
): Promise<TypedPage<TSlug, TSelect> | undefined> {
|
|
71
|
+
const options: ReadOptions = typeof readOptions === 'object'
|
|
72
|
+
? readOptions
|
|
73
|
+
: { draft: readOptions, depth: 0 };
|
|
74
|
+
const read = buildReadOptions({
|
|
75
|
+
...options,
|
|
76
|
+
select: withEnvelopeSelect(options.select),
|
|
77
|
+
user,
|
|
78
|
+
locale,
|
|
79
|
+
});
|
|
30
80
|
try {
|
|
31
|
-
const base = buildBaseOptions(user, locale, draftMode);
|
|
32
81
|
const page = await payload.findByID({
|
|
82
|
+
...read,
|
|
33
83
|
collection: slug,
|
|
34
84
|
id,
|
|
35
|
-
locale: base.locale,
|
|
36
|
-
fallbackLocale: base.fallbackLocale,
|
|
37
|
-
draft: base.draft,
|
|
38
|
-
depth: base.depth,
|
|
39
|
-
user: base.user,
|
|
40
|
-
overrideAccess: base.overrideAccess,
|
|
41
85
|
disableErrors: true,
|
|
42
86
|
context: mixerContext,
|
|
43
87
|
});
|
|
@@ -69,13 +113,14 @@ export async function getPage<TSlug extends CollectionSlug>(
|
|
|
69
113
|
alternates,
|
|
70
114
|
breadcrumb,
|
|
71
115
|
parentRoute,
|
|
72
|
-
} as unknown as TypedPage<TSlug>;
|
|
116
|
+
} as unknown as TypedPage<TSlug, TSelect>;
|
|
73
117
|
} else {
|
|
74
118
|
console.log('PageService.getPage.notfound', slug, id, locale);
|
|
75
119
|
return undefined;
|
|
76
120
|
}
|
|
77
|
-
} catch {
|
|
78
|
-
|
|
121
|
+
} catch (error) {
|
|
122
|
+
console.error('PageService.getPage.error', slug, id, locale, error);
|
|
123
|
+
throw error;
|
|
79
124
|
}
|
|
80
125
|
}
|
|
81
126
|
|
package/src/types.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ICategorized, IComponent, ILayout, ILocale, IMarket, IPage, IPrettify, IRoute, PageProps } from '@websolutespa/bom-core';
|
|
2
2
|
import type { Category, EndUser, User } from '@websolutespa/payload-plugin-bowl';
|
|
3
3
|
import type { DynamicOptions, Loader } from 'next/dynamic';
|
|
4
|
-
import type { BasePayload, CollectionSlug, DataFromCollectionSlug, SanitizedConfig, TypedFallbackLocale, TypedLocale } from 'payload';
|
|
4
|
+
import type { BasePayload, CollectionSlug, DataFromCollectionSlug, JoinQuery, PopulateType, SanitizedConfig, SelectType, TransformCollectionWithSelect, TypedCollectionSelect, TypedFallbackLocale, TypedLocale } from 'payload';
|
|
5
5
|
import type { ComponentType, ReactNode } from 'react';
|
|
6
6
|
import type { BowlDecorator, MixerPayload } from './server/mixer-payload';
|
|
7
7
|
|
|
@@ -114,14 +114,116 @@ export type IContext = {
|
|
|
114
114
|
context: MixerContext;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
|
|
117
|
+
/** `true` / `false` forces draft mode, `'auto'` reads Next's `draftMode()`. */
|
|
118
|
+
export type DraftOption = boolean | 'auto';
|
|
119
|
+
|
|
120
|
+
/** Select accepted for a page collection, or `undefined` for the full document. */
|
|
121
|
+
export type PageSelect<TSlug extends CollectionSlug> = TypedCollectionSelect[TSlug] | undefined;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* A generated page collection document, narrowed by `select` when one is given.
|
|
125
|
+
* Without a select the full generated document type is returned.
|
|
126
|
+
*/
|
|
127
|
+
export type PageDocument<
|
|
128
|
+
TSlug extends CollectionSlug,
|
|
129
|
+
TSelect = undefined,
|
|
130
|
+
> = TSelect extends SelectType ? TransformCollectionWithSelect<TSlug, TSelect> : DataFromCollectionSlug<TSlug>;
|
|
131
|
+
|
|
132
|
+
/** Fields always read by `createPageContext`, whatever `select` is passed (see PAGE_ENVELOPE_FIELDS). */
|
|
133
|
+
export type PageEnvelopeField = 'id' | 'slug' | 'title' | 'category' | 'markets' | 'meta' | 'template';
|
|
134
|
+
|
|
135
|
+
type SelectInclude = { [key: string]: SelectInclude | true };
|
|
136
|
+
|
|
137
|
+
/** Type counterpart of `withEnvelopeSelect`: the envelope fields are always part of the result. */
|
|
138
|
+
export type WithEnvelopeSelect<TSelect> = TSelect extends SelectInclude
|
|
139
|
+
? TSelect & { [K in PageEnvelopeField]: true }
|
|
140
|
+
: Omit<TSelect, PageEnvelopeField>;
|
|
141
|
+
|
|
142
|
+
/** Envelope added by `getPage` to every page document. */
|
|
143
|
+
export type PageEnvelope = Pick<IPage, 'schema' | 'alternates' | 'breadcrumb' | 'href' | 'parentRoute'>;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* A generated page collection document enriched with Bowl's page envelope.
|
|
147
|
+
* With a `select`, only the selected fields (plus the envelope fields) are typed.
|
|
148
|
+
*/
|
|
149
|
+
export type TypedPage<
|
|
150
|
+
TSlug extends CollectionSlug,
|
|
151
|
+
TSelect extends PageSelect<TSlug> = undefined,
|
|
152
|
+
> = [TSelect] extends [SelectType]
|
|
153
|
+
? BowlDecorator<PageDocument<TSlug, WithEnvelopeSelect<TSelect>>> & PageEnvelope
|
|
154
|
+
: BowlDecorator<PageDocument<TSlug>> & IPage<ICategorized>;
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Narrows relationship / upload fields that are known to be populated
|
|
158
|
+
* (depth >= 1) from `string | T` (or `number | T`) to `T`.
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* const media = page.media as Populated<typeof page.media>;
|
|
162
|
+
*/
|
|
163
|
+
export type Populated<T> = T extends readonly (infer TItem)[]
|
|
164
|
+
? Populated<TItem>[]
|
|
165
|
+
: Exclude<T, string | number>;
|
|
166
|
+
|
|
167
|
+
/** Options for the layout fetch (`createLayoutContext`, or `layout` in `createPageContext`). */
|
|
168
|
+
export type LayoutOptions = {
|
|
169
|
+
/** Population depth for app, menus, labels, markets. Default `DEFAULT_LAYOUT_DEPTH` (1: app logo, menu media). */
|
|
170
|
+
depth?: number;
|
|
171
|
+
/** Default: the page draft option, or `'auto'` for `createLayoutContext`. */
|
|
172
|
+
draft?: DraftOption;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
/** The `layout` option of `createPageContext`: layout options, or `false` to skip the layout. */
|
|
176
|
+
export type LayoutOption = LayoutOptions | false;
|
|
177
|
+
|
|
178
|
+
/** `ILayout`, or `undefined` when the layout option is `false`. */
|
|
179
|
+
export type LayoutFor<TLayout extends LayoutOption> = TLayout extends false ? undefined : ILayout;
|
|
180
|
+
|
|
181
|
+
export type LayoutContextOptions = LayoutOptions & {
|
|
182
|
+
config: Promise<SanitizedConfig>;
|
|
183
|
+
headers?: ReadonlyHeaders;
|
|
184
|
+
};
|
|
118
185
|
|
|
119
|
-
|
|
120
|
-
|
|
186
|
+
export type PageContextOptions<
|
|
187
|
+
TSlug extends CollectionSlug = CollectionSlug,
|
|
188
|
+
TSelect extends PageSelect<TSlug> = undefined,
|
|
189
|
+
TLayout extends LayoutOption = LayoutOption,
|
|
190
|
+
> = {
|
|
191
|
+
config: Promise<SanitizedConfig>;
|
|
192
|
+
headers?: ReadonlyHeaders;
|
|
193
|
+
/**
|
|
194
|
+
* Population depth. Default `DEFAULT_PAGE_DEPTH` (2).
|
|
195
|
+
* 0 = ids only, 1 = direct relations/uploads (including those inside blocks),
|
|
196
|
+
* 2 = relations of relations (e.g. card covers).
|
|
197
|
+
*/
|
|
198
|
+
depth?: number;
|
|
199
|
+
/** Payload select for the page document. Envelope fields are always merged in. */
|
|
200
|
+
select?: TSelect;
|
|
201
|
+
/** Per-collection select applied to populated documents, e.g. `{ media: { url: true } }`. */
|
|
202
|
+
populate?: PopulateType;
|
|
203
|
+
joins?: JoinQuery<TSlug> | false;
|
|
204
|
+
/** `true` / `false`, or `'auto'` to read Next `draftMode()`. Default `'auto'`. */
|
|
205
|
+
draft?: DraftOption;
|
|
206
|
+
/** Options for the layout fetch, or `false` to skip loading the layout (`layout` is then `undefined`). */
|
|
207
|
+
layout?: TLayout;
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
/** Read options shared by every local API call made for a page or layout. */
|
|
211
|
+
export type ReadOptions = {
|
|
212
|
+
depth?: number;
|
|
213
|
+
draft?: boolean;
|
|
214
|
+
select?: SelectType;
|
|
215
|
+
populate?: PopulateType;
|
|
216
|
+
joins?: JoinQuery<any> | false;
|
|
217
|
+
};
|
|
121
218
|
|
|
122
|
-
export type TypedPageContext<
|
|
123
|
-
|
|
124
|
-
|
|
219
|
+
export type TypedPageContext<
|
|
220
|
+
TSlug extends CollectionSlug = CollectionSlug,
|
|
221
|
+
TSelect extends PageSelect<TSlug> = undefined,
|
|
222
|
+
TLayout extends LayoutOption = LayoutOptions,
|
|
223
|
+
> = {
|
|
224
|
+
/** `undefined` when the page context was created with `layout: false`. */
|
|
225
|
+
layout: LayoutFor<TLayout>;
|
|
226
|
+
page: TypedPage<TSlug, TSelect> | undefined;
|
|
125
227
|
user: IUser | IEndUser | null;
|
|
126
228
|
label: (key: string, params?: Record<string, any>) => string;
|
|
127
229
|
link: (category: string) => string | undefined;
|