@webamoki/web-svelte 0.7.4 → 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 -22
- package/dist/components/ui/choice/Choice.svelte.d.ts +7 -7
- package/dist/components/ui/choice/ChoiceInternal.svelte +73 -69
- package/dist/components/ui/choice/ChoiceInternal.svelte.d.ts +9 -9
- package/dist/components/ui/choice/ChoiceMulti.svelte +59 -53
- 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 +68 -68
- 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 -10
- package/dist/utils/email/ses.js +15 -23
- 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 +69 -54
|
@@ -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,23 +1,21 @@
|
|
|
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
|
+
subject: string;
|
|
12
|
+
text?: string;
|
|
13
|
+
to: string | string[];
|
|
11
14
|
}
|
|
12
15
|
/**
|
|
13
16
|
* Send an email using AWS SES API.
|
|
14
17
|
* Uses AWS Signature V4 signing and fetch API for Cloudflare Workers compatibility.
|
|
15
18
|
*
|
|
16
|
-
* Environment variables required:
|
|
17
|
-
* - AWS_REGION
|
|
18
|
-
* - AWS_ACCESS_KEY_ID
|
|
19
|
-
* - AWS_SECRET_ACCESS_KEY
|
|
20
|
-
*
|
|
21
19
|
* @returns messageId returned by SES
|
|
22
20
|
*/
|
|
23
21
|
export declare function sendEmail(options: SendEmailOptions): Promise<string>;
|
package/dist/utils/email/ses.js
CHANGED
|
@@ -3,17 +3,12 @@ import { signRequest } from './aws-signer.js';
|
|
|
3
3
|
* Send an email using AWS SES API.
|
|
4
4
|
* Uses AWS Signature V4 signing and fetch API for Cloudflare Workers compatibility.
|
|
5
5
|
*
|
|
6
|
-
* Environment variables required:
|
|
7
|
-
* - AWS_REGION
|
|
8
|
-
* - AWS_ACCESS_KEY_ID
|
|
9
|
-
* - AWS_SECRET_ACCESS_KEY
|
|
10
|
-
*
|
|
11
6
|
* @returns messageId returned by SES
|
|
12
7
|
*/
|
|
13
8
|
export async function sendEmail(options) {
|
|
14
9
|
if (!options)
|
|
15
10
|
throw new Error('sendEmail: options is required');
|
|
16
|
-
const {
|
|
11
|
+
const { awsAccessKeyId, awsRegion, awsSecretAccessKey, bcc, cc, from, fromName, html, replyTo, subject, text, to } = options;
|
|
17
12
|
if (!subject) {
|
|
18
13
|
throw new Error('sendEmail: subject is required');
|
|
19
14
|
}
|
|
@@ -38,12 +33,9 @@ export async function sendEmail(options) {
|
|
|
38
33
|
if (!toAddresses || toAddresses.length === 0) {
|
|
39
34
|
throw new Error('sendEmail: at least one valid recipient is required (to)');
|
|
40
35
|
}
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY;
|
|
45
|
-
if (!region || !accessKeyId || !secretAccessKey) {
|
|
46
|
-
throw new Error('sendEmail: missing required environment variables (AWS_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)');
|
|
36
|
+
// Validate AWS credentials
|
|
37
|
+
if (!awsRegion || !awsAccessKeyId || !awsSecretAccessKey) {
|
|
38
|
+
throw new Error('sendEmail: missing required AWS credentials (awsRegion, awsAccessKeyId, awsSecretAccessKey)');
|
|
47
39
|
}
|
|
48
40
|
// Format source with optional fromName
|
|
49
41
|
const source = fromName ? `${fromName} <${from}>` : from;
|
|
@@ -76,24 +68,24 @@ export async function sendEmail(options) {
|
|
|
76
68
|
params.append('Message.Body.Text.Charset', 'UTF-8');
|
|
77
69
|
}
|
|
78
70
|
const body = params.toString();
|
|
79
|
-
const host = `email.${
|
|
71
|
+
const host = `email.${awsRegion}.amazonaws.com`;
|
|
80
72
|
const path = '/';
|
|
81
73
|
try {
|
|
82
74
|
// Sign the request
|
|
83
75
|
const { headers } = await signRequest('POST', host, path, body, {
|
|
84
|
-
accessKeyId,
|
|
85
|
-
|
|
86
|
-
|
|
76
|
+
accessKeyId: awsAccessKeyId,
|
|
77
|
+
region: awsRegion,
|
|
78
|
+
secretAccessKey: awsSecretAccessKey
|
|
87
79
|
});
|
|
88
|
-
// Make the
|
|
80
|
+
// Make the request
|
|
89
81
|
const response = await fetch(`https://${host}${path}`, {
|
|
90
|
-
|
|
82
|
+
body,
|
|
91
83
|
headers: {
|
|
92
84
|
...headers,
|
|
93
|
-
|
|
94
|
-
|
|
85
|
+
'Content-Length': body.length.toString(),
|
|
86
|
+
Host: host
|
|
95
87
|
},
|
|
96
|
-
|
|
88
|
+
method: 'POST'
|
|
97
89
|
});
|
|
98
90
|
const responseText = await response.text();
|
|
99
91
|
if (!response.ok) {
|
|
@@ -111,7 +103,7 @@ export async function sendEmail(options) {
|
|
|
111
103
|
catch {
|
|
112
104
|
errorMessage = responseText || `HTTP ${response.status} ${response.statusText}`;
|
|
113
105
|
}
|
|
114
|
-
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 })}`);
|
|
115
107
|
}
|
|
116
108
|
// Parse success response for MessageId using regex (works in Node.js and browsers)
|
|
117
109
|
try {
|
|
@@ -141,7 +133,7 @@ export async function sendEmail(options) {
|
|
|
141
133
|
if (typeof e['name'] === 'string')
|
|
142
134
|
code = e['name'];
|
|
143
135
|
}
|
|
144
|
-
const details = {
|
|
136
|
+
const details = { code, message };
|
|
145
137
|
throw new Error(`sendEmail: failed to send email: ${JSON.stringify(details)}`);
|
|
146
138
|
}
|
|
147
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
|
}
|