@sveltejs/kit 3.0.0-next.23 → 3.0.0-next.24
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/package.json +40 -5
- package/src/cli.js +3 -3
- package/src/constants.js +13 -1
- package/src/core/adapt/builder.js +2 -3
- package/src/core/env.js +139 -181
- package/src/core/postbuild/analyse.js +9 -4
- package/src/core/postbuild/prerender.js +3 -4
- package/src/core/sync/create_manifest_data/index.js +29 -33
- package/src/core/sync/sync.js +23 -40
- package/src/core/sync/write_app_manifest.js +83 -0
- package/src/core/sync/write_client_manifest.js +6 -4
- package/src/core/sync/write_server.js +10 -6
- package/src/core/sync/write_types/index.js +2 -2
- package/src/core/utils.js +0 -28
- package/src/exports/hooks/public.d.ts +9 -1
- package/src/exports/node/index.js +77 -5
- package/src/exports/vite/build/build_server.js +3 -3
- package/src/exports/vite/build/utils.js +48 -4
- package/src/exports/vite/dev/index.js +11 -22
- package/src/exports/vite/index.js +62 -345
- package/src/exports/vite/module_ids.js +1 -11
- package/src/exports/vite/plugins/env-vars.js +117 -0
- package/src/exports/vite/preview/index.js +6 -4
- package/src/exports/vite/utils.js +2 -4
- package/src/runtime/app/env/{types.d.ts → client.js} +9 -4
- package/src/runtime/app/env/index.js +1 -2
- package/src/runtime/app/env/private/index.js +1 -0
- package/src/runtime/app/env/public/client.js +1 -1
- package/src/runtime/app/env/public/server.js +1 -1
- package/src/runtime/app/env/{internal.js → server.js} +4 -4
- package/src/runtime/app/forms/client.js +263 -0
- package/src/runtime/app/forms/index.js +1 -263
- package/src/runtime/app/forms/public.d.ts +1 -1
- package/src/runtime/app/forms/server.js +6 -0
- package/src/runtime/app/forms/shared.js +34 -0
- package/src/runtime/app/manifest/index.js +1 -1
- package/src/runtime/app/navigation/client.js +15 -0
- package/src/runtime/app/navigation/index.js +1 -15
- package/src/runtime/app/navigation/public.d.ts +1 -1
- package/src/runtime/app/navigation/server.js +15 -0
- package/src/runtime/app/paths/server.js +1 -1
- package/src/runtime/app/server/remote/form.js +11 -1
- package/src/runtime/app/server/remote/prerender.js +1 -2
- package/src/runtime/app/server/remote/query.js +1 -1
- package/src/runtime/app/state/client.svelte.js +207 -0
- package/src/runtime/app/state/index.js +1 -66
- package/src/runtime/app/state/public.d.ts +1 -1
- package/src/runtime/client/bundle.js +1 -1
- package/src/runtime/client/client.js +206 -274
- package/src/runtime/client/fetcher.js +18 -8
- package/src/runtime/client/remote-functions/form.svelte.js +9 -6
- package/src/runtime/client/remote-functions/prerender.svelte.js +1 -1
- package/src/runtime/client/remote-functions/query-live/iterator.js +1 -1
- package/src/runtime/client/remote-functions/shared.svelte.js +2 -2
- package/src/runtime/client/snapshots.js +1 -3
- package/src/runtime/client/stream.js +27 -20
- package/src/runtime/client/utils.js +7 -3
- package/src/runtime/components/root.svelte +5 -5
- package/src/runtime/env/dynamic/private.js +1 -1
- package/src/runtime/env/static/private.js +1 -1
- package/src/runtime/error-chain.js +54 -0
- package/src/runtime/form-utils.js +53 -77
- package/src/runtime/invalid-import.js +1 -0
- package/src/runtime/props.svelte.js +1 -1
- package/src/runtime/server/data/index.js +1 -1
- package/src/runtime/server/endpoint.js +8 -3
- package/src/runtime/server/env_module.js +1 -1
- package/src/runtime/server/errors.js +2 -2
- package/src/runtime/server/index.js +2 -2
- package/src/runtime/server/page/actions.js +77 -122
- package/src/runtime/server/page/index.js +37 -69
- package/src/runtime/server/page/render.js +18 -23
- package/src/runtime/server/remote-functions.js +14 -42
- package/src/runtime/server/respond.js +23 -3
- package/src/telemetry.js +1 -33
- package/src/types/ambient-private.d.ts +9 -17
- package/src/types/internal.d.ts +20 -4
- package/src/types/private.d.ts +1 -1
- package/src/utils/exports.js +1 -0
- package/src/utils/filesystem.js +9 -21
- package/src/utils/functions.js +10 -0
- package/src/utils/routing.js +0 -11
- package/src/utils/url.js +0 -11
- package/src/version.js +1 -1
- package/types/index.d.ts +34 -28
- package/types/index.d.ts.map +7 -5
- package/src/runtime/app/env/private.js +0 -1
- package/src/runtime/app/env/standard-schema.d.ts +0 -0
- package/src/runtime/app/state/client.js +0 -63
- package/src/runtime/client/state.svelte.js +0 -98
- package/src/runtime/server/ambient.d.ts +0 -4
- package/src/utils/path.js +0 -23
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { noop } from '../../utils/functions.js';
|
|
1
|
+
import { DEV } from 'esm-env';
|
|
3
2
|
import { hash_request } from '../../utils/hash.js';
|
|
4
3
|
import { base64_decode } from '../utils.js';
|
|
5
4
|
|
|
6
5
|
let loading = 0;
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
const native_fetch = BROWSER ? window.fetch : /** @type {any} */ (noop);
|
|
7
|
+
const native_fetch = window.fetch;
|
|
10
8
|
|
|
11
9
|
export function lock_fetch() {
|
|
12
10
|
loading += 1;
|
|
@@ -16,7 +14,7 @@ export function unlock_fetch() {
|
|
|
16
14
|
loading -= 1;
|
|
17
15
|
}
|
|
18
16
|
|
|
19
|
-
if (DEV
|
|
17
|
+
if (DEV) {
|
|
20
18
|
let can_inspect_stack_trace = false;
|
|
21
19
|
|
|
22
20
|
// detect whether async stack traces work
|
|
@@ -61,17 +59,17 @@ if (DEV && BROWSER) {
|
|
|
61
59
|
const method = input instanceof Request ? input.method : init?.method || 'GET';
|
|
62
60
|
|
|
63
61
|
if (method !== 'GET') {
|
|
64
|
-
cache.delete(build_selector(input));
|
|
62
|
+
cache.delete(build_selector(requested_url(input)));
|
|
65
63
|
}
|
|
66
64
|
|
|
67
65
|
return native_fetch(input, init);
|
|
68
66
|
};
|
|
69
|
-
} else
|
|
67
|
+
} else {
|
|
70
68
|
window.fetch = (input, init) => {
|
|
71
69
|
const method = input instanceof Request ? input.method : init?.method || 'GET';
|
|
72
70
|
|
|
73
71
|
if (method !== 'GET') {
|
|
74
|
-
cache.delete(build_selector(input));
|
|
72
|
+
cache.delete(build_selector(requested_url(input)));
|
|
75
73
|
}
|
|
76
74
|
|
|
77
75
|
return native_fetch(input, init);
|
|
@@ -153,6 +151,18 @@ export function dev_fetch(resource, opts) {
|
|
|
153
151
|
return window.fetch(resource, patched_opts);
|
|
154
152
|
}
|
|
155
153
|
|
|
154
|
+
/**
|
|
155
|
+
* Mirror the url normalization in `resolve_fetch_url`, so that non-GET requests
|
|
156
|
+
* evict the cache entry regardless of how the url is spelled
|
|
157
|
+
* @param {RequestInfo | URL} input
|
|
158
|
+
*/
|
|
159
|
+
function requested_url(input) {
|
|
160
|
+
const resolved = new URL(input instanceof Request ? input.url : input, location.href);
|
|
161
|
+
return resolved.origin === location.origin
|
|
162
|
+
? resolved.href.slice(location.origin.length)
|
|
163
|
+
: resolved.href;
|
|
164
|
+
}
|
|
165
|
+
|
|
156
166
|
/**
|
|
157
167
|
* Build the cache key for a given request
|
|
158
168
|
* @param {URL | RequestInfo} resource
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
handle_error,
|
|
12
12
|
refreshAll
|
|
13
13
|
} from '../client.js';
|
|
14
|
-
import { page } from '
|
|
14
|
+
import { page } from '#app/state/client';
|
|
15
15
|
import { tick } from 'svelte';
|
|
16
16
|
import { categorize_updates, remote_request } from './shared.svelte.js';
|
|
17
17
|
import { createAttachmentKey } from 'svelte/attachments';
|
|
@@ -133,7 +133,9 @@ export function form(id) {
|
|
|
133
133
|
if (await instance.submit()) {
|
|
134
134
|
await tick();
|
|
135
135
|
// We call reset from the prototype to avoid DOM clobbering
|
|
136
|
-
|
|
136
|
+
if (instance.element.isConnected) {
|
|
137
|
+
HTMLFormElement.prototype.reset.call(instance.element);
|
|
138
|
+
}
|
|
137
139
|
}
|
|
138
140
|
};
|
|
139
141
|
|
|
@@ -263,7 +265,7 @@ export function form(id) {
|
|
|
263
265
|
|
|
264
266
|
if (response.redirect) {
|
|
265
267
|
// Use internal version to allow redirects to external URLs
|
|
266
|
-
|
|
268
|
+
await _goto(response.redirect, {
|
|
267
269
|
refreshAll: should_refresh
|
|
268
270
|
});
|
|
269
271
|
return true;
|
|
@@ -273,7 +275,7 @@ export function form(id) {
|
|
|
273
275
|
|
|
274
276
|
if (succeeded) {
|
|
275
277
|
if (should_refresh) {
|
|
276
|
-
|
|
278
|
+
await refreshAll();
|
|
277
279
|
}
|
|
278
280
|
} else {
|
|
279
281
|
if (DEV) {
|
|
@@ -695,13 +697,14 @@ export function form(id) {
|
|
|
695
697
|
validate: {
|
|
696
698
|
/** @type {RemoteForm<any, any>['validate']} */
|
|
697
699
|
value: async ({ all = false, preflightOnly = false } = {}) => {
|
|
698
|
-
if (!element) return;
|
|
699
|
-
|
|
700
700
|
const id = ++validate_id;
|
|
701
701
|
|
|
702
702
|
// wait a tick in case the user is calling validate() right after set() which takes time to propagate
|
|
703
703
|
await tick();
|
|
704
704
|
|
|
705
|
+
// the form may have been removed from the DOM while we were waiting
|
|
706
|
+
if (!element) return;
|
|
707
|
+
|
|
705
708
|
const default_submitter = /** @type {HTMLElement | undefined} */ (
|
|
706
709
|
element.querySelector('button:not([type]), [type="submit"]')
|
|
707
710
|
);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @import { RemoteFunctionResponse } from 'types' */
|
|
2
2
|
import { app_dir, base } from '#app/paths';
|
|
3
3
|
import { app } from '../../client.js';
|
|
4
|
-
import { notify_version } from '
|
|
4
|
+
import { notify_version } from '#app/state/client';
|
|
5
5
|
import { handle_side_channel_response } from '../shared.svelte.js';
|
|
6
6
|
import * as devalue from 'devalue';
|
|
7
7
|
import { HttpError, HandledHttpError } from '@sveltejs/kit/internal';
|
|
@@ -6,7 +6,7 @@ import { app, _goto, live_query_map, query_map, query_responses } from '../clien
|
|
|
6
6
|
import { HttpError, Redirect, HandledHttpError } from '@sveltejs/kit/internal';
|
|
7
7
|
import { untrack } from 'svelte';
|
|
8
8
|
import { create_remote_key, split_remote_key } from '../../shared.js';
|
|
9
|
-
import { navigating, page, notify_version } from '
|
|
9
|
+
import { navigating, page, notify_version } from '#app/state/client';
|
|
10
10
|
|
|
11
11
|
/** Indicates a query function, as opposed to a query instance */
|
|
12
12
|
export const QUERY_FUNCTION_ID = Symbol('sveltekit.query_function_id');
|
|
@@ -97,7 +97,7 @@ export function get_remote_request_headers() {
|
|
|
97
97
|
// even in forks because it's state-based - therefore not using window.location.
|
|
98
98
|
// Use untrack(...) to Avoid accidental reactive dependency on pathname/search
|
|
99
99
|
return untrack(() => {
|
|
100
|
-
const url = navigating
|
|
100
|
+
const url = navigating?.to?.url ?? page.url;
|
|
101
101
|
|
|
102
102
|
return {
|
|
103
103
|
'x-sveltekit-pathname': url.pathname,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DEV } from 'esm-env';
|
|
2
2
|
import { onMount } from 'svelte';
|
|
3
3
|
import * as storage from './session-storage.js';
|
|
4
4
|
import { NAVIGATION_SNAPSHOT_KEY } from './constants.js';
|
|
@@ -105,8 +105,6 @@ function callsite_id(stack) {
|
|
|
105
105
|
* @returns {void}
|
|
106
106
|
*/
|
|
107
107
|
export function snapshot(options) {
|
|
108
|
-
if (!BROWSER) return;
|
|
109
|
-
|
|
110
108
|
let id = options.id;
|
|
111
109
|
if (id === undefined) {
|
|
112
110
|
// restore any lowered third-party limit, else every callsite collapses to one id
|
|
@@ -8,32 +8,39 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export async function* read_stream(reader, delimiter, options) {
|
|
10
10
|
let done = false;
|
|
11
|
-
|
|
11
|
+
/** @type {string[]} */
|
|
12
|
+
let parts = [];
|
|
13
|
+
let rest = '';
|
|
12
14
|
const decoder = new TextDecoder(undefined, options);
|
|
15
|
+
const carry = delimiter.length - 1;
|
|
13
16
|
|
|
14
|
-
while (
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
17
|
+
while (!done) {
|
|
18
|
+
const chunk = await reader.read();
|
|
19
|
+
done = chunk.done;
|
|
20
|
+
let text = rest;
|
|
21
|
+
if (chunk.value) text += decoder.decode(chunk.value, { stream: true });
|
|
22
|
+
if (done) text += decoder.decode();
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
let start = 0;
|
|
25
|
+
let split = text.indexOf(delimiter);
|
|
26
|
+
while (split !== -1) {
|
|
27
|
+
if (parts.length > 0) {
|
|
28
|
+
parts.push(text.slice(start, split));
|
|
29
|
+
yield parts.join('');
|
|
30
|
+
parts = [];
|
|
31
|
+
} else {
|
|
32
|
+
yield text.slice(start, split);
|
|
25
33
|
}
|
|
26
|
-
|
|
34
|
+
start = split + delimiter.length;
|
|
35
|
+
split = text.indexOf(delimiter, start);
|
|
27
36
|
}
|
|
28
37
|
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
38
|
+
const keep = Math.max(start, text.length - carry);
|
|
39
|
+
if (keep > start) parts.push(text.slice(start, keep));
|
|
40
|
+
rest = text.slice(keep);
|
|
41
|
+
}
|
|
34
42
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
43
|
+
if (parts.length > 0 || rest) {
|
|
44
|
+
yield parts.join('') + rest;
|
|
38
45
|
}
|
|
39
46
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DEV } from 'esm-env';
|
|
2
2
|
import { PRELOAD_PRIORITIES } from './constants.js';
|
|
3
3
|
|
|
4
|
-
export const origin =
|
|
4
|
+
export const origin = location.origin;
|
|
5
5
|
|
|
6
6
|
/** @param {string | URL} url */
|
|
7
7
|
export function resolve_url(url) {
|
|
@@ -105,7 +105,11 @@ function parent_element(element) {
|
|
|
105
105
|
*/
|
|
106
106
|
export function find_anchor(element, target) {
|
|
107
107
|
while (element && element !== target) {
|
|
108
|
-
|
|
108
|
+
// don't read `nodeName` — a form control named `nodeName` shadows it on its form
|
|
109
|
+
if (
|
|
110
|
+
(element instanceof HTMLAnchorElement || element instanceof SVGAElement) &&
|
|
111
|
+
element.hasAttribute('href')
|
|
112
|
+
) {
|
|
109
113
|
return /** @type {HTMLAnchorElement | SVGAElement} */ (element);
|
|
110
114
|
}
|
|
111
115
|
|
|
@@ -23,7 +23,11 @@
|
|
|
23
23
|
{const Error = $derived(n.error)}
|
|
24
24
|
{const data = $derived(n.data)}
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
{#snippet failed(error: unknown)}
|
|
27
|
+
<Error {error} />
|
|
28
|
+
{/snippet}
|
|
29
|
+
|
|
30
|
+
<svelte:boundary failed={Error ? failed : undefined} onerror={Error ? onerror : undefined}>
|
|
27
31
|
{#if n.child}
|
|
28
32
|
<!-- svelte-ignore binding_property_non_reactive -->
|
|
29
33
|
<Component bind:this={components[depth]} {data} {form} params={page.params}>
|
|
@@ -33,10 +37,6 @@
|
|
|
33
37
|
<!-- svelte-ignore binding_property_non_reactive -->
|
|
34
38
|
<Component bind:this={components[depth]} {data} {form} params={page.params} {error} />
|
|
35
39
|
{/if}
|
|
36
|
-
|
|
37
|
-
{#snippet failed(error: unknown)}
|
|
38
|
-
<Error {error} />
|
|
39
|
-
{/snippet}
|
|
40
40
|
</svelte:boundary>
|
|
41
41
|
{/snippet}
|
|
42
42
|
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/** @import { Component } from 'svelte'; */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Resolves the `+error.svelte` component that guards each node of `branch`, aligned to the
|
|
5
|
+
* branch with its empty slots removed. A node is guarded by the closest error page declared
|
|
6
|
+
* at or above it, except the root layout, which wraps the root error component rather than
|
|
7
|
+
* being wrapped by it.
|
|
8
|
+
* @template T
|
|
9
|
+
* @param {Array<unknown>} branch
|
|
10
|
+
* @param {Array<T | undefined | null>} errors the error page declared at each depth, if any
|
|
11
|
+
* @param {(error: T) => Promise<Component | undefined> | undefined} load
|
|
12
|
+
* @returns {Promise<Array<Component | undefined>>}
|
|
13
|
+
*/
|
|
14
|
+
export function build_error_chain(branch, errors, load) {
|
|
15
|
+
/** @type {Array<Promise<Component | undefined> | undefined>} */
|
|
16
|
+
const chain = [undefined];
|
|
17
|
+
let last_idx = -1;
|
|
18
|
+
|
|
19
|
+
for (let i = 1; i < branch.length; i += 1) {
|
|
20
|
+
if (!branch[i]) continue;
|
|
21
|
+
|
|
22
|
+
let j = i - 1;
|
|
23
|
+
while (j > last_idx + 1 && errors[j] == null) j -= 1;
|
|
24
|
+
last_idx = j;
|
|
25
|
+
|
|
26
|
+
const error = errors[j];
|
|
27
|
+
chain.push(error == null ? undefined : load(error)?.catch(() => undefined));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// depths with no error page contribute `undefined` rather than a promise
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/await-thenable
|
|
32
|
+
return Promise.all(chain);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Walks up from the node at index `i` through the `+error.svelte` pages declared strictly
|
|
37
|
+
* above it, nearest first. Yields each candidate with the branch depth it attaches at,
|
|
38
|
+
* rewound past empty branch slots, so callers can skip candidates that fail to load.
|
|
39
|
+
* @template T
|
|
40
|
+
* @param {number} i
|
|
41
|
+
* @param {Array<unknown>} branch
|
|
42
|
+
* @param {Array<T | undefined | null>} errors the error page declared at each depth, if any
|
|
43
|
+
* @returns {Generator<{ error: T; idx: number }>}
|
|
44
|
+
*/
|
|
45
|
+
export function* nearest_error_pages(i, branch, errors) {
|
|
46
|
+
while (i--) {
|
|
47
|
+
const error = errors[i];
|
|
48
|
+
if (error != null) {
|
|
49
|
+
let j = i;
|
|
50
|
+
while (!branch[j]) j -= 1;
|
|
51
|
+
yield { error, idx: j + 1 };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -198,7 +198,9 @@ export async function deserialize_binary_form(request, form_id) {
|
|
|
198
198
|
|
|
199
199
|
let i = chunks.length;
|
|
200
200
|
while (i <= index) {
|
|
201
|
-
|
|
201
|
+
// chain reads so only one is ever pending — workerd forbids concurrent reads
|
|
202
|
+
const previous = chunks[i - 1] ?? Promise.resolve(undefined);
|
|
203
|
+
chunks[i] = previous.then(() => reader.read()).then((chunk) => chunk.value);
|
|
202
204
|
i++;
|
|
203
205
|
}
|
|
204
206
|
return chunks[index];
|
|
@@ -210,47 +212,23 @@ export async function deserialize_binary_form(request, form_id) {
|
|
|
210
212
|
* @returns {Promise<Uint8Array | null>}
|
|
211
213
|
*/
|
|
212
214
|
async function get_buffer(offset, length) {
|
|
213
|
-
/** @type {Uint8Array} */
|
|
214
|
-
|
|
215
|
-
let
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const chunk = await get_chunk(chunk_index);
|
|
220
|
-
if (!chunk) return null;
|
|
221
|
-
|
|
222
|
-
const chunk_end = chunk_start + chunk.byteLength;
|
|
223
|
-
// If this chunk contains the target offset
|
|
224
|
-
if (offset >= chunk_start && offset < chunk_end) {
|
|
225
|
-
start_chunk = chunk;
|
|
226
|
-
break;
|
|
227
|
-
}
|
|
228
|
-
chunk_start = chunk_end;
|
|
229
|
-
}
|
|
230
|
-
// If the buffer is completely contained in one chunk, do a subarray
|
|
231
|
-
if (offset + length <= chunk_start + start_chunk.byteLength) {
|
|
232
|
-
return start_chunk.subarray(offset - chunk_start, offset + length - chunk_start);
|
|
233
|
-
}
|
|
234
|
-
// Otherwise, copy the data into a new buffer
|
|
235
|
-
const chunks = [start_chunk.subarray(offset - chunk_start)];
|
|
236
|
-
let cursor = start_chunk.byteLength - offset + chunk_start;
|
|
237
|
-
while (cursor < length) {
|
|
238
|
-
chunk_index++;
|
|
239
|
-
let chunk = await get_chunk(chunk_index);
|
|
240
|
-
if (!chunk) return null;
|
|
241
|
-
if (chunk.byteLength > length - cursor) {
|
|
242
|
-
chunk = chunk.subarray(0, length - cursor);
|
|
243
|
-
}
|
|
244
|
-
chunks.push(chunk);
|
|
245
|
-
cursor += chunk.byteLength;
|
|
215
|
+
/** @type {Uint8Array<ArrayBuffer>[]} */
|
|
216
|
+
const parts = [];
|
|
217
|
+
let total = 0;
|
|
218
|
+
for await (const part of read_range(get_chunk, offset, length)) {
|
|
219
|
+
parts.push(part);
|
|
220
|
+
total += part.byteLength;
|
|
246
221
|
}
|
|
222
|
+
if (total < length || parts.length === 0) return null;
|
|
223
|
+
// If the buffer is completely contained in one chunk, return the subarray as-is
|
|
224
|
+
if (parts.length === 1) return parts[0];
|
|
225
|
+
|
|
247
226
|
const buffer = new Uint8Array(length);
|
|
248
|
-
cursor = 0;
|
|
249
|
-
for (const
|
|
250
|
-
buffer.set(
|
|
251
|
-
cursor +=
|
|
227
|
+
let cursor = 0;
|
|
228
|
+
for (const part of parts) {
|
|
229
|
+
buffer.set(part, cursor);
|
|
230
|
+
cursor += part.byteLength;
|
|
252
231
|
}
|
|
253
|
-
|
|
254
232
|
return buffer;
|
|
255
233
|
}
|
|
256
234
|
|
|
@@ -366,6 +344,32 @@ function deserialize_error(message) {
|
|
|
366
344
|
return new SvelteKitError(400, 'Bad Request', `Could not deserialize binary form: ${message}`);
|
|
367
345
|
}
|
|
368
346
|
|
|
347
|
+
/**
|
|
348
|
+
* Yields the chunks that make up the byte range `[offset, offset + length)`,
|
|
349
|
+
* trimmed to its boundaries. Ends early if the underlying data runs out.
|
|
350
|
+
* @param {(index: number) => Promise<Uint8Array<ArrayBuffer> | undefined>} get_chunk
|
|
351
|
+
* @param {number} offset
|
|
352
|
+
* @param {number} length
|
|
353
|
+
* @returns {AsyncGenerator<Uint8Array<ArrayBuffer>, void, void>}
|
|
354
|
+
*/
|
|
355
|
+
async function* read_range(get_chunk, offset, length) {
|
|
356
|
+
let chunk_start = 0;
|
|
357
|
+
for (let index = 0; ; index++) {
|
|
358
|
+
const chunk = await get_chunk(index);
|
|
359
|
+
if (!chunk) return;
|
|
360
|
+
|
|
361
|
+
const chunk_end = chunk_start + chunk.byteLength;
|
|
362
|
+
if (chunk_end > offset) {
|
|
363
|
+
yield chunk.subarray(
|
|
364
|
+
Math.max(0, offset - chunk_start),
|
|
365
|
+
Math.min(chunk.byteLength, offset + length - chunk_start)
|
|
366
|
+
);
|
|
367
|
+
if (offset + length <= chunk_end) return;
|
|
368
|
+
}
|
|
369
|
+
chunk_start = chunk_end;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
369
373
|
/** @implements {File} */
|
|
370
374
|
class LazyFile {
|
|
371
375
|
/** @type {(index: number) => Promise<Uint8Array<ArrayBuffer> | undefined>} */
|
|
@@ -436,49 +440,21 @@ class LazyFile {
|
|
|
436
440
|
return file;
|
|
437
441
|
}
|
|
438
442
|
stream() {
|
|
443
|
+
const range = read_range(this.#get_chunk, this.#offset, this.size);
|
|
439
444
|
let cursor = 0;
|
|
440
|
-
let chunk_index = 0;
|
|
441
445
|
return new ReadableStream({
|
|
442
|
-
start: async (controller) => {
|
|
443
|
-
let chunk_start = 0;
|
|
444
|
-
/** @type {Uint8Array} */
|
|
445
|
-
let start_chunk;
|
|
446
|
-
for (chunk_index = 0; ; chunk_index++) {
|
|
447
|
-
const chunk = await this.#get_chunk(chunk_index);
|
|
448
|
-
if (!chunk) return null;
|
|
449
|
-
|
|
450
|
-
const chunk_end = chunk_start + chunk.byteLength;
|
|
451
|
-
// If this chunk contains the target offset
|
|
452
|
-
if (this.#offset >= chunk_start && this.#offset < chunk_end) {
|
|
453
|
-
start_chunk = chunk;
|
|
454
|
-
break;
|
|
455
|
-
}
|
|
456
|
-
chunk_start = chunk_end;
|
|
457
|
-
}
|
|
458
|
-
// If the buffer is completely contained in one chunk, do a subarray
|
|
459
|
-
if (this.#offset + this.size <= chunk_start + start_chunk.byteLength) {
|
|
460
|
-
controller.enqueue(
|
|
461
|
-
start_chunk.subarray(this.#offset - chunk_start, this.#offset + this.size - chunk_start)
|
|
462
|
-
);
|
|
463
|
-
controller.close();
|
|
464
|
-
} else {
|
|
465
|
-
controller.enqueue(start_chunk.subarray(this.#offset - chunk_start));
|
|
466
|
-
cursor = start_chunk.byteLength - this.#offset + chunk_start;
|
|
467
|
-
}
|
|
468
|
-
},
|
|
469
446
|
pull: async (controller) => {
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
447
|
+
const { value, done } = await range.next();
|
|
448
|
+
if (done) {
|
|
449
|
+
if (cursor < this.size) {
|
|
450
|
+
controller.error('incomplete file data');
|
|
451
|
+
} else {
|
|
452
|
+
controller.close();
|
|
453
|
+
}
|
|
475
454
|
return;
|
|
476
455
|
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
}
|
|
480
|
-
controller.enqueue(chunk);
|
|
481
|
-
cursor += chunk.byteLength;
|
|
456
|
+
cursor += value.byteLength;
|
|
457
|
+
controller.enqueue(value);
|
|
482
458
|
if (cursor >= this.size) {
|
|
483
459
|
controller.close();
|
|
484
460
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
throw new Error('invalid import');
|
|
@@ -12,7 +12,7 @@ import { with_version_header } from '../utils.js';
|
|
|
12
12
|
/**
|
|
13
13
|
* @param {import('@sveltejs/kit').RequestEvent} event
|
|
14
14
|
* @param {import('types').RequestState} state
|
|
15
|
-
* @param {import('types').
|
|
15
|
+
* @param {{ page: Pick<import('types').PageNodeIndexes, 'layouts' | 'leaf'> | null }} route
|
|
16
16
|
* @param {import('types').SSROptions} options
|
|
17
17
|
* @param {import('@sveltejs/kit').SSRManifest} manifest
|
|
18
18
|
* @param {boolean[] | undefined} invalidated_data_nodes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Redirect } from '@sveltejs/kit/internal';
|
|
2
2
|
import { with_request_store } from '@sveltejs/kit/internal/server';
|
|
3
|
-
import { ENDPOINT_METHODS, PAGE_METHODS } from '../../constants.js';
|
|
3
|
+
import { BODY_DEPENDENT_METHODS, ENDPOINT_METHODS, PAGE_METHODS } from '../../constants.js';
|
|
4
4
|
import { negotiate } from '../../utils/http.js';
|
|
5
5
|
import { method_not_allowed } from './utils.js';
|
|
6
6
|
|
|
@@ -25,8 +25,13 @@ export async function render_endpoint(event, state, mod) {
|
|
|
25
25
|
|
|
26
26
|
const prerender = mod.prerender ?? state.prerender_default;
|
|
27
27
|
|
|
28
|
-
if (
|
|
29
|
-
|
|
28
|
+
if (
|
|
29
|
+
prerender &&
|
|
30
|
+
/** @type {import('types').HttpMethod[]} */ (BODY_DEPENDENT_METHODS).some(
|
|
31
|
+
(method) => mod[method]
|
|
32
|
+
)
|
|
33
|
+
) {
|
|
34
|
+
throw new Error('Cannot prerender endpoints with body-dependent methods');
|
|
30
35
|
}
|
|
31
36
|
|
|
32
37
|
if (state.prerendering && !state.prerendering.inside_reroute && !prerender) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { text } from '@sveltejs/kit';
|
|
2
2
|
import {
|
|
3
3
|
HandledHttpError,
|
|
4
4
|
HttpError,
|
|
@@ -28,7 +28,7 @@ export async function handle_fatal_error(event, state, options, error) {
|
|
|
28
28
|
]);
|
|
29
29
|
|
|
30
30
|
if (event.isDataRequest || type === 'application/json') {
|
|
31
|
-
return json(body, {
|
|
31
|
+
return Response.json(body, {
|
|
32
32
|
status
|
|
33
33
|
});
|
|
34
34
|
}
|
|
@@ -2,9 +2,9 @@ import { noop } from '../../utils/functions.js';
|
|
|
2
2
|
import { IN_WEBCONTAINER } from '../../constants.js';
|
|
3
3
|
import { respond } from './respond.js';
|
|
4
4
|
import { create_request_state } from './state.js';
|
|
5
|
-
import { options, get_hooks } from '
|
|
5
|
+
import { options, get_hooks } from '<sveltekit:generated>/server.js';
|
|
6
6
|
import { set_read_implementation, set_manifest, fix_stack_trace } from './internal.js';
|
|
7
|
-
import { set_env } from '
|
|
7
|
+
import { set_env } from '<sveltekit:generated>/env/config.js';
|
|
8
8
|
import { init_tracing } from '@sveltejs/kit/internal/server';
|
|
9
9
|
import { DEV } from 'esm-env';
|
|
10
10
|
import { init_transport } from '#app/internal/transport';
|