vike 0.4.180-commit-648cd01 → 0.4.181
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/node/runtime/renderPage/createHttpResponseObject/assertNoInfiniteHttpRedirect.js +1 -2
- package/dist/cjs/{shared/route → node/runtime/renderPage}/resolveRedirects.js +9 -11
- package/dist/cjs/node/runtime/renderPage.js +6 -9
- package/dist/cjs/shared/getPageContextUrlComputed.js +43 -37
- package/dist/cjs/shared/modifyUrl.js +31 -0
- package/dist/cjs/shared/route/abort.js +4 -10
- package/dist/cjs/shared/route/executeOnBeforeRouteHook.js +3 -1
- package/dist/cjs/utils/parseUrl.js +168 -87
- package/dist/cjs/utils/projectInfo.js +1 -1
- package/dist/cjs/utils/redirectHard.js +7 -0
- package/dist/cjs/utils/urlToFile.js +1 -1
- package/dist/esm/client/client-routing-runtime/createPageContext.d.ts +1 -1
- package/dist/esm/client/client-routing-runtime/getPageContextFromHooks.js +2 -2
- package/dist/esm/client/client-routing-runtime/navigate.js +2 -1
- package/dist/esm/client/client-routing-runtime/prefetch.js +5 -4
- package/dist/esm/client/client-routing-runtime/renderPageClientSide.js +7 -7
- package/dist/esm/client/client-routing-runtime/skipLink.js +11 -22
- package/dist/esm/client/client-routing-runtime/utils.d.ts +1 -2
- package/dist/esm/client/client-routing-runtime/utils.js +1 -2
- package/dist/esm/node/runtime/renderPage/createHttpResponseObject/assertNoInfiniteHttpRedirect.js +2 -3
- package/dist/esm/node/runtime/renderPage/renderPageAlreadyRouted.d.ts +5 -5
- package/dist/esm/{shared/route → node/runtime/renderPage}/resolveRedirects.js +9 -11
- package/dist/esm/node/runtime/renderPage.d.ts +2 -2
- package/dist/esm/node/runtime/renderPage.js +7 -10
- package/dist/esm/shared/getPageContextUrlComputed.d.ts +2 -24
- package/dist/esm/shared/getPageContextUrlComputed.js +43 -37
- package/dist/esm/shared/modifyUrl.d.ts +14 -0
- package/dist/esm/shared/modifyUrl.js +28 -0
- package/dist/esm/shared/route/abort.js +5 -11
- package/dist/esm/shared/route/executeOnBeforeRouteHook.js +4 -2
- package/dist/esm/types/index.d.ts +1 -1
- package/dist/esm/utils/parseUrl.d.ts +43 -10
- package/dist/esm/utils/parseUrl.js +167 -86
- package/dist/esm/utils/projectInfo.d.ts +2 -2
- package/dist/esm/utils/projectInfo.js +1 -1
- package/dist/esm/utils/redirectHard.d.ts +1 -0
- package/dist/esm/utils/redirectHard.js +3 -0
- package/dist/esm/utils/urlToFile.js +1 -1
- package/package.json +17 -2
- package/dist/cjs/utils/isExternalLink.js +0 -7
- package/dist/cjs/utils/serverSideRouteTo.js +0 -7
- package/dist/esm/utils/isExternalLink.d.ts +0 -2
- package/dist/esm/utils/isExternalLink.js +0 -4
- package/dist/esm/utils/serverSideRouteTo.d.ts +0 -2
- package/dist/esm/utils/serverSideRouteTo.js +0 -4
- /package/dist/esm/{shared/route → node/runtime/renderPage}/resolveRedirects.d.ts +0 -0
package/dist/cjs/node/runtime/renderPage/createHttpResponseObject/assertNoInfiniteHttpRedirect.js
CHANGED
|
@@ -10,7 +10,7 @@ const globalObject = (0, utils_js_1.getGlobalObject)('assertNoInfiniteHttpRedire
|
|
|
10
10
|
redirectGraph: {}
|
|
11
11
|
});
|
|
12
12
|
function assertNoInfiniteHttpRedirect(urlRedirectTarget, urlLogical) {
|
|
13
|
-
if (
|
|
13
|
+
if (!urlRedirectTarget.startsWith('/')) {
|
|
14
14
|
// We assume that urlRedirectTarget points to an origin that is external (not the same origin), and we can therefore assume that the app doesn't define an infinite loop (in itself).
|
|
15
15
|
// - There isn't a reliable way to check whether the redirect points to an external origin or the same origin. For same origins, we assume/hope the user to pass the URL without origin.
|
|
16
16
|
// ```js
|
|
@@ -19,7 +19,6 @@ function assertNoInfiniteHttpRedirect(urlRedirectTarget, urlLogical) {
|
|
|
19
19
|
// ```
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
|
-
(0, utils_js_1.assert)(urlRedirectTarget.startsWith('/'));
|
|
23
22
|
(0, utils_js_1.assert)(urlLogical.startsWith('/'));
|
|
24
23
|
const graph = copy(globalObject.redirectGraph);
|
|
25
24
|
graph[urlRedirectTarget] ?? (graph[urlRedirectTarget] = new Set());
|
|
@@ -4,13 +4,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.resolveRouteStringRedirect = exports.resolveRedirects = void 0;
|
|
7
|
-
const assertIsNotBrowser_js_1 = require("
|
|
8
|
-
const utils_js_1 = require("
|
|
9
|
-
const resolveUrlPathname_js_1 = require("
|
|
10
|
-
const resolveRouteString_js_1 = require("
|
|
7
|
+
const assertIsNotBrowser_js_1 = require("../../../utils/assertIsNotBrowser.js");
|
|
8
|
+
const utils_js_1 = require("../../../shared/utils.js");
|
|
9
|
+
const resolveUrlPathname_js_1 = require("../../../shared/route/resolveUrlPathname.js");
|
|
10
|
+
const resolveRouteString_js_1 = require("../../../shared/route/resolveRouteString.js");
|
|
11
11
|
const picocolors_1 = __importDefault(require("@brillout/picocolors"));
|
|
12
12
|
(0, assertIsNotBrowser_js_1.assertIsNotBrowser)(); // Don't bloat the client
|
|
13
|
-
// TODO/
|
|
13
|
+
// TODO/next-major-release: update
|
|
14
14
|
const configSrc = '[vite.config.js > vike({ redirects })]';
|
|
15
15
|
function resolveRedirects(redirects, urlPathname) {
|
|
16
16
|
for (const [urlSource, urlTarget] of Object.entries(redirects)) {
|
|
@@ -23,10 +23,8 @@ function resolveRedirects(redirects, urlPathname) {
|
|
|
23
23
|
exports.resolveRedirects = resolveRedirects;
|
|
24
24
|
function resolveRouteStringRedirect(urlSource, urlTarget, urlPathname) {
|
|
25
25
|
(0, resolveRouteString_js_1.assertRouteString)(urlSource, `${configSrc} Invalid`);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
(0, utils_js_1.isUriWithProtocol)(urlTarget) ||
|
|
29
|
-
urlTarget === '*', `${configSrc} Invalid redirection target URL ${picocolors_1.default.cyan(urlTarget)}: the target URL should start with ${picocolors_1.default.cyan('/')}, a valid protocol (${picocolors_1.default.cyan('https:')}, ${picocolors_1.default.cyan('http:')}, ${picocolors_1.default.cyan('mailto:')}, ${picocolors_1.default.cyan('ipfs:')}, ${picocolors_1.default.cyan('magnet:')}, ...), or be ${picocolors_1.default.cyan('*')}`);
|
|
26
|
+
// Is allowing any protocol a safety issue? https://github.com/vikejs/vike/pull/1292#issuecomment-1828043917
|
|
27
|
+
(0, utils_js_1.assertUsageUrlRedirectTarget)(urlTarget, `${configSrc} The URL redirection target`, true);
|
|
30
28
|
assertParams(urlSource, urlTarget);
|
|
31
29
|
const match = (0, resolveRouteString_js_1.resolveRouteString)(urlSource, urlPathname);
|
|
32
30
|
if (!match)
|
|
@@ -34,7 +32,7 @@ function resolveRouteStringRedirect(urlSource, urlTarget, urlPathname) {
|
|
|
34
32
|
const urlResolved = (0, resolveUrlPathname_js_1.resolveUrlPathname)(urlTarget, match.routeParams);
|
|
35
33
|
if (urlResolved === urlPathname)
|
|
36
34
|
return null;
|
|
37
|
-
(0, utils_js_1.assert)(
|
|
35
|
+
(0, utils_js_1.assert)((0, utils_js_1.isUrlRedirectTarget)(urlResolved));
|
|
38
36
|
return urlResolved;
|
|
39
37
|
}
|
|
40
38
|
exports.resolveRouteStringRedirect = resolveRouteStringRedirect;
|
|
@@ -43,7 +41,7 @@ function assertParams(urlSource, urlTarget) {
|
|
|
43
41
|
routeSegments.forEach((routeSegment) => {
|
|
44
42
|
if (routeSegment.startsWith('@') || routeSegment.startsWith('*')) {
|
|
45
43
|
const segments = urlSource.split('/');
|
|
46
|
-
(0, utils_js_1.assertUsage)(segments.includes(routeSegment), `${configSrc} The redirection source URL ${picocolors_1.default.
|
|
44
|
+
(0, utils_js_1.assertUsage)(segments.includes(routeSegment), `${configSrc} The redirection source URL ${picocolors_1.default.string(urlSource)} is missing the URL parameter ${picocolors_1.default.string(routeSegment)} used by the redirection target URL ${picocolors_1.default.string(urlTarget)}`);
|
|
47
45
|
}
|
|
48
46
|
});
|
|
49
47
|
}
|
|
@@ -21,7 +21,7 @@ const serializePageContextClientSide_js_1 = require("./html/serializePageContext
|
|
|
21
21
|
const error_page_js_1 = require("../../shared/error-page.js");
|
|
22
22
|
const handleErrorWithoutErrorPage_js_1 = require("./renderPage/handleErrorWithoutErrorPage.js");
|
|
23
23
|
const loadUserFilesServerSide_js_1 = require("./renderPage/loadUserFilesServerSide.js");
|
|
24
|
-
const resolveRedirects_js_1 = require("
|
|
24
|
+
const resolveRedirects_js_1 = require("./renderPage/resolveRedirects.js");
|
|
25
25
|
const globalObject = (0, utils_js_1.getGlobalObject)('runtime/renderPage.ts', {
|
|
26
26
|
httpRequestsCount: 0,
|
|
27
27
|
pendingRequestsCount: 0
|
|
@@ -332,12 +332,9 @@ function getRequestId() {
|
|
|
332
332
|
return httpRequestId;
|
|
333
333
|
}
|
|
334
334
|
function isIgnoredUrl(urlOriginal) {
|
|
335
|
-
const
|
|
336
|
-
(0, utils_js_1.assertWarning)(!
|
|
337
|
-
return (urlOriginal.endsWith('/__vite_ping') ||
|
|
338
|
-
urlOriginal.endsWith('/favicon.ico') ||
|
|
339
|
-
!(0, utils_js_1.isParsable)(urlOriginal) ||
|
|
340
|
-
isViteClientRequest);
|
|
335
|
+
const isViteRequest = urlOriginal.endsWith('/@vite/client') || urlOriginal.startsWith('/@fs/');
|
|
336
|
+
(0, utils_js_1.assertWarning)(!isViteRequest, `The vike middleware renderPage() was called with the URL ${urlOriginal} which is unexpected because the HTTP request should have already been handled by Vite's development middleware. Make sure to 1. install Vite's development middleware and 2. add Vite's middleware *before* Vike's middleware, see https://vike.dev/renderPage`, { onlyOnce: true });
|
|
337
|
+
return (urlOriginal.endsWith('/__vite_ping') || urlOriginal.endsWith('/favicon.ico') || !(0, utils_js_1.isUrl)(urlOriginal) || isViteRequest);
|
|
341
338
|
}
|
|
342
339
|
function normalizeUrl(pageContextInit, httpRequestId) {
|
|
343
340
|
const { trailingSlash, disableUrlNormalization, baseServer } = (0, globalContext_js_1.getGlobalContext)();
|
|
@@ -365,9 +362,9 @@ function getPermanentRedirect(pageContextInit, httpRequestId) {
|
|
|
365
362
|
const urlTarget = (0, resolveRedirects_js_1.resolveRedirects)(redirects, urlPathname);
|
|
366
363
|
if (urlTarget === null)
|
|
367
364
|
return null;
|
|
368
|
-
if (!(0, utils_js_1.
|
|
365
|
+
if (!(0, utils_js_1.isUrl)(urlTarget)) {
|
|
369
366
|
// E.g. `urlTarget === 'mailto:some@example.com'`
|
|
370
|
-
(0, utils_js_1.assert)((0, utils_js_1.
|
|
367
|
+
(0, utils_js_1.assert)((0, utils_js_1.isUri)(urlTarget));
|
|
371
368
|
urlTargetExternal = urlTarget;
|
|
372
369
|
return null;
|
|
373
370
|
}
|
|
@@ -30,11 +30,6 @@ function getPageContextUrlComputed(pageContext) {
|
|
|
30
30
|
}
|
|
31
31
|
exports.getPageContextUrlComputed = getPageContextUrlComputed;
|
|
32
32
|
function getUrlParsed(pageContext) {
|
|
33
|
-
// We need a url handler function because the onBeforeRoute() hook may set pageContext.urlLogical (typically for i18n)
|
|
34
|
-
let urlHandler = pageContext._urlHandler;
|
|
35
|
-
if (!urlHandler) {
|
|
36
|
-
urlHandler = (url) => url;
|
|
37
|
-
}
|
|
38
33
|
// Example of i18n app using `throw render()`:
|
|
39
34
|
// 1. User goes to '/fr-FR/admin'.
|
|
40
35
|
// 2. The first onBeforeRoute() call accesses pageContext.urlPathname (its value is '/fr-FR/admin': the pathname of pageContext.urlOriginal, since both pageContext.urlLogical and pageContext._urlRewrite are undefined) and sets pageContext.urlLogical to '/admin'.
|
|
@@ -43,23 +38,36 @@ function getUrlParsed(pageContext) {
|
|
|
43
38
|
// 5. The second onBeforeRoute() call accesses pageContext.urlPathname (its value is '/fr-FR/login': the pathname of pageContext._urlRewrite, since pageContext.urlLogical is undefined) and sets pageContext.urlLogical to '/login'.
|
|
44
39
|
// 6. The value of pageContext.urlPathname is now '/login': the pathname of `pageContext.urlLogical`. (While pageContext.urlOriginal is still '/fr-FR/admin'.)
|
|
45
40
|
// Reproduction: https://github.com/vikejs/vike/discussions/1436#discussioncomment-8142023
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
41
|
+
// Determine logical URL
|
|
42
|
+
let urlResolved;
|
|
43
|
+
let baseToBeRemoved;
|
|
44
|
+
if (pageContext.urlLogical) {
|
|
45
|
+
// Set by onBeforeRoute()
|
|
46
|
+
urlResolved = pageContext.urlLogical;
|
|
47
|
+
baseToBeRemoved = false;
|
|
48
|
+
}
|
|
49
|
+
else if (pageContext._urlRewrite) {
|
|
49
50
|
// Set by `throw render()`
|
|
50
|
-
pageContext._urlRewrite
|
|
51
|
+
urlResolved = pageContext._urlRewrite;
|
|
52
|
+
baseToBeRemoved = false;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
51
55
|
// Set by renderPage()
|
|
52
|
-
pageContext.urlOriginal;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
console.log('pageContext.urlLogical', pageContext.urlLogical)
|
|
56
|
-
console.log('pageContext._urlRewrite', pageContext._urlRewrite)
|
|
57
|
-
console.log('pageContext.urlOriginal', pageContext.urlOriginal)
|
|
58
|
-
console.log()
|
|
59
|
-
//*/
|
|
60
|
-
const baseServer = pageContext._baseServer;
|
|
56
|
+
urlResolved = pageContext.urlOriginal;
|
|
57
|
+
baseToBeRemoved = true;
|
|
58
|
+
}
|
|
61
59
|
(0, utils_js_1.assert)(urlResolved && typeof urlResolved === 'string');
|
|
62
|
-
|
|
60
|
+
// Remove .pageContext.json
|
|
61
|
+
let urlHandler = pageContext._urlHandler;
|
|
62
|
+
if (!urlHandler)
|
|
63
|
+
urlHandler = (url) => url;
|
|
64
|
+
urlResolved = urlHandler(urlResolved);
|
|
65
|
+
// Remove Base URL.
|
|
66
|
+
// - We assume there isn't any Base URL to the URLs set by the user at `throw render()` and onBeforeRoute()
|
|
67
|
+
// - This makes sense because the Base URL is merely a setting: ideally the user should write code that doesn't know anything about it (so that the user can remove/add/change Base URL without having to modify any code).
|
|
68
|
+
// - pageContext.urlOriginal is the URL of the HTTP request and thus contains the Base URL.
|
|
69
|
+
const baseServer = !baseToBeRemoved ? '/' : pageContext._baseServer;
|
|
70
|
+
// Parse URL
|
|
63
71
|
return (0, utils_js_1.parseUrl)(urlResolved, baseServer);
|
|
64
72
|
}
|
|
65
73
|
function urlPathnameGetter() {
|
|
@@ -74,47 +82,45 @@ function urlGetter() {
|
|
|
74
82
|
return urlPathnameGetter.call(this);
|
|
75
83
|
}
|
|
76
84
|
function urlParsedGetter() {
|
|
77
|
-
const
|
|
78
|
-
|
|
85
|
+
const {
|
|
86
|
+
// remove hasBaseServer as it isn't part of UrlPublic
|
|
87
|
+
hasBaseServer: _, ...urlParsed } = getUrlParsed(this);
|
|
79
88
|
const hashIsAvailable = (0, utils_js_1.isBrowser)();
|
|
80
89
|
const warnHashNotAvailable = (prop) => {
|
|
81
90
|
(0, utils_js_1.assertWarning)(hashIsAvailable, `pageContext.urlParsed.${prop} isn't available on the server-side (HTTP requests don't include the URL hash)`, { onlyOnce: true, showStackTrace: true });
|
|
82
91
|
};
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
pathname,
|
|
86
|
-
pathnameOriginal,
|
|
87
|
-
search,
|
|
88
|
-
searchAll,
|
|
89
|
-
searchOriginal,
|
|
92
|
+
const urlParsedEnhanced = {
|
|
93
|
+
...urlParsed,
|
|
90
94
|
get hash() {
|
|
91
95
|
warnHashNotAvailable('hash');
|
|
92
|
-
return hash;
|
|
96
|
+
return urlParsed.hash;
|
|
93
97
|
},
|
|
94
98
|
get hashOriginal() {
|
|
95
99
|
warnHashNotAvailable('hashOriginal');
|
|
96
|
-
return hashOriginal;
|
|
100
|
+
return urlParsed.hashOriginal;
|
|
97
101
|
},
|
|
102
|
+
// TODO/next-major-release: remove
|
|
98
103
|
get hashString() {
|
|
99
104
|
(0, utils_js_1.assertWarning)(false, 'pageContext.urlParsed.hashString has been renamed to pageContext.urlParsed.hashOriginal', {
|
|
100
105
|
onlyOnce: true,
|
|
101
106
|
showStackTrace: true
|
|
102
107
|
});
|
|
103
108
|
warnHashNotAvailable('hashString');
|
|
104
|
-
return hashOriginal;
|
|
109
|
+
return urlParsed.hashOriginal;
|
|
105
110
|
},
|
|
111
|
+
// TODO/next-major-release: remove
|
|
106
112
|
get searchString() {
|
|
107
113
|
(0, utils_js_1.assertWarning)(false, 'pageContext.urlParsed.searchString has been renamed to pageContext.urlParsed.searchOriginal', { onlyOnce: true, showStackTrace: true });
|
|
108
|
-
return searchOriginal;
|
|
114
|
+
return urlParsed.searchOriginal;
|
|
109
115
|
}
|
|
110
116
|
};
|
|
111
|
-
(0, utils_js_1.changeEnumerable)(
|
|
112
|
-
(0, utils_js_1.changeEnumerable)(
|
|
117
|
+
(0, utils_js_1.changeEnumerable)(urlParsedEnhanced, 'hashString', false);
|
|
118
|
+
(0, utils_js_1.changeEnumerable)(urlParsedEnhanced, 'searchString', false);
|
|
113
119
|
if (!hashIsAvailable) {
|
|
114
|
-
(0, utils_js_1.changeEnumerable)(
|
|
115
|
-
(0, utils_js_1.changeEnumerable)(
|
|
120
|
+
(0, utils_js_1.changeEnumerable)(urlParsedEnhanced, 'hash', false);
|
|
121
|
+
(0, utils_js_1.changeEnumerable)(urlParsedEnhanced, 'hashOriginal', false);
|
|
116
122
|
}
|
|
117
|
-
return
|
|
123
|
+
return urlParsedEnhanced;
|
|
118
124
|
}
|
|
119
125
|
function assertPageContextUrl(pageContext) {
|
|
120
126
|
(0, utils_js_1.assert)(typeof pageContext.urlOriginal === 'string');
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.modifyUrl = void 0;
|
|
4
|
+
const utils_js_1 = require("./utils.js");
|
|
5
|
+
/**
|
|
6
|
+
* Modify a URL.
|
|
7
|
+
*
|
|
8
|
+
* Example: changing the URL pathname for internationalization.
|
|
9
|
+
*
|
|
10
|
+
* https://vike.dev/modifyUrl
|
|
11
|
+
*/
|
|
12
|
+
function modifyUrl(url, modify) {
|
|
13
|
+
const urlParsed = (0, utils_js_1.parseUrl)(url, '/');
|
|
14
|
+
// Pathname
|
|
15
|
+
const pathname = modify.pathname ?? urlParsed.pathname;
|
|
16
|
+
// Origin
|
|
17
|
+
const originParts = [
|
|
18
|
+
modify.protocol ?? urlParsed.protocol ?? '',
|
|
19
|
+
modify.hostname ?? urlParsed.hostname ?? ''
|
|
20
|
+
];
|
|
21
|
+
const port = modify.port ?? urlParsed.port;
|
|
22
|
+
if (port || port === 0) {
|
|
23
|
+
originParts.push(`:${port}`);
|
|
24
|
+
}
|
|
25
|
+
const origin = originParts.join('');
|
|
26
|
+
const urlModified = (0, utils_js_1.createUrlFromComponents)(origin, pathname,
|
|
27
|
+
// Should we also support modifying search and hash?
|
|
28
|
+
urlParsed.searchOriginal, urlParsed.hashOriginal);
|
|
29
|
+
return urlModified;
|
|
30
|
+
}
|
|
31
|
+
exports.modifyUrl = modifyUrl;
|
|
@@ -17,7 +17,7 @@ const picocolors_1 = __importDefault(require("@brillout/picocolors"));
|
|
|
17
17
|
*/
|
|
18
18
|
function redirect(url, statusCode) {
|
|
19
19
|
const abortCaller = 'throw redirect()';
|
|
20
|
-
|
|
20
|
+
(0, utils_js_1.assertUsageUrlRedirectTarget)(url, getErrPrefix(abortCaller));
|
|
21
21
|
const args = [JSON.stringify(url)];
|
|
22
22
|
if (!statusCode) {
|
|
23
23
|
statusCode = 302;
|
|
@@ -59,7 +59,7 @@ function render_(urlOrStatusCode, abortReason, abortCall, abortCaller, pageConte
|
|
|
59
59
|
}
|
|
60
60
|
if (typeof urlOrStatusCode === 'string') {
|
|
61
61
|
const url = urlOrStatusCode;
|
|
62
|
-
|
|
62
|
+
(0, utils_js_1.assertUsageUrlPathnameAbsolute)(url, getErrPrefix(abortCaller));
|
|
63
63
|
(0, utils_js_1.objectAssign)(pageContextAbort, {
|
|
64
64
|
_urlRewrite: url
|
|
65
65
|
});
|
|
@@ -174,12 +174,6 @@ function assertNoInfiniteAbortLoop(rewriteCount, redirectCount) {
|
|
|
174
174
|
(0, utils_js_1.assertUsage)(rewriteCount + redirectCount <= 7, `Maximum chain length of 7 ${abortCalls} exceeded. Did you define an infinite loop of ${abortCalls}?`);
|
|
175
175
|
}
|
|
176
176
|
exports.assertNoInfiniteAbortLoop = assertNoInfiniteAbortLoop;
|
|
177
|
-
function
|
|
178
|
-
|
|
179
|
-
`Invalid URL ${picocolors_1.default.cyan(url)} passed to ${picocolors_1.default.cyan(abortCaller)}:`,
|
|
180
|
-
`the URL should start with ${picocolors_1.default.cyan('/')}`,
|
|
181
|
-
allowAbsoluteUrl && `or a valid protocol (${picocolors_1.default.cyan('https:')}, ${picocolors_1.default.cyan('ipfs:')}, ...)`
|
|
182
|
-
]
|
|
183
|
-
.filter(Boolean)
|
|
184
|
-
.join(' '));
|
|
177
|
+
function getErrPrefix(abortCaller) {
|
|
178
|
+
return `URL passed to ${picocolors_1.default.code(abortCaller)}`;
|
|
185
179
|
}
|
|
@@ -71,7 +71,9 @@ async function getPageContextFromHook(onBeforeRouteHook, pageContext) {
|
|
|
71
71
|
delete hookReturn.pageContext.urlOriginal;
|
|
72
72
|
}
|
|
73
73
|
if ((0, utils_js_1.hasProp)(hookReturn.pageContext, 'urlLogical')) {
|
|
74
|
-
(0, utils_js_1.
|
|
74
|
+
(0, utils_js_1.assertUsageUrlPathnameAbsolute)(
|
|
75
|
+
// We type-cast to string instead of assertUsage() in order to save client-side KBs
|
|
76
|
+
hookReturn.pageContext.urlLogical, `${errPrefix} returned ${picocolors_1.default.cyan('{ pageContext: { urlLogical } }')} but ${picocolors_1.default.cyan('urlLogical')}`);
|
|
75
77
|
}
|
|
76
78
|
(0, assertPageContextProvidedByUser_js_1.assertPageContextProvidedByUser)(hookReturn.pageContext, {
|
|
77
79
|
hookFilePath: onBeforeRouteHook.hookFilePath,
|
|
@@ -6,35 +6,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
6
6
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
7
|
};
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.
|
|
9
|
+
exports.createUrlFromComponents = exports.assertUrlComponents = exports.isBaseServer = exports.isUrlExternal = exports.isUrlRedirectTarget = exports.isUri = exports.isUrl = exports.assertUsageUrlRedirectTarget = exports.assertUsageUrlPathnameAbsolute = exports.assertUsageUrlPathname = exports.parseUrl = void 0;
|
|
10
10
|
const slice_js_1 = require("./slice.js");
|
|
11
11
|
const assert_js_1 = require("./assert.js");
|
|
12
12
|
const picocolors_1 = __importDefault(require("@brillout/picocolors"));
|
|
13
|
-
function isParsable(url) {
|
|
14
|
-
// `parseUrl()` works with these URLs
|
|
15
|
-
return (isUrlWithProtocol(url) ||
|
|
16
|
-
url.startsWith('/') ||
|
|
17
|
-
url.startsWith('.') ||
|
|
18
|
-
url.startsWith('?') ||
|
|
19
|
-
url.startsWith('#') ||
|
|
20
|
-
url === '');
|
|
21
|
-
}
|
|
22
|
-
exports.isParsable = isParsable;
|
|
23
|
-
function assertUsageUrl(url, errPrefix) {
|
|
24
|
-
(0, assert_js_1.assert)(errPrefix.includes(' but '));
|
|
25
|
-
(0, assert_js_1.assertUsage)(typeof url === 'string', `${errPrefix} should be a string`);
|
|
26
|
-
if (isParsable(url))
|
|
27
|
-
return;
|
|
28
|
-
if (!url.startsWith('/') && !url.includes(':')) {
|
|
29
|
-
(0, assert_js_1.assertUsage)(false, `${errPrefix} is ${picocolors_1.default.cyan(url)} and it should be /${picocolors_1.default.cyan(url)} instead (URL pathnames should start with a leading slash)`);
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
(0, assert_js_1.assertUsage)(false, `${errPrefix} isn't a valid URL`);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
exports.assertUsageUrl = assertUsageUrl;
|
|
36
13
|
function parseUrl(url, baseServer) {
|
|
37
|
-
(0, assert_js_1.assert)(
|
|
14
|
+
(0, assert_js_1.assert)(isUrl(url), url);
|
|
38
15
|
(0, assert_js_1.assert)(baseServer.startsWith('/'));
|
|
39
16
|
// Hash
|
|
40
17
|
const [urlWithoutHash, ...hashList] = url.split('#');
|
|
@@ -54,18 +31,24 @@ function parseUrl(url, baseServer) {
|
|
|
54
31
|
searchAll[key] = [...(searchAll.hasOwnProperty(key) ? searchAll[key] : []), val];
|
|
55
32
|
});
|
|
56
33
|
// Origin + pathname
|
|
57
|
-
|
|
58
|
-
(0, assert_js_1.assert)(origin === null || origin === decodeSafe(origin)); // AFAICT decoding the origin is useless
|
|
59
|
-
(0, assert_js_1.assert)(pathnameResolved.startsWith('/'));
|
|
60
|
-
(0, assert_js_1.assert)(origin === null || url.startsWith(origin));
|
|
61
|
-
// `pathnameOriginal`
|
|
34
|
+
let { protocol, origin, pathnameAbsoluteWithBase } = getPathnameAbsoluteWithBase(urlWithoutHashNorSearch, baseServer);
|
|
62
35
|
const pathnameOriginal = urlWithoutHashNorSearch.slice((origin || '').length);
|
|
63
36
|
assertUrlComponents(url, origin, pathnameOriginal, searchOriginal, hashOriginal);
|
|
64
37
|
// Base URL
|
|
65
|
-
let { pathname, hasBaseServer } =
|
|
38
|
+
let { pathname, hasBaseServer } = removeBaseServer(pathnameAbsoluteWithBase, baseServer);
|
|
39
|
+
// pageContext.urlParsed.href
|
|
40
|
+
const href = createUrlFromComponents(origin, pathname, searchOriginal, hashOriginal);
|
|
41
|
+
// pageContext.urlParsed.{hostname, port}
|
|
42
|
+
const host = !origin ? null : origin.slice(protocol.length);
|
|
43
|
+
const { hostname, port } = parseHost(host, url);
|
|
44
|
+
// decode after setting href
|
|
66
45
|
pathname = decodePathname(pathname);
|
|
67
46
|
(0, assert_js_1.assert)(pathname.startsWith('/'));
|
|
68
47
|
return {
|
|
48
|
+
href,
|
|
49
|
+
protocol,
|
|
50
|
+
hostname,
|
|
51
|
+
port,
|
|
69
52
|
origin,
|
|
70
53
|
pathname,
|
|
71
54
|
pathnameOriginal: pathnameOriginal,
|
|
@@ -97,20 +80,20 @@ function decodePathname(urlPathname) {
|
|
|
97
80
|
.join('/');
|
|
98
81
|
return urlPathname;
|
|
99
82
|
}
|
|
100
|
-
function
|
|
83
|
+
function getPathnameAbsoluteWithBase(url, baseServer) {
|
|
101
84
|
// Search and hash already extracted
|
|
102
85
|
(0, assert_js_1.assert)(!url.includes('?') && !url.includes('#'));
|
|
103
86
|
// url has origin
|
|
104
87
|
{
|
|
105
|
-
const { origin, pathname } = parseOrigin(url);
|
|
88
|
+
const { protocol, origin, pathname } = parseOrigin(url);
|
|
106
89
|
if (origin) {
|
|
107
|
-
return { origin, pathname };
|
|
90
|
+
return { protocol, origin, pathnameAbsoluteWithBase: pathname };
|
|
108
91
|
}
|
|
109
92
|
(0, assert_js_1.assert)(pathname === url);
|
|
110
93
|
}
|
|
111
94
|
// url doesn't have origin
|
|
112
95
|
if (url.startsWith('/')) {
|
|
113
|
-
return { origin: null,
|
|
96
|
+
return { protocol: null, origin: null, pathnameAbsoluteWithBase: url };
|
|
114
97
|
}
|
|
115
98
|
else {
|
|
116
99
|
// url is a relative path
|
|
@@ -125,21 +108,70 @@ function getPathname(url, baseServer) {
|
|
|
125
108
|
else {
|
|
126
109
|
base = baseServer;
|
|
127
110
|
}
|
|
128
|
-
const
|
|
129
|
-
return { origin: null,
|
|
111
|
+
const pathnameAbsoluteWithBase = resolveUrlPathnameRelative(url, base);
|
|
112
|
+
return { protocol: null, origin: null, pathnameAbsoluteWithBase: pathnameAbsoluteWithBase };
|
|
130
113
|
}
|
|
131
114
|
}
|
|
132
115
|
function parseOrigin(url) {
|
|
133
116
|
if (!isUrlWithProtocol(url)) {
|
|
134
|
-
|
|
135
|
-
return { pathname: url, origin: null };
|
|
117
|
+
return { pathname: url, origin: null, protocol: null };
|
|
136
118
|
}
|
|
137
119
|
else {
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
const
|
|
141
|
-
|
|
120
|
+
const { protocol, uriWithoutProtocol } = parseProtocol(url);
|
|
121
|
+
(0, assert_js_1.assert)(protocol);
|
|
122
|
+
const [host, ...rest] = uriWithoutProtocol.split('/');
|
|
123
|
+
const origin = protocol + host;
|
|
124
|
+
const pathname = '/' + rest.join('/');
|
|
125
|
+
return { pathname, origin, protocol };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function parseHost(host, url) {
|
|
129
|
+
const ret = { hostname: null, port: null };
|
|
130
|
+
if (!host)
|
|
131
|
+
return ret;
|
|
132
|
+
// hostname
|
|
133
|
+
const [hostname, ...rest] = host.split(':');
|
|
134
|
+
ret.hostname = hostname;
|
|
135
|
+
// port
|
|
136
|
+
if (rest.length > 0) {
|
|
137
|
+
(0, assert_js_1.assert)(rest.length === 1, url);
|
|
138
|
+
const portStr = rest[0];
|
|
139
|
+
const port = parseInt(portStr, 10);
|
|
140
|
+
(0, assert_js_1.assert)(port || port === 0, url);
|
|
141
|
+
ret.port = port;
|
|
142
142
|
}
|
|
143
|
+
return ret;
|
|
144
|
+
}
|
|
145
|
+
function parseProtocol(uri) {
|
|
146
|
+
const SEP = ':';
|
|
147
|
+
const [before, ...after] = uri.split(SEP);
|
|
148
|
+
if (after.length === 0 ||
|
|
149
|
+
// https://github.com/vikejs/vike/commit/886a99ff21e86a8ca699a25cee7edc184aa058e4#r143308934
|
|
150
|
+
// https://en.wikipedia.org/wiki/List_of_URI_schemes
|
|
151
|
+
// https://www.rfc-editor.org/rfc/rfc7595
|
|
152
|
+
!/^[a-z][a-z0-9\+\-]*$/i.test(before)) {
|
|
153
|
+
return { protocol: null, uriWithoutProtocol: uri };
|
|
154
|
+
}
|
|
155
|
+
let protocol = before + SEP;
|
|
156
|
+
let uriWithoutProtocol = after.join(SEP);
|
|
157
|
+
const SEP2 = '//';
|
|
158
|
+
if (uriWithoutProtocol.startsWith(SEP2)) {
|
|
159
|
+
protocol = protocol + SEP2;
|
|
160
|
+
uriWithoutProtocol = uriWithoutProtocol.slice(SEP2.length);
|
|
161
|
+
}
|
|
162
|
+
return { protocol, uriWithoutProtocol };
|
|
163
|
+
}
|
|
164
|
+
function isUrlProtocol(protocol) {
|
|
165
|
+
// Is there an altenrative to having a blacklist?
|
|
166
|
+
// - If the blacklist becomes too big, maybe use a whitelist instead ['tauri://', 'file://', 'capacitor://', 'http://', 'https://']
|
|
167
|
+
const blacklist = [
|
|
168
|
+
// https://docs.ipfs.tech/how-to/address-ipfs-on-web
|
|
169
|
+
'ipfs://',
|
|
170
|
+
'ipns://'
|
|
171
|
+
];
|
|
172
|
+
if (blacklist.includes(protocol))
|
|
173
|
+
return false;
|
|
174
|
+
return protocol.endsWith('://');
|
|
143
175
|
}
|
|
144
176
|
// Adapted from https://stackoverflow.com/questions/14780350/convert-relative-path-to-absolute-using-javascript/14780463#14780463
|
|
145
177
|
function resolveUrlPathnameRelative(pathnameRelative, base) {
|
|
@@ -170,34 +202,15 @@ function resolveUrlPathnameRelative(pathnameRelative, base) {
|
|
|
170
202
|
pathnameAbsolute = '/' + pathnameAbsolute;
|
|
171
203
|
return pathnameAbsolute;
|
|
172
204
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
assertUsage(
|
|
176
|
-
!baseServer.startsWith('http'),
|
|
177
|
-
usageErrorMessagePrefix +
|
|
178
|
-
'`base` is not allowed to start with `http`. Consider using `baseAssets` instead, see https://vike.dev/base-url'
|
|
179
|
-
)
|
|
180
|
-
assertUsage(
|
|
181
|
-
baseServer.startsWith('/'),
|
|
182
|
-
usageErrorMessagePrefix + 'Wrong `base` value `' + baseServer + '`; `base` should start with `/`.'
|
|
183
|
-
)
|
|
184
|
-
assert(isBaseServer(baseServer))
|
|
185
|
-
}
|
|
186
|
-
*/
|
|
187
|
-
function assertPathname(urlPathname) {
|
|
188
|
-
(0, assert_js_1.assert)(urlPathname.startsWith('/'));
|
|
189
|
-
(0, assert_js_1.assert)(!urlPathname.includes('?'));
|
|
190
|
-
(0, assert_js_1.assert)(!urlPathname.includes('#'));
|
|
191
|
-
}
|
|
192
|
-
function analyzeBaseServer(urlPathnameWithBase, baseServer) {
|
|
193
|
-
assertPathname(urlPathnameWithBase);
|
|
205
|
+
function removeBaseServer(pathnameAbsoluteWithBase, baseServer) {
|
|
206
|
+
(0, assert_js_1.assert)(pathnameAbsoluteWithBase.startsWith('/'));
|
|
194
207
|
(0, assert_js_1.assert)(isBaseServer(baseServer));
|
|
195
208
|
// Mutable
|
|
196
|
-
let urlPathname =
|
|
209
|
+
let urlPathname = pathnameAbsoluteWithBase;
|
|
197
210
|
(0, assert_js_1.assert)(urlPathname.startsWith('/'));
|
|
198
211
|
(0, assert_js_1.assert)(baseServer.startsWith('/'));
|
|
199
212
|
if (baseServer === '/') {
|
|
200
|
-
const pathname =
|
|
213
|
+
const pathname = pathnameAbsoluteWithBase;
|
|
201
214
|
return { pathname, hasBaseServer: true };
|
|
202
215
|
}
|
|
203
216
|
// Support `url === '/some-base-url' && baseServer === '/some-base-url/'`
|
|
@@ -207,7 +220,7 @@ function analyzeBaseServer(urlPathnameWithBase, baseServer) {
|
|
|
207
220
|
(0, assert_js_1.assert)(urlPathname === baseServerNormalized);
|
|
208
221
|
}
|
|
209
222
|
if (!urlPathname.startsWith(baseServerNormalized)) {
|
|
210
|
-
const pathname =
|
|
223
|
+
const pathname = pathnameAbsoluteWithBase;
|
|
211
224
|
return { pathname, hasBaseServer: false };
|
|
212
225
|
}
|
|
213
226
|
(0, assert_js_1.assert)(urlPathname.startsWith('/') || urlPathname.startsWith('http'));
|
|
@@ -222,30 +235,98 @@ function isBaseServer(baseServer) {
|
|
|
222
235
|
return baseServer.startsWith('/');
|
|
223
236
|
}
|
|
224
237
|
exports.isBaseServer = isBaseServer;
|
|
225
|
-
function assertUrlComponents(url, origin,
|
|
226
|
-
const urlRecreated = createUrlFromComponents(origin,
|
|
238
|
+
function assertUrlComponents(url, origin, pathnameOriginal, searchOriginal, hashOriginal) {
|
|
239
|
+
const urlRecreated = createUrlFromComponents(origin, pathnameOriginal, searchOriginal, hashOriginal);
|
|
227
240
|
(0, assert_js_1.assert)(url === urlRecreated);
|
|
228
241
|
}
|
|
229
242
|
exports.assertUrlComponents = assertUrlComponents;
|
|
230
|
-
function createUrlFromComponents(origin, pathname,
|
|
231
|
-
const urlRecreated = `${origin || ''}${pathname}${
|
|
243
|
+
function createUrlFromComponents(origin, pathname, search, hash) {
|
|
244
|
+
const urlRecreated = `${origin || ''}${pathname}${search || ''}${hash || ''}`;
|
|
232
245
|
return urlRecreated;
|
|
233
246
|
}
|
|
234
247
|
exports.createUrlFromComponents = createUrlFromComponents;
|
|
235
|
-
function
|
|
236
|
-
//
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
return
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
248
|
+
function isUrl(url) {
|
|
249
|
+
// parseUrl() works with these URLs
|
|
250
|
+
return isUrlWithProtocol(url) || url.startsWith('/') || isUrlPathnameRelative(url);
|
|
251
|
+
}
|
|
252
|
+
exports.isUrl = isUrl;
|
|
253
|
+
function isUrlRedirectTarget(url) {
|
|
254
|
+
return url.startsWith('/') || isUri(url) || isUrlWithProtocol(url);
|
|
255
|
+
}
|
|
256
|
+
exports.isUrlRedirectTarget = isUrlRedirectTarget;
|
|
257
|
+
function isUrlPathnameRelative(url) {
|
|
258
|
+
return ['.', '?', '#'].some((c) => url.startsWith(c)) || url === '';
|
|
259
|
+
}
|
|
260
|
+
function isUrlExternal(url) {
|
|
261
|
+
return !url.startsWith('/') && !isUrlPathnameRelative(url);
|
|
262
|
+
}
|
|
263
|
+
exports.isUrlExternal = isUrlExternal;
|
|
264
|
+
/*
|
|
265
|
+
URL with protocol.
|
|
266
|
+
|
|
267
|
+
http://example.com
|
|
268
|
+
https://exmaple.com
|
|
269
|
+
tauri://localhost
|
|
270
|
+
file://example.com
|
|
271
|
+
capacitor://localhost/assets/chunks/chunk-DJBYDrsP.js
|
|
272
|
+
|
|
273
|
+
[Tauri](https://github.com/vikejs/vike/issues/808)
|
|
274
|
+
[Electron (`file://`)](https://github.com/vikejs/vike/issues/1557)
|
|
275
|
+
[Capacitor](https://github.com/vikejs/vike/issues/1706)
|
|
276
|
+
*/
|
|
277
|
+
function isUrlWithProtocol(url) {
|
|
278
|
+
const { protocol } = parseProtocol(url);
|
|
279
|
+
return !!protocol && isUrlProtocol(protocol);
|
|
280
|
+
}
|
|
281
|
+
/*
|
|
282
|
+
URIs that aren't URLs.
|
|
283
|
+
|
|
284
|
+
mailto:john@example.com
|
|
285
|
+
|
|
286
|
+
ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/wiki/Vincent_van_Gogh.html
|
|
287
|
+
|
|
288
|
+
magnet:?xt=urn:btih:3a15e1ac49683d91b20c2ffc252ea612a6c01bd7&dn=The.Empire.Strikes.Back.1980.Remastered.1080p.BluRay.DDP.7.1.x265-EDGE2020.mkv&xl=3225443573&tr=udp://tracker.opentrackr.org:1337/announce&tr=udp://tracker.torrent.eu.org:451&tr=udp://open.stealth.si:80/announce&tr=udp://tracker.openbittorrent.com:6969&tr=udp://tracker.tiny-vps.com:6969/announce&tr=udp://open.demonii.com:1337
|
|
289
|
+
|
|
290
|
+
We need to treat URIs differently than URLs.
|
|
291
|
+
- For example, we cannot parse URIs (their structure is unknown e.g. a `magnet:` URI is completely different than a `http://` URL).
|
|
292
|
+
- The protocols tauri:// file:// capacitor:// follow the same structure as http:// and https:// URLs.
|
|
293
|
+
- Thus we can parse them like http:// and https:// URLs.
|
|
294
|
+
*/
|
|
295
|
+
function isUri(uri) {
|
|
296
|
+
const { protocol } = parseProtocol(uri);
|
|
297
|
+
return !!protocol && !isUrlProtocol(uri);
|
|
298
|
+
}
|
|
299
|
+
exports.isUri = isUri;
|
|
300
|
+
function assertUsageUrlPathname(url, errPrefix) {
|
|
301
|
+
assertUsageUrl(url, errPrefix, { allowRelative: true });
|
|
302
|
+
}
|
|
303
|
+
exports.assertUsageUrlPathname = assertUsageUrlPathname;
|
|
304
|
+
function assertUsageUrlPathnameAbsolute(url, errPrefix) {
|
|
305
|
+
assertUsageUrl(url, errPrefix);
|
|
306
|
+
}
|
|
307
|
+
exports.assertUsageUrlPathnameAbsolute = assertUsageUrlPathnameAbsolute;
|
|
308
|
+
function assertUsageUrlRedirectTarget(url, errPrefix, isUnresolved) {
|
|
309
|
+
assertUsageUrl(url, errPrefix, { isRedirectTarget: isUnresolved ? 'unresolved' : true });
|
|
310
|
+
}
|
|
311
|
+
exports.assertUsageUrlRedirectTarget = assertUsageUrlRedirectTarget;
|
|
312
|
+
function assertUsageUrl(url, errPrefix, { allowRelative, isRedirectTarget } = {}) {
|
|
313
|
+
if (url.startsWith('/'))
|
|
314
|
+
return;
|
|
315
|
+
let errMsg = `${errPrefix} is ${picocolors_1.default.string(url)} but it should start with ${picocolors_1.default.string('/')}`;
|
|
316
|
+
if (isRedirectTarget) {
|
|
317
|
+
if (isUrlRedirectTarget(url))
|
|
318
|
+
return;
|
|
319
|
+
errMsg += ` or a protocol (${picocolors_1.default.string('http://')}, ${picocolors_1.default.string('mailto:')}, ...)`;
|
|
320
|
+
if (isRedirectTarget === 'unresolved') {
|
|
321
|
+
if (url === '*')
|
|
322
|
+
return;
|
|
323
|
+
errMsg += `, or be ${picocolors_1.default.string('*')}`;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (allowRelative) {
|
|
327
|
+
if (isUrlPathnameRelative(url))
|
|
328
|
+
return;
|
|
329
|
+
errMsg += ', or be a relative URL';
|
|
330
|
+
}
|
|
331
|
+
(0, assert_js_1.assertUsage)(false, errMsg);
|
|
251
332
|
}
|