@websolutespa/bom-next 4.0.0-next.3 → 4.0.0-next.4
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 +17 -0
- package/README.md +89 -89
- package/dist/client/client.d.ts +2 -2
- package/dist/client/extra.d.ts +3 -3
- package/dist/client/extra.d.ts.map +1 -1
- package/dist/client/label.d.ts +3 -3
- package/dist/client/layout.d.ts +3 -3
- package/dist/client/metadata.d.ts +3 -3
- package/dist/client/page.d.ts +3 -3
- package/dist/client/useApi.d.ts +7 -7
- package/dist/client/useCollectionApi.d.ts +6 -6
- package/dist/client/user.d.ts +3 -3
- package/dist/proxy/route-auto-detection.d.ts.map +1 -1
- package/dist/proxy/route-auto-detection.js +8 -1
- package/dist/proxy/route-auto-detection.js.map +1 -1
- package/dist/server/helpers.d.ts +1 -2
- package/dist/server/helpers.d.ts.map +1 -1
- package/dist/server/json-ld.d.ts +2 -2
- package/dist/server/json-ld.d.ts.map +1 -1
- package/dist/server/metadata.d.ts +6 -3
- package/dist/server/metadata.d.ts.map +1 -1
- package/dist/server/metadata.js +11 -5
- package/dist/server/metadata.js.map +1 -1
- package/dist/server/mixer.d.ts +5 -3
- package/dist/server/mixer.d.ts.map +1 -1
- package/dist/server/mixer.js +9 -8
- package/dist/server/mixer.js.map +1 -1
- package/dist/types.d.ts +6 -3
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/proxy/route-auto-detection.test.ts +5 -0
- package/src/proxy/route-auto-detection.ts +11 -1
- package/src/server/context.test.ts +31 -7
- package/src/server/metadata.ts +7 -7
- package/src/server/mixer.ts +7 -13
- package/src/server/request-data.test.ts +37 -0
- package/src/server/session/session.ts +22 -17
- package/src/types.ts +6 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @websolutespa/bom-next
|
|
2
2
|
|
|
3
|
+
## 4.0.0-next.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Helpers no longer read request data; only the template does and passes it down.
|
|
8
|
+
- `getPageMetadata` / `getMetadata` read only `params` (no more `DYNAMIC_SERVER_USAGE` on static/ISR pages). A dynamic template awaits its own `searchParams` and calls `buildPageMetadata(page, layout, { searchParams })`.
|
|
9
|
+
- `getPayload` no longer calls `headers()`: in draft mode pass `headers` from the template.
|
|
10
|
+
- `draft` defaults to `false` in `createPageContext` and `createLayoutContext`; `'auto'` (reads `draftMode()`) is an explicit opt-in.
|
|
11
|
+
- Session helpers (`createSession`, `getSession`, `hasValidSession`, `updateSession`, `deleteSession`) take the cookie store as an argument.
|
|
12
|
+
- `detectedRoute` cookie values with dot segments (`..`, also percent-encoded) or backslashes are rejected.
|
|
13
|
+
|
|
14
|
+
- Updated dependencies
|
|
15
|
+
- @websolutespa/payload-plugin-bowl@4.0.0-next.3
|
|
16
|
+
- @websolutespa/payload-db-memory@3.0.3
|
|
17
|
+
- @websolutespa/payload-utils@4.0.0-next.0
|
|
18
|
+
- @websolutespa/bom-core@4.0.0-next.1
|
|
19
|
+
|
|
3
20
|
## 4.0.0-next.3
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,89 +1,89 @@
|
|
|
1
|
-
# @websolutespa/bom-next
|
|
2
|
-
|
|
3
|
-
[](https://badge.fury.io/js/%40websolutespa%2Fbom-next)
|
|
4
|
-
|
|
5
|
-
[](https://shields.io/)
|
|
6
|
-
|
|
7
|
-
Next module of the [BOM Repository](https://github.com/websolutespa/bom) by [websolute](https://www.websolute.com/).
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
##### *this library is for internal usage and not production ready*
|
|
12
|
-
|
|
13
|
-
## Page context
|
|
14
|
-
|
|
15
|
-
```ts
|
|
16
|
-
import { createPageContext, getMetadata } from '@websolutespa/bom-next/server';
|
|
17
|
-
|
|
18
|
-
export const generateMetadata = getMetadata('post_detail', config);
|
|
19
|
-
|
|
20
|
-
const { page, layout, label, link } = await createPageContext(market, locale, 'post_detail', id, {
|
|
21
|
-
config,
|
|
22
|
-
depth: 2, // default DEFAULT_PAGE_DEPTH
|
|
23
|
-
select: { title: true, abstract: true, media: true, components: true },
|
|
24
|
-
populate: { media: { url: true, alt: true, width: true, height: true, type: true } },
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
const { layout } = await createLayoutContext(market, locale, { config }); // depth: DEFAULT_LAYOUT_DEPTH (1)
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
| option | default | |
|
|
31
|
-
|---|---|---|
|
|
32
|
-
| `depth` | `2` | `0` ids only, `1` direct relations/uploads (including those inside blocks), `2` relations of relations |
|
|
33
|
-
| `select` | – | Payload select; envelope fields (`id`, `slug`, `title`, `category`, `markets`, `meta`, `template`) are always read |
|
|
34
|
-
| `populate` | – | per-collection select for populated documents |
|
|
35
|
-
| `draft` | `'auto'` | `true` / `false`, or `'auto'` to read Next `draftMode()` |
|
|
36
|
-
| `layout` | `{ depth: 1 }` | layout options, or `false` to skip the layout |
|
|
37
|
-
|
|
38
|
-
Page and layout reads are memoized per request, so `getMetadata` and the page component share them when called with the same options.
|
|
39
|
-
To bind `config` once: `export const { createPageContext, createLayoutContext, getMetadata } = createContextHelpers({ config, defaults: { depth: 2 } });`
|
|
40
|
-
|
|
41
|
-
## Metadata
|
|
42
|
-
|
|
43
|
-
`getPageMetadata` (and `getMetadata`, its `config`-first form) returns a `generateMetadata` function that renders on the server: plain-text title and description, canonical (keeping `?pagination[page]=N` after the first page), `alternates.languages` with one `locale-COUNTRY` entry per market country plus `x-default`, robots, keywords, Open Graph and Twitter.
|
|
44
|
-
|
|
45
|
-
```ts
|
|
46
|
-
import { getPageMetadata, JsonLd, buildPageStructuredData } from '@websolutespa/bom-next/server';
|
|
47
|
-
|
|
48
|
-
export const generateMetadata = getPageMetadata('post_detail', {
|
|
49
|
-
config,
|
|
50
|
-
metadata: {
|
|
51
|
-
brand: { name: 'Example', logo: '/logo.png', twitterName: '@example' },
|
|
52
|
-
extend: (metadata, { page }) => ({ ...metadata, title: `${metadata.title} | Example` }),
|
|
53
|
-
},
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
// JSON-LD in the page component
|
|
57
|
-
<JsonLd data={buildPageStructuredData(page, layout, { brand: { name: 'Example' } })} />
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
`buildPageMetadata(page, layout, options)` is the same builder for custom routes. URLs are resolved against `NEXT_PUBLIC_URL` unless `baseUrl` is passed. Robots come from `meta.robots`, or `meta.robot` (the `@payloadcms/plugin-seo` field).
|
|
61
|
-
|
|
62
|
-
The client `MetaDataProvider` only computes values for `useMetaData`; the `next/head` based `Meta`, `OpenGraph` and `StructuredData` components of the mixer packages render nothing in the App Router.
|
|
63
|
-
|
|
64
|
-
`layout.homeHref` is the root page href for the current market and locale; prefer it to `layout.topLevelHrefs.<slug>`, which is keyed by collection slug or template.
|
|
65
|
-
|
|
66
|
-
## Routing proxy
|
|
67
|
-
|
|
68
|
-
`createRouteProxy` resolves each request through `/api/-route` and caches the result per instance: found routes for `BOM_ROUTE_CACHE_TTL` seconds (default `30`, `0` disables), misses and redirects for at most 10 seconds. Draft requests and server errors are never cached. CMS redirects send the browser to the target returned by the resolver.
|
|
69
|
-
|
|
70
|
-
`routeAutoDetection` redirects `/` straight from the `detectedRoute` cookie when present; otherwise it detects the market (GeoIP, 2 s timeout, cached per IP for one hour) and the locale.
|
|
71
|
-
|
|
72
|
-
The server context (`getContext`) reads routes from the Bowl route store and caches the rest per market, locale and user for `MEMORY_CACHE_DURATION` seconds (default 300). Any route store change, local or from another instance through Redis, clears it. Draft contexts are never cached.
|
|
73
|
-
|
|
74
|
-
## Environment
|
|
75
|
-
|
|
76
|
-
Per-request diagnostics (proxy, local API calls, context cache) are logged in development only (`NODE_ENV` unset or `development`).
|
|
77
|
-
|
|
78
|
-
| Variable | Default | |
|
|
79
|
-
|---|---|---|
|
|
80
|
-
| `BOM_ROUTE_CACHE_TTL` | `30` | proxy route cache lifetime in seconds, `0` disables it |
|
|
81
|
-
| `MEMORY_CACHE_DURATION` | `300` | server context cache lifetime in seconds |
|
|
82
|
-
| `UI_REGISTRY_SOURCE_DIR` | `packages/ui/src` | registry source directory |
|
|
83
|
-
| `UI_REGISTRY_COMPONENTS_JSON` | nearest `components.json` | shadcn config whose aliases (e.g. `@/ui/lib/utils`) are mapped to registry imports |
|
|
84
|
-
| `UI_REGISTRY_SOURCE_ALIAS` | – | extra import prefix pointing at the registry source, e.g. `@/ui/` |
|
|
85
|
-
| `UI_REGISTRY_SKIP_UNRESOLVED` | – | `1` hides registry items that import app code; otherwise they are listed with `meta.unresolvedImports` |
|
|
86
|
-
|
|
87
|
-
## User
|
|
88
|
-
|
|
89
|
-
`UserProvider` reads `/api/auth/me` once per
|
|
1
|
+
# @websolutespa/bom-next
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/js/%40websolutespa%2Fbom-next)
|
|
4
|
+
|
|
5
|
+
[](https://shields.io/)
|
|
6
|
+
|
|
7
|
+
Next module of the [BOM Repository](https://github.com/websolutespa/bom) by [websolute](https://www.websolute.com/).
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
##### *this library is for internal usage and not production ready*
|
|
12
|
+
|
|
13
|
+
## Page context
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { createPageContext, getMetadata } from '@websolutespa/bom-next/server';
|
|
17
|
+
|
|
18
|
+
export const generateMetadata = getMetadata('post_detail', config);
|
|
19
|
+
|
|
20
|
+
const { page, layout, label, link } = await createPageContext(market, locale, 'post_detail', id, {
|
|
21
|
+
config,
|
|
22
|
+
depth: 2, // default DEFAULT_PAGE_DEPTH
|
|
23
|
+
select: { title: true, abstract: true, media: true, components: true },
|
|
24
|
+
populate: { media: { url: true, alt: true, width: true, height: true, type: true } },
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const { layout } = await createLayoutContext(market, locale, { config }); // depth: DEFAULT_LAYOUT_DEPTH (1)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
| option | default | |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| `depth` | `2` | `0` ids only, `1` direct relations/uploads (including those inside blocks), `2` relations of relations |
|
|
33
|
+
| `select` | – | Payload select; envelope fields (`id`, `slug`, `title`, `category`, `markets`, `meta`, `template`) are always read |
|
|
34
|
+
| `populate` | – | per-collection select for populated documents |
|
|
35
|
+
| `draft` | `'auto'` | `true` / `false`, or `'auto'` to read Next `draftMode()` |
|
|
36
|
+
| `layout` | `{ depth: 1 }` | layout options, or `false` to skip the layout |
|
|
37
|
+
|
|
38
|
+
Page and layout reads are memoized per request, so `getMetadata` and the page component share them when called with the same options.
|
|
39
|
+
To bind `config` once: `export const { createPageContext, createLayoutContext, getMetadata } = createContextHelpers({ config, defaults: { depth: 2 } });`
|
|
40
|
+
|
|
41
|
+
## Metadata
|
|
42
|
+
|
|
43
|
+
`getPageMetadata` (and `getMetadata`, its `config`-first form) returns a `generateMetadata` function that renders on the server: plain-text title and description, canonical (keeping `?pagination[page]=N` after the first page), `alternates.languages` with one `locale-COUNTRY` entry per market country plus `x-default`, robots, keywords, Open Graph and Twitter.
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { getPageMetadata, JsonLd, buildPageStructuredData } from '@websolutespa/bom-next/server';
|
|
47
|
+
|
|
48
|
+
export const generateMetadata = getPageMetadata('post_detail', {
|
|
49
|
+
config,
|
|
50
|
+
metadata: {
|
|
51
|
+
brand: { name: 'Example', logo: '/logo.png', twitterName: '@example' },
|
|
52
|
+
extend: (metadata, { page }) => ({ ...metadata, title: `${metadata.title} | Example` }),
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// JSON-LD in the page component
|
|
57
|
+
<JsonLd data={buildPageStructuredData(page, layout, { brand: { name: 'Example' } })} />
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`buildPageMetadata(page, layout, options)` is the same builder for custom routes. URLs are resolved against `NEXT_PUBLIC_URL` unless `baseUrl` is passed. Robots come from `meta.robots`, or `meta.robot` (the `@payloadcms/plugin-seo` field).
|
|
61
|
+
|
|
62
|
+
The client `MetaDataProvider` only computes values for `useMetaData`; the `next/head` based `Meta`, `OpenGraph` and `StructuredData` components of the mixer packages render nothing in the App Router.
|
|
63
|
+
|
|
64
|
+
`layout.homeHref` is the root page href for the current market and locale; prefer it to `layout.topLevelHrefs.<slug>`, which is keyed by collection slug or template.
|
|
65
|
+
|
|
66
|
+
## Routing proxy
|
|
67
|
+
|
|
68
|
+
`createRouteProxy` resolves each request through `/api/-route` and caches the result per instance: found routes for `BOM_ROUTE_CACHE_TTL` seconds (default `30`, `0` disables), misses and redirects for at most 10 seconds. Draft requests and server errors are never cached. CMS redirects send the browser to the target returned by the resolver.
|
|
69
|
+
|
|
70
|
+
`routeAutoDetection` redirects `/` straight from the `detectedRoute` cookie when present; otherwise it detects the market (GeoIP, 2 s timeout, cached per IP for one hour) and the locale.
|
|
71
|
+
|
|
72
|
+
The server context (`getContext`) reads routes from the Bowl route store and caches the rest per market, locale and user for `MEMORY_CACHE_DURATION` seconds (default 300). Any route store change, local or from another instance through Redis, clears it. Draft contexts are never cached.
|
|
73
|
+
|
|
74
|
+
## Environment
|
|
75
|
+
|
|
76
|
+
Per-request diagnostics (proxy, local API calls, context cache) are logged in development only (`NODE_ENV` unset or `development`).
|
|
77
|
+
|
|
78
|
+
| Variable | Default | |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| `BOM_ROUTE_CACHE_TTL` | `30` | proxy route cache lifetime in seconds, `0` disables it |
|
|
81
|
+
| `MEMORY_CACHE_DURATION` | `300` | server context cache lifetime in seconds |
|
|
82
|
+
| `UI_REGISTRY_SOURCE_DIR` | `packages/ui/src` | registry source directory |
|
|
83
|
+
| `UI_REGISTRY_COMPONENTS_JSON` | nearest `components.json` | shadcn config whose aliases (e.g. `@/ui/lib/utils`) are mapped to registry imports |
|
|
84
|
+
| `UI_REGISTRY_SOURCE_ALIAS` | – | extra import prefix pointing at the registry source, e.g. `@/ui/` |
|
|
85
|
+
| `UI_REGISTRY_SKIP_UNRESOLVED` | – | `1` hides registry items that import app code; otherwise they are listed with `meta.unresolvedImports` |
|
|
86
|
+
|
|
87
|
+
## User
|
|
88
|
+
|
|
89
|
+
`UserProvider` reads `/api/auth/me` once per page load, shared by every mount and client navigation. Pass `initialUser` (a user or `null`) when the server already knows it to skip the request; `setUser` and `invalidateUser()` keep the cached value current after login or logout.
|
package/dist/client/client.d.ts
CHANGED
package/dist/client/extra.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react0 from "react";
|
|
2
2
|
|
|
3
3
|
//#region src/client/extra.d.ts
|
|
4
4
|
type IExtraContext = Record<string, any>;
|
|
5
|
-
declare const ExtraContext:
|
|
5
|
+
declare const ExtraContext: react0.Context<IExtraContext | undefined>;
|
|
6
6
|
declare function ExtraProvider({
|
|
7
7
|
extra,
|
|
8
8
|
children
|
|
9
9
|
}: {
|
|
10
10
|
extra?: Record<string, any>;
|
|
11
11
|
children?: React.ReactNode;
|
|
12
|
-
}):
|
|
12
|
+
}): react0.JSX.Element;
|
|
13
13
|
//# sourceMappingURL=extra.d.ts.map
|
|
14
14
|
|
|
15
15
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extra.d.ts","names":[],"sources":["../../src/client/extra.tsx"],"sourcesContent":[],"mappings":";;;KAIY,aAAA,GAAgB;cAEf,cAAY,MAAA,CAAA,QAAA;iBAET,aAAA;;;;EAJJ,KAAA,CAAA,EAQF,MARE,CAAA,MAAa,EAAA,GAAA,
|
|
1
|
+
{"version":3,"file":"extra.d.ts","names":[],"sources":["../../src/client/extra.tsx"],"sourcesContent":[],"mappings":";;;KAIY,aAAA,GAAgB;cAEf,cAAY,MAAA,CAAA,QAAA;iBAET,aAAA;;;;EAJJ,KAAA,CAAA,EAQF,MARE,CAAA,MAAa,EAAA,GAAA,CAAG;EAEf,QAAA,CAAA,EAOA,KAAA,CAAM,SAP4D;CAAA,CAAA,EAQ9E,MAAA,CAAA,GAAA,CAAA,OAR8E"}
|
package/dist/client/label.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react2 from "react";
|
|
2
2
|
|
|
3
3
|
//#region src/client/label.d.ts
|
|
4
4
|
type ILabelContext = (key: string, params?: Record<string, any>) => string;
|
|
5
|
-
declare const LabelContext:
|
|
5
|
+
declare const LabelContext: react2.Context<ILabelContext | undefined>;
|
|
6
6
|
declare function LabelProvider({
|
|
7
7
|
children
|
|
8
8
|
}: {
|
|
9
9
|
children?: React.ReactNode;
|
|
10
|
-
}):
|
|
10
|
+
}): react2.JSX.Element;
|
|
11
11
|
//# sourceMappingURL=label.d.ts.map
|
|
12
12
|
|
|
13
13
|
//#endregion
|
package/dist/client/layout.d.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { ILayout } from "@websolutespa/bom-core";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react4 from "react";
|
|
3
3
|
|
|
4
4
|
//#region src/client/layout.d.ts
|
|
5
5
|
type ILayoutContext = ILayout;
|
|
6
|
-
declare const LayoutContext:
|
|
6
|
+
declare const LayoutContext: react4.Context<ILayoutContext | undefined>;
|
|
7
7
|
declare function LayoutProvider({
|
|
8
8
|
layout,
|
|
9
9
|
children
|
|
10
10
|
}: {
|
|
11
11
|
layout: ILayout;
|
|
12
12
|
children?: React.ReactNode;
|
|
13
|
-
}):
|
|
13
|
+
}): react4.JSX.Element;
|
|
14
14
|
//# sourceMappingURL=layout.d.ts.map
|
|
15
15
|
|
|
16
16
|
//#endregion
|
|
@@ -2,7 +2,7 @@ import { OpenGraphType } from "../lib/open-graph.js";
|
|
|
2
2
|
import { StructuredDataType } from "../lib/structured-data.js";
|
|
3
3
|
import { TwitterCardType } from "../lib/twitter-card.js";
|
|
4
4
|
import { IMetaData } from "../lib/meta-data.js";
|
|
5
|
-
import * as
|
|
5
|
+
import * as react6 from "react";
|
|
6
6
|
import { ReactNode } from "react";
|
|
7
7
|
|
|
8
8
|
//#region src/client/metadata.d.ts
|
|
@@ -29,7 +29,7 @@ type IMetaDataOptions = {
|
|
|
29
29
|
twitterCard?: TwitterCardType;
|
|
30
30
|
};
|
|
31
31
|
type IMetaDataContext = IMetaData;
|
|
32
|
-
declare const MetaDataContext:
|
|
32
|
+
declare const MetaDataContext: react6.Context<IMetaData | undefined>;
|
|
33
33
|
/**
|
|
34
34
|
* Computes page metadata for client components (`useMetaData`). It renders
|
|
35
35
|
* nothing into `<head>`: in the App Router, export `generateMetadata` built
|
|
@@ -46,7 +46,7 @@ declare function MetaDataProvider({
|
|
|
46
46
|
metaData: IMetaDataOptions;
|
|
47
47
|
search?: string;
|
|
48
48
|
children?: ReactNode;
|
|
49
|
-
}):
|
|
49
|
+
}): react6.JSX.Element;
|
|
50
50
|
//# sourceMappingURL=metadata.d.ts.map
|
|
51
51
|
//#endregion
|
|
52
52
|
export { IMetaDataContext, IMetaDataOptions, MetaDataContext, MetaDataProvider };
|
package/dist/client/page.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as _websolutespa_bom_core0 from "@websolutespa/bom-core";
|
|
2
2
|
import { ILocalized, IPage } from "@websolutespa/bom-core";
|
|
3
|
-
import * as
|
|
3
|
+
import * as react8 from "react";
|
|
4
4
|
|
|
5
5
|
//#region src/client/page.d.ts
|
|
6
6
|
type IPageContext = ILocalized<IPage>;
|
|
7
|
-
declare const PageContext:
|
|
7
|
+
declare const PageContext: react8.Context<{
|
|
8
8
|
[x: string]: unknown;
|
|
9
9
|
id: _websolutespa_bom_core0.IEquatable;
|
|
10
10
|
schema: string;
|
|
@@ -398,7 +398,7 @@ declare function PageProvider({
|
|
|
398
398
|
}: {
|
|
399
399
|
page: ILocalized<IPage>;
|
|
400
400
|
children?: React.ReactNode;
|
|
401
|
-
}):
|
|
401
|
+
}): react8.JSX.Element;
|
|
402
402
|
//# sourceMappingURL=page.d.ts.map
|
|
403
403
|
//#endregion
|
|
404
404
|
export { IPageContext, PageContext, PageProvider };
|
package/dist/client/useApi.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { ApiRequestOptions } from "../lib/http.js";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react15 from "react";
|
|
3
3
|
|
|
4
4
|
//#region src/client/useApi.d.ts
|
|
5
|
-
declare function useApiFetch<T = unknown>(pathname: string, options?: ApiRequestOptions): [T | undefined, boolean, any,
|
|
6
|
-
declare function useApiGet<T = unknown>(pathname: string, options?: ApiRequestOptions): [T | undefined, boolean, any,
|
|
7
|
-
declare function useApiPost<T = unknown>(pathname: string, payload: unknown, options?: ApiRequestOptions): [T | undefined, boolean, any,
|
|
8
|
-
declare function useApiPut<T = unknown>(pathname: string, payload: unknown, options?: ApiRequestOptions): [T | undefined, boolean, any,
|
|
9
|
-
declare function useApiPatch<T = unknown>(pathname: string, payload: unknown, options?: ApiRequestOptions): [T | undefined, boolean, any,
|
|
10
|
-
declare function useApiDelete<T = unknown>(pathname: string, options?: ApiRequestOptions): [T | undefined, boolean, any,
|
|
5
|
+
declare function useApiFetch<T = unknown>(pathname: string, options?: ApiRequestOptions): [T | undefined, boolean, any, react15.Dispatch<any>];
|
|
6
|
+
declare function useApiGet<T = unknown>(pathname: string, options?: ApiRequestOptions): [T | undefined, boolean, any, react15.Dispatch<any>];
|
|
7
|
+
declare function useApiPost<T = unknown>(pathname: string, payload: unknown, options?: ApiRequestOptions): [T | undefined, boolean, any, react15.Dispatch<any>];
|
|
8
|
+
declare function useApiPut<T = unknown>(pathname: string, payload: unknown, options?: ApiRequestOptions): [T | undefined, boolean, any, react15.Dispatch<any>];
|
|
9
|
+
declare function useApiPatch<T = unknown>(pathname: string, payload: unknown, options?: ApiRequestOptions): [T | undefined, boolean, any, react15.Dispatch<any>];
|
|
10
|
+
declare function useApiDelete<T = unknown>(pathname: string, options?: ApiRequestOptions): [T | undefined, boolean, any, react15.Dispatch<any>];
|
|
11
11
|
type Api = {
|
|
12
12
|
get: <T = unknown>(pathname: string, options?: ApiRequestOptions) => Promise<T>;
|
|
13
13
|
post: <T = unknown>(pathname: string, payload?: unknown, options?: ApiRequestOptions) => Promise<T>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ApiRequestOptions } from "../lib/http.js";
|
|
2
2
|
import { QueryParams } from "@websolutespa/bom-core";
|
|
3
|
-
import * as
|
|
3
|
+
import * as react10 from "react";
|
|
4
4
|
|
|
5
5
|
//#region src/client/useCollectionApi.d.ts
|
|
6
6
|
type CollectionApi = {
|
|
@@ -11,11 +11,11 @@ type CollectionApi = {
|
|
|
11
11
|
delete: <T = unknown>(pathname: string, options?: ApiRequestOptions) => Promise<T>;
|
|
12
12
|
};
|
|
13
13
|
declare function useCollectionApi(): CollectionApi;
|
|
14
|
-
declare function useCollectionApiGet<T = unknown>(pathname: string, params?: QueryParams, options?: ApiRequestOptions): [T | undefined, boolean, any,
|
|
15
|
-
declare function useCollectionApiPost<T = unknown>(pathname: string, payload: unknown, options?: ApiRequestOptions): [T | undefined, boolean, any,
|
|
16
|
-
declare function useCollectionApiPut<T = unknown>(pathname: string, payload: unknown, options?: ApiRequestOptions): [T | undefined, boolean, any,
|
|
17
|
-
declare function useCollectionApiPatch<T = unknown>(pathname: string, payload: unknown, options?: ApiRequestOptions): [T | undefined, boolean, any,
|
|
18
|
-
declare function useCollectionApiDelete<T = unknown>(pathname: string, options?: ApiRequestOptions): [T | undefined, boolean, any,
|
|
14
|
+
declare function useCollectionApiGet<T = unknown>(pathname: string, params?: QueryParams, options?: ApiRequestOptions): [T | undefined, boolean, any, react10.Dispatch<any>];
|
|
15
|
+
declare function useCollectionApiPost<T = unknown>(pathname: string, payload: unknown, options?: ApiRequestOptions): [T | undefined, boolean, any, react10.Dispatch<any>];
|
|
16
|
+
declare function useCollectionApiPut<T = unknown>(pathname: string, payload: unknown, options?: ApiRequestOptions): [T | undefined, boolean, any, react10.Dispatch<any>];
|
|
17
|
+
declare function useCollectionApiPatch<T = unknown>(pathname: string, payload: unknown, options?: ApiRequestOptions): [T | undefined, boolean, any, react10.Dispatch<any>];
|
|
18
|
+
declare function useCollectionApiDelete<T = unknown>(pathname: string, options?: ApiRequestOptions): [T | undefined, boolean, any, react10.Dispatch<any>];
|
|
19
19
|
//#endregion
|
|
20
20
|
export { useCollectionApi, useCollectionApiDelete, useCollectionApiGet, useCollectionApiPatch, useCollectionApiPost, useCollectionApiPut };
|
|
21
21
|
//# sourceMappingURL=useCollectionApi.d.ts.map
|
package/dist/client/user.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IEndUser, IUser } from "../types.js";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react21 from "react";
|
|
3
3
|
import { ReactNode } from "react";
|
|
4
4
|
|
|
5
5
|
//#region src/client/user.d.ts
|
|
@@ -8,7 +8,7 @@ type UserContextType = {
|
|
|
8
8
|
user?: UserValue;
|
|
9
9
|
setUser: (user?: UserValue) => void;
|
|
10
10
|
};
|
|
11
|
-
declare const UserContext:
|
|
11
|
+
declare const UserContext: react21.Context<UserContextType>;
|
|
12
12
|
/** Forces the next UserProvider mount to read `/auth/me` again. */
|
|
13
13
|
declare function invalidateUser(): void;
|
|
14
14
|
/**
|
|
@@ -21,7 +21,7 @@ declare function UserProvider({
|
|
|
21
21
|
}: {
|
|
22
22
|
initialUser?: UserValue;
|
|
23
23
|
children: ReactNode;
|
|
24
|
-
}):
|
|
24
|
+
}): react21.JSX.Element;
|
|
25
25
|
//#endregion
|
|
26
26
|
export { UserContext, UserContextType, UserProvider, invalidateUser };
|
|
27
27
|
//# sourceMappingURL=user.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-auto-detection.d.ts","names":[],"sources":["../../src/proxy/route-auto-detection.ts"],"sourcesContent":[],"mappings":";;;;iBAMsB,YAAA,UAAsB,sCAAmC;;AAA/E;;;AAA+E,iBA2C/D,oBAAA,CA3C+D,KAAA,CAAA,EAAA,MAAA,CAAA,EAAA,KAAA,IAAA,MAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"route-auto-detection.d.ts","names":[],"sources":["../../src/proxy/route-auto-detection.ts"],"sourcesContent":[],"mappings":";;;;iBAMsB,YAAA,UAAsB,sCAAmC;;AAA/E;;;AAA+E,iBA2C/D,oBAAA,CA3C+D,KAAA,CAAA,EAAA,MAAA,CAAA,EAAA,KAAA,IAAA,MAAA;AAAA,iBAyDzD,aAAA,CAzDyD,OAAA,EAyDlC,WAzDkC,EAAA,aAAA,CAAA,EAAA,MAAA,CAAA,EAyDC,OAzDD,CAAA,MAAA,GAAA,SAAA,CAAA;AA2C/D,cA0DH,kBA1DuB,EA0DH,UA1DG;AAcpC"}
|
|
@@ -42,7 +42,14 @@ function setCachedCountry(ip, country) {
|
|
|
42
42
|
|
|
43
43
|
*/
|
|
44
44
|
function isValidDetectedRoute(value) {
|
|
45
|
-
|
|
45
|
+
if (!value || !value.startsWith("/") || value.startsWith("//") || value === "/" || value.includes("\\")) return false;
|
|
46
|
+
let decoded;
|
|
47
|
+
try {
|
|
48
|
+
decoded = decodeURIComponent(value);
|
|
49
|
+
} catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
return !decoded.split(/[/?#]/).some((segment) => segment === "." || segment === "..") && !decoded.includes("\\");
|
|
46
53
|
}
|
|
47
54
|
async function detectCountry(request, defaultMarket$1) {
|
|
48
55
|
let ip = request.headers.get("x-forwarded-for") || request.headers.get("x-real-ip");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-auto-detection.js","names":["request: NextRequest","defaultLocale?: string","defaultLocale","ip: string","country: string","value?: string","defaultMarket?: string","defaultMarket","routeAutoDetection: Middleware","redirectUrl: string | undefined","rootRoutes: IRoute[]","markets: IMarket[]","countries: string[]","x","market","origin: string","redirectUrl: string"],"sources":["../../src/proxy/route-auto-detection.ts"],"sourcesContent":["import { asEquatable, defaultLocale, defaultMarket, IMarket, IRoute } from '@websolutespa/bom-core';\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport { debug } from '../lib/debug';\r\nimport { localApiGet } from '../lib/http';\r\nimport { getRequestOrigin, Middleware, MiddlewareOptions } from './proxy';\r\n\r\nexport async function detectLocale(request: NextRequest, defaultLocale?: string) {\r\n const acceptLanguage = request.headers.get('accept-language')?.split(',')[0];\r\n const detectedLocale = request.cookies.get('NEXT_LOCALE')?.value || acceptLanguage || defaultLocale || process.env.DEFAULT_LOCALE;\r\n return detectedLocale as string;\r\n}\r\n\r\nconst GEOIP_TIMEOUT = 2000;\r\nconst GEOIP_CACHE_TTL = 60 * 60 * 1000;\r\nconst GEOIP_CACHE_MAX = 1000;\r\n\r\ntype GeoIpCacheEntry = { country: string; expires: number };\r\nconst globalForGeoIp = globalThis as typeof globalThis & { _bomGeoIpCache?: Map<string, GeoIpCacheEntry> };\r\n// Country lookups are external calls; cache them per IP so repeat visitors\r\n// and crawlers do not hit the GeoIP service on every request to `/`.\r\nconst geoIpCache = globalForGeoIp._bomGeoIpCache ??= new Map<string, GeoIpCacheEntry>();\r\n\r\nfunction getCachedCountry(ip: string): string | undefined {\r\n const entry = geoIpCache.get(ip);\r\n if (!entry) {\r\n return undefined;\r\n }\r\n if (entry.expires < Date.now()) {\r\n geoIpCache.delete(ip);\r\n return undefined;\r\n }\r\n return entry.country;\r\n}\r\n\r\nfunction setCachedCountry(ip: string, country: string) {\r\n if (geoIpCache.size >= GEOIP_CACHE_MAX) {\r\n // Maps iterate in insertion order, so the first key is the oldest entry.\r\n const oldest = geoIpCache.keys().next().value;\r\n if (oldest !== undefined) {\r\n geoIpCache.delete(oldest);\r\n }\r\n }\r\n geoIpCache.set(ip, { country, expires: Date.now() + GEOIP_CACHE_TTL });\r\n}\r\n\r\n/**\r\n * A relative, same-origin path previously set by this middleware. Anything\r\n * else (absolute or protocol-relative URLs) is ignored to avoid open redirects.\r\n */\r\nexport function isValidDetectedRoute(value?: string): value is string {\r\n return Boolean(value && value.startsWith('/') && !value.startsWith('//') && value !== '/');\r\n}\r\n\r\nexport async function detectCountry(request: NextRequest, defaultMarket?: string) {\r\n let ip = request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip');\r\n if (ip) {\r\n ip = ip.split(',')[0]!.trim();\r\n }\r\n const isValidIp = ip?.match(/^(\\d+?)\\.(\\d+?)\\.(\\d+?)\\.(\\d+?)$/);\r\n const cachedCountry = isValidIp && ip ? getCachedCountry(ip) : undefined;\r\n if (cachedCountry !== undefined) {\r\n return cachedCountry || defaultMarket || process.env.DEFAULT_MARKET;\r\n }\r\n let detectedCountry = '';\r\n try {\r\n const token = process.env.IPINFO_TOKEN;\r\n if (token) {\r\n const url = isValidIp ?\r\n `https://api.ipinfo.io/lite/${ip}/country_code?token=${token}` :\r\n `https://api.ipinfo.io/lite/me/country_code?token=${token}`;\r\n const response = await fetch(url, { signal: AbortSignal.timeout(GEOIP_TIMEOUT) });\r\n if (response.ok) {\r\n const data = await response.text();\r\n detectedCountry = data.toLowerCase();\r\n }\r\n } else {\r\n const url = `https://geoip.websolute.it/Ip2Location/get_info.aspx?ipaddress=${isValidIp ? ip : ''}`;\r\n const response = await fetch(url, { signal: AbortSignal.timeout(GEOIP_TIMEOUT) });\r\n if (response.ok) {\r\n const xml = await response.text();\r\n detectedCountry = (\r\n ((xml.split('<CountryCode><![CDATA[')[1] || '').split(']]></CountryCode>')[0] || '')\r\n ).replace('-', '').toLowerCase();\r\n // console.log('detectedCountry', detectedCountry);\r\n }\r\n }\r\n // console.log('routeInterceptor.detectCountry', detectedCountry);\r\n if (isValidIp && ip) {\r\n setCachedCountry(ip, detectedCountry);\r\n }\r\n return detectedCountry || defaultMarket || process.env.DEFAULT_MARKET;\r\n } catch (error) {\r\n console.warn('routeInterceptor.detectCountry.error', error);\r\n }\r\n return (defaultMarket || process.env.DEFAULT_MARKET) as string;\r\n}\r\n\r\nexport const routeAutoDetection: Middleware = async ({ request }: MiddlewareOptions) => {\r\n let redirectUrl: string | undefined = undefined;\r\n const url = request.nextUrl;\r\n const origin = getRequestOrigin(request);\r\n if (url.pathname === '/') {\r\n const cookie = request.cookies.get('detectedRoute');\r\n if (isValidDetectedRoute(cookie?.value)) {\r\n // The cookie is only set after a successful detection, so trust it and\r\n // skip the route, market and GeoIP lookups entirely.\r\n return createDetectedRouteResponse(request, origin, cookie.value);\r\n }\r\n // console.log('routeInterceptor.routeAutoDetection', url.pathname);\r\n const rootRoutes: IRoute[] = await localApiGet('/-route?where[isRoot][equals]=true', {}, undefined, origin);\r\n // console.log('routeInterceptor.routeAutoDetection.rootRoutes', rootRoutes);\r\n const defaultRoute = rootRoutes.find(x => x.id === '/');\r\n // console.log('routeInterceptor.routeAutoDetection.defaultRoute', defaultRoute);\r\n if (defaultRoute) {\r\n return;\r\n }\r\n const markets: IMarket[] = await localApiGet('/market?pagination=false', {}, undefined, origin);\r\n // console.log('routeInterceptor.routeAutoDetection.markets', markets);\r\n const market = markets.find(x => x.isDefault) || markets.find(x => x.id === defaultMarket) || markets[0];\r\n // console.log('routeInterceptor.routeAutoDetection.market', market);\r\n const detectedCountry = await detectCountry(request, market.id);\r\n // console.log('routeInterceptor.routeAutoDetection.detectedCountry', detectedCountry);\r\n const detectedMarket = detectedCountry ? (\r\n markets.filter(x => Array.isArray(x.countries)).find(x => {\r\n const countries: string[] = (x.countries || []).map(x => typeof x === 'string' ? x : x.id as string);\r\n return countries.includes(detectedCountry);\r\n }) ||\r\n markets.find(x => !Array.isArray(x.countries))\r\n ) : undefined;\r\n // console.log('routeInterceptor.routeAutoDetection.detectedMarket', detectedMarket);\r\n let detectedMarketRoutes = rootRoutes.filter(x => x.market === detectedMarket?.id);\r\n if (detectedMarketRoutes.length === 0) {\r\n detectedMarketRoutes = rootRoutes.filter(x => x.market === market.id);\r\n }\r\n // console.log('routeInterceptor.routeAutoDetection.detectedMarketRoutes', detectedMarketRoutes);\r\n const defaultMarketLocale = market.defaultLanguage ? (\r\n typeof market.defaultLanguage === 'string' ? market.defaultLanguage : market.defaultLanguage.id\r\n ) as string : defaultLocale;\r\n // console.log('routeInterceptor.routeAutoDetection.defaultMarketLocale', defaultMarketLocale);\r\n const detectedLocale = await detectLocale(request, defaultMarketLocale);\r\n // console.log('routeInterceptor.routeAutoDetection.detectedLocale', detectedLocale);\r\n const detectedLocaleRoutes = detectedMarketRoutes.filter(x => x.locale === detectedLocale);\r\n const detectedRoute =\r\n detectedLocaleRoutes.length > 0 ?\r\n detectedLocaleRoutes[0]! :\r\n detectedMarketRoutes.find(x => {\r\n const market = markets.find(m => m.id === x.market)!;\r\n const marketLocale = (market.defaultLanguage ? asEquatable(market.defaultLanguage as string) : defaultMarketLocale);\r\n return x.locale === marketLocale;\r\n })!;\r\n // console.log('routeInterceptor.routeAutoDetection.detectedRoute', detectedRoute);\r\n if (detectedRoute && detectedRoute.id !== url.pathname) {\r\n debug('routeInterceptor.routeAutoDetection', detectedLocale, detectedCountry, detectedRoute.id);\r\n redirectUrl = detectedRoute.id;\r\n }\r\n // console.log('routeInterceptor.routeAutoDetection', locale, detectedCountry, rootRoutes);\r\n }\r\n if (redirectUrl) {\r\n return createDetectedRouteResponse(request, origin, redirectUrl);\r\n }\r\n};\r\n\r\nfunction createDetectedRouteResponse(request: NextRequest, origin: string, redirectUrl: string) {\r\n const resolvedUrl = new URL(redirectUrl, origin).href;\r\n const search = request.nextUrl.search;\r\n const response = NextResponse.redirect(resolvedUrl + search, { status: 307 });\r\n response.cookies.set({\r\n expires: new Date(Date.now() + 1 * 24 * 60 * 60 * 1000),\r\n httpOnly: true,\r\n name: 'detectedRoute',\r\n path: '/',\r\n sameSite: 'lax',\r\n secure: true,\r\n value: redirectUrl,\r\n });\r\n return response;\r\n}\r\n"],"mappings":";;;;;;;AAMA,eAAsB,aAAaA,SAAsBC,iBAAwB;CAC/E,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,kBAAkB,EAAE,MAAM,IAAI,CAAC;CAC1E,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,cAAc,EAAE,SAAS,kBAAkBC,mBAAiB,QAAQ,IAAI;AACnH,QAAO;AACR;AAED,MAAM,gBAAgB;AACtB,MAAM,kBAAkB,OAAU;AAClC,MAAM,kBAAkB;AAGxB,MAAM,iBAAiB;AAGvB,MAAM,aAAa,eAAe,mCAAmB,IAAI;AAEzD,SAAS,iBAAiBC,IAAgC;CACxD,MAAM,QAAQ,WAAW,IAAI,GAAG;AAChC,KAAI,CAAC,MACH,QAAO;AAET,KAAI,MAAM,UAAU,KAAK,KAAK,EAAE;EAC9B,WAAW,OAAO,GAAG;AACrB,SAAO;CACR;AACD,QAAO,MAAM;AACd;AAED,SAAS,iBAAiBA,IAAYC,SAAiB;AACrD,KAAI,WAAW,QAAQ,iBAAiB;EAEtC,MAAM,SAAS,WAAW,MAAM,CAAC,MAAM,CAAC;AACxC,MAAI,WAAW,QACb,WAAW,OAAO,OAAO;CAE5B;CACD,WAAW,IAAI,IAAI;EAAE;EAAS,SAAS,KAAK,KAAK,GAAG;CAAiB,EAAC;AACvE;;;;;;;;AAMD,SAAgB,qBAAqBC,OAAiC;AACpE,QAAO,QAAQ,SAAS,MAAM,WAAW,IAAI,IAAI,CAAC,MAAM,WAAW,KAAK,IAAI,UAAU,IAAI;AAC3F;AAED,eAAsB,cAAcL,SAAsBM,iBAAwB;CAChF,IAAI,KAAK,QAAQ,QAAQ,IAAI,kBAAkB,IAAI,QAAQ,QAAQ,IAAI,YAAY;AACnF,KAAI,IACF,KAAK,GAAG,MAAM,IAAI,CAAC,GAAI,MAAM;CAE/B,MAAM,YAAY,IAAI,MAAM,mCAAmC;CAC/D,MAAM,gBAAgB,aAAa,KAAK,iBAAiB,GAAG,GAAG;AAC/D,KAAI,kBAAkB,OACpB,QAAO,iBAAiBC,mBAAiB,QAAQ,IAAI;CAEvD,IAAI,kBAAkB;AACtB,KAAI;EACF,MAAM,QAAQ,QAAQ,IAAI;AAC1B,MAAI,OAAO;GACT,MAAM,MAAM,YACV,CAAC,2BAA2B,EAAE,GAAG,oBAAoB,EAAE,OAAO,GAC9D,CAAC,iDAAiD,EAAE,OAAO;GAC7D,MAAM,WAAW,MAAM,MAAM,KAAK,EAAE,QAAQ,YAAY,QAAQ,cAAc,CAAE,EAAC;AACjF,OAAI,SAAS,IAAI;IACf,MAAM,OAAO,MAAM,SAAS,MAAM;IAClC,kBAAkB,KAAK,aAAa;GACrC;EACF,OAAM;GACL,MAAM,MAAM,CAAC,+DAA+D,EAAE,YAAY,KAAK,IAAI;GACnG,MAAM,WAAW,MAAM,MAAM,KAAK,EAAE,QAAQ,YAAY,QAAQ,cAAc,CAAE,EAAC;AACjF,OAAI,SAAS,IAAI;IACf,MAAM,MAAM,MAAM,SAAS,MAAM;IACjC,oBACI,IAAI,MAAM,yBAAyB,CAAC,MAAM,IAAI,MAAM,oBAAoB,CAAC,MAAM,IACjF,QAAQ,KAAK,GAAG,CAAC,aAAa;GAEjC;EACF;AAED,MAAI,aAAa,IACf,iBAAiB,IAAI,gBAAgB;AAEvC,SAAO,mBAAmBA,mBAAiB,QAAQ,IAAI;CACxD,SAAQ,OAAO;EACd,QAAQ,KAAK,wCAAwC,MAAM;CAC5D;AACD,QAAQA,mBAAiB,QAAQ,IAAI;AACtC;AAED,MAAaC,qBAAiC,OAAO,EAAE,SAA4B,KAAK;CACtF,IAAIC,cAAkC;CACtC,MAAM,MAAM,QAAQ;CACpB,MAAM,SAAS,iBAAiB,QAAQ;AACxC,KAAI,IAAI,aAAa,KAAK;EACxB,MAAM,SAAS,QAAQ,QAAQ,IAAI,gBAAgB;AACnD,MAAI,qBAAqB,QAAQ,MAAM,CAGrC,QAAO,4BAA4B,SAAS,QAAQ,OAAO,MAAM;EAGnE,MAAMC,aAAuB,MAAM,YAAY,sCAAsC,CAAE,GAAE,QAAW,OAAO;EAE3G,MAAM,eAAe,WAAW,KAAK,OAAK,EAAE,OAAO,IAAI;AAEvD,MAAI,aACF;EAEF,MAAMC,UAAqB,MAAM,YAAY,4BAA4B,CAAE,GAAE,QAAW,OAAO;EAE/F,MAAM,SAAS,QAAQ,KAAK,OAAK,EAAE,UAAU,IAAI,QAAQ,KAAK,OAAK,EAAE,OAAO,cAAc,IAAI,QAAQ;EAEtG,MAAM,kBAAkB,MAAM,cAAc,SAAS,OAAO,GAAG;EAE/D,MAAM,iBAAiB,kBACrB,QAAQ,OAAO,OAAK,MAAM,QAAQ,EAAE,UAAU,CAAC,CAAC,KAAK,OAAK;GACxD,MAAMC,aAAuB,EAAE,aAAa,CAAE,GAAE,IAAI,SAAK,OAAOC,QAAM,WAAWA,MAAIA,IAAE,GAAa;AACpG,UAAO,UAAU,SAAS,gBAAgB;EAC3C,EAAC,IACF,QAAQ,KAAK,OAAK,CAAC,MAAM,QAAQ,EAAE,UAAU,CAAC,GAC5C;EAEJ,IAAI,uBAAuB,WAAW,OAAO,OAAK,EAAE,WAAW,gBAAgB,GAAG;AAClF,MAAI,qBAAqB,WAAW,GAClC,uBAAuB,WAAW,OAAO,OAAK,EAAE,WAAW,OAAO,GAAG;EAGvE,MAAM,sBAAsB,OAAO,kBACjC,OAAO,OAAO,oBAAoB,WAAW,OAAO,kBAAkB,OAAO,gBAAgB,KACjF;EAEd,MAAM,iBAAiB,MAAM,aAAa,SAAS,oBAAoB;EAEvE,MAAM,uBAAuB,qBAAqB,OAAO,OAAK,EAAE,WAAW,eAAe;EAC1F,MAAM,gBACJ,qBAAqB,SAAS,IAC5B,qBAAqB,KACrB,qBAAqB,KAAK,OAAK;GAC7B,MAAMC,WAAS,QAAQ,KAAK,OAAK,EAAE,OAAO,EAAE,OAAO;GACnD,MAAM,eAAgBA,SAAO,kBAAkB,YAAYA,SAAO,gBAA0B,GAAG;AAC/F,UAAO,EAAE,WAAW;EACrB,EAAC;AAEN,MAAI,iBAAiB,cAAc,OAAO,IAAI,UAAU;GACtD,MAAM,uCAAuC,gBAAgB,iBAAiB,cAAc,GAAG;GAC/F,cAAc,cAAc;EAC7B;CAEF;AACD,KAAI,YACF,QAAO,4BAA4B,SAAS,QAAQ,YAAY;AAEnE;AAED,SAAS,4BAA4Bd,SAAsBe,QAAgBC,aAAqB;CAC9F,MAAM,cAAc,IAAI,IAAI,aAAa,QAAQ;CACjD,MAAM,SAAS,QAAQ,QAAQ;CAC/B,MAAM,WAAW,aAAa,SAAS,cAAc,QAAQ,EAAE,QAAQ,IAAK,EAAC;CAC7E,SAAS,QAAQ,IAAI;EACnB,SAAS,IAAI,KAAK,KAAK,KAAK,GAAG,OAAc,KAAK;EAClD,UAAU;EACV,MAAM;EACN,MAAM;EACN,UAAU;EACV,QAAQ;EACR,OAAO;CACR,EAAC;AACF,QAAO;AACR"}
|
|
1
|
+
{"version":3,"file":"route-auto-detection.js","names":["request: NextRequest","defaultLocale?: string","defaultLocale","ip: string","country: string","value?: string","decoded: string","defaultMarket?: string","defaultMarket","routeAutoDetection: Middleware","redirectUrl: string | undefined","rootRoutes: IRoute[]","markets: IMarket[]","countries: string[]","x","market","origin: string","redirectUrl: string"],"sources":["../../src/proxy/route-auto-detection.ts"],"sourcesContent":["import { asEquatable, defaultLocale, defaultMarket, IMarket, IRoute } from '@websolutespa/bom-core';\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport { debug } from '../lib/debug';\r\nimport { localApiGet } from '../lib/http';\r\nimport { getRequestOrigin, Middleware, MiddlewareOptions } from './proxy';\r\n\r\nexport async function detectLocale(request: NextRequest, defaultLocale?: string) {\r\n const acceptLanguage = request.headers.get('accept-language')?.split(',')[0];\r\n const detectedLocale = request.cookies.get('NEXT_LOCALE')?.value || acceptLanguage || defaultLocale || process.env.DEFAULT_LOCALE;\r\n return detectedLocale as string;\r\n}\r\n\r\nconst GEOIP_TIMEOUT = 2000;\r\nconst GEOIP_CACHE_TTL = 60 * 60 * 1000;\r\nconst GEOIP_CACHE_MAX = 1000;\r\n\r\ntype GeoIpCacheEntry = { country: string; expires: number };\r\nconst globalForGeoIp = globalThis as typeof globalThis & { _bomGeoIpCache?: Map<string, GeoIpCacheEntry> };\r\n// Country lookups are external calls; cache them per IP so repeat visitors\r\n// and crawlers do not hit the GeoIP service on every request to `/`.\r\nconst geoIpCache = globalForGeoIp._bomGeoIpCache ??= new Map<string, GeoIpCacheEntry>();\r\n\r\nfunction getCachedCountry(ip: string): string | undefined {\r\n const entry = geoIpCache.get(ip);\r\n if (!entry) {\r\n return undefined;\r\n }\r\n if (entry.expires < Date.now()) {\r\n geoIpCache.delete(ip);\r\n return undefined;\r\n }\r\n return entry.country;\r\n}\r\n\r\nfunction setCachedCountry(ip: string, country: string) {\r\n if (geoIpCache.size >= GEOIP_CACHE_MAX) {\r\n // Maps iterate in insertion order, so the first key is the oldest entry.\r\n const oldest = geoIpCache.keys().next().value;\r\n if (oldest !== undefined) {\r\n geoIpCache.delete(oldest);\r\n }\r\n }\r\n geoIpCache.set(ip, { country, expires: Date.now() + GEOIP_CACHE_TTL });\r\n}\r\n\r\n/**\r\n * A relative, same-origin path previously set by this middleware. Anything\r\n * else (absolute or protocol-relative URLs) is ignored to avoid open redirects.\r\n */\r\nexport function isValidDetectedRoute(value?: string): value is string {\r\n if (!value || !value.startsWith('/') || value.startsWith('//') || value === '/' || value.includes('\\\\')) {\r\n return false;\r\n }\r\n // dot segments (also percent-encoded) would resolve to a different path on redirect\r\n let decoded: string;\r\n try {\r\n decoded = decodeURIComponent(value);\r\n } catch {\r\n return false;\r\n }\r\n return !decoded.split(/[/?#]/).some(segment => segment === '.' || segment === '..') && !decoded.includes('\\\\');\r\n}\r\n\r\nexport async function detectCountry(request: NextRequest, defaultMarket?: string) {\r\n let ip = request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip');\r\n if (ip) {\r\n ip = ip.split(',')[0]!.trim();\r\n }\r\n const isValidIp = ip?.match(/^(\\d+?)\\.(\\d+?)\\.(\\d+?)\\.(\\d+?)$/);\r\n const cachedCountry = isValidIp && ip ? getCachedCountry(ip) : undefined;\r\n if (cachedCountry !== undefined) {\r\n return cachedCountry || defaultMarket || process.env.DEFAULT_MARKET;\r\n }\r\n let detectedCountry = '';\r\n try {\r\n const token = process.env.IPINFO_TOKEN;\r\n if (token) {\r\n const url = isValidIp ?\r\n `https://api.ipinfo.io/lite/${ip}/country_code?token=${token}` :\r\n `https://api.ipinfo.io/lite/me/country_code?token=${token}`;\r\n const response = await fetch(url, { signal: AbortSignal.timeout(GEOIP_TIMEOUT) });\r\n if (response.ok) {\r\n const data = await response.text();\r\n detectedCountry = data.toLowerCase();\r\n }\r\n } else {\r\n const url = `https://geoip.websolute.it/Ip2Location/get_info.aspx?ipaddress=${isValidIp ? ip : ''}`;\r\n const response = await fetch(url, { signal: AbortSignal.timeout(GEOIP_TIMEOUT) });\r\n if (response.ok) {\r\n const xml = await response.text();\r\n detectedCountry = (\r\n ((xml.split('<CountryCode><![CDATA[')[1] || '').split(']]></CountryCode>')[0] || '')\r\n ).replace('-', '').toLowerCase();\r\n // console.log('detectedCountry', detectedCountry);\r\n }\r\n }\r\n // console.log('routeInterceptor.detectCountry', detectedCountry);\r\n if (isValidIp && ip) {\r\n setCachedCountry(ip, detectedCountry);\r\n }\r\n return detectedCountry || defaultMarket || process.env.DEFAULT_MARKET;\r\n } catch (error) {\r\n console.warn('routeInterceptor.detectCountry.error', error);\r\n }\r\n return (defaultMarket || process.env.DEFAULT_MARKET) as string;\r\n}\r\n\r\nexport const routeAutoDetection: Middleware = async ({ request }: MiddlewareOptions) => {\r\n let redirectUrl: string | undefined = undefined;\r\n const url = request.nextUrl;\r\n const origin = getRequestOrigin(request);\r\n if (url.pathname === '/') {\r\n const cookie = request.cookies.get('detectedRoute');\r\n if (isValidDetectedRoute(cookie?.value)) {\r\n // The cookie is only set after a successful detection, so trust it and\r\n // skip the route, market and GeoIP lookups entirely.\r\n return createDetectedRouteResponse(request, origin, cookie.value);\r\n }\r\n // console.log('routeInterceptor.routeAutoDetection', url.pathname);\r\n const rootRoutes: IRoute[] = await localApiGet('/-route?where[isRoot][equals]=true', {}, undefined, origin);\r\n // console.log('routeInterceptor.routeAutoDetection.rootRoutes', rootRoutes);\r\n const defaultRoute = rootRoutes.find(x => x.id === '/');\r\n // console.log('routeInterceptor.routeAutoDetection.defaultRoute', defaultRoute);\r\n if (defaultRoute) {\r\n return;\r\n }\r\n const markets: IMarket[] = await localApiGet('/market?pagination=false', {}, undefined, origin);\r\n // console.log('routeInterceptor.routeAutoDetection.markets', markets);\r\n const market = markets.find(x => x.isDefault) || markets.find(x => x.id === defaultMarket) || markets[0];\r\n // console.log('routeInterceptor.routeAutoDetection.market', market);\r\n const detectedCountry = await detectCountry(request, market.id);\r\n // console.log('routeInterceptor.routeAutoDetection.detectedCountry', detectedCountry);\r\n const detectedMarket = detectedCountry ? (\r\n markets.filter(x => Array.isArray(x.countries)).find(x => {\r\n const countries: string[] = (x.countries || []).map(x => typeof x === 'string' ? x : x.id as string);\r\n return countries.includes(detectedCountry);\r\n }) ||\r\n markets.find(x => !Array.isArray(x.countries))\r\n ) : undefined;\r\n // console.log('routeInterceptor.routeAutoDetection.detectedMarket', detectedMarket);\r\n let detectedMarketRoutes = rootRoutes.filter(x => x.market === detectedMarket?.id);\r\n if (detectedMarketRoutes.length === 0) {\r\n detectedMarketRoutes = rootRoutes.filter(x => x.market === market.id);\r\n }\r\n // console.log('routeInterceptor.routeAutoDetection.detectedMarketRoutes', detectedMarketRoutes);\r\n const defaultMarketLocale = market.defaultLanguage ? (\r\n typeof market.defaultLanguage === 'string' ? market.defaultLanguage : market.defaultLanguage.id\r\n ) as string : defaultLocale;\r\n // console.log('routeInterceptor.routeAutoDetection.defaultMarketLocale', defaultMarketLocale);\r\n const detectedLocale = await detectLocale(request, defaultMarketLocale);\r\n // console.log('routeInterceptor.routeAutoDetection.detectedLocale', detectedLocale);\r\n const detectedLocaleRoutes = detectedMarketRoutes.filter(x => x.locale === detectedLocale);\r\n const detectedRoute =\r\n detectedLocaleRoutes.length > 0 ?\r\n detectedLocaleRoutes[0]! :\r\n detectedMarketRoutes.find(x => {\r\n const market = markets.find(m => m.id === x.market)!;\r\n const marketLocale = (market.defaultLanguage ? asEquatable(market.defaultLanguage as string) : defaultMarketLocale);\r\n return x.locale === marketLocale;\r\n })!;\r\n // console.log('routeInterceptor.routeAutoDetection.detectedRoute', detectedRoute);\r\n if (detectedRoute && detectedRoute.id !== url.pathname) {\r\n debug('routeInterceptor.routeAutoDetection', detectedLocale, detectedCountry, detectedRoute.id);\r\n redirectUrl = detectedRoute.id;\r\n }\r\n // console.log('routeInterceptor.routeAutoDetection', locale, detectedCountry, rootRoutes);\r\n }\r\n if (redirectUrl) {\r\n return createDetectedRouteResponse(request, origin, redirectUrl);\r\n }\r\n};\r\n\r\nfunction createDetectedRouteResponse(request: NextRequest, origin: string, redirectUrl: string) {\r\n const resolvedUrl = new URL(redirectUrl, origin).href;\r\n const search = request.nextUrl.search;\r\n const response = NextResponse.redirect(resolvedUrl + search, { status: 307 });\r\n response.cookies.set({\r\n expires: new Date(Date.now() + 1 * 24 * 60 * 60 * 1000),\r\n httpOnly: true,\r\n name: 'detectedRoute',\r\n path: '/',\r\n sameSite: 'lax',\r\n secure: true,\r\n value: redirectUrl,\r\n });\r\n return response;\r\n}\r\n"],"mappings":"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"}
|
package/dist/server/helpers.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IPageContext, LayoutContextOptions, LayoutOption, LayoutOptions, PageContextOptions, PageSelect,
|
|
1
|
+
import { IPageContext, LayoutContextOptions, LayoutOption, LayoutOptions, PageContextOptions, PageSelect, TypedPageContext } from "../types.js";
|
|
2
2
|
import { CollectionSlug, SanitizedConfig } from "payload";
|
|
3
3
|
import * as next0 from "next";
|
|
4
4
|
|
|
@@ -40,7 +40,6 @@ declare function createContextHelpers({
|
|
|
40
40
|
locale: string;
|
|
41
41
|
id: string;
|
|
42
42
|
}>;
|
|
43
|
-
searchParams?: Promise<SearchParams>;
|
|
44
43
|
}>, _parent?: next0.ResolvingMetadata) => Promise<next0.Metadata>;
|
|
45
44
|
};
|
|
46
45
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","names":[],"sources":["../../src/server/helpers.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AACkH;;KAS7G,eAAA,GAAkB,IAAK,CAAA,kBAAA,EAAA,QAAA,GAAA,SAAA,GAAA,QAAA,GAAA,UAAA,GAAA,OAAA,GAAA,QAAA,CAAA,GAAA;EAAkB,MAAvB,CAAA,EACZ,aADY;CAAI;AACH,KAGnB,WAHmB,CAAA,cAGO,cAHP,EAAA,gBAGuC,UAHvC,CAGkD,KAHlD,CAAA,EAAA,gBAG0E,YAH1E,CAAA,GAItB,IAJsB,CAIjB,kBAJiB,CAIE,KAJF,EAIS,OAJT,EAIkB,OAJlB,CAAA,EAAA,QAAA,CAAA,GAAA;EAGnB,MAAA,CAAA,EACsE,OAD3D,CACmE,eADnE,CAAA;CAAA;;;;;;;;;;AACmE,iBAWnE,oBAAA,CAXmE;EAAA,MAAA;EAAA;AAWnF,CAXmF,EAAA;EAAe,MAAvB,EAejE,OAfiE,CAezD,eAfyD,CAAA;EAAO,QAAA,CAAA,EAgBrE,eAhBqE;AAWlF,CAAA,CAAA,EAAgB;EAAoB,iBAAA,CAAA,cAYA,cAZA,EAAA,gBAYgC,UAZhC,CAY2C,KAZ3C,CAAA,GAAA,SAAA,EAAA,gBAY+E,YAZ/E,GAY2F,aAZ3F,CAAA,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,IAAA,EAaQ,KAbR,EAAA,EAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAaqC,WAbrC,CAaiD,KAbjD,EAawD,OAbxD,EAaiE,OAbjE,CAAA,CAAA,EAayE,OAbzE,CAayE,gBAbzE,CAayE,KAbzE,EAayE,OAbzE,EAayE,OAbzE,CAAA,CAAA;EAAA,qBAClC,CAAA,cAgBsC,cAhBtC,EAAA,gBAgBsE,UAhBtE,CAgBiF,KAhBjF,CAAA,GAAA,SAAA,EAAA,gBAgBqH,YAhBrH,GAgBiI,aAhBjI,CAAA,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,IAAA,EAiB0C,KAjB1C,EAAA,EAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAiBuE,WAjBvE,CAiBmF,KAjBnF,EAiB0F,OAjB1F,EAiBmG,OAjBnG,CAAA,CAAA,EAiB2G,OAjB3G,CAiB2G,gBAjB3G,CAiB2G,KAjB3G,EAiB2G,OAjB3G,EAiB2G,OAjB3G,CAAA,CAAA;EAAM,mBACN,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAoBgE,OApBhE,CAoBwE,oBApBxE,CAAA,CAAA,EAoB6F,OApB7F,CAoBuE,YAAA,CApBvE;EAAa,WAEG,CAAA,cAqBY,cArBZ,EAAA,gBAqB4C,UArB5C,CAqBuD,KArBvD,CAAA,GAAA,SAAA,CAAA,CAAA,IAAA,EAsBN,KAtBM,EAAA,OAAA,CAAA,EAsBW,IAtBX,CAsBgB,kBAtBhB,CAsBmC,KAtBnC,EAsB0C,OAtB1C,EAsBmD,YAtBnD,CAAA,EAAA,QAAA,CAAA,CAAA,EAAA,CAAA,KAAA,EAsB2E,QAtB3E,CAAA;IAAR,MAAA,EAsBuB,OAtBvB,CAAA;MACG,MAAA,EAAA,MAAA;MAOuB,MAAA,EAAA,MAAA;MAA2C,EAAA,EAAA,MAAA;IAAX,CAAA,CAAA;
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","names":[],"sources":["../../src/server/helpers.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AACkH;;KAS7G,eAAA,GAAkB,IAAK,CAAA,kBAAA,EAAA,QAAA,GAAA,SAAA,GAAA,QAAA,GAAA,UAAA,GAAA,OAAA,GAAA,QAAA,CAAA,GAAA;EAAkB,MAAvB,CAAA,EACZ,aADY;CAAI;AACH,KAGnB,WAHmB,CAAA,cAGO,cAHP,EAAA,gBAGuC,UAHvC,CAGkD,KAHlD,CAAA,EAAA,gBAG0E,YAH1E,CAAA,GAItB,IAJsB,CAIjB,kBAJiB,CAIE,KAJF,EAIS,OAJT,EAIkB,OAJlB,CAAA,EAAA,QAAA,CAAA,GAAA;EAGnB,MAAA,CAAA,EACsE,OAD3D,CACmE,eADnE,CAAA;CAAA;;;;;;;;;;AACmE,iBAWnE,oBAAA,CAXmE;EAAA,MAAA;EAAA;AAWnF,CAXmF,EAAA;EAAe,MAAvB,EAejE,OAfiE,CAezD,eAfyD,CAAA;EAAO,QAAA,CAAA,EAgBrE,eAhBqE;AAWlF,CAAA,CAAA,EAAgB;EAAoB,iBAAA,CAAA,cAYA,cAZA,EAAA,gBAYgC,UAZhC,CAY2C,KAZ3C,CAAA,GAAA,SAAA,EAAA,gBAY+E,YAZ/E,GAY2F,aAZ3F,CAAA,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,IAAA,EAaQ,KAbR,EAAA,EAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAaqC,WAbrC,CAaiD,KAbjD,EAawD,OAbxD,EAaiE,OAbjE,CAAA,CAAA,EAayE,OAbzE,CAayE,gBAbzE,CAayE,KAbzE,EAayE,OAbzE,EAayE,OAbzE,CAAA,CAAA;EAAA,qBAClC,CAAA,cAgBsC,cAhBtC,EAAA,gBAgBsE,UAhBtE,CAgBiF,KAhBjF,CAAA,GAAA,SAAA,EAAA,gBAgBqH,YAhBrH,GAgBiI,aAhBjI,CAAA,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,IAAA,EAiB0C,KAjB1C,EAAA,EAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAiBuE,WAjBvE,CAiBmF,KAjBnF,EAiB0F,OAjB1F,EAiBmG,OAjBnG,CAAA,CAAA,EAiB2G,OAjB3G,CAiB2G,gBAjB3G,CAiB2G,KAjB3G,EAiB2G,OAjB3G,EAiB2G,OAjB3G,CAAA,CAAA;EAAM,mBACN,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAoBgE,OApBhE,CAoBwE,oBApBxE,CAAA,CAAA,EAoB6F,OApB7F,CAoBuE,YAAA,CApBvE;EAAa,WAEG,CAAA,cAqBY,cArBZ,EAAA,gBAqB4C,UArB5C,CAqBuD,KArBvD,CAAA,GAAA,SAAA,CAAA,CAAA,IAAA,EAsBN,KAtBM,EAAA,OAAA,CAAA,EAsBW,IAtBX,CAsBgB,kBAtBhB,CAsBmC,KAtBnC,EAsB0C,OAtB1C,EAsBmD,YAtBnD,CAAA,EAAA,QAAA,CAAA,CAAA,EAAA,CAAA,KAAA,EAsB2E,QAtB3E,CAAA;IAAR,MAAA,EAsBuB,OAtBvB,CAAA;MACG,MAAA,EAAA,MAAA;MAOuB,MAAA,EAAA,MAAA;MAA2C,EAAA,EAAA,MAAA;IAAX,CAAA,CAAA;EAAU,CAAA,CAAA,EAAqC,OAAA,CAAA,EActB,KAAA,CAAA,iBAdsB,EAAA,UAAA,gBAAA;CAAY"}
|
package/dist/server/json-ld.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PageMetadataOptions } from "../lib/page-metadata.js";
|
|
2
2
|
import { ILayout, IPage } from "@websolutespa/bom-core";
|
|
3
|
-
import * as
|
|
3
|
+
import * as react23 from "react";
|
|
4
4
|
import { WebPage, WithContext } from "schema-dts";
|
|
5
5
|
|
|
6
6
|
//#region src/server/json-ld.d.ts
|
|
@@ -25,7 +25,7 @@ declare function JsonLd({
|
|
|
25
25
|
data
|
|
26
26
|
}: {
|
|
27
27
|
data: object;
|
|
28
|
-
}):
|
|
28
|
+
}): react23.JSX.Element;
|
|
29
29
|
//# sourceMappingURL=json-ld.d.ts.map
|
|
30
30
|
|
|
31
31
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-ld.d.ts","names":[],"sources":["../../src/server/json-ld.tsx"],"sourcesContent":[],"mappings":";;;;;;KAKY,yBAAA,GAA4B,KAAK;;;IAAjC,IAAA,CAAA,EAAA,MAAA;IAAyB,GAAA,CAAA,EAAA,MAAA;IAAQ,MAAA,CAAA,EAKhC,MALgC,CAAA,MAAA,EAAA,MAAA,CAAA;EAAmB,CAAA;CAApB;AAKzB;AAQnB;;;AAA8D,iBAA9C,uBAAA,CAA8C,IAAA,EAAhB,KAAgB,EAAA,MAAA,CAAA,EAAA,OAAA,EAAA,OAAA,CAAA,EAAkB,yBAAlB,CAAA,EAAmD,WAAnD,CAA+D,OAA/D,CAAA;;;;AAA8D;AA4B5G,iBAAA,MAAA,CAAM;EAAA;CAAA,EAAA;EAAA,IAAA,EAAA,MAAA;CAAA,CAAA,EAA2B,
|
|
1
|
+
{"version":3,"file":"json-ld.d.ts","names":[],"sources":["../../src/server/json-ld.tsx"],"sourcesContent":[],"mappings":";;;;;;KAKY,yBAAA,GAA4B,KAAK;;;IAAjC,IAAA,CAAA,EAAA,MAAA;IAAyB,GAAA,CAAA,EAAA,MAAA;IAAQ,MAAA,CAAA,EAKhC,MALgC,CAAA,MAAA,EAAA,MAAA,CAAA;EAAmB,CAAA;CAApB;AAKzB;AAQnB;;;AAA8D,iBAA9C,uBAAA,CAA8C,IAAA,EAAhB,KAAgB,EAAA,MAAA,CAAA,EAAA,OAAA,EAAA,OAAA,CAAA,EAAkB,yBAAlB,CAAA,EAAmD,WAAnD,CAA+D,OAA/D,CAAA;;;;AAA8D;AA4B5G,iBAAA,MAAA,CAAM;EAAA;CAAA,EAAA;EAAA,IAAA,EAAA,MAAA;CAAA,CAAA,EAA2B,OAAA,CAAA,GAAA,CAAA,OAAxB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LayoutOption, PageContextOptions, PageParams, PageSelect
|
|
1
|
+
import { LayoutOption, PageContextOptions, PageParams, PageSelect } from "../types.js";
|
|
2
2
|
import { PageMetadataBrand, PageMetadataContext, PageMetadataOptions, PageMetadataSearchParams, buildPageMetadata, getPageAlternates, getPageXDefault, getPaginationQuery, inheritParentMetadata, resolveMetadataUrl, toPlainText } from "../lib/page-metadata.js";
|
|
3
3
|
import { CollectionSlug, SanitizedConfig } from "payload";
|
|
4
4
|
import { Metadata, ResolvingMetadata } from "next";
|
|
@@ -6,7 +6,6 @@ import { Metadata, ResolvingMetadata } from "next";
|
|
|
6
6
|
//#region src/server/metadata.d.ts
|
|
7
7
|
type PageMetadataProps = Readonly<{
|
|
8
8
|
params: Promise<PageParams>;
|
|
9
|
-
searchParams?: Promise<SearchParams>;
|
|
10
9
|
}>;
|
|
11
10
|
type GetPageMetadataOptions<TSlug extends CollectionSlug, TSelect extends PageSelect<TSlug> = undefined> = PageContextOptions<TSlug, TSelect, LayoutOption> & {
|
|
12
11
|
metadata?: PageMetadataOptions;
|
|
@@ -19,6 +18,11 @@ type GetPageMetadataOptions<TSlug extends CollectionSlug, TSelect extends PageSe
|
|
|
19
18
|
* It uses the same defaults as `createPageContext`, so the page read is
|
|
20
19
|
* memoized and shared with the page component within the same request.
|
|
21
20
|
* Pass the same options used by the page (depth, select, headers…) to hit that cache.
|
|
21
|
+
*
|
|
22
|
+
* It reads only `params`, never request data, so static/ISR pages stay static.
|
|
23
|
+
* A dynamic template (e.g. a paginated listing that wants `pagination[page]` in
|
|
24
|
+
* the canonical) writes its own `generateMetadata`, awaits its own
|
|
25
|
+
* `props.searchParams` and passes it to `buildPageMetadata(page, layout, { searchParams })`.
|
|
22
26
|
*/
|
|
23
27
|
declare function getPageMetadata<TSlug extends CollectionSlug, TSelect extends PageSelect<TSlug> = undefined>(slug: TSlug, options: GetPageMetadataOptions<TSlug, TSelect>): (props: PageMetadataProps, _parent?: ResolvingMetadata) => Promise<Metadata>;
|
|
24
28
|
/**
|
|
@@ -31,7 +35,6 @@ declare function getMetadata<TSlug extends CollectionSlug, TSelect extends PageS
|
|
|
31
35
|
locale: string;
|
|
32
36
|
id: string;
|
|
33
37
|
}>;
|
|
34
|
-
searchParams?: Promise<SearchParams>;
|
|
35
38
|
}>, _parent?: ResolvingMetadata) => Promise<Metadata>;
|
|
36
39
|
//# sourceMappingURL=metadata.d.ts.map
|
|
37
40
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadata.d.ts","names":[],"sources":["../../src/server/metadata.ts"],"sourcesContent":[],"mappings":";;;;;;KAQY,iBAAA,GAAoB;EAApB,MAAA,EACA,OADA,CACQ,UADS,CAAA;
|
|
1
|
+
{"version":3,"file":"metadata.d.ts","names":[],"sources":["../../src/server/metadata.ts"],"sourcesContent":[],"mappings":";;;;;;KAQY,iBAAA,GAAoB;EAApB,MAAA,EACA,OADA,CACQ,UADS,CAAA;CAAA,CAAA;AACT,KAGR,sBAHQ,CAAA,cAG6B,cAH7B,EAAA,gBAG6D,UAH7D,CAGwE,KAHxE,CAAA,GAAA,SAAA,CAAA,GAIhB,kBAJgB,CAIG,KAJH,EAIU,OAJV,EAImB,YAJnB,CAAA,GAAA;EAAU,QAAlB,CAAA,EAKO,mBALP;CAAO;AADqB;AAIxC;;;;;;;;;;AAEsC;AAiBtC;;AAA8C,iBAA9B,eAA8B,CAAA,cAAA,cAAA,EAAA,gBAAgC,UAAhC,CAA2C,KAA3C,CAAA,GAAA,SAAA,CAAA,CAAA,IAAA,EACpC,KADoC,EAAA,OAAA,EAEjC,sBAFiC,CAEV,KAFU,EAEH,OAFG,CAAA,CAAA,EAAA,CAAA,KAAA,EAM/B,iBAN+B,EAAA,OAAA,CAAA,EAO5B,iBAP4B,EAAA,GAQvC,OARuC,CAQ/B,QAR+B,CAAA;;;;;AAEH,iBAqB3B,WArB2B,CAAA,cAqBD,cArBC,EAAA,gBAqB+B,UArB/B,CAqB0C,KArB1C,CAAA,GAAA,SAAA,CAAA,CAAA,IAAA,EAsBjC,KAtBiC,EAAA,MAAA,EAuB/B,OAvB+B,CAuBvB,eAvBuB,CAAA,EAAA,OAAA,CAAA,EAwB7B,IAxB6B,CAwBxB,sBAxBwB,CAwBD,KAxBC,EAwBM,OAxBN,CAAA,EAAA,QAAA,CAAA,CAAA,EAAA,CAAA,KAAA,EAwByB,QAxBzB,CAAA;EAAO,MAArC,EAwBK,OAxBL,CAAA;IAIE,MAAA,EAAA,MAAA;IACG,MAAA,EAAA,MAAA;IACH,EAAA,EAAA,MAAA;EAAQ,CAAA,CAAA;AAAT,CAAA,CAAA,EAAA,OAAA,CAAA,EADI,iBACJ,EAAA,GAAP,OAAO,CAAC,QAAD,CAAA;AAed"}
|