@websolutespa/bom-next 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/README.md +11 -0
- package/dist/config.client-B8As5DY0.js +2 -0
- package/dist/config.edge-B8As5DY0.js +2 -0
- package/dist/config.server-B8As5DY0.js +2 -0
- package/dist/exports/client-xcFJNcG7.d.ts +979 -0
- package/dist/exports/client-xcFJNcG7.d.ts.map +1 -0
- package/dist/exports/client.js +5735 -0
- package/dist/exports/client.js.map +1 -0
- package/dist/exports/instrumentation-DBO6QH4d.d.ts +13 -0
- package/dist/exports/instrumentation-DBO6QH4d.d.ts.map +1 -0
- package/dist/exports/instrumentation.js +25 -0
- package/dist/exports/instrumentation.js.map +1 -0
- package/dist/exports/proxy-Cv7QFVci.d.ts +71 -0
- package/dist/exports/proxy-Cv7QFVci.d.ts.map +1 -0
- package/dist/exports/proxy.js +254 -0
- package/dist/exports/proxy.js.map +1 -0
- package/dist/exports/server-BHObJHJ6.d.ts +402 -0
- package/dist/exports/server-BHObJHJ6.d.ts.map +1 -0
- package/dist/exports/server.js +1974 -0
- package/dist/exports/server.js.map +1 -0
- package/dist/http-_2M-UFRx.js +61 -0
- package/dist/http-_2M-UFRx.js.map +1 -0
- package/dist/index-CdYcvudT.d.ts +4 -0
- package/dist/index-CtfAJ0y7.d.ts +499 -0
- package/dist/index-CtfAJ0y7.d.ts.map +1 -0
- package/dist/index.js +201 -0
- package/dist/index.js.map +1 -0
- package/dist/route-DzFwERQP.js +65 -0
- package/dist/route-DzFwERQP.js.map +1 -0
- package/dist/store-CJzqrHsl.js +73 -0
- package/dist/store-CJzqrHsl.js.map +1 -0
- package/dist/types-BatUTdbZ.d.ts +15 -0
- package/dist/types-BatUTdbZ.d.ts.map +1 -0
- package/dist/types-D29_snYY.d.ts +191 -0
- package/dist/types-D29_snYY.d.ts.map +1 -0
- package/dist/utils-Ca7xh5mm.js +78 -0
- package/dist/utils-Ca7xh5mm.js.map +1 -0
- package/dist/utils-YwteTbk7.js +23 -0
- package/dist/utils-YwteTbk7.js.map +1 -0
- package/package.json +156 -0
- package/src/client/client.tsx +18 -0
- package/src/client/extra.tsx +21 -0
- package/src/client/label.tsx +24 -0
- package/src/client/layout.tsx +22 -0
- package/src/client/local.collection.ts +33 -0
- package/src/client/metadata.tsx +217 -0
- package/src/client/page.tsx +22 -0
- package/src/client/useApi.test.tsx +203 -0
- package/src/client/useApi.ts +59 -0
- package/src/client/useCollectionApi.test.tsx +201 -0
- package/src/client/useCollectionApi.ts +66 -0
- package/src/client/useExtra.tsx +12 -0
- package/src/client/useHttp.ts +54 -0
- package/src/client/useLabel.test.tsx +76 -0
- package/src/client/useLabel.tsx +12 -0
- package/src/client/useLayout.tsx +13 -0
- package/src/client/useLink.tsx +13 -0
- package/src/client/useMetaData.tsx +12 -0
- package/src/client/usePage.tsx +12 -0
- package/src/client/useUser.tsx +12 -0
- package/src/client/user.tsx +43 -0
- package/src/exports/client.ts +20 -0
- package/src/exports/instrumentation.ts +1 -0
- package/src/exports/proxy.ts +5 -0
- package/src/exports/server.ts +19 -0
- package/src/global.d.ts +6 -0
- package/src/index.ts +17 -0
- package/src/instrumentation/client.ts +19 -0
- package/src/instrumentation/sentry/capture.requestError.ts +6 -0
- package/src/instrumentation/sentry/capture.routerTransitionStart.ts +4 -0
- package/src/instrumentation/sentry/config.client.ts +9 -0
- package/src/instrumentation/sentry/config.edge.ts +9 -0
- package/src/instrumentation/sentry/config.server.ts +9 -0
- package/src/instrumentation/server.ts +24 -0
- package/src/instrumentation/types.ts +12 -0
- package/src/lib/breadcrumb.ts +21 -0
- package/src/lib/const.ts +3 -0
- package/src/lib/http.test.ts +25 -0
- package/src/lib/http.ts +74 -0
- package/src/lib/label.ts +43 -0
- package/src/lib/layout.defaults.ts +167 -0
- package/src/lib/link.ts +19 -0
- package/src/lib/meta-data.ts +60 -0
- package/src/lib/open-graph.ts +165 -0
- package/src/lib/pagination.ts +78 -0
- package/src/lib/payload.config.ts +12 -0
- package/src/lib/route.ts +83 -0
- package/src/lib/store.ts +63 -0
- package/src/lib/structured-data.ts +24 -0
- package/src/lib/twitter-card.ts +49 -0
- package/src/lib/utils.ts +45 -0
- package/src/mock.ts +264 -0
- package/src/proxy/protected-route.test.ts +75 -0
- package/src/proxy/protected-route.ts +57 -0
- package/src/proxy/proxy.test.ts +48 -0
- package/src/proxy/proxy.ts +64 -0
- package/src/proxy/route-auto-detection.ts +126 -0
- package/src/proxy/route-proxy.ts +187 -0
- package/src/server/context.ts +147 -0
- package/src/server/handlers/auth.handler.ts +27 -0
- package/src/server/handlers/captions.handler.ts +32 -0
- package/src/server/handlers/collection.handler.test.ts +57 -0
- package/src/server/handlers/collection.handler.ts +212 -0
- package/src/server/handlers/error-response.ts +45 -0
- package/src/server/handlers/index.handler.ts +146 -0
- package/src/server/handlers/preview.handler.ts +63 -0
- package/src/server/handlers/registry.handler.test.ts +65 -0
- package/src/server/handlers/registry.handler.ts +259 -0
- package/src/server/handlers/route.handler.ts +161 -0
- package/src/server/handlers/sitemap.handler.ts +374 -0
- package/src/server/handlers/static-params.handler.ts +111 -0
- package/src/server/handlers/vars.handler.ts +167 -0
- package/src/server/layout.ts +120 -0
- package/src/server/lazy.ts +41 -0
- package/src/server/local-api.ts +63 -0
- package/src/server/metadata.ts +87 -0
- package/src/server/mixer-payload.ts +124 -0
- package/src/server/mixer-payload.type-test.ts +27 -0
- package/src/server/mixer.ts +439 -0
- package/src/server/mock/category.ts +34 -0
- package/src/server/mock/collection.ts +21 -0
- package/src/server/mock/page.ts +62 -0
- package/src/server/mock/route.ts +36 -0
- package/src/server/mock/store.ts +159 -0
- package/src/server/page.ts +86 -0
- package/src/server/session/session.ts +101 -0
- package/src/server/utils.ts +23 -0
- package/src/server/utmz.ts +11 -0
- package/src/types.ts +211 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ILayout, ILocalized, IPage } from '@websolutespa/bom-core';
|
|
2
|
+
import { ContactPoint, Organization, PostalAddress } from 'schema-dts';
|
|
3
|
+
import { OpenGraphType } from './open-graph';
|
|
4
|
+
import { StructuredDataType } from './structured-data';
|
|
5
|
+
import { TwitterCardType } from './twitter-card';
|
|
6
|
+
|
|
7
|
+
export type IBrand = {
|
|
8
|
+
name: string;
|
|
9
|
+
businessName: string;
|
|
10
|
+
appName: string;
|
|
11
|
+
logo: string;
|
|
12
|
+
url: string;
|
|
13
|
+
// contact
|
|
14
|
+
email?: string;
|
|
15
|
+
telephone?: string;
|
|
16
|
+
// address
|
|
17
|
+
address?: string;
|
|
18
|
+
city?: string;
|
|
19
|
+
zipCode?: string;
|
|
20
|
+
provinceCode?: string;
|
|
21
|
+
countryCode?: string;
|
|
22
|
+
twitterName?: string;
|
|
23
|
+
social?: Record<string, string>;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type IAlternate = {
|
|
27
|
+
id: string;
|
|
28
|
+
href: string;
|
|
29
|
+
hrefLang: string;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type IMeta = {
|
|
33
|
+
title: string;
|
|
34
|
+
description?: string;
|
|
35
|
+
image: string;
|
|
36
|
+
slug: string;
|
|
37
|
+
url: string;
|
|
38
|
+
canonical: string;
|
|
39
|
+
alternates: IAlternate[];
|
|
40
|
+
xDefault?: IAlternate;
|
|
41
|
+
keywords?: string;
|
|
42
|
+
robots?: string;
|
|
43
|
+
/*
|
|
44
|
+
relPrev?: string;
|
|
45
|
+
relNext?: string;
|
|
46
|
+
*/
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export type IMetaData = {
|
|
50
|
+
layout: ILayout;
|
|
51
|
+
page: ILocalized<IPage>;
|
|
52
|
+
brand: IBrand;
|
|
53
|
+
contactPoint: ContactPoint;
|
|
54
|
+
meta: IMeta;
|
|
55
|
+
openGraph: OpenGraphType;
|
|
56
|
+
organization: Organization;
|
|
57
|
+
postalAddress: PostalAddress;
|
|
58
|
+
structuredData: StructuredDataType;
|
|
59
|
+
twitterCard?: TwitterCardType;
|
|
60
|
+
};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
// Open Graph Types
|
|
2
|
+
|
|
3
|
+
export interface OpenGraphBase {
|
|
4
|
+
type: string;
|
|
5
|
+
title?: string;
|
|
6
|
+
image?: string | OpenGraphImage | OpenGraphImage[];
|
|
7
|
+
url?: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
siteName?: string;
|
|
10
|
+
locale?: string;
|
|
11
|
+
localeAlternate?: string[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface OpenGraphImage {
|
|
15
|
+
url: string;
|
|
16
|
+
secureUrl?: string;
|
|
17
|
+
type?: string;
|
|
18
|
+
width?: number;
|
|
19
|
+
height?: number;
|
|
20
|
+
alt?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface OpenGraphAudio {
|
|
24
|
+
url: string;
|
|
25
|
+
secureUrl?: string;
|
|
26
|
+
type?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface OpenGraphWebsite extends OpenGraphBase {
|
|
30
|
+
type: 'website';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface OpenGraphArticle extends OpenGraphBase {
|
|
34
|
+
type: 'article';
|
|
35
|
+
publishedTime?: string;
|
|
36
|
+
modifiedTime?: string;
|
|
37
|
+
expirationTime?: string;
|
|
38
|
+
author?: string | string[];
|
|
39
|
+
section?: string;
|
|
40
|
+
tag?: string | string[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface OpenGraphBook extends OpenGraphBase {
|
|
44
|
+
type: 'book';
|
|
45
|
+
author?: string | string[];
|
|
46
|
+
isbn?: string;
|
|
47
|
+
releaseDate?: string;
|
|
48
|
+
tag?: string | string[];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface OpenGraphProfile extends OpenGraphBase {
|
|
52
|
+
type: 'profile';
|
|
53
|
+
firstName?: string;
|
|
54
|
+
lastName?: string;
|
|
55
|
+
username?: string;
|
|
56
|
+
gender?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface OpenGraphMusic extends OpenGraphBase {
|
|
60
|
+
type: 'music.song' | 'music.album' | 'music.playlist' | 'music.radio_station';
|
|
61
|
+
duration?: number;
|
|
62
|
+
album?: string | string[];
|
|
63
|
+
musician?: string | string[];
|
|
64
|
+
song?: string | string[];
|
|
65
|
+
creator?: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface OpenGraphVideo extends Omit<OpenGraphBase, 'type'> {
|
|
69
|
+
type: 'video.movie' | 'video.episode' | 'video.tv_show' | 'video.other';
|
|
70
|
+
actor?: string | string[];
|
|
71
|
+
director?: string | string[];
|
|
72
|
+
writer?: string | string[];
|
|
73
|
+
duration?: number;
|
|
74
|
+
releaseDate?: string;
|
|
75
|
+
tag?: string | string[];
|
|
76
|
+
series?: string;
|
|
77
|
+
url: string;
|
|
78
|
+
secureUrl?: string;
|
|
79
|
+
width?: number;
|
|
80
|
+
height?: number;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface OpenGraphProduct extends OpenGraphBase {
|
|
84
|
+
type: 'product';
|
|
85
|
+
price?: {
|
|
86
|
+
amount: number;
|
|
87
|
+
currency: string;
|
|
88
|
+
};
|
|
89
|
+
availability?: 'instock' | 'oos' | 'pending';
|
|
90
|
+
condition?: 'new' | 'refurbished' | 'used';
|
|
91
|
+
priceAmount?: number;
|
|
92
|
+
priceCurrency?: string;
|
|
93
|
+
retailerItemId?: string;
|
|
94
|
+
brand?: string;
|
|
95
|
+
category?: string;
|
|
96
|
+
color?: string;
|
|
97
|
+
material?: string;
|
|
98
|
+
pattern?: string;
|
|
99
|
+
size?: string;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface OpenGraphProductGroup extends OpenGraphBase {
|
|
103
|
+
type: 'product.group';
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface OpenGraphPlace extends OpenGraphBase {
|
|
107
|
+
type: 'place';
|
|
108
|
+
latitude?: number;
|
|
109
|
+
longitude?: number;
|
|
110
|
+
streetAddress?: string;
|
|
111
|
+
locality?: string;
|
|
112
|
+
region?: string;
|
|
113
|
+
postalCode?: string;
|
|
114
|
+
countryName?: string;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface OpenGraphRestaurant extends Omit<OpenGraphPlace, 'type'> {
|
|
118
|
+
type: 'restaurant.restaurant';
|
|
119
|
+
contactData?: {
|
|
120
|
+
streetAddress?: string;
|
|
121
|
+
locality?: string;
|
|
122
|
+
region?: string;
|
|
123
|
+
postalCode?: string;
|
|
124
|
+
countryName?: string;
|
|
125
|
+
email?: string;
|
|
126
|
+
phoneNumber?: string;
|
|
127
|
+
faxNumber?: string;
|
|
128
|
+
};
|
|
129
|
+
menu?: string;
|
|
130
|
+
section?: string;
|
|
131
|
+
priceRange?: string;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface OpenGraphBusiness extends OpenGraphBase {
|
|
135
|
+
type: 'business.business';
|
|
136
|
+
contactData?: {
|
|
137
|
+
streetAddress?: string;
|
|
138
|
+
locality?: string;
|
|
139
|
+
region?: string;
|
|
140
|
+
postalCode?: string;
|
|
141
|
+
countryName?: string;
|
|
142
|
+
email?: string;
|
|
143
|
+
phoneNumber?: string;
|
|
144
|
+
faxNumber?: string;
|
|
145
|
+
website?: string;
|
|
146
|
+
};
|
|
147
|
+
hours?: {
|
|
148
|
+
day: string;
|
|
149
|
+
start: string;
|
|
150
|
+
end: string;
|
|
151
|
+
}[];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export type OpenGraphType =
|
|
155
|
+
| OpenGraphArticle
|
|
156
|
+
| OpenGraphBook
|
|
157
|
+
| OpenGraphBusiness
|
|
158
|
+
| OpenGraphMusic
|
|
159
|
+
| OpenGraphPlace
|
|
160
|
+
| OpenGraphProduct
|
|
161
|
+
| OpenGraphProductGroup
|
|
162
|
+
| OpenGraphProfile
|
|
163
|
+
| OpenGraphRestaurant
|
|
164
|
+
| OpenGraphVideo
|
|
165
|
+
| OpenGraphWebsite;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { isArray, isObject } from '@websolutespa/bom-core';
|
|
2
|
+
|
|
3
|
+
export type IPaginationItem = any;
|
|
4
|
+
|
|
5
|
+
export type IPaginationOptions = {
|
|
6
|
+
mode?: 'pagination' | 'infinite'; // default to pagination
|
|
7
|
+
page?: number;
|
|
8
|
+
perPage?: number;
|
|
9
|
+
delayInMs?: number;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type IPaginationInfo<T extends IPaginationItem = IPaginationItem> = {
|
|
13
|
+
items: T[];
|
|
14
|
+
hasMore: boolean;
|
|
15
|
+
nextPage: number | undefined;
|
|
16
|
+
page: number;
|
|
17
|
+
pages: number;
|
|
18
|
+
perPage: number;
|
|
19
|
+
prevPage: number | undefined;
|
|
20
|
+
total: number;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export function isPaginationInfo(item: unknown): item is IPaginationInfo {
|
|
24
|
+
return isObject(item) && (
|
|
25
|
+
typeof item.page === 'number' &&
|
|
26
|
+
typeof item.pages === 'number' &&
|
|
27
|
+
typeof item.perPage === 'number' &&
|
|
28
|
+
typeof item.total === 'number' &&
|
|
29
|
+
isArray(item.items)
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function getPagedItems<T extends IPaginationItem = IPaginationItem>(
|
|
34
|
+
items: T[],
|
|
35
|
+
page: number,
|
|
36
|
+
perPage: number
|
|
37
|
+
): T[] {
|
|
38
|
+
const from = (page - 1) * perPage;
|
|
39
|
+
const to = Math.min(page * perPage, items.length);
|
|
40
|
+
return items.slice(from, to);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function getMoreItems<T extends IPaginationItem = IPaginationItem>(
|
|
44
|
+
items: T[],
|
|
45
|
+
page: number,
|
|
46
|
+
perPage: number
|
|
47
|
+
): T[] {
|
|
48
|
+
const total = items.length;
|
|
49
|
+
const position = Math.min(total, perPage * page);
|
|
50
|
+
return items.slice(0, position);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function getPaginationInfo<T extends IPaginationItem = IPaginationItem>(
|
|
54
|
+
items: T[],
|
|
55
|
+
options?: IPaginationOptions
|
|
56
|
+
): IPaginationInfo<T> {
|
|
57
|
+
const mode = options?.mode || 'pagination';
|
|
58
|
+
const page = options?.page || 1;
|
|
59
|
+
const perPage = options?.perPage || 12;
|
|
60
|
+
const total = items.length;
|
|
61
|
+
const pages = Math.ceil(total / perPage);
|
|
62
|
+
const hasMore = page < pages;
|
|
63
|
+
const prevPage = page > 1 ? page - 1 : undefined;
|
|
64
|
+
const nextPage = page < pages ? page + 1 : undefined;
|
|
65
|
+
const pagedItems = mode === 'pagination' ?
|
|
66
|
+
getPagedItems(items, page, perPage) :
|
|
67
|
+
getMoreItems(items, page, perPage);
|
|
68
|
+
return {
|
|
69
|
+
items: pagedItems,
|
|
70
|
+
hasMore,
|
|
71
|
+
nextPage,
|
|
72
|
+
page,
|
|
73
|
+
pages,
|
|
74
|
+
perPage,
|
|
75
|
+
prevPage,
|
|
76
|
+
total,
|
|
77
|
+
};
|
|
78
|
+
}
|
package/src/lib/route.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { asCategoryId, findRouteOfCategory, ICategory, IRoute, IRouteLink, localize } from '@websolutespa/bom-core';
|
|
2
|
+
|
|
3
|
+
export function getRouteLinkCategory(
|
|
4
|
+
locale: string,
|
|
5
|
+
routes: IRoute[],
|
|
6
|
+
categories: ICategory[],
|
|
7
|
+
rootCategory: ICategory,
|
|
8
|
+
category: ICategory
|
|
9
|
+
): IRouteLink | IRouteLink[] | undefined {
|
|
10
|
+
const route = findRouteOfCategory(routes, category.id);
|
|
11
|
+
const otherCategories = categories.filter(x => x.id !== category.id);
|
|
12
|
+
const childCategories = otherCategories.filter(x => asCategoryId(x.category) === category.id);
|
|
13
|
+
// console.log('childCategories', category.id, childCategories.map(x => x.id));
|
|
14
|
+
const routeLink = newRouteLink(category, route, locale);
|
|
15
|
+
// console.log('getRouteLinkCategory', href, category.id, route);
|
|
16
|
+
const items: IRouteLink[] = [];
|
|
17
|
+
for (const childCategory of childCategories) {
|
|
18
|
+
const itemOrItems = getRouteLinkCategory(locale, routes, otherCategories, rootCategory, childCategory);
|
|
19
|
+
if (Array.isArray(itemOrItems)) {
|
|
20
|
+
items.push(...itemOrItems);
|
|
21
|
+
} else if (itemOrItems) {
|
|
22
|
+
items.push(itemOrItems);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (
|
|
26
|
+
!route ||
|
|
27
|
+
(category.isHidden && category.id !== rootCategory.id)
|
|
28
|
+
) {
|
|
29
|
+
return items;
|
|
30
|
+
}
|
|
31
|
+
routeLink.items = items;
|
|
32
|
+
return routeLink;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function newRouteLink(category: ICategory, route: IRoute | undefined, locale: string): IRouteLink {
|
|
36
|
+
const href = (route && route.id) ? route.id.toString() : '/';
|
|
37
|
+
const id = route?.page || category.id;
|
|
38
|
+
const media = category.media || route?.media;
|
|
39
|
+
const schema = route?.template || route?.schema || category?.schema || 'unknown';
|
|
40
|
+
const title = localize(category.title || route?.title || 'untitled', locale);
|
|
41
|
+
const routeLink = {
|
|
42
|
+
category: category.id,
|
|
43
|
+
href,
|
|
44
|
+
id,
|
|
45
|
+
items: [],
|
|
46
|
+
media,
|
|
47
|
+
schema,
|
|
48
|
+
title,
|
|
49
|
+
};
|
|
50
|
+
return routeLink;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function resolveRoute(route: IRoute) {
|
|
54
|
+
return `/${route.market}/${route.locale}/${route.schema}/${route.page}`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function routeToRouteLink(route: IRoute): IRouteLink {
|
|
58
|
+
const routeLink: IRouteLink = {
|
|
59
|
+
category: asCategoryId(route.category),
|
|
60
|
+
href: route.id,
|
|
61
|
+
id: route.page,
|
|
62
|
+
items: [],
|
|
63
|
+
media: route.media,
|
|
64
|
+
schema: route.schema,
|
|
65
|
+
title: route.title,
|
|
66
|
+
};
|
|
67
|
+
return routeLink;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Converts a route (and optional override title) into an IRouteLink.
|
|
72
|
+
* route.id is the pathname (href), route.page is the document ID.
|
|
73
|
+
*/
|
|
74
|
+
export function routeToLink(route: IRoute, title?: string): IRouteLink {
|
|
75
|
+
return {
|
|
76
|
+
category: route.category,
|
|
77
|
+
href: route.id,
|
|
78
|
+
id: route.page,
|
|
79
|
+
schema: route.schema,
|
|
80
|
+
title: title ?? route.title,
|
|
81
|
+
media: route.media,
|
|
82
|
+
};
|
|
83
|
+
}
|
package/src/lib/store.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export enum NextPhase {
|
|
2
|
+
Export = 'phase-export',
|
|
3
|
+
ProductionBuild = 'phase-production-build',
|
|
4
|
+
ProductionServer = 'phase-production-server',
|
|
5
|
+
DevelopmentServer = 'phase-development-server',
|
|
6
|
+
Test = 'phase-test',
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function getNextPhase(): NextPhase {
|
|
10
|
+
let nextPhase = NextPhase.Export;
|
|
11
|
+
if (typeof process !== 'undefined' && process.env.NEXT_PHASE) {
|
|
12
|
+
nextPhase = process.env.NEXT_PHASE as NextPhase;
|
|
13
|
+
}
|
|
14
|
+
return nextPhase;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const nextPhase: NextPhase = getNextPhase();
|
|
18
|
+
|
|
19
|
+
// buildStrategy
|
|
20
|
+
export enum BuildStrategy {
|
|
21
|
+
Static = 'static',
|
|
22
|
+
Runtime = 'runtime',
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getBuildStrategy(): BuildStrategy {
|
|
26
|
+
let buildStrategy = BuildStrategy.Static;
|
|
27
|
+
if (typeof process !== 'undefined' && process.env.BUILD_STRATEGY) {
|
|
28
|
+
buildStrategy = process.env.BUILD_STRATEGY as BuildStrategy;
|
|
29
|
+
}
|
|
30
|
+
return buildStrategy;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const buildStrategy: BuildStrategy = getBuildStrategy();
|
|
34
|
+
|
|
35
|
+
// storeStrategy
|
|
36
|
+
export enum StoreStrategy {
|
|
37
|
+
Local = 'local',
|
|
38
|
+
Api = 'api',
|
|
39
|
+
DecoratedApi = 'decoratedApi',
|
|
40
|
+
Data = 'data',
|
|
41
|
+
Mock = 'mock',
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function getStoreStrategy(): StoreStrategy {
|
|
45
|
+
let storeStrategy = StoreStrategy.Mock;
|
|
46
|
+
if (typeof process !== 'undefined' && process.env.STORE_STRATEGY) {
|
|
47
|
+
storeStrategy = process.env.STORE_STRATEGY as StoreStrategy;
|
|
48
|
+
}
|
|
49
|
+
return storeStrategy;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const storeStrategy: StoreStrategy = getStoreStrategy();
|
|
53
|
+
|
|
54
|
+
// storeCacheDuration
|
|
55
|
+
function getStoreCacheDuration(): number {
|
|
56
|
+
let storeCacheDuration = (1 * 60 * 1000);
|
|
57
|
+
if (typeof process !== 'undefined' && process.env.STORE_CACHE_DURATION) {
|
|
58
|
+
storeCacheDuration = parseInt(process.env.STORE_CACHE_DURATION);
|
|
59
|
+
}
|
|
60
|
+
return storeCacheDuration;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const storeCacheDuration: number = getStoreCacheDuration();
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as StructuredData from 'schema-dts';
|
|
2
|
+
|
|
3
|
+
export type StructuredDataType =
|
|
4
|
+
| StructuredData.Article
|
|
5
|
+
| StructuredData.AudioObject
|
|
6
|
+
| StructuredData.BlogPosting
|
|
7
|
+
| StructuredData.BreadcrumbList
|
|
8
|
+
| StructuredData.Course
|
|
9
|
+
| StructuredData.Event
|
|
10
|
+
| StructuredData.FAQPage
|
|
11
|
+
| StructuredData.HowTo
|
|
12
|
+
| StructuredData.ItemList
|
|
13
|
+
| StructuredData.JobPosting
|
|
14
|
+
| StructuredData.ListItem
|
|
15
|
+
| StructuredData.LocalBusiness
|
|
16
|
+
| StructuredData.NewsArticle
|
|
17
|
+
| StructuredData.Organization
|
|
18
|
+
| StructuredData.Person
|
|
19
|
+
| StructuredData.Place
|
|
20
|
+
| StructuredData.Product
|
|
21
|
+
| StructuredData.Recipe
|
|
22
|
+
| StructuredData.VideoObject
|
|
23
|
+
| StructuredData.WebPage
|
|
24
|
+
| StructuredData.WebSite;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Twitter Card Types
|
|
2
|
+
|
|
3
|
+
export interface TwitterCardBase {
|
|
4
|
+
card: 'summary' | 'summary_large_image' | 'app' | 'player';
|
|
5
|
+
site?: string;
|
|
6
|
+
siteId?: string;
|
|
7
|
+
creator?: string;
|
|
8
|
+
creatorId?: string;
|
|
9
|
+
title?: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
image?: string;
|
|
12
|
+
imageAlt?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface TwitterCardSummary extends TwitterCardBase {
|
|
16
|
+
card: 'summary';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface TwitterCardSummaryLargeImage extends TwitterCardBase {
|
|
20
|
+
card: 'summary_large_image';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface TwitterCardApp extends TwitterCardBase {
|
|
24
|
+
card: 'app';
|
|
25
|
+
appNameIphone?: string;
|
|
26
|
+
appIdIphone?: string;
|
|
27
|
+
appUrlIphone?: string;
|
|
28
|
+
appNameIpad?: string;
|
|
29
|
+
appIdIpad?: string;
|
|
30
|
+
appUrlIpad?: string;
|
|
31
|
+
appNameGoogleplay?: string;
|
|
32
|
+
appIdGoogleplay?: string;
|
|
33
|
+
appUrlGoogleplay?: string;
|
|
34
|
+
appCountry?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface TwitterCardPlayer extends TwitterCardBase {
|
|
38
|
+
card: 'player';
|
|
39
|
+
player: string;
|
|
40
|
+
playerWidth: number;
|
|
41
|
+
playerHeight: number;
|
|
42
|
+
playerStream?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type TwitterCardType =
|
|
46
|
+
| TwitterCardApp
|
|
47
|
+
| TwitterCardPlayer
|
|
48
|
+
| TwitterCardSummary
|
|
49
|
+
| TwitterCardSummaryLargeImage;
|
package/src/lib/utils.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
|
|
2
|
+
export function getPublicUrl() {
|
|
3
|
+
const publicUrl = process.env && process.env.NEXT_PUBLIC_URL ? process.env.NEXT_PUBLIC_URL : '';
|
|
4
|
+
return publicUrl;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function resolveHref(href: string = '') {
|
|
8
|
+
return href.startsWith('http') ? href : `${getPublicUrl()}${href}`;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function trimTerminalSlash(path: string) {
|
|
12
|
+
return path.replace(/\/+$/, '');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function sanitizeHref(url: URL, urlBeforeRedirect: URL | null) {
|
|
16
|
+
if (urlBeforeRedirect) {
|
|
17
|
+
const sanitizedUrl = new URL(urlBeforeRedirect);
|
|
18
|
+
sanitizedUrl.protocol = url.protocol;
|
|
19
|
+
return trimTerminalSlash(sanitizedUrl.href);
|
|
20
|
+
} else {
|
|
21
|
+
return trimTerminalSlash(url.href);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function sanitizeRedirectFrom(path: string, url: URL, urlBeforeRedirect: URL | null) {
|
|
26
|
+
path = trimTerminalSlash(path);
|
|
27
|
+
if (urlBeforeRedirect) {
|
|
28
|
+
return path.replace(/^(\^?)((https?:\/\/)+)/, `$1${url.protocol}//`);
|
|
29
|
+
} else {
|
|
30
|
+
return path.replace(/^(\^?)((https?:\/\/)+(\w|\.|:)+)/, `$1${url.origin}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function sanitizeRedirectTo(path?: string) {
|
|
35
|
+
return path ? trimTerminalSlash(path) : undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function sanitizeRedirectUrl(path: string | undefined, url: URL) {
|
|
39
|
+
if (path != null) {
|
|
40
|
+
path = trimTerminalSlash(path);
|
|
41
|
+
return path.match(/^((https?:\/\/)+)/) ? path : `${url.origin}${path}`;
|
|
42
|
+
} else {
|
|
43
|
+
return path;
|
|
44
|
+
}
|
|
45
|
+
}
|