@websolutespa/bom-mixer-store 1.7.0 → 1.7.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 +6 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +73 -32
- package/dist/index.mjs +73 -32
- package/package.json +1 -1
- package/src/middleware/middleware.service.ts +6 -7
- package/src/store/store.handler.ts +82 -27
package/CHANGELOG.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -231,7 +231,7 @@ declare function collectionPatch<T extends IStore>(storePromise: () => Promise<T
|
|
|
231
231
|
declare function collectionDelete<T extends IStore>(storePromise: () => Promise<T>): (request: NextApiRequest, response: NextApiResponse) => Promise<void>;
|
|
232
232
|
declare function routePost(store: IStore, request: NextApiRequest, response: NextApiResponse): Promise<void>;
|
|
233
233
|
declare function storeIndexHandler(): any;
|
|
234
|
-
declare function findRoute(store: IStore, pathname: string, href: string): Promise<IRoute | undefined>;
|
|
234
|
+
declare function findRoute(store: IStore, pathname: string, href: string, hrefBeforeRedirect: string | null): Promise<IRoute | undefined>;
|
|
235
235
|
|
|
236
236
|
declare function getStore<T extends IStore>(): Promise<T>;
|
|
237
237
|
|
package/dist/index.js
CHANGED
|
@@ -649,18 +649,18 @@ async function localApiDelete(url, options = {}, serviceOptions) {
|
|
|
649
649
|
var mime = __toESM(require("mime"));
|
|
650
650
|
var API_BASE2 = process.env.NEXT_PUBLIC_API || "/api";
|
|
651
651
|
function isStaticRequest(request) {
|
|
652
|
-
const
|
|
653
|
-
const isStatic = mime.getType(
|
|
652
|
+
const { pathname } = request.nextUrl;
|
|
653
|
+
const isStatic = mime.getType(pathname) !== null;
|
|
654
654
|
return isStatic;
|
|
655
655
|
}
|
|
656
656
|
function isNextRequest(request) {
|
|
657
|
-
const
|
|
658
|
-
const isNext =
|
|
657
|
+
const { pathname } = request.nextUrl;
|
|
658
|
+
const isNext = pathname.startsWith("/_next");
|
|
659
659
|
return isNext;
|
|
660
660
|
}
|
|
661
661
|
function isApiRequest(request) {
|
|
662
|
-
const
|
|
663
|
-
const isApi =
|
|
662
|
+
const { pathname } = request.nextUrl;
|
|
663
|
+
const isApi = pathname.startsWith(API_BASE2);
|
|
664
664
|
return isApi;
|
|
665
665
|
}
|
|
666
666
|
|
|
@@ -1730,30 +1730,31 @@ function collectionDelete(storePromise) {
|
|
|
1730
1730
|
};
|
|
1731
1731
|
}
|
|
1732
1732
|
async function routePost(store, request, response) {
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1733
|
+
try {
|
|
1734
|
+
const { pathname, href, hrefBeforeRedirect } = request.body;
|
|
1735
|
+
console.log("routePost", pathname, href, hrefBeforeRedirect);
|
|
1736
|
+
if (pathname && href) {
|
|
1737
|
+
const route = await findRoute(store, pathname, href, hrefBeforeRedirect);
|
|
1737
1738
|
return response.status(200).json(route);
|
|
1738
|
-
}
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1739
|
+
} else {
|
|
1740
|
+
return response.status(400).send("bad request");
|
|
1741
|
+
}
|
|
1742
|
+
} catch (error) {
|
|
1743
|
+
if (error.status < 500) {
|
|
1744
|
+
if (error.status < 400) {
|
|
1745
|
+
return response.status(error.status).send({
|
|
1746
|
+
redirectUrl: error.redirectUrl
|
|
1747
|
+
});
|
|
1748
|
+
}
|
|
1749
|
+
if (error.status === 404) {
|
|
1750
|
+
return response.status(404).send("not found");
|
|
1750
1751
|
} else {
|
|
1751
|
-
|
|
1752
|
-
throw error;
|
|
1752
|
+
return response.status(error.status).send("gone");
|
|
1753
1753
|
}
|
|
1754
|
+
} else {
|
|
1755
|
+
console.error("storeHandler.error.500", error);
|
|
1756
|
+
throw error;
|
|
1754
1757
|
}
|
|
1755
|
-
} else {
|
|
1756
|
-
return response.status(400).send("bad request");
|
|
1757
1758
|
}
|
|
1758
1759
|
}
|
|
1759
1760
|
function storeIndexHandler() {
|
|
@@ -1887,7 +1888,38 @@ function storeIndexHandler() {
|
|
|
1887
1888
|
}
|
|
1888
1889
|
});
|
|
1889
1890
|
}
|
|
1890
|
-
|
|
1891
|
+
var trimTerminalSlash = (path) => {
|
|
1892
|
+
return path.replace(/\/+$/, "");
|
|
1893
|
+
};
|
|
1894
|
+
var sanitizeHref = (url, urlBeforeRedirect) => {
|
|
1895
|
+
if (urlBeforeRedirect) {
|
|
1896
|
+
const sanitizedUrl = new URL(urlBeforeRedirect);
|
|
1897
|
+
sanitizedUrl.protocol = url.protocol;
|
|
1898
|
+
return trimTerminalSlash(sanitizedUrl.href);
|
|
1899
|
+
} else {
|
|
1900
|
+
return trimTerminalSlash(url.href);
|
|
1901
|
+
}
|
|
1902
|
+
};
|
|
1903
|
+
var sanitizeRedirectFrom = (path, url, urlBeforeRedirect) => {
|
|
1904
|
+
path = trimTerminalSlash(path);
|
|
1905
|
+
if (urlBeforeRedirect) {
|
|
1906
|
+
return path.replace(/^(\^?)((https?:\/\/)+)/, `$1${url.protocol}//`);
|
|
1907
|
+
} else {
|
|
1908
|
+
return path.replace(/^(\^?)((https?:\/\/)+(\w|\.|:)+)/, `$1${url.origin}`);
|
|
1909
|
+
}
|
|
1910
|
+
};
|
|
1911
|
+
var sanitizeRedirectTo = (path) => {
|
|
1912
|
+
return path ? trimTerminalSlash(path) : void 0;
|
|
1913
|
+
};
|
|
1914
|
+
var sanitizeRedirectUrl = (path, url) => {
|
|
1915
|
+
if (path != null) {
|
|
1916
|
+
path = trimTerminalSlash(path);
|
|
1917
|
+
return path.match(/^((https?:\/\/)+)/) ? path : `${url.origin}${path}`;
|
|
1918
|
+
} else {
|
|
1919
|
+
return path;
|
|
1920
|
+
}
|
|
1921
|
+
};
|
|
1922
|
+
async function findRoute(store, pathname, href, hrefBeforeRedirect) {
|
|
1891
1923
|
const routes = await store.route.findMany({
|
|
1892
1924
|
where: {
|
|
1893
1925
|
id: {
|
|
@@ -1916,23 +1948,31 @@ async function findRoute(store, pathname, href) {
|
|
|
1916
1948
|
if (splatRoute) {
|
|
1917
1949
|
return splatRoute;
|
|
1918
1950
|
}
|
|
1919
|
-
const
|
|
1951
|
+
const url = new URL(href);
|
|
1952
|
+
const urlBeforeRedirect = hrefBeforeRedirect ? new URL(hrefBeforeRedirect) : null;
|
|
1953
|
+
const sanitizedHref = sanitizeHref(url, urlBeforeRedirect);
|
|
1954
|
+
let redirects = await store.redirect.findMany({
|
|
1920
1955
|
where: {
|
|
1921
1956
|
isActive: {
|
|
1922
1957
|
equals: true
|
|
1923
1958
|
}
|
|
1924
1959
|
}
|
|
1925
1960
|
});
|
|
1961
|
+
redirects = redirects.map((x) => ({
|
|
1962
|
+
...x,
|
|
1963
|
+
from: sanitizeRedirectFrom(x.from, url, urlBeforeRedirect),
|
|
1964
|
+
to: sanitizeRedirectTo(x.to)
|
|
1965
|
+
}));
|
|
1926
1966
|
const exactMatchResolver = (redirect) => {
|
|
1927
1967
|
const status = parseInt(redirect.status) || 307;
|
|
1928
1968
|
if (status < 400) {
|
|
1929
|
-
const redirectUrl = redirect.to;
|
|
1969
|
+
const redirectUrl = sanitizeRedirectUrl(redirect.to, url);
|
|
1930
1970
|
throw { status, redirectUrl };
|
|
1931
1971
|
} else {
|
|
1932
1972
|
throw { status };
|
|
1933
1973
|
}
|
|
1934
1974
|
};
|
|
1935
|
-
const exactMatchRedirect = redirects.find((x) => x.from ===
|
|
1975
|
+
const exactMatchRedirect = redirects.find((x) => x.from === sanitizedHref);
|
|
1936
1976
|
if (exactMatchRedirect !== void 0) {
|
|
1937
1977
|
return exactMatchResolver(exactMatchRedirect);
|
|
1938
1978
|
}
|
|
@@ -1944,7 +1984,8 @@ async function findRoute(store, pathname, href) {
|
|
|
1944
1984
|
let redirectUrl = redirect.to.replace(/\*/g, (...rest) => {
|
|
1945
1985
|
return `$${++i}`;
|
|
1946
1986
|
});
|
|
1947
|
-
redirectUrl =
|
|
1987
|
+
redirectUrl = sanitizedHref.replace(regexp, redirectUrl);
|
|
1988
|
+
redirectUrl = sanitizeRedirectUrl(redirectUrl, url);
|
|
1948
1989
|
throw { status, redirectUrl };
|
|
1949
1990
|
} else {
|
|
1950
1991
|
throw { status };
|
|
@@ -1956,7 +1997,7 @@ async function findRoute(store, pathname, href) {
|
|
|
1956
1997
|
expression = `^${expression.replace(/(^\^)|(\$$)/g, "")}$`;
|
|
1957
1998
|
x.from = expression;
|
|
1958
1999
|
});
|
|
1959
|
-
const firstMatch = redirects.find((x) =>
|
|
2000
|
+
const firstMatch = redirects.find((x) => sanitizedHref.match(x.from));
|
|
1960
2001
|
if (firstMatch) {
|
|
1961
2002
|
return patternMatchResolver(firstMatch);
|
|
1962
2003
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -541,18 +541,18 @@ async function localApiDelete(url, options = {}, serviceOptions) {
|
|
|
541
541
|
import * as mime from "mime";
|
|
542
542
|
var API_BASE2 = process.env.NEXT_PUBLIC_API || "/api";
|
|
543
543
|
function isStaticRequest(request) {
|
|
544
|
-
const
|
|
545
|
-
const isStatic = mime.getType(
|
|
544
|
+
const { pathname } = request.nextUrl;
|
|
545
|
+
const isStatic = mime.getType(pathname) !== null;
|
|
546
546
|
return isStatic;
|
|
547
547
|
}
|
|
548
548
|
function isNextRequest(request) {
|
|
549
|
-
const
|
|
550
|
-
const isNext =
|
|
549
|
+
const { pathname } = request.nextUrl;
|
|
550
|
+
const isNext = pathname.startsWith("/_next");
|
|
551
551
|
return isNext;
|
|
552
552
|
}
|
|
553
553
|
function isApiRequest(request) {
|
|
554
|
-
const
|
|
555
|
-
const isApi =
|
|
554
|
+
const { pathname } = request.nextUrl;
|
|
555
|
+
const isApi = pathname.startsWith(API_BASE2);
|
|
556
556
|
return isApi;
|
|
557
557
|
}
|
|
558
558
|
|
|
@@ -1622,30 +1622,31 @@ function collectionDelete(storePromise) {
|
|
|
1622
1622
|
};
|
|
1623
1623
|
}
|
|
1624
1624
|
async function routePost(store, request, response) {
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1625
|
+
try {
|
|
1626
|
+
const { pathname, href, hrefBeforeRedirect } = request.body;
|
|
1627
|
+
console.log("routePost", pathname, href, hrefBeforeRedirect);
|
|
1628
|
+
if (pathname && href) {
|
|
1629
|
+
const route = await findRoute(store, pathname, href, hrefBeforeRedirect);
|
|
1629
1630
|
return response.status(200).json(route);
|
|
1630
|
-
}
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1631
|
+
} else {
|
|
1632
|
+
return response.status(400).send("bad request");
|
|
1633
|
+
}
|
|
1634
|
+
} catch (error) {
|
|
1635
|
+
if (error.status < 500) {
|
|
1636
|
+
if (error.status < 400) {
|
|
1637
|
+
return response.status(error.status).send({
|
|
1638
|
+
redirectUrl: error.redirectUrl
|
|
1639
|
+
});
|
|
1640
|
+
}
|
|
1641
|
+
if (error.status === 404) {
|
|
1642
|
+
return response.status(404).send("not found");
|
|
1642
1643
|
} else {
|
|
1643
|
-
|
|
1644
|
-
throw error;
|
|
1644
|
+
return response.status(error.status).send("gone");
|
|
1645
1645
|
}
|
|
1646
|
+
} else {
|
|
1647
|
+
console.error("storeHandler.error.500", error);
|
|
1648
|
+
throw error;
|
|
1646
1649
|
}
|
|
1647
|
-
} else {
|
|
1648
|
-
return response.status(400).send("bad request");
|
|
1649
1650
|
}
|
|
1650
1651
|
}
|
|
1651
1652
|
function storeIndexHandler() {
|
|
@@ -1779,7 +1780,38 @@ function storeIndexHandler() {
|
|
|
1779
1780
|
}
|
|
1780
1781
|
});
|
|
1781
1782
|
}
|
|
1782
|
-
|
|
1783
|
+
var trimTerminalSlash = (path) => {
|
|
1784
|
+
return path.replace(/\/+$/, "");
|
|
1785
|
+
};
|
|
1786
|
+
var sanitizeHref = (url, urlBeforeRedirect) => {
|
|
1787
|
+
if (urlBeforeRedirect) {
|
|
1788
|
+
const sanitizedUrl = new URL(urlBeforeRedirect);
|
|
1789
|
+
sanitizedUrl.protocol = url.protocol;
|
|
1790
|
+
return trimTerminalSlash(sanitizedUrl.href);
|
|
1791
|
+
} else {
|
|
1792
|
+
return trimTerminalSlash(url.href);
|
|
1793
|
+
}
|
|
1794
|
+
};
|
|
1795
|
+
var sanitizeRedirectFrom = (path, url, urlBeforeRedirect) => {
|
|
1796
|
+
path = trimTerminalSlash(path);
|
|
1797
|
+
if (urlBeforeRedirect) {
|
|
1798
|
+
return path.replace(/^(\^?)((https?:\/\/)+)/, `$1${url.protocol}//`);
|
|
1799
|
+
} else {
|
|
1800
|
+
return path.replace(/^(\^?)((https?:\/\/)+(\w|\.|:)+)/, `$1${url.origin}`);
|
|
1801
|
+
}
|
|
1802
|
+
};
|
|
1803
|
+
var sanitizeRedirectTo = (path) => {
|
|
1804
|
+
return path ? trimTerminalSlash(path) : void 0;
|
|
1805
|
+
};
|
|
1806
|
+
var sanitizeRedirectUrl = (path, url) => {
|
|
1807
|
+
if (path != null) {
|
|
1808
|
+
path = trimTerminalSlash(path);
|
|
1809
|
+
return path.match(/^((https?:\/\/)+)/) ? path : `${url.origin}${path}`;
|
|
1810
|
+
} else {
|
|
1811
|
+
return path;
|
|
1812
|
+
}
|
|
1813
|
+
};
|
|
1814
|
+
async function findRoute(store, pathname, href, hrefBeforeRedirect) {
|
|
1783
1815
|
const routes = await store.route.findMany({
|
|
1784
1816
|
where: {
|
|
1785
1817
|
id: {
|
|
@@ -1808,23 +1840,31 @@ async function findRoute(store, pathname, href) {
|
|
|
1808
1840
|
if (splatRoute) {
|
|
1809
1841
|
return splatRoute;
|
|
1810
1842
|
}
|
|
1811
|
-
const
|
|
1843
|
+
const url = new URL(href);
|
|
1844
|
+
const urlBeforeRedirect = hrefBeforeRedirect ? new URL(hrefBeforeRedirect) : null;
|
|
1845
|
+
const sanitizedHref = sanitizeHref(url, urlBeforeRedirect);
|
|
1846
|
+
let redirects = await store.redirect.findMany({
|
|
1812
1847
|
where: {
|
|
1813
1848
|
isActive: {
|
|
1814
1849
|
equals: true
|
|
1815
1850
|
}
|
|
1816
1851
|
}
|
|
1817
1852
|
});
|
|
1853
|
+
redirects = redirects.map((x) => ({
|
|
1854
|
+
...x,
|
|
1855
|
+
from: sanitizeRedirectFrom(x.from, url, urlBeforeRedirect),
|
|
1856
|
+
to: sanitizeRedirectTo(x.to)
|
|
1857
|
+
}));
|
|
1818
1858
|
const exactMatchResolver = (redirect) => {
|
|
1819
1859
|
const status = parseInt(redirect.status) || 307;
|
|
1820
1860
|
if (status < 400) {
|
|
1821
|
-
const redirectUrl = redirect.to;
|
|
1861
|
+
const redirectUrl = sanitizeRedirectUrl(redirect.to, url);
|
|
1822
1862
|
throw { status, redirectUrl };
|
|
1823
1863
|
} else {
|
|
1824
1864
|
throw { status };
|
|
1825
1865
|
}
|
|
1826
1866
|
};
|
|
1827
|
-
const exactMatchRedirect = redirects.find((x) => x.from ===
|
|
1867
|
+
const exactMatchRedirect = redirects.find((x) => x.from === sanitizedHref);
|
|
1828
1868
|
if (exactMatchRedirect !== void 0) {
|
|
1829
1869
|
return exactMatchResolver(exactMatchRedirect);
|
|
1830
1870
|
}
|
|
@@ -1836,7 +1876,8 @@ async function findRoute(store, pathname, href) {
|
|
|
1836
1876
|
let redirectUrl = redirect.to.replace(/\*/g, (...rest) => {
|
|
1837
1877
|
return `$${++i}`;
|
|
1838
1878
|
});
|
|
1839
|
-
redirectUrl =
|
|
1879
|
+
redirectUrl = sanitizedHref.replace(regexp, redirectUrl);
|
|
1880
|
+
redirectUrl = sanitizeRedirectUrl(redirectUrl, url);
|
|
1840
1881
|
throw { status, redirectUrl };
|
|
1841
1882
|
} else {
|
|
1842
1883
|
throw { status };
|
|
@@ -1848,7 +1889,7 @@ async function findRoute(store, pathname, href) {
|
|
|
1848
1889
|
expression = `^${expression.replace(/(^\^)|(\$$)/g, "")}$`;
|
|
1849
1890
|
x.from = expression;
|
|
1850
1891
|
});
|
|
1851
|
-
const firstMatch = redirects.find((x) =>
|
|
1892
|
+
const firstMatch = redirects.find((x) => sanitizedHref.match(x.from));
|
|
1852
1893
|
if (firstMatch) {
|
|
1853
1894
|
return patternMatchResolver(firstMatch);
|
|
1854
1895
|
}
|
package/package.json
CHANGED
|
@@ -4,20 +4,19 @@ import { NextRequest } from 'next/server';
|
|
|
4
4
|
const API_BASE = process.env.NEXT_PUBLIC_API || '/api';
|
|
5
5
|
|
|
6
6
|
export function isStaticRequest(request: NextRequest) {
|
|
7
|
-
const
|
|
8
|
-
const isStatic = mime.getType(
|
|
9
|
-
// const isStatic = url.pathname.indexOf('.') !== -1;
|
|
7
|
+
const { pathname } = request.nextUrl;
|
|
8
|
+
const isStatic = mime.getType(pathname) !== null;
|
|
10
9
|
return isStatic;
|
|
11
10
|
}
|
|
12
11
|
|
|
13
12
|
export function isNextRequest(request: NextRequest) {
|
|
14
|
-
const
|
|
15
|
-
const isNext =
|
|
13
|
+
const { pathname } = request.nextUrl;
|
|
14
|
+
const isNext = pathname.startsWith('/_next');
|
|
16
15
|
return isNext;
|
|
17
16
|
}
|
|
18
17
|
|
|
19
18
|
export function isApiRequest(request: NextRequest) {
|
|
20
|
-
const
|
|
21
|
-
const isApi =
|
|
19
|
+
const { pathname } = request.nextUrl;
|
|
20
|
+
const isApi = pathname.startsWith(API_BASE);
|
|
22
21
|
return isApi;
|
|
23
22
|
}
|
|
@@ -152,30 +152,31 @@ export function collectionDelete<T extends IStore>(storePromise: () => Promise<T
|
|
|
152
152
|
// route post resolver
|
|
153
153
|
// !!! todo, should be moved to models -> route service
|
|
154
154
|
export async function routePost(store: IStore, request: NextApiRequest, response: NextApiResponse) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
155
|
+
try {
|
|
156
|
+
const { pathname, href, hrefBeforeRedirect } = request.body;
|
|
157
|
+
console.log('routePost', pathname, href, hrefBeforeRedirect);
|
|
158
|
+
if (pathname && href) {
|
|
159
|
+
const route = await findRoute(store, pathname, href, hrefBeforeRedirect);
|
|
159
160
|
return response.status(200).json(route);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
161
|
+
} else {
|
|
162
|
+
return response.status(400).send('bad request');
|
|
163
|
+
}
|
|
164
|
+
} catch (error: any) {
|
|
165
|
+
if (error.status < 500) {
|
|
166
|
+
if (error.status < 400) {
|
|
167
|
+
return response.status(error.status).send({
|
|
168
|
+
redirectUrl: error.redirectUrl,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
if (error.status === 404) {
|
|
172
|
+
return response.status(404).send('not found');
|
|
172
173
|
} else {
|
|
173
|
-
|
|
174
|
-
throw error;
|
|
174
|
+
return response.status(error.status).send('gone');
|
|
175
175
|
}
|
|
176
|
+
} else {
|
|
177
|
+
console.error('storeHandler.error.500', error);
|
|
178
|
+
throw error;
|
|
176
179
|
}
|
|
177
|
-
} else {
|
|
178
|
-
return response.status(400).send('bad request');
|
|
179
180
|
}
|
|
180
181
|
}
|
|
181
182
|
|
|
@@ -314,7 +315,43 @@ export function storeIndexHandler() {
|
|
|
314
315
|
});
|
|
315
316
|
}
|
|
316
317
|
|
|
317
|
-
|
|
318
|
+
const trimTerminalSlash = (path: string) => {
|
|
319
|
+
return path.replace(/\/+$/, '');
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
const sanitizeHref = (url: URL, urlBeforeRedirect: URL | null) => {
|
|
323
|
+
if (urlBeforeRedirect) {
|
|
324
|
+
const sanitizedUrl = new URL(urlBeforeRedirect);
|
|
325
|
+
sanitizedUrl.protocol = url.protocol;
|
|
326
|
+
return trimTerminalSlash(sanitizedUrl.href);
|
|
327
|
+
} else {
|
|
328
|
+
return trimTerminalSlash(url.href);
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
const sanitizeRedirectFrom = (path: string, url: URL, urlBeforeRedirect: URL | null) => {
|
|
333
|
+
path = trimTerminalSlash(path);
|
|
334
|
+
if (urlBeforeRedirect) {
|
|
335
|
+
return path.replace(/^(\^?)((https?:\/\/)+)/, `$1${url.protocol}//`);
|
|
336
|
+
} else {
|
|
337
|
+
return path.replace(/^(\^?)((https?:\/\/)+(\w|\.|:)+)/, `$1${url.origin}`);
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
const sanitizeRedirectTo = (path?: string) => {
|
|
342
|
+
return path ? trimTerminalSlash(path) : undefined;
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
const sanitizeRedirectUrl = (path: string | undefined, url: URL) => {
|
|
346
|
+
if (path != null) {
|
|
347
|
+
path = trimTerminalSlash(path);
|
|
348
|
+
return path.match(/^((https?:\/\/)+)/) ? path : `${url.origin}${path}`;
|
|
349
|
+
} else {
|
|
350
|
+
return path;
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
export async function findRoute(store: IStore, pathname: string, href: string, hrefBeforeRedirect: string | null): Promise<IRoute | undefined> {
|
|
318
355
|
// here we use findMany because route id would break api url
|
|
319
356
|
const routes = await store.route.findMany<IRoute>({
|
|
320
357
|
where: {
|
|
@@ -323,6 +360,7 @@ export async function findRoute(store: IStore, pathname: string, href: string):
|
|
|
323
360
|
},
|
|
324
361
|
},
|
|
325
362
|
});
|
|
363
|
+
// console.log('routes', routes);
|
|
326
364
|
// console.log('pathname', pathname);
|
|
327
365
|
if (routes.length > 0) {
|
|
328
366
|
return routes[0];
|
|
@@ -336,7 +374,6 @@ export async function findRoute(store: IStore, pathname: string, href: string):
|
|
|
336
374
|
},
|
|
337
375
|
},
|
|
338
376
|
});
|
|
339
|
-
// console.log('splatRoutes', splatRoutes);
|
|
340
377
|
// find best match splat route
|
|
341
378
|
const splatRoute = splatRoutes.reduce((p: (IRoute & { splat: string }) | undefined, c: IRoute) => {
|
|
342
379
|
const match = pathname.indexOf(c.id) === 0;
|
|
@@ -349,27 +386,42 @@ export async function findRoute(store: IStore, pathname: string, href: string):
|
|
|
349
386
|
if (splatRoute) {
|
|
350
387
|
return splatRoute;
|
|
351
388
|
}
|
|
389
|
+
const url = new URL(href);
|
|
390
|
+
const urlBeforeRedirect = hrefBeforeRedirect ? new URL(hrefBeforeRedirect) : null;
|
|
391
|
+
const sanitizedHref = sanitizeHref(url, urlBeforeRedirect);
|
|
392
|
+
/*
|
|
393
|
+
console.log('href', url.href);
|
|
394
|
+
console.log('hrefBeforeRedirect', urlBeforeRedirect?.href);
|
|
395
|
+
console.log('sanitizedHref', sanitizedHref);
|
|
396
|
+
*/
|
|
352
397
|
// collect redirects
|
|
353
|
-
|
|
398
|
+
let redirects = await store.redirect.findMany<IRedirect>({
|
|
354
399
|
where: {
|
|
355
400
|
isActive: {
|
|
356
401
|
equals: true,
|
|
357
402
|
},
|
|
358
403
|
},
|
|
359
404
|
});
|
|
405
|
+
redirects = redirects.map(x => ({
|
|
406
|
+
...x,
|
|
407
|
+
from: sanitizeRedirectFrom(x.from, url, urlBeforeRedirect),
|
|
408
|
+
to: sanitizeRedirectTo(x.to),
|
|
409
|
+
}));
|
|
360
410
|
// redirects.sort((a, b) => a.order - b.order);
|
|
411
|
+
// console.log('findRoute redirects', redirects);
|
|
361
412
|
// exact match redirect resolver
|
|
362
413
|
const exactMatchResolver = (redirect: IRedirect) => {
|
|
363
414
|
const status: number = parseInt(redirect.status) || 307;
|
|
364
415
|
if (status < 400) {
|
|
365
|
-
const redirectUrl = redirect.to;
|
|
416
|
+
const redirectUrl = sanitizeRedirectUrl(redirect.to, url);
|
|
417
|
+
// console.log('>>>>>>>>>> findRoute exactMatchResolver', status, redirectUrl, redirect.to);
|
|
366
418
|
throw { status, redirectUrl };
|
|
367
419
|
} else {
|
|
368
420
|
throw { status };
|
|
369
421
|
}
|
|
370
422
|
};
|
|
371
423
|
// check exact match redirects
|
|
372
|
-
const exactMatchRedirect = redirects.find(x => x.from ===
|
|
424
|
+
const exactMatchRedirect = redirects.find(x => x.from === sanitizedHref);
|
|
373
425
|
if (exactMatchRedirect !== undefined) {
|
|
374
426
|
return exactMatchResolver(exactMatchRedirect);
|
|
375
427
|
}
|
|
@@ -382,7 +434,9 @@ export async function findRoute(store: IStore, pathname: string, href: string):
|
|
|
382
434
|
let redirectUrl = (redirect.to as string).replace(/\*/g, (...rest) => {
|
|
383
435
|
return `$${++i}`;
|
|
384
436
|
});
|
|
385
|
-
redirectUrl =
|
|
437
|
+
redirectUrl = sanitizedHref.replace(regexp, redirectUrl);
|
|
438
|
+
redirectUrl = sanitizeRedirectUrl(redirectUrl, url) as string;
|
|
439
|
+
// console.log('>>>>>>>>>> findRoute patternMatchResolver', status, redirectUrl, redirect.to);
|
|
386
440
|
throw { status, redirectUrl };
|
|
387
441
|
} else {
|
|
388
442
|
throw { status };
|
|
@@ -398,7 +452,8 @@ export async function findRoute(store: IStore, pathname: string, href: string):
|
|
|
398
452
|
x.from = expression;
|
|
399
453
|
});
|
|
400
454
|
// check if a regex pattern redirect does match
|
|
401
|
-
const firstMatch = redirects.find(x =>
|
|
455
|
+
const firstMatch = redirects.find(x => sanitizedHref.match(x.from));
|
|
456
|
+
// console.log('>>>>>>>>>> findRoute firstMatch', firstMatch);
|
|
402
457
|
if (firstMatch) {
|
|
403
458
|
return patternMatchResolver(firstMatch);
|
|
404
459
|
}
|