@sveltejs/kit 3.0.0-next.25 → 3.0.0-next.27
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 +5 -7
- package/src/core/adapt/builder.js +127 -31
- package/src/core/adapt/index.js +3 -0
- package/src/core/config/index.js +4 -7
- package/src/core/env.js +36 -8
- package/src/core/generate_manifest/index.js +42 -43
- package/src/core/postbuild/analyse.js +4 -4
- package/src/core/postbuild/fallback.js +1 -1
- package/src/core/postbuild/prerender.js +2 -2
- package/src/core/sync/create_manifest_data/index.js +0 -1
- package/src/core/sync/write_app_manifest.js +3 -2
- package/src/exports/public.d.ts +100 -48
- package/src/exports/vite/build/index.js +1173 -0
- package/src/exports/vite/build/remote.js +4 -4
- package/src/exports/vite/dev/generate_manifest.js +308 -0
- package/src/exports/vite/dev/index.js +28 -284
- package/src/exports/vite/index.js +117 -1308
- package/src/exports/vite/plugins/env-vars.js +11 -34
- package/src/exports/vite/plugins/guard.js +19 -7
- package/src/exports/vite/plugins/remote.js +237 -0
- package/src/exports/vite/preview/index.js +8 -8
- package/src/exports/vite/static_analysis/index.js +15 -15
- package/src/exports/vite/utils.js +1 -1
- package/src/runner.js +4 -3
- package/src/runtime/app/paths/server.js +2 -2
- package/src/runtime/app/server/index.js +3 -3
- package/src/runtime/app/server/public.d.ts +114 -57
- package/src/runtime/app/server/remote/requested.js +31 -15
- package/src/runtime/app/state/client.svelte.js +3 -1
- package/src/runtime/client/client.js +39 -194
- package/src/runtime/client/fetcher.js +6 -6
- package/src/runtime/client/focus.js +120 -0
- package/src/runtime/client/remote-functions/command.svelte.js +20 -9
- package/src/runtime/client/remote-functions/form.svelte.js +12 -7
- package/src/runtime/client/remote-functions/query/instance.svelte.js +19 -5
- package/src/runtime/client/remote-functions/shared.svelte.js +22 -1
- package/src/runtime/client/scroll.js +39 -0
- package/src/runtime/client/utils.js +28 -0
- package/src/runtime/form-utils.js +243 -245
- package/src/runtime/server/data/index.js +3 -10
- package/src/runtime/server/fetch.js +13 -15
- package/src/runtime/server/index.js +8 -7
- package/src/runtime/server/internal.js +1 -2
- package/src/runtime/server/page/index.js +10 -15
- package/src/runtime/server/page/load_data.js +2 -2
- package/src/runtime/server/page/render.js +8 -13
- package/src/runtime/server/page/respond_with_error.js +4 -5
- package/src/runtime/server/page/server_routing.js +21 -27
- package/src/runtime/server/remote-functions.js +14 -14
- package/src/runtime/server/respond.js +17 -40
- package/src/runtime/server/state.js +1 -0
- package/src/runtime/server/utils.js +4 -4
- package/src/runtime/shared.js +9 -0
- package/src/types/ambient-private.d.ts +1 -2
- package/src/types/internal.d.ts +49 -6
- package/src/utils/filesystem.js +43 -27
- package/src/version.js +1 -1
- package/types/index.d.ts +215 -92
- package/types/index.d.ts.map +6 -2
|
@@ -26,6 +26,12 @@ export function set_nested_value(object, field, value) {
|
|
|
26
26
|
export function parse_form_key(form_id, key) {
|
|
27
27
|
const suffix = '/' + form_id;
|
|
28
28
|
let name = key;
|
|
29
|
+
let image_coordinate = '';
|
|
30
|
+
|
|
31
|
+
if (name.startsWith('i:') && (name.endsWith(suffix + '.x') || name.endsWith(suffix + '.y'))) {
|
|
32
|
+
image_coordinate = name[name.length - 1];
|
|
33
|
+
name = name.slice(0, -2);
|
|
34
|
+
}
|
|
29
35
|
|
|
30
36
|
if (!name.endsWith(suffix)) {
|
|
31
37
|
throw new Error(`Form contained a field that wasn't created with form.fields.as(...): ${name}`);
|
|
@@ -42,10 +48,14 @@ export function parse_form_key(form_id, key) {
|
|
|
42
48
|
} else if (name.startsWith('b:')) {
|
|
43
49
|
name = name.slice(2);
|
|
44
50
|
type = 'boolean';
|
|
51
|
+
} else if (name.startsWith('i:')) {
|
|
52
|
+
name = name.slice(2);
|
|
53
|
+
type = 'number';
|
|
45
54
|
}
|
|
46
55
|
|
|
47
56
|
const is_array = name.endsWith('[]');
|
|
48
57
|
if (is_array) name = name.slice(0, -2);
|
|
58
|
+
if (image_coordinate) name += '.' + image_coordinate;
|
|
49
59
|
|
|
50
60
|
return { name, type, is_array };
|
|
51
61
|
}
|
|
@@ -465,7 +475,12 @@ const path_regex = /^[a-zA-Z_$]\w*(\.[a-zA-Z_$]\w*|\[\d+\])*$/;
|
|
|
465
475
|
*/
|
|
466
476
|
export function split_path(path) {
|
|
467
477
|
if (!path_regex.test(path)) {
|
|
468
|
-
throw new Error(
|
|
478
|
+
throw new Error(
|
|
479
|
+
`Invalid field name ${path}` +
|
|
480
|
+
(DEV
|
|
481
|
+
? ': field names are written in JS object notation, so keys that would need quoting are not supported. See https://svelte.dev/docs/kit/remote-functions#form-Fields'
|
|
482
|
+
: '')
|
|
483
|
+
);
|
|
469
484
|
}
|
|
470
485
|
|
|
471
486
|
return path.split(/\.|\[|\]/).filter(Boolean);
|
|
@@ -592,32 +607,51 @@ export function flatten_issues(issues) {
|
|
|
592
607
|
* @param {(string | number)[]} path
|
|
593
608
|
* @returns {any}
|
|
594
609
|
*/
|
|
595
|
-
|
|
596
610
|
export function deep_get(object, path) {
|
|
597
611
|
let current = object;
|
|
598
612
|
for (const key of path) {
|
|
599
|
-
if (current
|
|
600
|
-
return current;
|
|
601
|
-
}
|
|
613
|
+
if (current === null || typeof current !== 'object') return undefined;
|
|
602
614
|
current = current[key];
|
|
603
615
|
}
|
|
604
616
|
return current;
|
|
605
617
|
}
|
|
606
618
|
|
|
619
|
+
/** name prefixes that tell the server which type to coerce a submitted string to */
|
|
620
|
+
const type_prefixes = /** @type {Record<string, string | undefined>} */ ({
|
|
621
|
+
number: 'n:',
|
|
622
|
+
boolean: 'b:'
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* adds props; a function becomes a getter that is computed each time it is read
|
|
627
|
+
* @param {Record<string, any>} base_props
|
|
628
|
+
* @param {Record<string, unknown>} props
|
|
629
|
+
*/
|
|
630
|
+
function add_props(base_props, props) {
|
|
631
|
+
for (const prop in props) {
|
|
632
|
+
const value = props[prop];
|
|
633
|
+
if (typeof value === 'function') {
|
|
634
|
+
Object.defineProperty(base_props, prop, {
|
|
635
|
+
enumerable: true,
|
|
636
|
+
get: /** @type {() => unknown} */ (value)
|
|
637
|
+
});
|
|
638
|
+
} else {
|
|
639
|
+
base_props[prop] = value;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
return base_props;
|
|
643
|
+
}
|
|
644
|
+
|
|
607
645
|
/**
|
|
608
|
-
*
|
|
609
|
-
* @param {string} field_type
|
|
646
|
+
* @param {string} type
|
|
610
647
|
* @param {boolean} is_array
|
|
611
648
|
* @param {unknown} input_value
|
|
612
649
|
*/
|
|
613
|
-
function get_type_prefix(
|
|
614
|
-
if (
|
|
615
|
-
if (
|
|
616
|
-
if (
|
|
617
|
-
|
|
618
|
-
if (input_type === 'number') return 'n:';
|
|
619
|
-
if (input_type === 'boolean') return 'b:';
|
|
620
|
-
}
|
|
650
|
+
function get_type_prefix(type, is_array, input_value) {
|
|
651
|
+
if (type === 'number' || type === 'range') return 'n:';
|
|
652
|
+
if (type === 'image') return 'i:';
|
|
653
|
+
if (type === 'checkbox' && !is_array) return 'b:';
|
|
654
|
+
if (type === 'hidden' || type === 'submit') return type_prefixes[typeof input_value] ?? '';
|
|
621
655
|
return '';
|
|
622
656
|
}
|
|
623
657
|
|
|
@@ -653,270 +687,234 @@ function deep_clone(value) {
|
|
|
653
687
|
return value;
|
|
654
688
|
}
|
|
655
689
|
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
690
|
+
const warned_sites = new Set();
|
|
691
|
+
|
|
692
|
+
// keyed by the stack, so every place that enumerates warns once with its call site
|
|
693
|
+
const warn_no_keys = () => {
|
|
694
|
+
const error = new Error(
|
|
695
|
+
'The properties of `form.fields` are virtual, so operators like `in` and `Object.keys` are meaningless. If you need the current value of a form field, use `form.fields.x.value()`'
|
|
696
|
+
);
|
|
697
|
+
if (warned_sites.has(error.stack)) return;
|
|
698
|
+
warned_sites.add(error.stack);
|
|
699
|
+
console.warn(error);
|
|
700
|
+
};
|
|
701
|
+
|
|
702
|
+
// fields are created as they are accessed, so there is nothing to enumerate
|
|
703
|
+
/** @type {ProxyHandler<object> | null} */
|
|
704
|
+
const dev_traps = DEV
|
|
705
|
+
? {
|
|
706
|
+
has(target, prop) {
|
|
707
|
+
if (typeof prop !== 'symbol') warn_no_keys();
|
|
708
|
+
return prop in target;
|
|
709
|
+
},
|
|
710
|
+
ownKeys(target) {
|
|
711
|
+
warn_no_keys();
|
|
712
|
+
return Reflect.ownKeys(target);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
: null;
|
|
716
|
+
|
|
717
|
+
/** @param {InternalRemoteFormIssue} issue */
|
|
718
|
+
const public_issue = (issue) => ({ path: issue.path, message: issue.message });
|
|
719
|
+
|
|
720
|
+
/** @typedef {{
|
|
659
721
|
* form_id: string,
|
|
660
722
|
* get: () => Record<string, any>,
|
|
661
723
|
* set: (path: (string | number)[], value: any) => void,
|
|
662
724
|
* get_issues: (path?: (string | number)[], all?: boolean) => Record<string, InternalRemoteFormIssue[]>,
|
|
663
725
|
* get_touched: () => Record<string, boolean>,
|
|
664
726
|
* get_dirty: () => Record<string, boolean>
|
|
665
|
-
* }}
|
|
666
|
-
* @param {any} target - Function or empty POJO
|
|
667
|
-
* @param {(string | number)[]} path - Current access path
|
|
668
|
-
* @returns {any} Proxy object with name(), value(), and issues() methods
|
|
669
|
-
*/
|
|
670
|
-
export function create_field_proxy(context, target = {}, path = []) {
|
|
671
|
-
const get_value = () => {
|
|
672
|
-
const value = deep_get(context.get(), path);
|
|
673
|
-
return deep_clone(value);
|
|
674
|
-
};
|
|
675
|
-
|
|
676
|
-
return new Proxy(target, {
|
|
677
|
-
get(target, prop) {
|
|
678
|
-
if (typeof prop === 'symbol') return target[prop];
|
|
679
|
-
|
|
680
|
-
// Handle array access like jobs[0]
|
|
681
|
-
if (/^\d+$/.test(prop)) {
|
|
682
|
-
return create_field_proxy(context, {}, [...path, parseInt(prop, 10)]);
|
|
683
|
-
}
|
|
727
|
+
* }} FieldContext */
|
|
684
728
|
|
|
729
|
+
/**
|
|
730
|
+
* @param {FieldContext} context
|
|
731
|
+
* @param {(string | number)[]} path
|
|
732
|
+
* @param {string} prop
|
|
733
|
+
* @returns {any} a method of the field at `path`, or undefined for a nested field
|
|
734
|
+
*/
|
|
735
|
+
function create_field_method(context, path, prop) {
|
|
736
|
+
switch (prop) {
|
|
737
|
+
case 'set':
|
|
738
|
+
return (/** @type {any} */ value) => {
|
|
739
|
+
context.set(path, value);
|
|
740
|
+
return value;
|
|
741
|
+
};
|
|
742
|
+
case 'value':
|
|
743
|
+
return () => deep_clone(deep_get(context.get(), path));
|
|
744
|
+
case 'issues':
|
|
745
|
+
case 'allIssues': {
|
|
746
|
+
const key = build_path_string(path);
|
|
747
|
+
const all = prop === 'allIssues';
|
|
748
|
+
|
|
749
|
+
return () => {
|
|
750
|
+
const issues = context.get_issues(path, all)[key === '' ? '$' : key];
|
|
751
|
+
if (all) return issues?.map(public_issue);
|
|
752
|
+
const own = issues?.filter((issue) => issue.name === key).map(public_issue);
|
|
753
|
+
return own?.length ? own : undefined;
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
case 'touched':
|
|
757
|
+
case 'dirty': {
|
|
685
758
|
const key = build_path_string(path);
|
|
686
|
-
const next = [...path, prop];
|
|
687
|
-
|
|
688
|
-
if (prop === 'set') {
|
|
689
|
-
const set_func = function (/** @type {any} */ newValue) {
|
|
690
|
-
context.set(path, newValue);
|
|
691
|
-
return newValue;
|
|
692
|
-
};
|
|
693
|
-
return create_field_proxy(context, set_func, next);
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
if (prop === 'value') {
|
|
697
|
-
return create_field_proxy(context, get_value, next);
|
|
698
|
-
}
|
|
699
759
|
|
|
700
|
-
|
|
701
|
-
const
|
|
702
|
-
|
|
760
|
+
return () => {
|
|
761
|
+
const object = prop === 'dirty' ? context.get_dirty() : context.get_touched();
|
|
762
|
+
if (Object.hasOwn(object, key)) return true;
|
|
763
|
+
for (const candidate in object) {
|
|
764
|
+
if (!Object.hasOwn(object, candidate)) continue;
|
|
765
|
+
if (key === '') return true;
|
|
766
|
+
if (!candidate.startsWith(key)) continue;
|
|
767
|
+
const next = candidate[key.length];
|
|
768
|
+
if (next === '.' || next === '[') return true;
|
|
769
|
+
}
|
|
770
|
+
return false;
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
case 'as': {
|
|
774
|
+
const key = build_path_string(path);
|
|
703
775
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
776
|
+
/**
|
|
777
|
+
* the field's value, or `fallback` until the field has been edited
|
|
778
|
+
* (without a fallback there is nothing to suppress, so `dirty` is not read)
|
|
779
|
+
* @param {unknown} [fallback]
|
|
780
|
+
*/
|
|
781
|
+
const read = (fallback) =>
|
|
782
|
+
deep_get(context.get(), path) ??
|
|
783
|
+
(fallback !== undefined && Object.hasOwn(context.get_dirty(), key) ? undefined : fallback);
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* @param {string} type
|
|
787
|
+
* @param {unknown} [input_value]
|
|
788
|
+
* @param {boolean} [checked]
|
|
789
|
+
*/
|
|
790
|
+
return (type, input_value, checked) => {
|
|
791
|
+
const is_array =
|
|
792
|
+
type === 'file multiple' ||
|
|
793
|
+
type === 'select multiple' ||
|
|
794
|
+
(type === 'checkbox' && typeof input_value === 'string');
|
|
795
|
+
|
|
796
|
+
const type_prefix = get_type_prefix(type, is_array, input_value);
|
|
797
|
+
|
|
798
|
+
// Base properties for all input types
|
|
799
|
+
/** @type {Record<string, any>} */
|
|
800
|
+
const base_props = {
|
|
801
|
+
name: type_prefix + key + (is_array ? '[]' : '') + '/' + context.form_id,
|
|
802
|
+
get 'aria-invalid'() {
|
|
803
|
+
const issues = context.get_issues();
|
|
804
|
+
return key in issues ? 'true' : undefined;
|
|
709
805
|
}
|
|
710
|
-
|
|
711
|
-
const issues = all_issues
|
|
712
|
-
?.filter((issue) => issue.name === key)
|
|
713
|
-
?.map((issue) => ({
|
|
714
|
-
path: issue.path,
|
|
715
|
-
message: issue.message
|
|
716
|
-
}));
|
|
717
|
-
|
|
718
|
-
return issues?.length ? issues : undefined;
|
|
719
806
|
};
|
|
720
807
|
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
const fn = () => {
|
|
726
|
-
const object = prop === 'dirty' ? context.get_dirty() : context.get_touched();
|
|
727
|
-
|
|
728
|
-
if (key === '') {
|
|
729
|
-
return Object.keys(object).length > 0;
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
if (Object.hasOwn(object, key)) {
|
|
733
|
-
return true;
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
for (const candidate in object) {
|
|
737
|
-
if (!Object.hasOwn(object, candidate)) continue;
|
|
738
|
-
if (!candidate.startsWith(key)) continue;
|
|
808
|
+
// Add type attribute only for non-text inputs and non-select elements
|
|
809
|
+
if (type !== 'text' && type !== 'select' && type !== 'select multiple') {
|
|
810
|
+
base_props.type = type === 'file multiple' ? 'file' : type;
|
|
811
|
+
}
|
|
739
812
|
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
813
|
+
// Handle submit and hidden inputs
|
|
814
|
+
if (type === 'submit' || type === 'hidden') {
|
|
815
|
+
if (DEV) {
|
|
816
|
+
if (input_value === null || input_value === undefined) {
|
|
817
|
+
throw new Error(`\`${type}\` inputs must have a value`);
|
|
743
818
|
}
|
|
744
819
|
}
|
|
745
820
|
|
|
746
|
-
return
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
if (prop === 'as') {
|
|
753
|
-
/**
|
|
754
|
-
* @param {string} type
|
|
755
|
-
* @param {unknown} [input_value]
|
|
756
|
-
*/
|
|
757
|
-
const as_func = (type, input_value) => {
|
|
758
|
-
const is_array =
|
|
759
|
-
type === 'file multiple' ||
|
|
760
|
-
type === 'select multiple' ||
|
|
761
|
-
(type === 'checkbox' && typeof input_value === 'string');
|
|
762
|
-
|
|
763
|
-
const type_prefix = get_type_prefix(type, is_array, input_value);
|
|
764
|
-
|
|
765
|
-
// Base properties for all input types
|
|
766
|
-
/** @type {Record<string, any>} */
|
|
767
|
-
const base_props = {
|
|
768
|
-
name: type_prefix + key + (is_array ? '[]' : '') + '/' + context.form_id,
|
|
769
|
-
get 'aria-invalid'() {
|
|
770
|
-
const issues = context.get_issues();
|
|
771
|
-
return key in issues ? 'true' : undefined;
|
|
772
|
-
}
|
|
773
|
-
};
|
|
774
|
-
|
|
775
|
-
// Add type attribute only for non-text inputs and non-select elements
|
|
776
|
-
if (type !== 'text' && type !== 'select' && type !== 'select multiple') {
|
|
777
|
-
base_props.type = type === 'file multiple' ? 'file' : type;
|
|
778
|
-
}
|
|
821
|
+
return add_props(base_props, {
|
|
822
|
+
value: typeof input_value === 'boolean' ? (input_value ? 'on' : 'off') : input_value
|
|
823
|
+
});
|
|
824
|
+
}
|
|
779
825
|
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
826
|
+
// Handle select inputs
|
|
827
|
+
if (type === 'select' || type === 'select multiple') {
|
|
828
|
+
return add_props(base_props, {
|
|
829
|
+
multiple: is_array,
|
|
830
|
+
value: () => {
|
|
831
|
+
const value = read(input_value);
|
|
832
|
+
// copied, so the state array can't be edited through the props
|
|
833
|
+
return Array.isArray(value) ? [...value] : value;
|
|
786
834
|
}
|
|
835
|
+
});
|
|
836
|
+
}
|
|
787
837
|
|
|
788
|
-
|
|
789
|
-
|
|
838
|
+
// Handle checkbox inputs
|
|
839
|
+
if (type === 'checkbox' || type === 'radio') {
|
|
840
|
+
// radio and checkbox array inputs take their option as the second argument
|
|
841
|
+
// and whether it is checked as the third, a single checkbox only the latter
|
|
842
|
+
const has_option = type === 'radio' || is_array;
|
|
790
843
|
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
844
|
+
if (DEV && has_option && !input_value) {
|
|
845
|
+
throw new Error(
|
|
846
|
+
`${type === 'radio' ? 'Radio' : 'Checkbox array'} inputs must have a value`
|
|
847
|
+
);
|
|
794
848
|
}
|
|
795
849
|
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
value: {
|
|
801
|
-
enumerable: true,
|
|
802
|
-
get() {
|
|
803
|
-
return get_value() ?? input_value;
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
});
|
|
850
|
+
if (has_option) {
|
|
851
|
+
base_props.value = input_value ?? 'on';
|
|
852
|
+
} else {
|
|
853
|
+
checked = /** @type {boolean | undefined} */ (input_value);
|
|
807
854
|
}
|
|
808
855
|
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
856
|
+
return add_props(base_props, {
|
|
857
|
+
defaultChecked: checked,
|
|
858
|
+
checked: () => {
|
|
859
|
+
const value = read();
|
|
860
|
+
if (value == null) return read(checked);
|
|
861
|
+
if (type === 'radio') return value === input_value;
|
|
862
|
+
if (is_array) return /** @type {unknown[]} */ (value).includes(input_value);
|
|
863
|
+
return value;
|
|
864
|
+
}
|
|
865
|
+
});
|
|
866
|
+
}
|
|
815
867
|
|
|
816
|
-
|
|
817
|
-
|
|
868
|
+
// Handle file inputs
|
|
869
|
+
if (type === 'file' || type === 'file multiple') {
|
|
870
|
+
return add_props(base_props, {
|
|
871
|
+
multiple: is_array,
|
|
872
|
+
files: () => {
|
|
873
|
+
const value = read();
|
|
874
|
+
const files = value instanceof File ? [value] : value;
|
|
875
|
+
if (!Array.isArray(files) || !files.every((f) => f instanceof File)) return null;
|
|
876
|
+
|
|
877
|
+
// a FileList-like object where DataTransfer does not exist
|
|
878
|
+
if (typeof DataTransfer === 'undefined') {
|
|
879
|
+
return Object.assign({ length: files.length }, files);
|
|
818
880
|
}
|
|
819
|
-
}
|
|
820
881
|
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
enumerable: true,
|
|
825
|
-
get() {
|
|
826
|
-
return input_value;
|
|
827
|
-
}
|
|
828
|
-
},
|
|
829
|
-
checked: {
|
|
830
|
-
enumerable: true,
|
|
831
|
-
get() {
|
|
832
|
-
return get_value() ?? input_value;
|
|
833
|
-
}
|
|
834
|
-
}
|
|
835
|
-
});
|
|
882
|
+
const transfer = new DataTransfer();
|
|
883
|
+
for (const file of files) transfer.items.add(file);
|
|
884
|
+
return transfer.files;
|
|
836
885
|
}
|
|
886
|
+
});
|
|
887
|
+
}
|
|
837
888
|
|
|
838
|
-
|
|
839
|
-
value: { value: input_value ?? 'on', enumerable: true },
|
|
840
|
-
checked: {
|
|
841
|
-
enumerable: true,
|
|
842
|
-
get() {
|
|
843
|
-
const value = get_value();
|
|
844
|
-
|
|
845
|
-
if (type === 'radio') {
|
|
846
|
-
return value === input_value;
|
|
847
|
-
}
|
|
889
|
+
if (type === 'image') return base_props;
|
|
848
890
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
multiple: { value: is_array, enumerable: true },
|
|
859
|
-
files: {
|
|
860
|
-
enumerable: true,
|
|
861
|
-
get() {
|
|
862
|
-
const value = get_value();
|
|
863
|
-
|
|
864
|
-
// Convert File/File[] to FileList-like object
|
|
865
|
-
if (value instanceof File) {
|
|
866
|
-
// In browsers, we can create a proper FileList using DataTransfer
|
|
867
|
-
if (typeof DataTransfer !== 'undefined') {
|
|
868
|
-
const fileList = new DataTransfer();
|
|
869
|
-
fileList.items.add(value);
|
|
870
|
-
return fileList.files;
|
|
871
|
-
}
|
|
872
|
-
// Fallback for environments without DataTransfer
|
|
873
|
-
return { 0: value, length: 1 };
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
if (Array.isArray(value) && value.every((f) => f instanceof File)) {
|
|
877
|
-
if (typeof DataTransfer !== 'undefined') {
|
|
878
|
-
const fileList = new DataTransfer();
|
|
879
|
-
value.forEach((file) => fileList.items.add(file));
|
|
880
|
-
return fileList.files;
|
|
881
|
-
}
|
|
882
|
-
// Fallback for environments without DataTransfer
|
|
883
|
-
/** @type {any} */
|
|
884
|
-
const fileListLike = { length: value.length };
|
|
885
|
-
value.forEach((file, index) => {
|
|
886
|
-
fileListLike[index] = file;
|
|
887
|
-
});
|
|
888
|
-
return fileListLike;
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
return null;
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
});
|
|
895
|
-
}
|
|
891
|
+
// Handle all other input types (text, number, etc.)
|
|
892
|
+
return add_props(base_props, {
|
|
893
|
+
defaultValue: input_value,
|
|
894
|
+
value: () => String(read(input_value) ?? '')
|
|
895
|
+
});
|
|
896
|
+
};
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
}
|
|
896
900
|
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
return value != null ? String(value) : '';
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
});
|
|
913
|
-
};
|
|
901
|
+
/**
|
|
902
|
+
* Creates a proxy-based field accessor for form data
|
|
903
|
+
* @param {FieldContext} context
|
|
904
|
+
* @param {any} target - Function or empty POJO
|
|
905
|
+
* @param {(string | number)[]} path - Current access path
|
|
906
|
+
* @returns {any} Proxy object with name(), value(), and issues() methods
|
|
907
|
+
*/
|
|
908
|
+
export function create_field_proxy(context, target = {}, path = []) {
|
|
909
|
+
return new Proxy(target, {
|
|
910
|
+
...dev_traps,
|
|
911
|
+
get(target, prop) {
|
|
912
|
+
if (typeof prop === 'symbol') return target[prop];
|
|
914
913
|
|
|
915
|
-
|
|
916
|
-
|
|
914
|
+
// array access like jobs[0]
|
|
915
|
+
const next = [...path, /^\d+$/.test(prop) ? parseInt(prop, 10) : prop];
|
|
917
916
|
|
|
918
|
-
|
|
919
|
-
return create_field_proxy(context, {}, next);
|
|
917
|
+
return create_field_proxy(context, create_field_method(context, path, prop), next);
|
|
920
918
|
}
|
|
921
919
|
});
|
|
922
920
|
}
|
|
@@ -8,24 +8,17 @@ import { handle_error_and_jsonify } from '../errors.js';
|
|
|
8
8
|
import { normalize_path } from '../../../utils/url.js';
|
|
9
9
|
import { stream_text } from '../../utils.js';
|
|
10
10
|
import { with_version_header } from '../utils.js';
|
|
11
|
+
import { manifest } from '../internal.js';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* @param {import('@sveltejs/kit').RequestEvent} event
|
|
14
15
|
* @param {import('types').RequestState} state
|
|
15
16
|
* @param {{ page: Pick<import('types').PageNodeIndexes, 'layouts' | 'leaf'> | null }} route
|
|
16
|
-
* @param {import('@sveltejs/kit').SSRManifest} manifest
|
|
17
17
|
* @param {boolean[] | undefined} invalidated_data_nodes
|
|
18
18
|
* @param {import('types').TrailingSlash} trailing_slash
|
|
19
19
|
* @returns {Promise<Response>}
|
|
20
20
|
*/
|
|
21
|
-
export async function render_data(
|
|
22
|
-
event,
|
|
23
|
-
state,
|
|
24
|
-
route,
|
|
25
|
-
manifest,
|
|
26
|
-
invalidated_data_nodes,
|
|
27
|
-
trailing_slash
|
|
28
|
-
) {
|
|
21
|
+
export async function render_data(event, state, route, invalidated_data_nodes, trailing_slash) {
|
|
29
22
|
if (!route.page) {
|
|
30
23
|
// requesting /__data.json should fail for a +server.js
|
|
31
24
|
return with_version_header(new Response(undefined, { status: 404 }));
|
|
@@ -52,7 +45,7 @@ export async function render_data(
|
|
|
52
45
|
}
|
|
53
46
|
|
|
54
47
|
// == because it could be undefined (in dev) or null (in build, because of JSON.stringify)
|
|
55
|
-
const node = n == undefined ? n : await manifest.
|
|
48
|
+
const node = n == undefined ? n : await manifest.nodes[n]();
|
|
56
49
|
// load this. for the child, return as is. for the final result, stream things
|
|
57
50
|
return load_server_data({
|
|
58
51
|
event: new_event,
|