@sveltejs/kit 1.0.0-next.298 → 1.0.0-next.299
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/assets/client/start.js +203 -115
- package/assets/server/index.js +170 -141
- package/dist/chunks/index.js +30 -29
- package/dist/chunks/index2.js +8 -4
- package/dist/chunks/index3.js +31 -30
- package/dist/chunks/index4.js +1 -0
- package/dist/chunks/routing.js +39 -0
- package/dist/chunks/sync.js +93 -53
- package/dist/cli.js +7 -8
- package/package.json +1 -1
- package/types/index.d.ts +13 -15
- package/types/internal.d.ts +25 -22
- package/types/private.d.ts +4 -8
package/assets/server/index.js
CHANGED
|
@@ -88,10 +88,8 @@ function is_pojo(body) {
|
|
|
88
88
|
|
|
89
89
|
return true;
|
|
90
90
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
* @returns string
|
|
94
|
-
*/
|
|
91
|
+
|
|
92
|
+
/** @param {import('types').RequestEvent} event */
|
|
95
93
|
function normalize_request_method(event) {
|
|
96
94
|
const method = event.request.method.toLowerCase();
|
|
97
95
|
return method === 'delete' ? 'del' : method; // 'delete' is a reserved word
|
|
@@ -132,7 +130,7 @@ function is_text(content_type) {
|
|
|
132
130
|
/**
|
|
133
131
|
* @param {import('types').RequestEvent} event
|
|
134
132
|
* @param {{ [method: string]: import('types').RequestHandler }} mod
|
|
135
|
-
* @returns {Promise<Response
|
|
133
|
+
* @returns {Promise<Response>}
|
|
136
134
|
*/
|
|
137
135
|
async function render_endpoint(event, mod) {
|
|
138
136
|
const method = normalize_request_method(event);
|
|
@@ -143,8 +141,17 @@ async function render_endpoint(event, mod) {
|
|
|
143
141
|
if (!handler && method === 'head') {
|
|
144
142
|
handler = mod.get;
|
|
145
143
|
}
|
|
144
|
+
|
|
146
145
|
if (!handler) {
|
|
147
|
-
return
|
|
146
|
+
return event.request.headers.get('x-sveltekit-load')
|
|
147
|
+
? // TODO would be nice to avoid these requests altogether,
|
|
148
|
+
// by noting whether or not page endpoints export `get`
|
|
149
|
+
new Response(undefined, {
|
|
150
|
+
status: 204
|
|
151
|
+
})
|
|
152
|
+
: new Response('Method not allowed', {
|
|
153
|
+
status: 405
|
|
154
|
+
});
|
|
148
155
|
}
|
|
149
156
|
|
|
150
157
|
const response = await handler(event);
|
|
@@ -154,8 +161,12 @@ async function render_endpoint(event, mod) {
|
|
|
154
161
|
return error(`${preface}: expected an object, got ${typeof response}`);
|
|
155
162
|
}
|
|
156
163
|
|
|
164
|
+
// TODO remove for 1.0
|
|
165
|
+
// @ts-expect-error
|
|
157
166
|
if (response.fallthrough) {
|
|
158
|
-
|
|
167
|
+
throw new Error(
|
|
168
|
+
'fallthrough is no longer supported. Use validators instead: https://kit.svelte.dev/docs/routing#advanced-routing-validation'
|
|
169
|
+
);
|
|
159
170
|
}
|
|
160
171
|
|
|
161
172
|
const { status = 200, body = {} } = response;
|
|
@@ -1081,9 +1092,8 @@ const updated = {
|
|
|
1081
1092
|
* $session: any;
|
|
1082
1093
|
* page_config: { hydrate: boolean, router: boolean };
|
|
1083
1094
|
* status: number;
|
|
1084
|
-
* error
|
|
1085
|
-
*
|
|
1086
|
-
* params: Record<string, string>;
|
|
1095
|
+
* error: Error | null;
|
|
1096
|
+
* event: import('types').RequestEvent;
|
|
1087
1097
|
* resolve_opts: import('types').RequiredResolveOptions;
|
|
1088
1098
|
* stuff: Record<string, any>;
|
|
1089
1099
|
* }} opts
|
|
@@ -1095,9 +1105,8 @@ async function render_response({
|
|
|
1095
1105
|
$session,
|
|
1096
1106
|
page_config,
|
|
1097
1107
|
status,
|
|
1098
|
-
error,
|
|
1099
|
-
|
|
1100
|
-
params,
|
|
1108
|
+
error = null,
|
|
1109
|
+
event,
|
|
1101
1110
|
resolve_opts,
|
|
1102
1111
|
stuff
|
|
1103
1112
|
}) {
|
|
@@ -1155,12 +1164,14 @@ async function render_response({
|
|
|
1155
1164
|
session,
|
|
1156
1165
|
updated
|
|
1157
1166
|
},
|
|
1167
|
+
/** @type {import('types').Page} */
|
|
1158
1168
|
page: {
|
|
1159
|
-
url: state.prerender ? create_prerendering_url_proxy(url) : url,
|
|
1160
|
-
params,
|
|
1161
|
-
status,
|
|
1162
1169
|
error,
|
|
1163
|
-
|
|
1170
|
+
params: event.params,
|
|
1171
|
+
routeId: event.routeId,
|
|
1172
|
+
status,
|
|
1173
|
+
stuff,
|
|
1174
|
+
url: state.prerender ? create_prerendering_url_proxy(event.url) : event.url
|
|
1164
1175
|
},
|
|
1165
1176
|
components: branch.map(({ node }) => node.module.default)
|
|
1166
1177
|
};
|
|
@@ -1236,7 +1247,8 @@ async function render_response({
|
|
|
1236
1247
|
.map(({ node }) => `import(${s(options.prefix + node.entry)})`)
|
|
1237
1248
|
.join(',\n\t\t\t\t\t\t')}
|
|
1238
1249
|
],
|
|
1239
|
-
params: ${devalue(params)}
|
|
1250
|
+
params: ${devalue(event.params)},
|
|
1251
|
+
routeId: ${s(event.routeId)}
|
|
1240
1252
|
}` : 'null'}
|
|
1241
1253
|
});
|
|
1242
1254
|
`;
|
|
@@ -1352,7 +1364,7 @@ async function render_response({
|
|
|
1352
1364
|
}
|
|
1353
1365
|
}
|
|
1354
1366
|
|
|
1355
|
-
const segments = url.pathname.slice(options.paths.base.length).split('/').slice(2);
|
|
1367
|
+
const segments = event.url.pathname.slice(options.paths.base.length).split('/').slice(2);
|
|
1356
1368
|
const assets =
|
|
1357
1369
|
options.paths.assets || (segments.length > 0 ? segments.map(() => '..').join('/') : '.');
|
|
1358
1370
|
|
|
@@ -1541,8 +1553,6 @@ function normalize_path(path, trailing_slash) {
|
|
|
1541
1553
|
* options: import('types').SSROptions;
|
|
1542
1554
|
* state: import('types').SSRState;
|
|
1543
1555
|
* route: import('types').SSRPage | null;
|
|
1544
|
-
* url: URL;
|
|
1545
|
-
* params: Record<string, string>;
|
|
1546
1556
|
* node: import('types').SSRNode;
|
|
1547
1557
|
* $session: any;
|
|
1548
1558
|
* stuff: Record<string, any>;
|
|
@@ -1551,15 +1561,13 @@ function normalize_path(path, trailing_slash) {
|
|
|
1551
1561
|
* status?: number;
|
|
1552
1562
|
* error?: Error;
|
|
1553
1563
|
* }} opts
|
|
1554
|
-
* @returns {Promise<import('./types').Loaded
|
|
1564
|
+
* @returns {Promise<import('./types').Loaded>}
|
|
1555
1565
|
*/
|
|
1556
1566
|
async function load_node({
|
|
1557
1567
|
event,
|
|
1558
1568
|
options,
|
|
1559
1569
|
state,
|
|
1560
1570
|
route,
|
|
1561
|
-
url,
|
|
1562
|
-
params,
|
|
1563
1571
|
node,
|
|
1564
1572
|
$session,
|
|
1565
1573
|
stuff,
|
|
@@ -1580,7 +1588,7 @@ async function load_node({
|
|
|
1580
1588
|
*/
|
|
1581
1589
|
let set_cookie_headers = [];
|
|
1582
1590
|
|
|
1583
|
-
/** @type {import('types').
|
|
1591
|
+
/** @type {import('types').LoadOutput} */
|
|
1584
1592
|
let loaded;
|
|
1585
1593
|
|
|
1586
1594
|
/** @type {import('types').ShadowData} */
|
|
@@ -1593,8 +1601,6 @@ async function load_node({
|
|
|
1593
1601
|
)
|
|
1594
1602
|
: {};
|
|
1595
1603
|
|
|
1596
|
-
if (shadow.fallthrough) return;
|
|
1597
|
-
|
|
1598
1604
|
if (shadow.cookies) {
|
|
1599
1605
|
set_cookie_headers.push(...shadow.cookies);
|
|
1600
1606
|
}
|
|
@@ -1612,9 +1618,10 @@ async function load_node({
|
|
|
1612
1618
|
} else if (module.load) {
|
|
1613
1619
|
/** @type {import('types').LoadInput | import('types').ErrorLoadInput} */
|
|
1614
1620
|
const load_input = {
|
|
1615
|
-
url: state.prerender ? create_prerendering_url_proxy(url) : url,
|
|
1616
|
-
params,
|
|
1621
|
+
url: state.prerender ? create_prerendering_url_proxy(event.url) : event.url,
|
|
1622
|
+
params: event.params,
|
|
1617
1623
|
props: shadow.body || {},
|
|
1624
|
+
routeId: event.routeId,
|
|
1618
1625
|
get session() {
|
|
1619
1626
|
uses_credentials = true;
|
|
1620
1627
|
return $session;
|
|
@@ -1692,7 +1699,10 @@ async function load_node({
|
|
|
1692
1699
|
headers: type ? { 'content-type': type } : {}
|
|
1693
1700
|
});
|
|
1694
1701
|
} else {
|
|
1695
|
-
response = await fetch(
|
|
1702
|
+
response = await fetch(
|
|
1703
|
+
`${event.url.origin}/${file}`,
|
|
1704
|
+
/** @type {RequestInit} */ (opts)
|
|
1705
|
+
);
|
|
1696
1706
|
}
|
|
1697
1707
|
} else if (is_root_relative(resolved)) {
|
|
1698
1708
|
if (opts.credentials !== 'omit') {
|
|
@@ -1719,7 +1729,6 @@ async function load_node({
|
|
|
1719
1729
|
}
|
|
1720
1730
|
|
|
1721
1731
|
response = await respond(new Request(new URL(requested, event.url).href, opts), options, {
|
|
1722
|
-
fetched: requested,
|
|
1723
1732
|
getClientAddress: state.getClientAddress,
|
|
1724
1733
|
initiator: route,
|
|
1725
1734
|
prerender: state.prerender
|
|
@@ -1855,8 +1864,17 @@ async function load_node({
|
|
|
1855
1864
|
loaded = await module.load.call(null, load_input);
|
|
1856
1865
|
|
|
1857
1866
|
if (!loaded) {
|
|
1867
|
+
// TODO do we still want to enforce this now that there's no fallthrough?
|
|
1858
1868
|
throw new Error(`load function must return a value${options.dev ? ` (${node.entry})` : ''}`);
|
|
1859
1869
|
}
|
|
1870
|
+
|
|
1871
|
+
// TODO remove for 1.0
|
|
1872
|
+
// @ts-expect-error
|
|
1873
|
+
if (loaded.fallthrough) {
|
|
1874
|
+
throw new Error(
|
|
1875
|
+
'fallthrough is no longer supported. Use validators instead: https://kit.svelte.dev/docs/routing#advanced-routing-validation'
|
|
1876
|
+
);
|
|
1877
|
+
}
|
|
1860
1878
|
} else if (shadow.body) {
|
|
1861
1879
|
loaded = {
|
|
1862
1880
|
props: shadow.body
|
|
@@ -1865,10 +1883,6 @@ async function load_node({
|
|
|
1865
1883
|
loaded = {};
|
|
1866
1884
|
}
|
|
1867
1885
|
|
|
1868
|
-
if (loaded.fallthrough && !is_error) {
|
|
1869
|
-
return;
|
|
1870
|
-
}
|
|
1871
|
-
|
|
1872
1886
|
// generate __data.json files when prerendering
|
|
1873
1887
|
if (shadow.body && state.prerender) {
|
|
1874
1888
|
const pathname = `${event.url.pathname.replace(/\/$/, '')}/__data.json`;
|
|
@@ -1931,7 +1945,13 @@ async function load_shadow_data(route, event, options, prerender) {
|
|
|
1931
1945
|
if (!is_get) {
|
|
1932
1946
|
const result = await handler(event);
|
|
1933
1947
|
|
|
1934
|
-
|
|
1948
|
+
// TODO remove for 1.0
|
|
1949
|
+
// @ts-expect-error
|
|
1950
|
+
if (result.fallthrough) {
|
|
1951
|
+
throw new Error(
|
|
1952
|
+
'fallthrough is no longer supported. Use validators instead: https://kit.svelte.dev/docs/routing#advanced-routing-validation'
|
|
1953
|
+
);
|
|
1954
|
+
}
|
|
1935
1955
|
|
|
1936
1956
|
const { status, headers, body } = validate_shadow_output(result);
|
|
1937
1957
|
data.status = status;
|
|
@@ -1956,7 +1976,13 @@ async function load_shadow_data(route, event, options, prerender) {
|
|
|
1956
1976
|
if (get) {
|
|
1957
1977
|
const result = await get(event);
|
|
1958
1978
|
|
|
1959
|
-
|
|
1979
|
+
// TODO remove for 1.0
|
|
1980
|
+
// @ts-expect-error
|
|
1981
|
+
if (result.fallthrough) {
|
|
1982
|
+
throw new Error(
|
|
1983
|
+
'fallthrough is no longer supported. Use validators instead: https://kit.svelte.dev/docs/routing#advanced-routing-validation'
|
|
1984
|
+
);
|
|
1985
|
+
}
|
|
1960
1986
|
|
|
1961
1987
|
const { status, headers, body } = validate_shadow_output(result);
|
|
1962
1988
|
add_cookies(/** @type {string[]} */ (data.cookies), headers);
|
|
@@ -2058,17 +2084,12 @@ async function respond_with_error({
|
|
|
2058
2084
|
const default_layout = await options.manifest._.nodes[0](); // 0 is always the root layout
|
|
2059
2085
|
const default_error = await options.manifest._.nodes[1](); // 1 is always the root error
|
|
2060
2086
|
|
|
2061
|
-
/** @type {Record<string, string>} */
|
|
2062
|
-
const params = {}; // error page has no params
|
|
2063
|
-
|
|
2064
2087
|
const layout_loaded = /** @type {Loaded} */ (
|
|
2065
2088
|
await load_node({
|
|
2066
2089
|
event,
|
|
2067
2090
|
options,
|
|
2068
2091
|
state,
|
|
2069
2092
|
route: null,
|
|
2070
|
-
url: event.url, // TODO this is redundant, no?
|
|
2071
|
-
params,
|
|
2072
2093
|
node: default_layout,
|
|
2073
2094
|
$session,
|
|
2074
2095
|
stuff: {},
|
|
@@ -2083,8 +2104,6 @@ async function respond_with_error({
|
|
|
2083
2104
|
options,
|
|
2084
2105
|
state,
|
|
2085
2106
|
route: null,
|
|
2086
|
-
url: event.url,
|
|
2087
|
-
params,
|
|
2088
2107
|
node: default_error,
|
|
2089
2108
|
$session,
|
|
2090
2109
|
stuff: layout_loaded ? layout_loaded.stuff : {},
|
|
@@ -2107,8 +2126,7 @@ async function respond_with_error({
|
|
|
2107
2126
|
status,
|
|
2108
2127
|
error,
|
|
2109
2128
|
branch: [layout_loaded, error_loaded],
|
|
2110
|
-
|
|
2111
|
-
params,
|
|
2129
|
+
event,
|
|
2112
2130
|
resolve_opts
|
|
2113
2131
|
});
|
|
2114
2132
|
} catch (err) {
|
|
@@ -2137,9 +2155,8 @@ async function respond_with_error({
|
|
|
2137
2155
|
* $session: any;
|
|
2138
2156
|
* resolve_opts: import('types').RequiredResolveOptions;
|
|
2139
2157
|
* route: import('types').SSRPage;
|
|
2140
|
-
* params: Record<string, string>;
|
|
2141
2158
|
* }} opts
|
|
2142
|
-
* @returns {Promise<Response
|
|
2159
|
+
* @returns {Promise<Response>}
|
|
2143
2160
|
*/
|
|
2144
2161
|
async function respond$1(opts) {
|
|
2145
2162
|
const { event, options, state, $session, route, resolve_opts } = opts;
|
|
@@ -2156,7 +2173,8 @@ async function respond$1(opts) {
|
|
|
2156
2173
|
router: true
|
|
2157
2174
|
},
|
|
2158
2175
|
status: 200,
|
|
2159
|
-
|
|
2176
|
+
error: null,
|
|
2177
|
+
event,
|
|
2160
2178
|
stuff: {}
|
|
2161
2179
|
});
|
|
2162
2180
|
}
|
|
@@ -2204,8 +2222,8 @@ async function respond$1(opts) {
|
|
|
2204
2222
|
/** @type {number} */
|
|
2205
2223
|
let status = 200;
|
|
2206
2224
|
|
|
2207
|
-
/** @type {Error|
|
|
2208
|
-
let error;
|
|
2225
|
+
/** @type {Error | null} */
|
|
2226
|
+
let error = null;
|
|
2209
2227
|
|
|
2210
2228
|
/** @type {string[]} */
|
|
2211
2229
|
let set_cookie_headers = [];
|
|
@@ -2223,15 +2241,12 @@ async function respond$1(opts) {
|
|
|
2223
2241
|
try {
|
|
2224
2242
|
loaded = await load_node({
|
|
2225
2243
|
...opts,
|
|
2226
|
-
url: event.url,
|
|
2227
2244
|
node,
|
|
2228
2245
|
stuff,
|
|
2229
2246
|
is_error: false,
|
|
2230
2247
|
is_leaf: i === nodes.length - 1
|
|
2231
2248
|
});
|
|
2232
2249
|
|
|
2233
|
-
if (!loaded) return;
|
|
2234
|
-
|
|
2235
2250
|
set_cookie_headers = set_cookie_headers.concat(loaded.set_cookie_headers);
|
|
2236
2251
|
|
|
2237
2252
|
if (loaded.loaded.redirect) {
|
|
@@ -2278,7 +2293,6 @@ async function respond$1(opts) {
|
|
|
2278
2293
|
const error_loaded = /** @type {import('./types').Loaded} */ (
|
|
2279
2294
|
await load_node({
|
|
2280
2295
|
...opts,
|
|
2281
|
-
url: event.url,
|
|
2282
2296
|
node: error_node,
|
|
2283
2297
|
stuff: node_loaded.stuff,
|
|
2284
2298
|
is_error: true,
|
|
@@ -2338,7 +2352,7 @@ async function respond$1(opts) {
|
|
|
2338
2352
|
await render_response({
|
|
2339
2353
|
...opts,
|
|
2340
2354
|
stuff,
|
|
2341
|
-
|
|
2355
|
+
event,
|
|
2342
2356
|
page_config,
|
|
2343
2357
|
status,
|
|
2344
2358
|
error,
|
|
@@ -2399,7 +2413,7 @@ function with_cookies(response, set_cookie_headers) {
|
|
|
2399
2413
|
* @param {import('types').SSROptions} options
|
|
2400
2414
|
* @param {import('types').SSRState} state
|
|
2401
2415
|
* @param {import('types').RequiredResolveOptions} resolve_opts
|
|
2402
|
-
* @returns {Promise<Response
|
|
2416
|
+
* @returns {Promise<Response>}
|
|
2403
2417
|
*/
|
|
2404
2418
|
async function render_page(event, route, options, state, resolve_opts) {
|
|
2405
2419
|
if (state.initiator === route) {
|
|
@@ -2422,29 +2436,14 @@ async function render_page(event, route, options, state, resolve_opts) {
|
|
|
2422
2436
|
|
|
2423
2437
|
const $session = await options.hooks.getSession(event);
|
|
2424
2438
|
|
|
2425
|
-
|
|
2439
|
+
return respond$1({
|
|
2426
2440
|
event,
|
|
2427
2441
|
options,
|
|
2428
2442
|
state,
|
|
2429
2443
|
$session,
|
|
2430
2444
|
resolve_opts,
|
|
2431
|
-
route
|
|
2432
|
-
params: event.params // TODO this is redundant
|
|
2445
|
+
route
|
|
2433
2446
|
});
|
|
2434
|
-
|
|
2435
|
-
if (response) {
|
|
2436
|
-
return response;
|
|
2437
|
-
}
|
|
2438
|
-
|
|
2439
|
-
if (state.fetched) {
|
|
2440
|
-
// we came here because of a bad request in a `load` function.
|
|
2441
|
-
// rather than render the error page — which could lead to an
|
|
2442
|
-
// infinite loop, if the `load` belonged to the root layout,
|
|
2443
|
-
// we respond with a bare-bones 500
|
|
2444
|
-
return new Response(`Bad request in load function: failed to fetch ${state.fetched}`, {
|
|
2445
|
-
status: 500
|
|
2446
|
-
});
|
|
2447
|
-
}
|
|
2448
2447
|
}
|
|
2449
2448
|
|
|
2450
2449
|
/**
|
|
@@ -2499,6 +2498,36 @@ function negotiate(accept, types) {
|
|
|
2499
2498
|
return accepted;
|
|
2500
2499
|
}
|
|
2501
2500
|
|
|
2501
|
+
/** @param {string} key */
|
|
2502
|
+
|
|
2503
|
+
/**
|
|
2504
|
+
* @param {RegExpMatchArray} match
|
|
2505
|
+
* @param {string[]} names
|
|
2506
|
+
* @param {string[]} types
|
|
2507
|
+
* @param {Record<string, import('types').ParamValidator>} validators
|
|
2508
|
+
*/
|
|
2509
|
+
function exec(match, names, types, validators) {
|
|
2510
|
+
/** @type {Record<string, string>} */
|
|
2511
|
+
const params = {};
|
|
2512
|
+
|
|
2513
|
+
for (let i = 0; i < names.length; i += 1) {
|
|
2514
|
+
const name = names[i];
|
|
2515
|
+
const type = types[i];
|
|
2516
|
+
const value = match[i + 1] || '';
|
|
2517
|
+
|
|
2518
|
+
if (type) {
|
|
2519
|
+
const validator = validators[type];
|
|
2520
|
+
if (!validator) throw new Error(`Missing "${type}" param validator`); // TODO do this ahead of time?
|
|
2521
|
+
|
|
2522
|
+
if (!validator(value)) return;
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2525
|
+
params[name] = value;
|
|
2526
|
+
}
|
|
2527
|
+
|
|
2528
|
+
return params;
|
|
2529
|
+
}
|
|
2530
|
+
|
|
2502
2531
|
const DATA_SUFFIX = '/__data.json';
|
|
2503
2532
|
|
|
2504
2533
|
/** @param {{ html: string }} opts */
|
|
@@ -2506,11 +2535,11 @@ const default_transform = ({ html }) => html;
|
|
|
2506
2535
|
|
|
2507
2536
|
/** @type {import('types').Respond} */
|
|
2508
2537
|
async function respond(request, options, state) {
|
|
2509
|
-
|
|
2538
|
+
let url = new URL(request.url);
|
|
2510
2539
|
|
|
2511
2540
|
const normalized = normalize_path(url.pathname, options.trailing_slash);
|
|
2512
2541
|
|
|
2513
|
-
if (normalized !== url.pathname) {
|
|
2542
|
+
if (normalized !== url.pathname && !state.prerender?.fallback) {
|
|
2514
2543
|
return new Response(undefined, {
|
|
2515
2544
|
status: 301,
|
|
2516
2545
|
headers: {
|
|
@@ -2544,6 +2573,50 @@ async function respond(request, options, state) {
|
|
|
2544
2573
|
}
|
|
2545
2574
|
}
|
|
2546
2575
|
|
|
2576
|
+
let decoded = decodeURI(url.pathname);
|
|
2577
|
+
|
|
2578
|
+
/** @type {import('types').SSRRoute | null} */
|
|
2579
|
+
let route = null;
|
|
2580
|
+
|
|
2581
|
+
/** @type {Record<string, string>} */
|
|
2582
|
+
let params = {};
|
|
2583
|
+
|
|
2584
|
+
if (options.paths.base) {
|
|
2585
|
+
if (!decoded.startsWith(options.paths.base)) {
|
|
2586
|
+
return new Response(undefined, { status: 404 });
|
|
2587
|
+
}
|
|
2588
|
+
decoded = decoded.slice(options.paths.base.length) || '/';
|
|
2589
|
+
}
|
|
2590
|
+
|
|
2591
|
+
const is_data_request = decoded.endsWith(DATA_SUFFIX);
|
|
2592
|
+
|
|
2593
|
+
if (is_data_request) {
|
|
2594
|
+
decoded = decoded.slice(0, -DATA_SUFFIX.length) || '/';
|
|
2595
|
+
|
|
2596
|
+
const normalized = normalize_path(
|
|
2597
|
+
url.pathname.slice(0, -DATA_SUFFIX.length),
|
|
2598
|
+
options.trailing_slash
|
|
2599
|
+
);
|
|
2600
|
+
|
|
2601
|
+
url = new URL(url.origin + normalized + url.search);
|
|
2602
|
+
}
|
|
2603
|
+
|
|
2604
|
+
if (!state.prerender || !state.prerender.fallback) {
|
|
2605
|
+
const validators = await options.manifest._.validators();
|
|
2606
|
+
|
|
2607
|
+
for (const candidate of options.manifest._.routes) {
|
|
2608
|
+
const match = candidate.pattern.exec(decoded);
|
|
2609
|
+
if (!match) continue;
|
|
2610
|
+
|
|
2611
|
+
const matched = exec(match, candidate.names, candidate.types, validators);
|
|
2612
|
+
if (matched) {
|
|
2613
|
+
route = candidate;
|
|
2614
|
+
params = decode_params(matched);
|
|
2615
|
+
break;
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
|
|
2547
2620
|
/** @type {import('types').RequestEvent} */
|
|
2548
2621
|
const event = {
|
|
2549
2622
|
get clientAddress() {
|
|
@@ -2562,9 +2635,10 @@ async function respond(request, options, state) {
|
|
|
2562
2635
|
return event.clientAddress;
|
|
2563
2636
|
},
|
|
2564
2637
|
locals: {},
|
|
2565
|
-
params
|
|
2638
|
+
params,
|
|
2566
2639
|
platform: state.platform,
|
|
2567
2640
|
request,
|
|
2641
|
+
routeId: route && route.id,
|
|
2568
2642
|
url
|
|
2569
2643
|
};
|
|
2570
2644
|
|
|
@@ -2607,6 +2681,8 @@ async function respond(request, options, state) {
|
|
|
2607
2681
|
transformPage: default_transform
|
|
2608
2682
|
};
|
|
2609
2683
|
|
|
2684
|
+
// TODO match route before calling handle?
|
|
2685
|
+
|
|
2610
2686
|
try {
|
|
2611
2687
|
const response = await options.hooks.handle({
|
|
2612
2688
|
event,
|
|
@@ -2620,14 +2696,14 @@ async function respond(request, options, state) {
|
|
|
2620
2696
|
|
|
2621
2697
|
if (state.prerender && state.prerender.fallback) {
|
|
2622
2698
|
return await render_response({
|
|
2623
|
-
|
|
2624
|
-
params: event.params,
|
|
2699
|
+
event,
|
|
2625
2700
|
options,
|
|
2626
2701
|
state,
|
|
2627
2702
|
$session: await options.hooks.getSession(event),
|
|
2628
2703
|
page_config: { router: true, hydrate: true },
|
|
2629
2704
|
stuff: {},
|
|
2630
2705
|
status: 200,
|
|
2706
|
+
error: null,
|
|
2631
2707
|
branch: [],
|
|
2632
2708
|
resolve_opts: {
|
|
2633
2709
|
...resolve_opts,
|
|
@@ -2636,75 +2712,28 @@ async function respond(request, options, state) {
|
|
|
2636
2712
|
});
|
|
2637
2713
|
}
|
|
2638
2714
|
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
if (options.paths.base) {
|
|
2642
|
-
if (!decoded.startsWith(options.paths.base)) {
|
|
2643
|
-
return new Response(undefined, { status: 404 });
|
|
2644
|
-
}
|
|
2645
|
-
decoded = decoded.slice(options.paths.base.length) || '/';
|
|
2646
|
-
}
|
|
2647
|
-
|
|
2648
|
-
const is_data_request = decoded.endsWith(DATA_SUFFIX);
|
|
2649
|
-
|
|
2650
|
-
if (is_data_request) {
|
|
2651
|
-
decoded = decoded.slice(0, -DATA_SUFFIX.length) || '/';
|
|
2652
|
-
|
|
2653
|
-
const normalized = normalize_path(
|
|
2654
|
-
url.pathname.slice(0, -DATA_SUFFIX.length),
|
|
2655
|
-
options.trailing_slash
|
|
2656
|
-
);
|
|
2657
|
-
|
|
2658
|
-
event.url = new URL(event.url.origin + normalized + event.url.search);
|
|
2659
|
-
}
|
|
2660
|
-
|
|
2661
|
-
// `key` will be set if this request came from a client-side navigation
|
|
2662
|
-
// to a page with a matching endpoint
|
|
2663
|
-
const key = request.headers.get('x-sveltekit-load');
|
|
2664
|
-
|
|
2665
|
-
for (const route of options.manifest._.routes) {
|
|
2666
|
-
if (key) {
|
|
2667
|
-
// client is requesting data for a specific endpoint
|
|
2668
|
-
if (route.type !== 'page') continue;
|
|
2669
|
-
if (route.key !== key) continue;
|
|
2670
|
-
}
|
|
2671
|
-
|
|
2672
|
-
const match = route.pattern.exec(decoded);
|
|
2673
|
-
if (!match) continue;
|
|
2674
|
-
|
|
2675
|
-
event.params = route.params ? decode_params(route.params(match)) : {};
|
|
2676
|
-
|
|
2677
|
-
/** @type {Response | undefined} */
|
|
2715
|
+
if (route) {
|
|
2716
|
+
/** @type {Response} */
|
|
2678
2717
|
let response;
|
|
2679
2718
|
|
|
2680
2719
|
if (is_data_request && route.type === 'page' && route.shadow) {
|
|
2681
2720
|
response = await render_endpoint(event, await route.shadow());
|
|
2682
2721
|
|
|
2683
2722
|
// loading data for a client-side transition is a special case
|
|
2684
|
-
if (
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
});
|
|
2698
|
-
}
|
|
2723
|
+
if (request.headers.has('x-sveltekit-load')) {
|
|
2724
|
+
// since redirects are opaque to the browser, we need to repackage
|
|
2725
|
+
// 3xx responses as 200s with a custom header
|
|
2726
|
+
if (response.status >= 300 && response.status < 400) {
|
|
2727
|
+
const location = response.headers.get('location');
|
|
2728
|
+
|
|
2729
|
+
if (location) {
|
|
2730
|
+
const headers = new Headers(response.headers);
|
|
2731
|
+
headers.set('x-sveltekit-location', location);
|
|
2732
|
+
response = new Response(undefined, {
|
|
2733
|
+
status: 204,
|
|
2734
|
+
headers
|
|
2735
|
+
});
|
|
2699
2736
|
}
|
|
2700
|
-
} else {
|
|
2701
|
-
// fallthrough
|
|
2702
|
-
response = new Response(undefined, {
|
|
2703
|
-
status: 204,
|
|
2704
|
-
headers: {
|
|
2705
|
-
'content-type': 'application/json'
|
|
2706
|
-
}
|
|
2707
|
-
});
|
|
2708
2737
|
}
|
|
2709
2738
|
}
|
|
2710
2739
|
} else {
|
package/dist/chunks/index.js
CHANGED
|
@@ -11,6 +11,7 @@ import { update, init } from './sync.js';
|
|
|
11
11
|
import { getRequest, setResponse } from '../node.js';
|
|
12
12
|
import { sequence } from '../hooks.js';
|
|
13
13
|
import { p as posixify } from './filesystem.js';
|
|
14
|
+
import { p as parse_route_id } from './routing.js';
|
|
14
15
|
import 'sade';
|
|
15
16
|
import 'child_process';
|
|
16
17
|
import 'net';
|
|
@@ -116,12 +117,15 @@ async function create_plugin(config, cwd) {
|
|
|
116
117
|
};
|
|
117
118
|
}),
|
|
118
119
|
routes: manifest_data.routes.map((route) => {
|
|
120
|
+
const { pattern, names, types } = parse_route_id(route.id);
|
|
121
|
+
|
|
119
122
|
if (route.type === 'page') {
|
|
120
123
|
return {
|
|
121
124
|
type: 'page',
|
|
122
|
-
|
|
123
|
-
pattern
|
|
124
|
-
|
|
125
|
+
id: route.id,
|
|
126
|
+
pattern,
|
|
127
|
+
names,
|
|
128
|
+
types,
|
|
125
129
|
shadow: route.shadow
|
|
126
130
|
? async () => {
|
|
127
131
|
const url = path__default.resolve(cwd, /** @type {string} */ (route.shadow));
|
|
@@ -135,14 +139,34 @@ async function create_plugin(config, cwd) {
|
|
|
135
139
|
|
|
136
140
|
return {
|
|
137
141
|
type: 'endpoint',
|
|
138
|
-
|
|
139
|
-
|
|
142
|
+
id: route.id,
|
|
143
|
+
pattern,
|
|
144
|
+
names,
|
|
145
|
+
types,
|
|
140
146
|
load: async () => {
|
|
141
147
|
const url = path__default.resolve(cwd, route.file);
|
|
142
148
|
return await vite.ssrLoadModule(url);
|
|
143
149
|
}
|
|
144
150
|
};
|
|
145
|
-
})
|
|
151
|
+
}),
|
|
152
|
+
validators: async () => {
|
|
153
|
+
/** @type {Record<string, import('types').ParamValidator>} */
|
|
154
|
+
const validators = {};
|
|
155
|
+
|
|
156
|
+
for (const key in manifest_data.validators) {
|
|
157
|
+
const file = manifest_data.validators[key];
|
|
158
|
+
const url = path__default.resolve(cwd, file);
|
|
159
|
+
const module = await vite.ssrLoadModule(url);
|
|
160
|
+
|
|
161
|
+
if (module.validate) {
|
|
162
|
+
validators[key] = module.validate;
|
|
163
|
+
} else {
|
|
164
|
+
throw new Error(`${file} does not export a \`validate\` function`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return validators;
|
|
169
|
+
}
|
|
146
170
|
}
|
|
147
171
|
};
|
|
148
172
|
}
|
|
@@ -355,29 +379,6 @@ async function create_plugin(config, cwd) {
|
|
|
355
379
|
};
|
|
356
380
|
}
|
|
357
381
|
|
|
358
|
-
/** @param {string[]} array */
|
|
359
|
-
function get_params(array) {
|
|
360
|
-
// given an array of params like `['x', 'y', 'z']` for
|
|
361
|
-
// src/routes/[x]/[y]/[z]/svelte, create a function
|
|
362
|
-
// that turns a RegExpExecArray into ({ x, y, z })
|
|
363
|
-
|
|
364
|
-
/** @param {RegExpExecArray} match */
|
|
365
|
-
const fn = (match) => {
|
|
366
|
-
/** @type {Record<string, string>} */
|
|
367
|
-
const params = {};
|
|
368
|
-
array.forEach((key, i) => {
|
|
369
|
-
if (key.startsWith('...')) {
|
|
370
|
-
params[key.slice(3)] = match[i + 1] || '';
|
|
371
|
-
} else {
|
|
372
|
-
params[key] = match[i + 1];
|
|
373
|
-
}
|
|
374
|
-
});
|
|
375
|
-
return params;
|
|
376
|
-
};
|
|
377
|
-
|
|
378
|
-
return fn;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
382
|
/** @param {import('http').ServerResponse} res */
|
|
382
383
|
function not_found(res) {
|
|
383
384
|
res.statusCode = 404;
|