@webamoki/web-svelte 0.8.0 → 1.0.0
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/README.md +83 -3
- package/dist/components/form/Button.svelte +24 -23
- package/dist/components/form/Button.svelte.d.ts +2 -2
- package/dist/components/form/Errors.svelte +13 -13
- package/dist/components/form/FieldWrapper.svelte +57 -55
- package/dist/components/form/FieldWrapper.svelte.d.ts +4 -4
- package/dist/components/form/Form.svelte +18 -14
- package/dist/components/form/Form.svelte.d.ts +31 -22
- package/dist/components/form/IconInputWrapper.svelte +30 -29
- package/dist/components/form/IconInputWrapper.svelte.d.ts +7 -7
- package/dist/components/form/fields/ChoiceField.svelte +45 -43
- package/dist/components/form/fields/ChoiceField.svelte.d.ts +28 -23
- package/dist/components/form/fields/ChoiceMultiField.svelte +44 -42
- package/dist/components/form/fields/ChoiceMultiField.svelte.d.ts +28 -23
- package/dist/components/form/fields/DateField.svelte +42 -40
- package/dist/components/form/fields/DateField.svelte.d.ts +29 -22
- package/dist/components/form/fields/HexColorField.svelte +21 -19
- package/dist/components/form/fields/HexColorField.svelte.d.ts +24 -19
- package/dist/components/form/fields/MessageField.svelte +39 -60
- package/dist/components/form/fields/MessageField.svelte.d.ts +33 -24
- package/dist/components/form/fields/NumberField.svelte +38 -36
- package/dist/components/form/fields/NumberField.svelte.d.ts +32 -23
- package/dist/components/form/fields/PasswordField.svelte +45 -39
- package/dist/components/form/fields/PasswordField.svelte.d.ts +28 -21
- package/dist/components/form/fields/SelectField.svelte +84 -79
- package/dist/components/form/fields/SelectField.svelte.d.ts +39 -26
- package/dist/components/form/fields/SelectMultiField.svelte +90 -85
- package/dist/components/form/fields/SelectMultiField.svelte.d.ts +38 -25
- package/dist/components/form/fields/TextField.svelte +31 -29
- package/dist/components/form/fields/TextField.svelte.d.ts +32 -23
- package/dist/components/form/fields/TextFieldNullable.svelte +49 -47
- package/dist/components/form/fields/TextFieldNullable.svelte.d.ts +32 -23
- package/dist/components/form/fields/TimeField.svelte +66 -64
- package/dist/components/form/fields/TimeField.svelte.d.ts +33 -24
- package/dist/components/form/fields/WeekdayChoiceField.svelte +37 -35
- package/dist/components/form/fields/WeekdayChoiceField.svelte.d.ts +27 -22
- package/dist/components/form/fields/WeekdayChoiceMultiField.svelte +37 -35
- package/dist/components/form/fields/WeekdayChoiceMultiField.svelte.d.ts +27 -22
- package/dist/components/showcase/CodeBlock.svelte +41 -41
- package/dist/components/showcase/Container.svelte +7 -7
- package/dist/components/showcase/Preview.svelte +4 -4
- package/dist/components/showcase/Sidebar.svelte +4 -4
- package/dist/components/showcase/SidebarLink.svelte +3 -3
- package/dist/components/ui/choice/Choice.svelte +25 -25
- package/dist/components/ui/choice/Choice.svelte.d.ts +7 -7
- package/dist/components/ui/choice/ChoiceInternal.svelte +73 -72
- package/dist/components/ui/choice/ChoiceInternal.svelte.d.ts +9 -9
- package/dist/components/ui/choice/ChoiceMulti.svelte +59 -56
- package/dist/components/ui/choice/ChoiceMulti.svelte.d.ts +7 -7
- package/dist/components/ui/choice/WeekdayChoice.svelte +22 -21
- package/dist/components/ui/choice/WeekdayChoice.svelte.d.ts +6 -6
- package/dist/components/ui/choice/WeekdayChoiceMulti.svelte +24 -22
- package/dist/components/ui/choice/WeekdayChoiceMulti.svelte.d.ts +6 -6
- package/dist/components/ui/context-menu/ContextMenu.svelte +51 -50
- package/dist/components/ui/context-menu/ContextMenu.svelte.d.ts +1 -1
- package/dist/components/ui/context-menu/ContextMenuContent.svelte +92 -91
- package/dist/components/ui/context-menu/ContextMenuItem.svelte +26 -25
- package/dist/components/ui/context-menu/ContextMenuItem.svelte.d.ts +1 -1
- package/dist/components/ui/context-menu/ContextMenuTrigger.svelte +16 -15
- package/dist/components/ui/context-menu/context-menu-state.svelte.d.ts +3 -3
- package/dist/components/ui/context-menu/context-menu-state.svelte.js +15 -15
- package/dist/components/ui/drag-drop/Draggable.svelte +73 -72
- package/dist/components/ui/drag-drop/Draggable.svelte.d.ts +2 -2
- package/dist/components/ui/drag-drop/Dropzone.svelte +56 -54
- package/dist/components/ui/drag-drop/Dropzone.svelte.d.ts +3 -3
- package/dist/components/ui/drag-drop/drag-manager.d.ts +2 -2
- package/dist/components/ui/drag-drop/drag-manager.js +9 -9
- package/dist/components/ui/index.d.ts +2 -2
- package/dist/components/ui/index.js +5 -5
- package/dist/components/ui/search/SearchBar.svelte +18 -18
- package/dist/components/ui/search/SearchBar.svelte.d.ts +2 -2
- package/dist/highlight.js +2 -2
- package/dist/server/form-handler.d.ts +12 -12
- package/dist/server/form-handler.js +17 -17
- package/dist/server/form-processor.d.ts +1 -1
- package/dist/server/form-processor.js +0 -1
- package/dist/shadcn/components/ui/button/button.svelte +72 -71
- package/dist/shadcn/components/ui/button/button.svelte.d.ts +23 -23
- package/dist/shadcn/components/ui/button/index.d.ts +1 -1
- package/dist/shadcn/components/ui/button/index.js +2 -2
- package/dist/shadcn/components/ui/input/index.d.ts +1 -1
- package/dist/shadcn/components/ui/input/index.js +2 -2
- package/dist/shadcn/components/ui/input/input.svelte +35 -32
- package/dist/shadcn/components/ui/input/input.svelte.d.ts +2 -2
- package/dist/shadcn/components/ui/select/index.d.ts +6 -6
- package/dist/shadcn/components/ui/select/index.js +7 -7
- package/dist/shadcn/components/ui/select/select-content.svelte +35 -34
- package/dist/shadcn/components/ui/select/select-content.svelte.d.ts +1 -1
- package/dist/shadcn/components/ui/select/select-group-heading.svelte +15 -14
- package/dist/shadcn/components/ui/select/select-group.svelte +2 -2
- package/dist/shadcn/components/ui/select/select-item.svelte +31 -31
- package/dist/shadcn/components/ui/select/select-label.svelte +14 -13
- package/dist/shadcn/components/ui/select/select-label.svelte.d.ts +1 -1
- package/dist/shadcn/components/ui/select/select-scroll-down-button.svelte +13 -13
- package/dist/shadcn/components/ui/select/select-scroll-up-button.svelte +13 -13
- package/dist/shadcn/components/ui/select/select-separator.svelte +13 -12
- package/dist/shadcn/components/ui/select/select-trigger.svelte +26 -26
- package/dist/shadcn/components/ui/select/select-trigger.svelte.d.ts +2 -2
- package/dist/shadcn/components/ui/separator/separator.svelte +14 -14
- package/dist/shadcn/components/ui/textarea/textarea.svelte +22 -21
- package/dist/shadcn/components/ui/textarea/textarea.svelte.d.ts +1 -1
- package/dist/shadcn/utils.d.ts +4 -4
- package/dist/utils/datetime/index.d.ts +66 -66
- package/dist/utils/datetime/index.js +124 -124
- package/dist/utils/email/README.md +60 -60
- package/dist/utils/email/aws-signer.d.ts +1 -1
- package/dist/utils/email/aws-signer.js +39 -39
- package/dist/utils/email/ses.d.ts +8 -8
- package/dist/utils/email/ses.js +9 -9
- package/dist/utils/form/index.d.ts +11 -11
- package/dist/utils/form/index.js +23 -24
- package/dist/utils/form/virtual-form.d.ts +5 -5
- package/dist/utils/form/virtual-form.js +58 -58
- package/dist/utils/search.d.ts +1 -1
- package/dist/utils/search.js +22 -22
- package/dist/utils/types/arktype.d.ts +2 -2
- package/dist/utils/types/arktype.js +3 -3
- package/dist/utils/types/db.d.ts +2 -1
- package/dist/utils/types/db.js +7 -7
- package/package.json +46 -31
|
@@ -44,10 +44,10 @@ import { sendEmail } from '@webamoki/web-svelte/utils/email';
|
|
|
44
44
|
|
|
45
45
|
// Send a simple text email
|
|
46
46
|
const messageId = await sendEmail({
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
to: 'recipient@example.com',
|
|
48
|
+
subject: 'Hello from SES',
|
|
49
|
+
text: 'This is a plain text email.',
|
|
50
|
+
from: 'sender@example.com'
|
|
51
51
|
});
|
|
52
52
|
|
|
53
53
|
console.log('Email sent with message ID:', messageId);
|
|
@@ -57,12 +57,12 @@ console.log('Email sent with message ID:', messageId);
|
|
|
57
57
|
|
|
58
58
|
```typescript
|
|
59
59
|
await sendEmail({
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
to: 'recipient@example.com',
|
|
61
|
+
subject: 'Welcome!',
|
|
62
|
+
html: '<h1>Welcome to our service!</h1><p>Thanks for signing up.</p>',
|
|
63
|
+
text: 'Welcome to our service! Thanks for signing up.', // Fallback for email clients that don't support HTML
|
|
64
|
+
from: 'noreply@example.com',
|
|
65
|
+
fromName: 'My Application'
|
|
66
66
|
});
|
|
67
67
|
```
|
|
68
68
|
|
|
@@ -70,12 +70,12 @@ await sendEmail({
|
|
|
70
70
|
|
|
71
71
|
```typescript
|
|
72
72
|
await sendEmail({
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
to: ['user1@example.com', 'user2@example.com'],
|
|
74
|
+
cc: 'manager@example.com',
|
|
75
|
+
bcc: ['archive@example.com', 'backup@example.com'],
|
|
76
|
+
subject: 'Team Update',
|
|
77
|
+
text: 'This is a team-wide announcement.',
|
|
78
|
+
from: 'team@example.com'
|
|
79
79
|
});
|
|
80
80
|
```
|
|
81
81
|
|
|
@@ -83,12 +83,12 @@ await sendEmail({
|
|
|
83
83
|
|
|
84
84
|
```typescript
|
|
85
85
|
await sendEmail({
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
86
|
+
to: 'customer@example.com',
|
|
87
|
+
subject: 'Your order confirmation',
|
|
88
|
+
html: '<p>Your order has been confirmed!</p>',
|
|
89
|
+
from: 'noreply@example.com',
|
|
90
|
+
fromName: 'Order System',
|
|
91
|
+
replyTo: 'support@example.com'
|
|
92
92
|
});
|
|
93
93
|
```
|
|
94
94
|
|
|
@@ -110,15 +110,15 @@ Sends an email via AWS SES.
|
|
|
110
110
|
|
|
111
111
|
```typescript
|
|
112
112
|
interface SendEmailOptions {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
113
|
+
to: string | string[]; // Required: recipient email address(es)
|
|
114
|
+
cc?: string | string[]; // Optional: CC recipients
|
|
115
|
+
bcc?: string | string[]; // Optional: BCC recipients
|
|
116
|
+
subject: string; // Required: email subject
|
|
117
|
+
text?: string; // Optional: plain text body
|
|
118
|
+
html?: string; // Optional: HTML body
|
|
119
|
+
from: string; // Required: sender email
|
|
120
|
+
fromName?: string; // Optional: sender display name
|
|
121
|
+
replyTo?: string | string[]; // Optional: reply-to address(es)
|
|
122
122
|
}
|
|
123
123
|
```
|
|
124
124
|
|
|
@@ -136,16 +136,16 @@ Always wrap calls in try-catch:
|
|
|
136
136
|
|
|
137
137
|
```typescript
|
|
138
138
|
try {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
139
|
+
const messageId = await sendEmail({
|
|
140
|
+
to: 'user@example.com',
|
|
141
|
+
subject: 'Test',
|
|
142
|
+
text: 'Hello!',
|
|
143
|
+
from: 'sender@example.com'
|
|
144
|
+
});
|
|
145
|
+
console.log('Success:', messageId);
|
|
146
146
|
} catch (error) {
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
console.error('Failed to send email:', error.message);
|
|
148
|
+
// Handle error appropriately
|
|
149
149
|
}
|
|
150
150
|
```
|
|
151
151
|
|
|
@@ -163,26 +163,26 @@ import { sendEmail } from '@webamoki/web-svelte/utils/email';
|
|
|
163
163
|
import type { Actions } from './$types';
|
|
164
164
|
|
|
165
165
|
export const actions: Actions = {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
166
|
+
default: async ({ request }) => {
|
|
167
|
+
const formData = await request.formData();
|
|
168
|
+
const email = formData.get('email') as string;
|
|
169
|
+
const message = formData.get('message') as string;
|
|
170
|
+
|
|
171
|
+
try {
|
|
172
|
+
await sendEmail({
|
|
173
|
+
to: 'admin@example.com',
|
|
174
|
+
subject: `Contact form submission from ${email}`,
|
|
175
|
+
text: message,
|
|
176
|
+
from: 'noreply@example.com',
|
|
177
|
+
replyTo: email
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
return { success: true };
|
|
181
|
+
} catch (error) {
|
|
182
|
+
console.error('Email error:', error);
|
|
183
|
+
return { success: false, error: 'Failed to send message' };
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
186
|
};
|
|
187
187
|
```
|
|
188
188
|
|
|
@@ -2,47 +2,11 @@
|
|
|
2
2
|
* AWS Signature Version 4 signing utilities for SES API
|
|
3
3
|
* Compatible with Cloudflare Workers and other edge runtimes
|
|
4
4
|
*/
|
|
5
|
-
/**
|
|
6
|
-
* Create a SHA-256 hash
|
|
7
|
-
*/
|
|
8
|
-
async function sha256(message) {
|
|
9
|
-
const encoder = new TextEncoder();
|
|
10
|
-
const data = encoder.encode(message);
|
|
11
|
-
return await crypto.subtle.digest('SHA-256', data);
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Create a SHA-256 HMAC
|
|
15
|
-
*/
|
|
16
|
-
async function hmacSha256(key, message) {
|
|
17
|
-
const encoder = new TextEncoder();
|
|
18
|
-
const keyData = key instanceof ArrayBuffer ? new Uint8Array(key) : key;
|
|
19
|
-
const cryptoKey = await crypto.subtle.importKey('raw', keyData, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
|
|
20
|
-
return await crypto.subtle.sign('HMAC', cryptoKey, encoder.encode(message));
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Convert ArrayBuffer to hex string
|
|
24
|
-
*/
|
|
25
|
-
function bufferToHex(buffer) {
|
|
26
|
-
return Array.from(new Uint8Array(buffer))
|
|
27
|
-
.map((b) => b.toString(16).padStart(2, '0'))
|
|
28
|
-
.join('');
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Get signing key for AWS Signature V4
|
|
32
|
-
*/
|
|
33
|
-
async function getSignatureKey(key, dateStamp, regionName, serviceName) {
|
|
34
|
-
const encoder = new TextEncoder();
|
|
35
|
-
const kDate = await hmacSha256(encoder.encode('AWS4' + key), dateStamp);
|
|
36
|
-
const kRegion = await hmacSha256(kDate, regionName);
|
|
37
|
-
const kService = await hmacSha256(kRegion, serviceName);
|
|
38
|
-
const kSigning = await hmacSha256(kService, 'aws4_request');
|
|
39
|
-
return kSigning;
|
|
40
|
-
}
|
|
41
5
|
/**
|
|
42
6
|
* Create AWS Signature V4 authorization header
|
|
43
7
|
*/
|
|
44
8
|
export async function signRequest(method, host, path, body, credentials, service = 'ses') {
|
|
45
|
-
const { accessKeyId,
|
|
9
|
+
const { accessKeyId, region, secretAccessKey } = credentials;
|
|
46
10
|
// Create timestamp
|
|
47
11
|
const now = new Date();
|
|
48
12
|
const amzDate = now.toISOString().replace(/[:-]|\.\d{3}/g, ''); // Format: YYYYMMDDTHHMMSSZ
|
|
@@ -75,9 +39,45 @@ export async function signRequest(method, host, path, body, credentials, service
|
|
|
75
39
|
return {
|
|
76
40
|
headers: {
|
|
77
41
|
Authorization: authorizationHeader,
|
|
78
|
-
'
|
|
79
|
-
'
|
|
42
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
43
|
+
'X-Amz-Date': amzDate
|
|
80
44
|
},
|
|
81
45
|
signedHeaders
|
|
82
46
|
};
|
|
83
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Convert ArrayBuffer to hex string
|
|
50
|
+
*/
|
|
51
|
+
function bufferToHex(buffer) {
|
|
52
|
+
return Array.from(new Uint8Array(buffer))
|
|
53
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
54
|
+
.join('');
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get signing key for AWS Signature V4
|
|
58
|
+
*/
|
|
59
|
+
async function getSignatureKey(key, dateStamp, regionName, serviceName) {
|
|
60
|
+
const encoder = new TextEncoder();
|
|
61
|
+
const kDate = await hmacSha256(encoder.encode('AWS4' + key), dateStamp);
|
|
62
|
+
const kRegion = await hmacSha256(kDate, regionName);
|
|
63
|
+
const kService = await hmacSha256(kRegion, serviceName);
|
|
64
|
+
const kSigning = await hmacSha256(kService, 'aws4_request');
|
|
65
|
+
return kSigning;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Create a SHA-256 HMAC
|
|
69
|
+
*/
|
|
70
|
+
async function hmacSha256(key, message) {
|
|
71
|
+
const encoder = new TextEncoder();
|
|
72
|
+
const keyData = key instanceof ArrayBuffer ? new Uint8Array(key) : key;
|
|
73
|
+
const cryptoKey = await crypto.subtle.importKey('raw', keyData, { hash: 'SHA-256', name: 'HMAC' }, false, ['sign']);
|
|
74
|
+
return await crypto.subtle.sign('HMAC', cryptoKey, encoder.encode(message));
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Create a SHA-256 hash
|
|
78
|
+
*/
|
|
79
|
+
async function sha256(message) {
|
|
80
|
+
const encoder = new TextEncoder();
|
|
81
|
+
const data = encoder.encode(message);
|
|
82
|
+
return await crypto.subtle.digest('SHA-256', data);
|
|
83
|
+
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
export interface SendEmailOptions {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
awsAccessKeyId: string;
|
|
3
|
+
awsRegion: string;
|
|
4
|
+
awsSecretAccessKey: string;
|
|
4
5
|
bcc?: string | string[];
|
|
5
|
-
|
|
6
|
-
text?: string;
|
|
7
|
-
html?: string;
|
|
6
|
+
cc?: string | string[];
|
|
8
7
|
from: string;
|
|
9
8
|
fromName?: string;
|
|
9
|
+
html?: string;
|
|
10
10
|
replyTo?: string | string[];
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
subject: string;
|
|
12
|
+
text?: string;
|
|
13
|
+
to: string | string[];
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
16
|
* Send an email using AWS SES API.
|
package/dist/utils/email/ses.js
CHANGED
|
@@ -8,7 +8,7 @@ import { signRequest } from './aws-signer.js';
|
|
|
8
8
|
export async function sendEmail(options) {
|
|
9
9
|
if (!options)
|
|
10
10
|
throw new Error('sendEmail: options is required');
|
|
11
|
-
const {
|
|
11
|
+
const { awsAccessKeyId, awsRegion, awsSecretAccessKey, bcc, cc, from, fromName, html, replyTo, subject, text, to } = options;
|
|
12
12
|
if (!subject) {
|
|
13
13
|
throw new Error('sendEmail: subject is required');
|
|
14
14
|
}
|
|
@@ -74,18 +74,18 @@ export async function sendEmail(options) {
|
|
|
74
74
|
// Sign the request
|
|
75
75
|
const { headers } = await signRequest('POST', host, path, body, {
|
|
76
76
|
accessKeyId: awsAccessKeyId,
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
region: awsRegion,
|
|
78
|
+
secretAccessKey: awsSecretAccessKey
|
|
79
79
|
});
|
|
80
80
|
// Make the request
|
|
81
81
|
const response = await fetch(`https://${host}${path}`, {
|
|
82
|
-
|
|
82
|
+
body,
|
|
83
83
|
headers: {
|
|
84
84
|
...headers,
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
'Content-Length': body.length.toString(),
|
|
86
|
+
Host: host
|
|
87
87
|
},
|
|
88
|
-
|
|
88
|
+
method: 'POST'
|
|
89
89
|
});
|
|
90
90
|
const responseText = await response.text();
|
|
91
91
|
if (!response.ok) {
|
|
@@ -103,7 +103,7 @@ export async function sendEmail(options) {
|
|
|
103
103
|
catch {
|
|
104
104
|
errorMessage = responseText || `HTTP ${response.status} ${response.statusText}`;
|
|
105
105
|
}
|
|
106
|
-
throw new Error(`sendEmail: failed to send email: ${JSON.stringify({
|
|
106
|
+
throw new Error(`sendEmail: failed to send email: ${JSON.stringify({ code: errorCode, message: errorMessage })}`);
|
|
107
107
|
}
|
|
108
108
|
// Parse success response for MessageId using regex (works in Node.js and browsers)
|
|
109
109
|
try {
|
|
@@ -133,7 +133,7 @@ export async function sendEmail(options) {
|
|
|
133
133
|
if (typeof e['name'] === 'string')
|
|
134
134
|
code = e['name'];
|
|
135
135
|
}
|
|
136
|
-
const details = {
|
|
136
|
+
const details = { code, message };
|
|
137
137
|
throw new Error(`sendEmail: failed to send email: ${JSON.stringify(details)}`);
|
|
138
138
|
}
|
|
139
139
|
}
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import { type } from 'arktype';
|
|
1
|
+
import type { type } from 'arktype';
|
|
2
2
|
import { type SuperValidated } from 'sveltekit-superforms';
|
|
3
3
|
export * from './virtual-form.js';
|
|
4
|
-
export declare function
|
|
4
|
+
export declare function prepareEmptyForm<S extends type.Any<Record<string, unknown>>>(schema: S, options?: Partial<{
|
|
5
5
|
invalidateAll: boolean;
|
|
6
|
-
resetForm: boolean;
|
|
7
|
-
onSuccess: (form: Readonly<SuperValidated<S['infer'], App.Superforms.Message, S['infer']>>) => void;
|
|
8
6
|
onError: (form: Readonly<SuperValidated<S['infer'], App.Superforms.Message, S['infer']>>) => void;
|
|
7
|
+
onSuccess: (form: Readonly<SuperValidated<S['infer'], App.Superforms.Message, S['infer']>>) => void;
|
|
8
|
+
resetForm: boolean;
|
|
9
9
|
}>): {
|
|
10
|
-
form: import("sveltekit-superforms").SuperForm<S["infer"], any>;
|
|
11
10
|
data: import("sveltekit-superforms/client").SuperFormData<S["infer"]>;
|
|
12
|
-
isProcessing: import("svelte/store").Readable<boolean>;
|
|
13
11
|
errors: import("sveltekit-superforms/client").SuperFormErrors<S["infer"]>;
|
|
12
|
+
form: import("sveltekit-superforms").SuperForm<S["infer"], any>;
|
|
13
|
+
isProcessing: import("svelte/store").Readable<boolean>;
|
|
14
14
|
};
|
|
15
|
-
export declare function
|
|
15
|
+
export declare function prepareForm<S extends type.Any<Record<string, unknown>>>(schema: S, validated: S['infer'] | SuperValidated<S['infer']>, options?: Partial<{
|
|
16
16
|
invalidateAll: boolean;
|
|
17
|
-
resetForm: boolean;
|
|
18
|
-
onSuccess: (form: Readonly<SuperValidated<S['infer'], App.Superforms.Message, S['infer']>>) => void;
|
|
19
17
|
onError: (form: Readonly<SuperValidated<S['infer'], App.Superforms.Message, S['infer']>>) => void;
|
|
18
|
+
onSuccess: (form: Readonly<SuperValidated<S['infer'], App.Superforms.Message, S['infer']>>) => void;
|
|
19
|
+
resetForm: boolean;
|
|
20
20
|
}>): {
|
|
21
|
-
form: import("sveltekit-superforms").SuperForm<S["infer"], any>;
|
|
22
21
|
data: import("sveltekit-superforms/client").SuperFormData<S["infer"]>;
|
|
23
|
-
isProcessing: import("svelte/store").Readable<boolean>;
|
|
24
22
|
errors: import("sveltekit-superforms/client").SuperFormErrors<S["infer"]>;
|
|
23
|
+
form: import("sveltekit-superforms").SuperForm<S["infer"], any>;
|
|
24
|
+
isProcessing: import("svelte/store").Readable<boolean>;
|
|
25
25
|
};
|
package/dist/utils/form/index.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { type } from 'arktype';
|
|
2
1
|
import { toast } from 'svelte-sonner';
|
|
3
2
|
import { defaults, superForm } from 'sveltekit-superforms';
|
|
4
3
|
import { arktype, arktypeClient } from 'sveltekit-superforms/adapters';
|
|
5
4
|
import { dateTransport } from '../datetime/index.js';
|
|
6
5
|
export * from './virtual-form.js';
|
|
7
|
-
export function
|
|
8
|
-
const form = superForm(
|
|
9
|
-
validators: arktypeClient(schema),
|
|
6
|
+
export function prepareEmptyForm(schema, options) {
|
|
7
|
+
const form = superForm(defaults(arktype(schema)), {
|
|
10
8
|
dataType: 'json',
|
|
11
9
|
invalidateAll: options?.invalidateAll ?? false,
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
onError({ result }) {
|
|
11
|
+
const message = result.error.message ?? 'There was an error submitting the form';
|
|
12
|
+
const status = result.status ?? 500;
|
|
13
|
+
toast.error(`${status} - ${message}`);
|
|
14
|
+
},
|
|
14
15
|
onUpdated({ form }) {
|
|
15
16
|
if (form.valid && form.message.success) {
|
|
16
17
|
options?.onSuccess?.(form);
|
|
@@ -25,23 +26,23 @@ export function prepareForm(schema, validated, options) {
|
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
28
|
},
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
toast.error(`${status} - ${message}`);
|
|
32
|
-
}
|
|
29
|
+
resetForm: options?.resetForm ?? true,
|
|
30
|
+
transport: dateTransport,
|
|
31
|
+
validators: arktypeClient(schema)
|
|
33
32
|
});
|
|
34
33
|
const isProcessing = form.delayed;
|
|
35
34
|
const errors = form.errors;
|
|
36
|
-
return {
|
|
35
|
+
return { data: form.form, errors, form, isProcessing };
|
|
37
36
|
}
|
|
38
|
-
export function
|
|
39
|
-
const form = superForm(
|
|
40
|
-
validators: arktypeClient(schema),
|
|
37
|
+
export function prepareForm(schema, validated, options) {
|
|
38
|
+
const form = superForm(validated, {
|
|
41
39
|
dataType: 'json',
|
|
42
|
-
invalidateAll: options?.invalidateAll
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
invalidateAll: options?.invalidateAll ?? false,
|
|
41
|
+
onError({ result }) {
|
|
42
|
+
const message = result.error.message ?? 'There was an error submitting the form';
|
|
43
|
+
const status = result.status ?? 500;
|
|
44
|
+
toast.error(`${status} - ${message}`);
|
|
45
|
+
},
|
|
45
46
|
onUpdated({ form }) {
|
|
46
47
|
if (form.valid && form.message.success) {
|
|
47
48
|
options?.onSuccess?.(form);
|
|
@@ -56,13 +57,11 @@ export function prepareEmptyForm(schema, options) {
|
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
59
|
},
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
toast.error(`${status} - ${message}`);
|
|
63
|
-
}
|
|
60
|
+
resetForm: options?.resetForm ?? true,
|
|
61
|
+
transport: dateTransport,
|
|
62
|
+
validators: arktypeClient(schema)
|
|
64
63
|
});
|
|
65
64
|
const isProcessing = form.delayed;
|
|
66
65
|
const errors = form.errors;
|
|
67
|
-
return {
|
|
66
|
+
return { data: form.form, errors, form, isProcessing };
|
|
68
67
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { type } from 'arktype';
|
|
2
|
-
import type { SuperValidated } from 'sveltekit-superforms/client';
|
|
3
1
|
import type { Transport } from '@sveltejs/kit';
|
|
2
|
+
import type { SuperValidated } from 'sveltekit-superforms/client';
|
|
3
|
+
import { type } from 'arktype';
|
|
4
4
|
export declare class VirtualForm<S extends type.Any<Record<string, unknown>>> {
|
|
5
5
|
#private;
|
|
6
|
+
get isProcessing(): boolean;
|
|
6
7
|
constructor(schema: S, action: string, options?: {
|
|
7
8
|
actionName?: string;
|
|
8
|
-
transport?: Transport;
|
|
9
|
-
onSuccess?: (form: Readonly<SuperValidated<S['infer'], App.Superforms.Message, S['infer']>>) => void;
|
|
10
9
|
onError?: (message: App.Superforms.Message) => void;
|
|
10
|
+
onSuccess?: (form: Readonly<SuperValidated<S['infer'], App.Superforms.Message, S['infer']>>) => void;
|
|
11
|
+
transport?: Transport;
|
|
11
12
|
});
|
|
12
13
|
submit(data: S['infer']): Promise<void>;
|
|
13
|
-
get isProcessing(): boolean;
|
|
14
14
|
}
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import { type } from 'arktype';
|
|
2
|
+
import { parse, stringify } from 'devalue';
|
|
2
3
|
import { toast } from 'svelte-sonner';
|
|
3
4
|
import { createSubscriber } from 'svelte/reactivity';
|
|
4
|
-
import { parse, stringify } from 'devalue';
|
|
5
5
|
import { dateTransport } from '../datetime/index.js';
|
|
6
6
|
export class VirtualForm {
|
|
7
|
+
get isProcessing() {
|
|
8
|
+
this.#subscribe();
|
|
9
|
+
return this.#isProcessing;
|
|
10
|
+
}
|
|
7
11
|
// state storage
|
|
8
12
|
#isProcessing = false;
|
|
9
|
-
#url = '';
|
|
10
|
-
#schema;
|
|
11
|
-
#transport;
|
|
12
|
-
#onSuccess;
|
|
13
13
|
#onError;
|
|
14
|
+
#onSuccess;
|
|
15
|
+
#schema;
|
|
14
16
|
// svelte reactive tracking
|
|
15
17
|
#subscribe;
|
|
16
|
-
#
|
|
18
|
+
#transport;
|
|
19
|
+
#url = '';
|
|
17
20
|
constructor(schema, action, options = {}) {
|
|
18
21
|
this.#url = `${action}${options.actionName ? '?/' + options.actionName : ''}`;
|
|
19
22
|
this.#schema = schema;
|
|
@@ -25,50 +28,6 @@ export class VirtualForm {
|
|
|
25
28
|
return () => { };
|
|
26
29
|
});
|
|
27
30
|
}
|
|
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
31
|
async submit(data) {
|
|
73
32
|
this.#isProcessing = true;
|
|
74
33
|
this.#update();
|
|
@@ -77,10 +36,10 @@ export class VirtualForm {
|
|
|
77
36
|
if (validated instanceof type.errors) {
|
|
78
37
|
console.error('Validation failed:', validated.summary);
|
|
79
38
|
this.#onError?.({
|
|
80
|
-
text: 'Validation failed',
|
|
81
39
|
data: validated.summary,
|
|
40
|
+
showToast: false,
|
|
82
41
|
success: false,
|
|
83
|
-
|
|
42
|
+
text: 'Validation failed'
|
|
84
43
|
});
|
|
85
44
|
return;
|
|
86
45
|
}
|
|
@@ -92,8 +51,8 @@ export class VirtualForm {
|
|
|
92
51
|
formData.append('__superform_id', '1');
|
|
93
52
|
formData.append('__superform_json', stringify(encodedData));
|
|
94
53
|
const res = await fetch(this.#url, {
|
|
95
|
-
|
|
96
|
-
|
|
54
|
+
body: formData,
|
|
55
|
+
method: 'POST'
|
|
97
56
|
});
|
|
98
57
|
const result = await res.json();
|
|
99
58
|
if (!res.ok || result.status === 400) {
|
|
@@ -122,13 +81,54 @@ export class VirtualForm {
|
|
|
122
81
|
}
|
|
123
82
|
catch (err) {
|
|
124
83
|
console.error(err);
|
|
125
|
-
this.#onError?.({
|
|
84
|
+
this.#onError?.({ data: err, showToast: false, success: false, text: 'Network error' });
|
|
126
85
|
}
|
|
127
86
|
this.#isProcessing = false;
|
|
128
87
|
this.#update();
|
|
129
88
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
89
|
+
// Apply transport decoding to received data
|
|
90
|
+
#decodeTransport(data) {
|
|
91
|
+
if (!this.#transport || typeof data !== 'object' || data === null) {
|
|
92
|
+
return data;
|
|
93
|
+
}
|
|
94
|
+
// Handle arrays
|
|
95
|
+
if (Array.isArray(data)) {
|
|
96
|
+
return data.map((item) => this.#decodeTransport(item));
|
|
97
|
+
}
|
|
98
|
+
// Check if this is a transport-encoded value
|
|
99
|
+
const obj = data;
|
|
100
|
+
if (obj.__type && obj.__value && this.#transport[obj.__type]) {
|
|
101
|
+
return this.#transport[obj.__type].decode(obj.__value);
|
|
102
|
+
}
|
|
103
|
+
// Recursively decode nested objects
|
|
104
|
+
const result = {};
|
|
105
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
106
|
+
result[key] = this.#decodeTransport(value);
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
// Apply transport encoding to data before sending
|
|
111
|
+
#encodeTransport(data) {
|
|
112
|
+
if (!this.#transport || typeof data !== 'object' || data === null) {
|
|
113
|
+
return data;
|
|
114
|
+
}
|
|
115
|
+
// Handle arrays
|
|
116
|
+
if (Array.isArray(data)) {
|
|
117
|
+
return data.map((item) => this.#encodeTransport(item));
|
|
118
|
+
}
|
|
119
|
+
// Try each transport encoder
|
|
120
|
+
for (const [key, encoder] of Object.entries(this.#transport)) {
|
|
121
|
+
const encoded = encoder.encode(data);
|
|
122
|
+
if (encoded !== false) {
|
|
123
|
+
return { __type: key, __value: encoded };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Recursively encode nested objects
|
|
127
|
+
const result = {};
|
|
128
|
+
for (const [key, value] of Object.entries(data)) {
|
|
129
|
+
result[key] = this.#encodeTransport(value);
|
|
130
|
+
}
|
|
131
|
+
return result;
|
|
133
132
|
}
|
|
133
|
+
#update = () => { };
|
|
134
134
|
}
|
package/dist/utils/search.d.ts
CHANGED