@webamoki/web-svelte 0.5.35 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server/form-handler.d.ts +9 -5
- package/dist/server/form-handler.js +13 -4
- package/dist/server/form-processor.d.ts +2 -0
- package/dist/server/form-processor.js +7 -0
- package/dist/utils/{form.d.ts → form/index.d.ts} +2 -1
- package/dist/utils/{form.js → form/index.js} +18 -21
- package/dist/utils/form/virtual-form.d.ts +14 -0
- package/dist/utils/form/virtual-form.js +134 -0
- package/package.json +10 -5
|
@@ -10,19 +10,23 @@ export declare function handleDbErrorForm<T extends Record<string, unknown>>(for
|
|
|
10
10
|
* check if an error returned by a try catch is a duplicate value error in postgre
|
|
11
11
|
*/
|
|
12
12
|
export declare function isDuplicateDbError(err: unknown): boolean;
|
|
13
|
-
export declare function successMessage<T extends Record<string, unknown>>(form: SuperValidated<T
|
|
14
|
-
|
|
13
|
+
export declare function successMessage<T extends Record<string, unknown>>(form: SuperValidated<T>, options?: {
|
|
14
|
+
showToast?: boolean;
|
|
15
|
+
text?: string;
|
|
16
|
+
data?: unknown;
|
|
17
|
+
}): {
|
|
18
|
+
form: SuperValidated<T, App.Superforms.Message, T>;
|
|
15
19
|
} | import("@sveltejs/kit").ActionFailure<{
|
|
16
|
-
form: SuperValidated<T,
|
|
20
|
+
form: SuperValidated<T, App.Superforms.Message, T>;
|
|
17
21
|
}>;
|
|
18
22
|
export declare function errorMessage<T extends Record<string, unknown>>(form: SuperValidated<T>, options?: {
|
|
19
23
|
showToast?: boolean;
|
|
20
24
|
text?: string;
|
|
21
25
|
data?: unknown;
|
|
22
26
|
}): {
|
|
23
|
-
form: SuperValidated<T,
|
|
27
|
+
form: SuperValidated<T, App.Superforms.Message, T>;
|
|
24
28
|
} | import("@sveltejs/kit").ActionFailure<{
|
|
25
|
-
form: SuperValidated<T,
|
|
29
|
+
form: SuperValidated<T, App.Superforms.Message, T>;
|
|
26
30
|
}>;
|
|
27
31
|
export declare function failFormValidation<T extends Record<string, unknown>>(form: SuperValidated<T>): import("@sveltejs/kit").ActionFailure<{
|
|
28
32
|
form: SuperValidated<T>;
|
|
@@ -18,17 +18,26 @@ export function handleDbErrorForm(form, message, err) {
|
|
|
18
18
|
export function isDuplicateDbError(err) {
|
|
19
19
|
return err instanceof DatabaseError && err.code === '23505';
|
|
20
20
|
}
|
|
21
|
-
export function successMessage(form) {
|
|
22
|
-
|
|
21
|
+
export function successMessage(form, options) {
|
|
22
|
+
const message = {
|
|
23
|
+
success: true,
|
|
24
|
+
showToast: options?.showToast ?? true,
|
|
25
|
+
text: options?.text ?? 'Success',
|
|
26
|
+
data: options?.data
|
|
27
|
+
};
|
|
28
|
+
return superFormMessage(form, message);
|
|
23
29
|
}
|
|
24
30
|
export function errorMessage(form, options) {
|
|
25
|
-
|
|
31
|
+
const message = {
|
|
26
32
|
success: false,
|
|
27
33
|
showToast: options?.showToast ?? false,
|
|
28
34
|
text: options?.text,
|
|
29
35
|
data: options?.data
|
|
30
|
-
}
|
|
36
|
+
};
|
|
37
|
+
return superFormMessage(form, message);
|
|
31
38
|
}
|
|
32
39
|
export function failFormValidation(form) {
|
|
40
|
+
if (form.valid)
|
|
41
|
+
throw new Error('Invalid form passed');
|
|
33
42
|
return fail(400, { form });
|
|
34
43
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { dateTransport } from '../utils/datetime/index.js';
|
|
2
|
+
import { type } from 'arktype';
|
|
3
|
+
import { superValidate } from 'sveltekit-superforms';
|
|
4
|
+
import { arktype } from 'sveltekit-superforms/adapters';
|
|
5
|
+
export async function processForm(request, schema) {
|
|
6
|
+
return await superValidate(request, arktype(schema), { transport: dateTransport });
|
|
7
|
+
}
|
|
@@ -4,6 +4,7 @@ export declare function prepareForm<S extends type.Any<Record<string, unknown>>>
|
|
|
4
4
|
invalidateAll: boolean;
|
|
5
5
|
resetForm: boolean;
|
|
6
6
|
onSuccess: (form: Readonly<SuperValidated<S['infer'], App.Superforms.Message, S['infer']>>) => void;
|
|
7
|
+
onError: (form: Readonly<SuperValidated<S['infer'], App.Superforms.Message, S['infer']>>) => void;
|
|
7
8
|
}>): {
|
|
8
9
|
form: import("sveltekit-superforms").SuperForm<S["infer"], any>;
|
|
9
10
|
data: import("sveltekit-superforms/client").SuperFormData<S["infer"]>;
|
|
@@ -14,10 +15,10 @@ export declare function prepareEmptyForm<S extends type.Any<Record<string, unkno
|
|
|
14
15
|
invalidateAll: boolean;
|
|
15
16
|
resetForm: boolean;
|
|
16
17
|
onSuccess: (form: Readonly<SuperValidated<S['infer'], App.Superforms.Message, S['infer']>>) => void;
|
|
18
|
+
onError: (form: Readonly<SuperValidated<S['infer'], App.Superforms.Message, S['infer']>>) => void;
|
|
17
19
|
}>): {
|
|
18
20
|
form: import("sveltekit-superforms").SuperForm<S["infer"], any>;
|
|
19
21
|
data: import("sveltekit-superforms/client").SuperFormData<S["infer"]>;
|
|
20
22
|
delayed: import("svelte/store").Readable<boolean>;
|
|
21
23
|
errors: import("sveltekit-superforms/client").SuperFormErrors<S["infer"]>;
|
|
22
24
|
};
|
|
23
|
-
export declare function getServerForm<S extends type.Any<Record<string, unknown>>>(request: Request, schema: S): Promise<SuperValidated<S["infer"], any, S["inferIn"]>>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type } from 'arktype';
|
|
2
2
|
import { toast } from 'svelte-sonner';
|
|
3
|
-
import { defaults, superForm
|
|
3
|
+
import { defaults, superForm } from 'sveltekit-superforms';
|
|
4
4
|
import { arktype, arktypeClient } from 'sveltekit-superforms/adapters';
|
|
5
|
-
import { dateTransport } from '
|
|
5
|
+
import { dateTransport } from '../datetime/index.js';
|
|
6
6
|
export function prepareForm(validated, schema, options) {
|
|
7
7
|
const form = superForm(validated, {
|
|
8
8
|
validators: arktypeClient(schema),
|
|
@@ -11,17 +11,17 @@ export function prepareForm(validated, schema, options) {
|
|
|
11
11
|
transport: dateTransport,
|
|
12
12
|
resetForm: options?.resetForm ?? true,
|
|
13
13
|
onUpdated({ form }) {
|
|
14
|
-
if (form.valid) {
|
|
14
|
+
if (form.valid && form.message.success) {
|
|
15
15
|
options?.onSuccess?.(form);
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return;
|
|
20
|
-
if (form.message.success) {
|
|
21
|
-
toast.success(text);
|
|
16
|
+
if (form.message?.text && form.message?.showToast) {
|
|
17
|
+
toast.success(form.message.text);
|
|
18
|
+
}
|
|
22
19
|
}
|
|
23
20
|
else {
|
|
24
|
-
|
|
21
|
+
options?.onError?.(form);
|
|
22
|
+
if (form.message?.text && form.message?.showToast) {
|
|
23
|
+
toast.error(form.message.text);
|
|
24
|
+
}
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
onError({ result }) {
|
|
@@ -42,17 +42,17 @@ export function prepareEmptyForm(schema, options) {
|
|
|
42
42
|
transport: dateTransport,
|
|
43
43
|
resetForm: options?.resetForm === undefined ? true : false,
|
|
44
44
|
onUpdated({ form }) {
|
|
45
|
-
if (form.valid) {
|
|
45
|
+
if (form.valid && form.message.success) {
|
|
46
46
|
options?.onSuccess?.(form);
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return;
|
|
51
|
-
if (form.message.success) {
|
|
52
|
-
toast.success(text);
|
|
47
|
+
if (form.message?.text && form.message?.showToast) {
|
|
48
|
+
toast.success(form.message.text);
|
|
49
|
+
}
|
|
53
50
|
}
|
|
54
51
|
else {
|
|
55
|
-
|
|
52
|
+
options?.onError?.(form);
|
|
53
|
+
if (form.message?.text && form.message?.showToast) {
|
|
54
|
+
toast.error(form.message.text);
|
|
55
|
+
}
|
|
56
56
|
}
|
|
57
57
|
},
|
|
58
58
|
onError({ result }) {
|
|
@@ -65,6 +65,3 @@ export function prepareEmptyForm(schema, options) {
|
|
|
65
65
|
const errors = form.errors;
|
|
66
66
|
return { form, data: form.form, delayed, errors };
|
|
67
67
|
}
|
|
68
|
-
export async function getServerForm(request, schema) {
|
|
69
|
-
return await superValidate(request, arktype(schema), { transport: dateTransport });
|
|
70
|
-
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type } from 'arktype';
|
|
2
|
+
import type { SuperValidated } from 'sveltekit-superforms/client';
|
|
3
|
+
import type { Transport } from '@sveltejs/kit';
|
|
4
|
+
export declare class VirtualForm<S extends type.Any<Record<string, unknown>>> {
|
|
5
|
+
#private;
|
|
6
|
+
constructor(schema: S, action: string, options?: {
|
|
7
|
+
actionName?: string;
|
|
8
|
+
transport?: Transport;
|
|
9
|
+
onSuccess?: (form: Readonly<SuperValidated<S['infer'], App.Superforms.Message, S['infer']>>) => void;
|
|
10
|
+
onError?: (message: App.Superforms.Message) => void;
|
|
11
|
+
});
|
|
12
|
+
submit(data: S['infer']): Promise<void>;
|
|
13
|
+
get isLoading(): boolean;
|
|
14
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { type } from 'arktype';
|
|
2
|
+
import { toast } from 'svelte-sonner';
|
|
3
|
+
import { createSubscriber } from 'svelte/reactivity';
|
|
4
|
+
import { parse, stringify } from 'devalue';
|
|
5
|
+
import { dateTransport } from '../datetime/index.js';
|
|
6
|
+
export class VirtualForm {
|
|
7
|
+
// state storage
|
|
8
|
+
#isLoading = false;
|
|
9
|
+
#url = '';
|
|
10
|
+
#schema;
|
|
11
|
+
#transport;
|
|
12
|
+
#onSuccess;
|
|
13
|
+
#onError;
|
|
14
|
+
// svelte reactive tracking
|
|
15
|
+
#subscribe;
|
|
16
|
+
#update = () => { };
|
|
17
|
+
constructor(schema, action, options = {}) {
|
|
18
|
+
this.#url = `${action}${options.actionName ? '?/' + options.actionName : ''}`;
|
|
19
|
+
this.#schema = schema;
|
|
20
|
+
this.#transport = options.transport ?? dateTransport;
|
|
21
|
+
this.#onSuccess = options.onSuccess;
|
|
22
|
+
this.#onError = options.onError;
|
|
23
|
+
this.#subscribe = createSubscriber((update) => {
|
|
24
|
+
this.#update = update;
|
|
25
|
+
return () => { };
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
// Apply transport encoding to data before sending
|
|
29
|
+
#encodeTransport(data) {
|
|
30
|
+
if (!this.#transport || typeof data !== 'object' || data === null) {
|
|
31
|
+
return data;
|
|
32
|
+
}
|
|
33
|
+
// Handle arrays
|
|
34
|
+
if (Array.isArray(data)) {
|
|
35
|
+
return data.map((item) => this.#encodeTransport(item));
|
|
36
|
+
}
|
|
37
|
+
// Try each transport encoder
|
|
38
|
+
for (const [key, encoder] of Object.entries(this.#transport)) {
|
|
39
|
+
const encoded = encoder.encode(data);
|
|
40
|
+
if (encoded !== false) {
|
|
41
|
+
return { __type: key, __value: encoded };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Recursively encode nested objects
|
|
45
|
+
const result = {};
|
|
46
|
+
for (const [key, value] of Object.entries(data)) {
|
|
47
|
+
result[key] = this.#encodeTransport(value);
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
// Apply transport decoding to received data
|
|
52
|
+
#decodeTransport(data) {
|
|
53
|
+
if (!this.#transport || typeof data !== 'object' || data === null) {
|
|
54
|
+
return data;
|
|
55
|
+
}
|
|
56
|
+
// Handle arrays
|
|
57
|
+
if (Array.isArray(data)) {
|
|
58
|
+
return data.map((item) => this.#decodeTransport(item));
|
|
59
|
+
}
|
|
60
|
+
// Check if this is a transport-encoded value
|
|
61
|
+
const obj = data;
|
|
62
|
+
if (obj.__type && obj.__value && this.#transport[obj.__type]) {
|
|
63
|
+
return this.#transport[obj.__type].decode(obj.__value);
|
|
64
|
+
}
|
|
65
|
+
// Recursively decode nested objects
|
|
66
|
+
const result = {};
|
|
67
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
68
|
+
result[key] = this.#decodeTransport(value);
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
async submit(data) {
|
|
73
|
+
this.#isLoading = true;
|
|
74
|
+
this.#update();
|
|
75
|
+
// Validate data against schema
|
|
76
|
+
const validated = this.#schema(data);
|
|
77
|
+
if (validated instanceof type.errors) {
|
|
78
|
+
console.error('Validation failed:', validated.summary);
|
|
79
|
+
this.#onError?.({
|
|
80
|
+
text: 'Validation failed',
|
|
81
|
+
data: validated.summary,
|
|
82
|
+
success: false,
|
|
83
|
+
showToast: false
|
|
84
|
+
});
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
// Apply transport encoding before sending
|
|
89
|
+
const encodedData = this.#encodeTransport(validated);
|
|
90
|
+
// Encode JSON as form data (like superforms does)
|
|
91
|
+
const formData = new FormData();
|
|
92
|
+
formData.append('__superform_id', '1');
|
|
93
|
+
formData.append('__superform_json', stringify(encodedData));
|
|
94
|
+
const res = await fetch(this.#url, {
|
|
95
|
+
method: 'POST',
|
|
96
|
+
body: formData
|
|
97
|
+
});
|
|
98
|
+
const result = await res.json();
|
|
99
|
+
if (!res.ok || result.status === 400) {
|
|
100
|
+
console.error('Request failed:', result);
|
|
101
|
+
this.#onError?.(result);
|
|
102
|
+
this.#isLoading = false;
|
|
103
|
+
this.#update();
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
// Parse and decode the response
|
|
107
|
+
const parsedData = parse(result['data']);
|
|
108
|
+
const decodedData = this.#decodeTransport(parsedData);
|
|
109
|
+
const form = decodedData['form'];
|
|
110
|
+
if (form.valid && form.message?.success) {
|
|
111
|
+
this.#onSuccess?.(form);
|
|
112
|
+
if (form.message.text && form.message.showToast) {
|
|
113
|
+
toast.success(form.message.text);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
this.#onError?.(form.message);
|
|
118
|
+
if (form.message?.text && form.message?.showToast) {
|
|
119
|
+
toast.error(form.message.text);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
console.error(err);
|
|
125
|
+
this.#onError?.({ text: 'Network error', data: err, success: false, showToast: false });
|
|
126
|
+
}
|
|
127
|
+
this.#isLoading = false;
|
|
128
|
+
this.#update();
|
|
129
|
+
}
|
|
130
|
+
get isLoading() {
|
|
131
|
+
this.#subscribe();
|
|
132
|
+
return this.#isLoading;
|
|
133
|
+
}
|
|
134
|
+
}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.6.1",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"files": [
|
|
9
9
|
"dist",
|
|
@@ -40,13 +40,17 @@
|
|
|
40
40
|
"import": "./dist/utils/types/db.js"
|
|
41
41
|
},
|
|
42
42
|
"./utils/form": {
|
|
43
|
-
"types": "./dist/utils/form.d.ts",
|
|
44
|
-
"import": "./dist/utils/form.js"
|
|
43
|
+
"types": "./dist/utils/form/index.d.ts",
|
|
44
|
+
"import": "./dist/utils/form/index.js"
|
|
45
45
|
},
|
|
46
46
|
"./server/form-handler": {
|
|
47
47
|
"types": "./dist/server/form-handler.d.ts",
|
|
48
48
|
"import": "./dist/server/form-handler.js"
|
|
49
49
|
},
|
|
50
|
+
"./server/form-processor": {
|
|
51
|
+
"types": "./dist/server/form-processor.d.ts",
|
|
52
|
+
"import": "./dist/server/form-processor.js"
|
|
53
|
+
},
|
|
50
54
|
"./utils/search": {
|
|
51
55
|
"types": "./dist/utils/search.d.ts",
|
|
52
56
|
"import": "./dist/utils/search.js"
|
|
@@ -57,13 +61,12 @@
|
|
|
57
61
|
"@lucide/svelte": "^0.553.0",
|
|
58
62
|
"arktype": "^2.1.22",
|
|
59
63
|
"svelte": "^5.43.6",
|
|
60
|
-
"sveltekit-superforms": "^2.
|
|
64
|
+
"sveltekit-superforms": "^2.28.1"
|
|
61
65
|
},
|
|
62
66
|
"devDependencies": {
|
|
63
67
|
"@changesets/cli": "^2.29.7",
|
|
64
68
|
"@eslint/compat": "^1.4.1",
|
|
65
69
|
"@eslint/js": "^9.39.1",
|
|
66
|
-
"@sveltejs/adapter-static": "^3.0.10",
|
|
67
70
|
"@sveltejs/kit": "^2.48.4",
|
|
68
71
|
"@sveltejs/package": "^2.5.4",
|
|
69
72
|
"@sveltejs/vite-plugin-svelte": "^6.2.1",
|
|
@@ -101,8 +104,10 @@
|
|
|
101
104
|
"dependencies": {
|
|
102
105
|
"@internationalized/date": "^3.10.0",
|
|
103
106
|
"@lucide/svelte": "^0.553.0",
|
|
107
|
+
"@sveltejs/adapter-auto": "^7.0.0",
|
|
104
108
|
"arktype": "^2.1.26",
|
|
105
109
|
"bits-ui": "^2.14.3",
|
|
110
|
+
"devalue": "^5.5.0",
|
|
106
111
|
"drizzle-orm": "^0.44.7",
|
|
107
112
|
"formsnap": "^2.0.1",
|
|
108
113
|
"pg": "^8.16.3",
|