@webamoki/web-svelte 0.6.0 → 0.6.2
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 +16 -15
- package/dist/server/form-handler.js +0 -14
- package/dist/server/form-processor.d.ts +1 -11
- package/dist/server/form-processor.js +1 -42
- package/dist/utils/form/index.d.ts +3 -0
- package/dist/utils/form/index.js +17 -16
- package/dist/utils/form/virtual-form.d.ts +4 -1
- package/dist/utils/form/virtual-form.js +65 -27
- package/package.json +3 -2
|
@@ -1,32 +1,33 @@
|
|
|
1
1
|
import { type SuperValidated } from 'sveltekit-superforms';
|
|
2
|
-
import { type VirtualFormValidated } from './form-processor.js';
|
|
3
2
|
/**
|
|
4
3
|
* automatically handle database errors from catch.
|
|
5
4
|
* used in form/action handling in page.server.ts
|
|
6
5
|
*/
|
|
7
|
-
export declare function handleDbErrorForm<T extends Record<string, unknown>>(form: SuperValidated<T
|
|
8
|
-
form: SuperValidated<T
|
|
6
|
+
export declare function handleDbErrorForm<T extends Record<string, unknown>>(form: SuperValidated<T>, message: string, err: unknown): import("@sveltejs/kit").ActionFailure<{
|
|
7
|
+
form: SuperValidated<T>;
|
|
9
8
|
}>;
|
|
10
9
|
/**
|
|
11
10
|
* check if an error returned by a try catch is a duplicate value error in postgre
|
|
12
11
|
*/
|
|
13
12
|
export declare function isDuplicateDbError(err: unknown): boolean;
|
|
14
|
-
export declare function successMessage<T extends Record<string, unknown>>(form: SuperValidated<T
|
|
13
|
+
export declare function successMessage<T extends Record<string, unknown>>(form: SuperValidated<T>, options?: {
|
|
15
14
|
showToast?: boolean;
|
|
16
15
|
text?: string;
|
|
17
16
|
data?: unknown;
|
|
18
|
-
}):
|
|
19
|
-
|
|
17
|
+
}): {
|
|
18
|
+
form: SuperValidated<T, App.Superforms.Message, T>;
|
|
19
|
+
} | import("@sveltejs/kit").ActionFailure<{
|
|
20
|
+
form: SuperValidated<T, App.Superforms.Message, T>;
|
|
21
|
+
}>;
|
|
22
|
+
export declare function errorMessage<T extends Record<string, unknown>>(form: SuperValidated<T>, options?: {
|
|
20
23
|
showToast?: boolean;
|
|
21
24
|
text?: string;
|
|
22
25
|
data?: unknown;
|
|
23
|
-
}):
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
form: SuperValidated<T
|
|
30
|
-
valid: boolean;
|
|
31
|
-
};
|
|
26
|
+
}): {
|
|
27
|
+
form: SuperValidated<T, App.Superforms.Message, T>;
|
|
28
|
+
} | import("@sveltejs/kit").ActionFailure<{
|
|
29
|
+
form: SuperValidated<T, App.Superforms.Message, T>;
|
|
30
|
+
}>;
|
|
31
|
+
export declare function failFormValidation<T extends Record<string, unknown>>(form: SuperValidated<T>): import("@sveltejs/kit").ActionFailure<{
|
|
32
|
+
form: SuperValidated<T>;
|
|
32
33
|
}>;
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { DatabaseError } from 'pg';
|
|
2
2
|
import { fail, message as superFormMessage } from 'sveltekit-superforms';
|
|
3
|
-
import { FormError } from './form-processor.js';
|
|
4
|
-
import { fail as failKit } from '@sveltejs/kit';
|
|
5
3
|
/**
|
|
6
4
|
* automatically handle database errors from catch.
|
|
7
5
|
* used in form/action handling in page.server.ts
|
|
@@ -14,9 +12,6 @@ export function handleDbErrorForm(form, message, err) {
|
|
|
14
12
|
console.error(`Unexpected Error ${message}:`, err);
|
|
15
13
|
return fail(500, { form });
|
|
16
14
|
}
|
|
17
|
-
function isVirtualFormValidated(form) {
|
|
18
|
-
return 'virtual' in form && form.virtual;
|
|
19
|
-
}
|
|
20
15
|
/**
|
|
21
16
|
* check if an error returned by a try catch is a duplicate value error in postgre
|
|
22
17
|
*/
|
|
@@ -30,9 +25,6 @@ export function successMessage(form, options) {
|
|
|
30
25
|
text: options?.text ?? 'Success',
|
|
31
26
|
data: options?.data
|
|
32
27
|
};
|
|
33
|
-
if ('virtual' in form && form.virtual) {
|
|
34
|
-
return message;
|
|
35
|
-
}
|
|
36
28
|
return superFormMessage(form, message);
|
|
37
29
|
}
|
|
38
30
|
export function errorMessage(form, options) {
|
|
@@ -42,16 +34,10 @@ export function errorMessage(form, options) {
|
|
|
42
34
|
text: options?.text,
|
|
43
35
|
data: options?.data
|
|
44
36
|
};
|
|
45
|
-
if (isVirtualFormValidated(form)) {
|
|
46
|
-
return message;
|
|
47
|
-
}
|
|
48
37
|
return superFormMessage(form, message);
|
|
49
38
|
}
|
|
50
39
|
export function failFormValidation(form) {
|
|
51
40
|
if (form.valid)
|
|
52
41
|
throw new Error('Invalid form passed');
|
|
53
|
-
if (form instanceof FormError) {
|
|
54
|
-
return failKit(400, { message: form.message });
|
|
55
|
-
}
|
|
56
42
|
return fail(400, { form });
|
|
57
43
|
}
|
|
@@ -1,12 +1,2 @@
|
|
|
1
1
|
import { type } from 'arktype';
|
|
2
|
-
export declare
|
|
3
|
-
message: string;
|
|
4
|
-
valid: false;
|
|
5
|
-
constructor(message: string);
|
|
6
|
-
}
|
|
7
|
-
export type VirtualFormValidated<T extends Record<string, unknown>> = {
|
|
8
|
-
data: T;
|
|
9
|
-
virtual: boolean;
|
|
10
|
-
valid: boolean;
|
|
11
|
-
};
|
|
12
|
-
export declare function processForm<S extends type.Any<Record<string, unknown>>>(request: Request, schema: S): Promise<FormError | import("sveltekit-superforms").SuperValidated<S["infer"], any, S["inferIn"]> | VirtualFormValidated<S["infer"]>>;
|
|
2
|
+
export declare function processForm<S extends type.Any<Record<string, unknown>>>(request: Request, schema: S): Promise<import("sveltekit-superforms").SuperValidated<S["infer"], any, S["inferIn"]>>;
|
|
@@ -2,47 +2,6 @@ import { dateTransport } from '../utils/datetime/index.js';
|
|
|
2
2
|
import { type } from 'arktype';
|
|
3
3
|
import { superValidate } from 'sveltekit-superforms';
|
|
4
4
|
import { arktype } from 'sveltekit-superforms/adapters';
|
|
5
|
-
export class FormError {
|
|
6
|
-
message;
|
|
7
|
-
valid;
|
|
8
|
-
constructor(message) {
|
|
9
|
-
this.message = message;
|
|
10
|
-
this.valid = false;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
5
|
export async function processForm(request, schema) {
|
|
14
|
-
|
|
15
|
-
try {
|
|
16
|
-
formData = await request.formData();
|
|
17
|
-
}
|
|
18
|
-
catch (error) {
|
|
19
|
-
return new FormError(error instanceof Error ? error.message : 'Invalid form data');
|
|
20
|
-
}
|
|
21
|
-
if ('__superform_id' in formData) {
|
|
22
|
-
return await superValidate(request, arktype(schema), { transport: dateTransport });
|
|
23
|
-
}
|
|
24
|
-
try {
|
|
25
|
-
// Parse form data and extract the JSON string
|
|
26
|
-
const dataString = formData.get('data');
|
|
27
|
-
if (typeof dataString !== 'string') {
|
|
28
|
-
return new FormError('Missing or invalid data field');
|
|
29
|
-
}
|
|
30
|
-
// Parse the JSON string
|
|
31
|
-
const body = JSON.parse(dataString);
|
|
32
|
-
// Validate against the schema
|
|
33
|
-
const validated = schema(body);
|
|
34
|
-
// Check if validation failed
|
|
35
|
-
if (validated instanceof type.errors) {
|
|
36
|
-
return new FormError(validated.summary);
|
|
37
|
-
}
|
|
38
|
-
// Return validated data
|
|
39
|
-
return {
|
|
40
|
-
data: validated,
|
|
41
|
-
virtual: true,
|
|
42
|
-
valid: true
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
catch (error) {
|
|
46
|
-
return new FormError(error instanceof Error ? error.message : 'Invalid form data');
|
|
47
|
-
}
|
|
6
|
+
return await superValidate(request, arktype(schema), { transport: dateTransport });
|
|
48
7
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { type } from 'arktype';
|
|
2
2
|
import { type SuperValidated } from 'sveltekit-superforms';
|
|
3
|
+
export * from './virtual-form.js';
|
|
3
4
|
export declare function prepareForm<S extends type.Any<Record<string, unknown>>>(validated: SuperValidated<S['infer']> | S['infer'], schema: S, options?: Partial<{
|
|
4
5
|
invalidateAll: boolean;
|
|
5
6
|
resetForm: boolean;
|
|
6
7
|
onSuccess: (form: Readonly<SuperValidated<S['infer'], App.Superforms.Message, S['infer']>>) => void;
|
|
8
|
+
onError: (form: Readonly<SuperValidated<S['infer'], App.Superforms.Message, S['infer']>>) => void;
|
|
7
9
|
}>): {
|
|
8
10
|
form: import("sveltekit-superforms").SuperForm<S["infer"], any>;
|
|
9
11
|
data: import("sveltekit-superforms/client").SuperFormData<S["infer"]>;
|
|
@@ -14,6 +16,7 @@ export declare function prepareEmptyForm<S extends type.Any<Record<string, unkno
|
|
|
14
16
|
invalidateAll: boolean;
|
|
15
17
|
resetForm: boolean;
|
|
16
18
|
onSuccess: (form: Readonly<SuperValidated<S['infer'], App.Superforms.Message, S['infer']>>) => void;
|
|
19
|
+
onError: (form: Readonly<SuperValidated<S['infer'], App.Superforms.Message, S['infer']>>) => void;
|
|
17
20
|
}>): {
|
|
18
21
|
form: import("sveltekit-superforms").SuperForm<S["infer"], any>;
|
|
19
22
|
data: import("sveltekit-superforms/client").SuperFormData<S["infer"]>;
|
package/dist/utils/form/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { toast } from 'svelte-sonner';
|
|
|
3
3
|
import { defaults, superForm } from 'sveltekit-superforms';
|
|
4
4
|
import { arktype, arktypeClient } from 'sveltekit-superforms/adapters';
|
|
5
5
|
import { dateTransport } from '../datetime/index.js';
|
|
6
|
+
export * from './virtual-form.js';
|
|
6
7
|
export function prepareForm(validated, schema, options) {
|
|
7
8
|
const form = superForm(validated, {
|
|
8
9
|
validators: arktypeClient(schema),
|
|
@@ -11,17 +12,17 @@ export function prepareForm(validated, schema, options) {
|
|
|
11
12
|
transport: dateTransport,
|
|
12
13
|
resetForm: options?.resetForm ?? true,
|
|
13
14
|
onUpdated({ form }) {
|
|
14
|
-
if (form.valid) {
|
|
15
|
+
if (form.valid && form.message.success) {
|
|
15
16
|
options?.onSuccess?.(form);
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return;
|
|
20
|
-
if (form.message.success) {
|
|
21
|
-
toast.success(text);
|
|
17
|
+
if (form.message?.text && form.message?.showToast) {
|
|
18
|
+
toast.success(form.message.text);
|
|
19
|
+
}
|
|
22
20
|
}
|
|
23
21
|
else {
|
|
24
|
-
|
|
22
|
+
options?.onError?.(form);
|
|
23
|
+
if (form.message?.text && form.message?.showToast) {
|
|
24
|
+
toast.error(form.message.text);
|
|
25
|
+
}
|
|
25
26
|
}
|
|
26
27
|
},
|
|
27
28
|
onError({ result }) {
|
|
@@ -42,17 +43,17 @@ export function prepareEmptyForm(schema, options) {
|
|
|
42
43
|
transport: dateTransport,
|
|
43
44
|
resetForm: options?.resetForm === undefined ? true : false,
|
|
44
45
|
onUpdated({ form }) {
|
|
45
|
-
if (form.valid) {
|
|
46
|
+
if (form.valid && form.message.success) {
|
|
46
47
|
options?.onSuccess?.(form);
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return;
|
|
51
|
-
if (form.message.success) {
|
|
52
|
-
toast.success(text);
|
|
48
|
+
if (form.message?.text && form.message?.showToast) {
|
|
49
|
+
toast.success(form.message.text);
|
|
50
|
+
}
|
|
53
51
|
}
|
|
54
52
|
else {
|
|
55
|
-
|
|
53
|
+
options?.onError?.(form);
|
|
54
|
+
if (form.message?.text && form.message?.showToast) {
|
|
55
|
+
toast.error(form.message.text);
|
|
56
|
+
}
|
|
56
57
|
}
|
|
57
58
|
},
|
|
58
59
|
onError({ result }) {
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { type } from 'arktype';
|
|
2
|
+
import type { SuperValidated } from 'sveltekit-superforms/client';
|
|
3
|
+
import type { Transport } from '@sveltejs/kit';
|
|
2
4
|
export declare class VirtualForm<S extends type.Any<Record<string, unknown>>> {
|
|
3
5
|
#private;
|
|
4
6
|
constructor(schema: S, action: string, options?: {
|
|
5
7
|
actionName?: string;
|
|
6
|
-
|
|
8
|
+
transport?: Transport;
|
|
9
|
+
onSuccess?: (form: Readonly<SuperValidated<S['infer'], App.Superforms.Message, S['infer']>>) => void;
|
|
7
10
|
onError?: (message: App.Superforms.Message) => void;
|
|
8
11
|
});
|
|
9
12
|
submit(data: S['infer']): Promise<void>;
|
|
@@ -1,28 +1,14 @@
|
|
|
1
1
|
import { type } from 'arktype';
|
|
2
2
|
import { toast } from 'svelte-sonner';
|
|
3
3
|
import { createSubscriber } from 'svelte/reactivity';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
// Basic validation
|
|
7
|
-
if (!Array.isArray(parsed) || typeof parsed[0] !== 'object' || parsed[0] === null) {
|
|
8
|
-
throw new Error('Invalid encoded message format');
|
|
9
|
-
}
|
|
10
|
-
const schema = parsed[0];
|
|
11
|
-
// resolve an index into the parsed array
|
|
12
|
-
const resolve = (idx) => (idx >= 0 ? parsed[idx] : undefined);
|
|
13
|
-
const output = {};
|
|
14
|
-
// dynamically resolve each schema key
|
|
15
|
-
for (const key of Object.keys(schema)) {
|
|
16
|
-
const index = schema[key];
|
|
17
|
-
output[key] = resolve(index);
|
|
18
|
-
}
|
|
19
|
-
return output;
|
|
20
|
-
}
|
|
4
|
+
import { parse, stringify } from 'devalue';
|
|
5
|
+
import { dateTransport } from '../datetime/index.js';
|
|
21
6
|
export class VirtualForm {
|
|
22
7
|
// state storage
|
|
23
8
|
#isLoading = false;
|
|
24
9
|
#url = '';
|
|
25
10
|
#schema;
|
|
11
|
+
#transport;
|
|
26
12
|
#onSuccess;
|
|
27
13
|
#onError;
|
|
28
14
|
// svelte reactive tracking
|
|
@@ -31,6 +17,7 @@ export class VirtualForm {
|
|
|
31
17
|
constructor(schema, action, options = {}) {
|
|
32
18
|
this.#url = `${action}${options.actionName ? '?/' + options.actionName : ''}`;
|
|
33
19
|
this.#schema = schema;
|
|
20
|
+
this.#transport = options.transport ?? dateTransport;
|
|
34
21
|
this.#onSuccess = options.onSuccess;
|
|
35
22
|
this.#onError = options.onError;
|
|
36
23
|
this.#subscribe = createSubscriber((update) => {
|
|
@@ -38,6 +25,50 @@ export class VirtualForm {
|
|
|
38
25
|
return () => { };
|
|
39
26
|
});
|
|
40
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
|
+
}
|
|
41
72
|
async submit(data) {
|
|
42
73
|
this.#isLoading = true;
|
|
43
74
|
this.#update();
|
|
@@ -54,9 +85,12 @@ export class VirtualForm {
|
|
|
54
85
|
return;
|
|
55
86
|
}
|
|
56
87
|
try {
|
|
88
|
+
// Apply transport encoding before sending
|
|
89
|
+
const encodedData = this.#encodeTransport(validated);
|
|
57
90
|
// Encode JSON as form data (like superforms does)
|
|
58
91
|
const formData = new FormData();
|
|
59
|
-
formData.append('
|
|
92
|
+
formData.append('__superform_id', '1');
|
|
93
|
+
formData.append('__superform_json', stringify(encodedData));
|
|
60
94
|
const res = await fetch(this.#url, {
|
|
61
95
|
method: 'POST',
|
|
62
96
|
body: formData
|
|
@@ -69,17 +103,21 @@ export class VirtualForm {
|
|
|
69
103
|
this.#update();
|
|
70
104
|
return;
|
|
71
105
|
}
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
+
}
|
|
78
115
|
}
|
|
79
116
|
else {
|
|
80
|
-
this.#onError?.(message);
|
|
81
|
-
if (text && message?.showToast)
|
|
82
|
-
toast.error(text);
|
|
117
|
+
this.#onError?.(form.message);
|
|
118
|
+
if (form.message?.text && form.message?.showToast) {
|
|
119
|
+
toast.error(form.message.text);
|
|
120
|
+
}
|
|
83
121
|
}
|
|
84
122
|
}
|
|
85
123
|
catch (err) {
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.6.
|
|
6
|
+
"version": "0.6.2",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"files": [
|
|
9
9
|
"dist",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"@lucide/svelte": "^0.553.0",
|
|
62
62
|
"arktype": "^2.1.22",
|
|
63
63
|
"svelte": "^5.43.6",
|
|
64
|
-
"sveltekit-superforms": "^2.
|
|
64
|
+
"sveltekit-superforms": "^2.28.1"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@changesets/cli": "^2.29.7",
|
|
@@ -107,6 +107,7 @@
|
|
|
107
107
|
"@sveltejs/adapter-auto": "^7.0.0",
|
|
108
108
|
"arktype": "^2.1.26",
|
|
109
109
|
"bits-ui": "^2.14.3",
|
|
110
|
+
"devalue": "^5.5.0",
|
|
110
111
|
"drizzle-orm": "^0.44.7",
|
|
111
112
|
"formsnap": "^2.0.1",
|
|
112
113
|
"pg": "^8.16.3",
|