@spfn/notification 0.1.0-beta.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/LICENSE +21 -0
- package/README.md +377 -0
- package/dist/config/index.d.ts +183 -0
- package/dist/config/index.js +101 -0
- package/dist/config/index.js.map +1 -0
- package/dist/index-D_XTwHmO.d.ts +170 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +683 -0
- package/dist/server.js +3807 -0
- package/dist/server.js.map +1 -0
- package/package.json +80 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 INFLIKE Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
# @spfn/notification
|
|
2
|
+
|
|
3
|
+
Multi-channel notification system for SPFN applications.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Multi-channel support**: Email, SMS (Slack, Push coming soon)
|
|
8
|
+
- **Provider pattern**: Pluggable providers (AWS SES, AWS SNS, etc.)
|
|
9
|
+
- **Template system**: Variable substitution with filters
|
|
10
|
+
- **Scheduled delivery**: Schedule notifications for later via pg-boss
|
|
11
|
+
- **History tracking**: Optional notification history with database storage
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add @spfn/notification
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Optional Dependencies
|
|
20
|
+
|
|
21
|
+
Install providers as needed:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# For AWS SES (Email)
|
|
25
|
+
pnpm add @aws-sdk/client-ses
|
|
26
|
+
|
|
27
|
+
# For AWS SNS (SMS)
|
|
28
|
+
pnpm add @aws-sdk/client-sns
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { sendEmail, sendSMS, configureNotification } from '@spfn/notification/server';
|
|
35
|
+
|
|
36
|
+
// Configure (optional - uses environment variables by default)
|
|
37
|
+
configureNotification({
|
|
38
|
+
email: {
|
|
39
|
+
from: 'noreply@example.com',
|
|
40
|
+
},
|
|
41
|
+
defaults: {
|
|
42
|
+
appName: 'MyApp',
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Send email with template
|
|
47
|
+
await sendEmail({
|
|
48
|
+
to: 'user@example.com',
|
|
49
|
+
template: 'verification-code',
|
|
50
|
+
data: { code: '123456' },
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Send SMS
|
|
54
|
+
await sendSMS({
|
|
55
|
+
to: '+821012345678',
|
|
56
|
+
template: 'verification-code',
|
|
57
|
+
data: { code: '123456' },
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Configuration
|
|
62
|
+
|
|
63
|
+
### Environment Variables
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Email
|
|
67
|
+
SPFN_NOTIFICATION_EMAIL_PROVIDER=aws-ses
|
|
68
|
+
SPFN_NOTIFICATION_EMAIL_FROM=noreply@example.com
|
|
69
|
+
|
|
70
|
+
# SMS
|
|
71
|
+
SPFN_NOTIFICATION_SMS_PROVIDER=aws-sns
|
|
72
|
+
|
|
73
|
+
# AWS Credentials
|
|
74
|
+
AWS_REGION=ap-northeast-2
|
|
75
|
+
AWS_ACCESS_KEY_ID=xxx
|
|
76
|
+
AWS_SECRET_ACCESS_KEY=xxx
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Code Configuration
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import { configureNotification } from '@spfn/notification/server';
|
|
83
|
+
|
|
84
|
+
configureNotification({
|
|
85
|
+
email: {
|
|
86
|
+
provider: 'aws-ses',
|
|
87
|
+
from: 'noreply@example.com',
|
|
88
|
+
replyTo: 'support@example.com',
|
|
89
|
+
},
|
|
90
|
+
sms: {
|
|
91
|
+
provider: 'aws-sns',
|
|
92
|
+
defaultCountryCode: '+82',
|
|
93
|
+
},
|
|
94
|
+
defaults: {
|
|
95
|
+
appName: 'MyApp',
|
|
96
|
+
},
|
|
97
|
+
enableHistory: true, // Enable notification history tracking
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Sending Notifications
|
|
102
|
+
|
|
103
|
+
### Email
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
import { sendEmail, sendEmailBulk } from '@spfn/notification/server';
|
|
107
|
+
|
|
108
|
+
// With template
|
|
109
|
+
await sendEmail({
|
|
110
|
+
to: 'user@example.com',
|
|
111
|
+
template: 'welcome',
|
|
112
|
+
data: { name: 'John' },
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// With direct content
|
|
116
|
+
await sendEmail({
|
|
117
|
+
to: 'user@example.com',
|
|
118
|
+
subject: 'Hello',
|
|
119
|
+
text: 'Plain text content',
|
|
120
|
+
html: '<h1>HTML content</h1>',
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Bulk send
|
|
124
|
+
await sendEmailBulk([
|
|
125
|
+
{ to: 'user1@example.com', template: 'welcome', data: { name: 'John' } },
|
|
126
|
+
{ to: 'user2@example.com', template: 'welcome', data: { name: 'Jane' } },
|
|
127
|
+
]);
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### SMS
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { sendSMS, sendSMSBulk } from '@spfn/notification/server';
|
|
134
|
+
|
|
135
|
+
// With template
|
|
136
|
+
await sendSMS({
|
|
137
|
+
to: '+821012345678',
|
|
138
|
+
template: 'verification-code',
|
|
139
|
+
data: { code: '123456' },
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// With direct message
|
|
143
|
+
await sendSMS({
|
|
144
|
+
to: '010-1234-5678', // Auto-normalized to E.164 format
|
|
145
|
+
message: 'Your code is 123456',
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Scheduled Notifications
|
|
150
|
+
|
|
151
|
+
Schedule notifications for later delivery using pg-boss:
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import { scheduleEmail, scheduleSMS } from '@spfn/notification/server';
|
|
155
|
+
|
|
156
|
+
// Schedule email for 1 hour later
|
|
157
|
+
const result = await scheduleEmail(
|
|
158
|
+
{
|
|
159
|
+
to: 'user@example.com',
|
|
160
|
+
template: 'reminder',
|
|
161
|
+
data: { eventName: 'Meeting' },
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
scheduledAt: new Date(Date.now() + 60 * 60 * 1000),
|
|
165
|
+
referenceType: 'event',
|
|
166
|
+
referenceId: 'event-123',
|
|
167
|
+
}
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
// Cancel scheduled notification
|
|
171
|
+
import { cancelNotification } from '@spfn/notification/server';
|
|
172
|
+
await cancelNotification(result.notificationId);
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Job Router Setup
|
|
176
|
+
|
|
177
|
+
Register the notification job router with your server:
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
import { defineServerConfig } from '@spfn/core/server';
|
|
181
|
+
import { defineJobRouter } from '@spfn/core/job';
|
|
182
|
+
import { notificationJobRouter } from '@spfn/notification/server';
|
|
183
|
+
|
|
184
|
+
defineServerConfig()
|
|
185
|
+
.jobs(defineJobRouter({
|
|
186
|
+
notification: notificationJobRouter,
|
|
187
|
+
}))
|
|
188
|
+
.build();
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Template System
|
|
192
|
+
|
|
193
|
+
### Built-in Templates
|
|
194
|
+
|
|
195
|
+
| Name | Channels | Purpose |
|
|
196
|
+
|------|----------|---------|
|
|
197
|
+
| `verification-code` | email, sms | Verification codes |
|
|
198
|
+
| `welcome` | email | Welcome message |
|
|
199
|
+
|
|
200
|
+
### Custom Templates
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
import { registerTemplate } from '@spfn/notification/server';
|
|
204
|
+
|
|
205
|
+
registerTemplate({
|
|
206
|
+
name: 'order-confirmation',
|
|
207
|
+
channels: ['email', 'sms'],
|
|
208
|
+
|
|
209
|
+
email: {
|
|
210
|
+
subject: '[{{appName}}] Order Confirmed',
|
|
211
|
+
html: `
|
|
212
|
+
<h1>Order #{{orderId}}</h1>
|
|
213
|
+
<p>Thank you, {{userName}}!</p>
|
|
214
|
+
<p>Total: {{amount | currency}}</p>
|
|
215
|
+
`,
|
|
216
|
+
text: 'Order #{{orderId}} confirmed. Total: {{amount}}',
|
|
217
|
+
},
|
|
218
|
+
|
|
219
|
+
sms: {
|
|
220
|
+
message: '[{{appName}}] Order #{{orderId}} confirmed. Total: {{amount | currency}}',
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Template Filters
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
{{variable}} - Basic substitution
|
|
229
|
+
{{variable | uppercase}} - Convert to uppercase
|
|
230
|
+
{{variable | lowercase}} - Convert to lowercase
|
|
231
|
+
{{variable | currency}} - Format as currency (1,000)
|
|
232
|
+
{{variable | date}} - Format as date
|
|
233
|
+
{{variable | date:YYYY-MM-DD}} - Custom date format
|
|
234
|
+
{{variable | truncate:20}} - Truncate to length
|
|
235
|
+
{{variable | default:N/A}} - Default value if empty
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Custom Filters
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
import { registerFilter } from '@spfn/notification/server';
|
|
242
|
+
|
|
243
|
+
registerFilter('phone', (value) => {
|
|
244
|
+
const str = String(value);
|
|
245
|
+
return `${str.slice(0, 3)}-${str.slice(3, 7)}-${str.slice(7)}`;
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// Usage: {{phoneNumber | phone}} -> 010-1234-5678
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Custom Providers
|
|
252
|
+
|
|
253
|
+
### Email Provider
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
import { registerEmailProvider, EmailProvider } from '@spfn/notification/server';
|
|
257
|
+
|
|
258
|
+
const sendgridProvider: EmailProvider = {
|
|
259
|
+
name: 'sendgrid',
|
|
260
|
+
async send(params) {
|
|
261
|
+
// Your SendGrid implementation
|
|
262
|
+
return { success: true, messageId: '...' };
|
|
263
|
+
},
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
registerEmailProvider(sendgridProvider);
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### SMS Provider
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
import { registerSMSProvider, SMSProvider } from '@spfn/notification/server';
|
|
273
|
+
|
|
274
|
+
const twilioProvider: SMSProvider = {
|
|
275
|
+
name: 'twilio',
|
|
276
|
+
async send(params) {
|
|
277
|
+
// Your Twilio implementation
|
|
278
|
+
return { success: true, messageId: '...' };
|
|
279
|
+
},
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
registerSMSProvider(twilioProvider);
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Notification History
|
|
286
|
+
|
|
287
|
+
Enable history tracking to store all notifications in the database:
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
configureNotification({
|
|
291
|
+
enableHistory: true,
|
|
292
|
+
});
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Query History
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
import {
|
|
299
|
+
findNotifications,
|
|
300
|
+
getNotificationStats,
|
|
301
|
+
findScheduledNotifications,
|
|
302
|
+
} from '@spfn/notification/server';
|
|
303
|
+
|
|
304
|
+
// Find notifications
|
|
305
|
+
const notifications = await findNotifications({
|
|
306
|
+
channel: 'email',
|
|
307
|
+
status: 'sent',
|
|
308
|
+
recipient: 'user@example.com',
|
|
309
|
+
from: new Date('2024-01-01'),
|
|
310
|
+
limit: 100,
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
// Get statistics
|
|
314
|
+
const stats = await getNotificationStats({ channel: 'email' });
|
|
315
|
+
// { total: 1000, scheduled: 10, pending: 5, sent: 980, failed: 3, cancelled: 2 }
|
|
316
|
+
|
|
317
|
+
// Find scheduled notifications
|
|
318
|
+
const scheduled = await findScheduledNotifications({
|
|
319
|
+
channel: 'email',
|
|
320
|
+
from: new Date(),
|
|
321
|
+
to: new Date(Date.now() + 24 * 60 * 60 * 1000),
|
|
322
|
+
});
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
## API Reference
|
|
326
|
+
|
|
327
|
+
### Exports
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
// From '@spfn/notification'
|
|
331
|
+
export type {
|
|
332
|
+
NotificationChannel,
|
|
333
|
+
SendResult,
|
|
334
|
+
SendEmailParams,
|
|
335
|
+
SendSMSParams,
|
|
336
|
+
TemplateDefinition,
|
|
337
|
+
TemplateData,
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
// From '@spfn/notification/server'
|
|
341
|
+
export {
|
|
342
|
+
// Configuration
|
|
343
|
+
configureNotification,
|
|
344
|
+
getNotificationConfig,
|
|
345
|
+
|
|
346
|
+
// Email
|
|
347
|
+
sendEmail,
|
|
348
|
+
sendEmailBulk,
|
|
349
|
+
registerEmailProvider,
|
|
350
|
+
|
|
351
|
+
// SMS
|
|
352
|
+
sendSMS,
|
|
353
|
+
sendSMSBulk,
|
|
354
|
+
registerSMSProvider,
|
|
355
|
+
|
|
356
|
+
// Scheduling
|
|
357
|
+
scheduleEmail,
|
|
358
|
+
scheduleSMS,
|
|
359
|
+
cancelNotification,
|
|
360
|
+
|
|
361
|
+
// Templates
|
|
362
|
+
registerTemplate,
|
|
363
|
+
renderTemplate,
|
|
364
|
+
registerFilter,
|
|
365
|
+
|
|
366
|
+
// History
|
|
367
|
+
findNotifications,
|
|
368
|
+
getNotificationStats,
|
|
369
|
+
|
|
370
|
+
// Jobs
|
|
371
|
+
notificationJobRouter,
|
|
372
|
+
};
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
## License
|
|
376
|
+
|
|
377
|
+
MIT
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import * as _spfn_core_env from '@spfn/core/env';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @spfn/notification - Environment Schema
|
|
5
|
+
*/
|
|
6
|
+
declare const notificationEnvSchema: {
|
|
7
|
+
SPFN_NOTIFICATION_EMAIL_PROVIDER: {
|
|
8
|
+
description: string;
|
|
9
|
+
default: string;
|
|
10
|
+
required: boolean;
|
|
11
|
+
examples: string[];
|
|
12
|
+
type: "string";
|
|
13
|
+
} & {
|
|
14
|
+
key: "SPFN_NOTIFICATION_EMAIL_PROVIDER";
|
|
15
|
+
};
|
|
16
|
+
SPFN_NOTIFICATION_EMAIL_FROM: {
|
|
17
|
+
description: string;
|
|
18
|
+
required: boolean;
|
|
19
|
+
examples: string[];
|
|
20
|
+
type: "string";
|
|
21
|
+
} & {
|
|
22
|
+
key: "SPFN_NOTIFICATION_EMAIL_FROM";
|
|
23
|
+
};
|
|
24
|
+
SPFN_NOTIFICATION_SMS_PROVIDER: {
|
|
25
|
+
description: string;
|
|
26
|
+
default: string;
|
|
27
|
+
required: boolean;
|
|
28
|
+
examples: string[];
|
|
29
|
+
type: "string";
|
|
30
|
+
} & {
|
|
31
|
+
key: "SPFN_NOTIFICATION_SMS_PROVIDER";
|
|
32
|
+
};
|
|
33
|
+
SPFN_NOTIFICATION_SLACK_WEBHOOK_URL: {
|
|
34
|
+
description: string;
|
|
35
|
+
required: boolean;
|
|
36
|
+
examples: string[];
|
|
37
|
+
type: "string";
|
|
38
|
+
} & {
|
|
39
|
+
key: "SPFN_NOTIFICATION_SLACK_WEBHOOK_URL";
|
|
40
|
+
};
|
|
41
|
+
AWS_REGION: {
|
|
42
|
+
description: string;
|
|
43
|
+
default: string;
|
|
44
|
+
required: boolean;
|
|
45
|
+
examples: string[];
|
|
46
|
+
type: "string";
|
|
47
|
+
} & {
|
|
48
|
+
key: "AWS_REGION";
|
|
49
|
+
};
|
|
50
|
+
AWS_ACCESS_KEY_ID: {
|
|
51
|
+
description: string;
|
|
52
|
+
required: boolean;
|
|
53
|
+
sensitive: boolean;
|
|
54
|
+
type: "string";
|
|
55
|
+
} & {
|
|
56
|
+
key: "AWS_ACCESS_KEY_ID";
|
|
57
|
+
};
|
|
58
|
+
AWS_SECRET_ACCESS_KEY: {
|
|
59
|
+
description: string;
|
|
60
|
+
required: boolean;
|
|
61
|
+
sensitive: boolean;
|
|
62
|
+
type: "string";
|
|
63
|
+
} & {
|
|
64
|
+
key: "AWS_SECRET_ACCESS_KEY";
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
declare const env: _spfn_core_env.InferEnvType<{
|
|
69
|
+
SPFN_NOTIFICATION_EMAIL_PROVIDER: {
|
|
70
|
+
description: string;
|
|
71
|
+
default: string;
|
|
72
|
+
required: boolean;
|
|
73
|
+
examples: string[];
|
|
74
|
+
type: "string";
|
|
75
|
+
} & {
|
|
76
|
+
key: "SPFN_NOTIFICATION_EMAIL_PROVIDER";
|
|
77
|
+
};
|
|
78
|
+
SPFN_NOTIFICATION_EMAIL_FROM: {
|
|
79
|
+
description: string;
|
|
80
|
+
required: boolean;
|
|
81
|
+
examples: string[];
|
|
82
|
+
type: "string";
|
|
83
|
+
} & {
|
|
84
|
+
key: "SPFN_NOTIFICATION_EMAIL_FROM";
|
|
85
|
+
};
|
|
86
|
+
SPFN_NOTIFICATION_SMS_PROVIDER: {
|
|
87
|
+
description: string;
|
|
88
|
+
default: string;
|
|
89
|
+
required: boolean;
|
|
90
|
+
examples: string[];
|
|
91
|
+
type: "string";
|
|
92
|
+
} & {
|
|
93
|
+
key: "SPFN_NOTIFICATION_SMS_PROVIDER";
|
|
94
|
+
};
|
|
95
|
+
SPFN_NOTIFICATION_SLACK_WEBHOOK_URL: {
|
|
96
|
+
description: string;
|
|
97
|
+
required: boolean;
|
|
98
|
+
examples: string[];
|
|
99
|
+
type: "string";
|
|
100
|
+
} & {
|
|
101
|
+
key: "SPFN_NOTIFICATION_SLACK_WEBHOOK_URL";
|
|
102
|
+
};
|
|
103
|
+
AWS_REGION: {
|
|
104
|
+
description: string;
|
|
105
|
+
default: string;
|
|
106
|
+
required: boolean;
|
|
107
|
+
examples: string[];
|
|
108
|
+
type: "string";
|
|
109
|
+
} & {
|
|
110
|
+
key: "AWS_REGION";
|
|
111
|
+
};
|
|
112
|
+
AWS_ACCESS_KEY_ID: {
|
|
113
|
+
description: string;
|
|
114
|
+
required: boolean;
|
|
115
|
+
sensitive: boolean;
|
|
116
|
+
type: "string";
|
|
117
|
+
} & {
|
|
118
|
+
key: "AWS_ACCESS_KEY_ID";
|
|
119
|
+
};
|
|
120
|
+
AWS_SECRET_ACCESS_KEY: {
|
|
121
|
+
description: string;
|
|
122
|
+
required: boolean;
|
|
123
|
+
sensitive: boolean;
|
|
124
|
+
type: "string";
|
|
125
|
+
} & {
|
|
126
|
+
key: "AWS_SECRET_ACCESS_KEY";
|
|
127
|
+
};
|
|
128
|
+
}>;
|
|
129
|
+
/**
|
|
130
|
+
* Notification configuration
|
|
131
|
+
*/
|
|
132
|
+
interface NotificationConfig {
|
|
133
|
+
email?: {
|
|
134
|
+
provider?: 'aws-ses' | 'sendgrid' | 'smtp';
|
|
135
|
+
from?: string;
|
|
136
|
+
replyTo?: string;
|
|
137
|
+
};
|
|
138
|
+
sms?: {
|
|
139
|
+
provider?: 'aws-sns' | 'twilio';
|
|
140
|
+
defaultCountryCode?: string;
|
|
141
|
+
};
|
|
142
|
+
slack?: {
|
|
143
|
+
webhookUrl?: string;
|
|
144
|
+
};
|
|
145
|
+
defaults?: {
|
|
146
|
+
appName?: string;
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* Enable notification history tracking (requires database)
|
|
150
|
+
* @default false
|
|
151
|
+
*/
|
|
152
|
+
enableHistory?: boolean;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Configure notification settings
|
|
156
|
+
*/
|
|
157
|
+
declare function configureNotification(config: NotificationConfig): void;
|
|
158
|
+
/**
|
|
159
|
+
* Get current notification configuration
|
|
160
|
+
*/
|
|
161
|
+
declare function getNotificationConfig(): NotificationConfig;
|
|
162
|
+
/**
|
|
163
|
+
* Get email from address
|
|
164
|
+
*/
|
|
165
|
+
declare function getEmailFrom(): string;
|
|
166
|
+
/**
|
|
167
|
+
* Get email reply-to address
|
|
168
|
+
*/
|
|
169
|
+
declare function getEmailReplyTo(): string | undefined;
|
|
170
|
+
/**
|
|
171
|
+
* Get SMS default country code
|
|
172
|
+
*/
|
|
173
|
+
declare function getSmsDefaultCountryCode(): string;
|
|
174
|
+
/**
|
|
175
|
+
* Get app name for templates
|
|
176
|
+
*/
|
|
177
|
+
declare function getAppName(): string;
|
|
178
|
+
/**
|
|
179
|
+
* Check if history tracking is enabled
|
|
180
|
+
*/
|
|
181
|
+
declare function isHistoryEnabled(): boolean;
|
|
182
|
+
|
|
183
|
+
export { type NotificationConfig, configureNotification, env, getAppName, getEmailFrom, getEmailReplyTo, getNotificationConfig, getSmsDefaultCountryCode, isHistoryEnabled, notificationEnvSchema };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// src/config/index.ts
|
|
2
|
+
import { createEnvRegistry } from "@spfn/core/env";
|
|
3
|
+
|
|
4
|
+
// src/config/schema.ts
|
|
5
|
+
import { defineEnvSchema, envString } from "@spfn/core/env";
|
|
6
|
+
var notificationEnvSchema = defineEnvSchema({
|
|
7
|
+
// Email
|
|
8
|
+
SPFN_NOTIFICATION_EMAIL_PROVIDER: {
|
|
9
|
+
...envString({
|
|
10
|
+
description: "Email provider (aws-ses, sendgrid, smtp)",
|
|
11
|
+
default: "aws-ses",
|
|
12
|
+
required: false,
|
|
13
|
+
examples: ["aws-ses", "sendgrid", "smtp"]
|
|
14
|
+
})
|
|
15
|
+
},
|
|
16
|
+
SPFN_NOTIFICATION_EMAIL_FROM: {
|
|
17
|
+
...envString({
|
|
18
|
+
description: "Default sender email address",
|
|
19
|
+
required: false,
|
|
20
|
+
examples: ["noreply@example.com"]
|
|
21
|
+
})
|
|
22
|
+
},
|
|
23
|
+
// SMS
|
|
24
|
+
SPFN_NOTIFICATION_SMS_PROVIDER: {
|
|
25
|
+
...envString({
|
|
26
|
+
description: "SMS provider (aws-sns, twilio)",
|
|
27
|
+
default: "aws-sns",
|
|
28
|
+
required: false,
|
|
29
|
+
examples: ["aws-sns", "twilio"]
|
|
30
|
+
})
|
|
31
|
+
},
|
|
32
|
+
// Slack
|
|
33
|
+
SPFN_NOTIFICATION_SLACK_WEBHOOK_URL: {
|
|
34
|
+
...envString({
|
|
35
|
+
description: "Slack webhook URL",
|
|
36
|
+
required: false,
|
|
37
|
+
examples: ["https://hooks.slack.com/services/xxx/xxx/xxx"]
|
|
38
|
+
})
|
|
39
|
+
},
|
|
40
|
+
// AWS (shared with other AWS services)
|
|
41
|
+
AWS_REGION: {
|
|
42
|
+
...envString({
|
|
43
|
+
description: "AWS region",
|
|
44
|
+
default: "ap-northeast-2",
|
|
45
|
+
required: false,
|
|
46
|
+
examples: ["ap-northeast-2", "us-east-1"]
|
|
47
|
+
})
|
|
48
|
+
},
|
|
49
|
+
AWS_ACCESS_KEY_ID: {
|
|
50
|
+
...envString({
|
|
51
|
+
description: "AWS access key ID",
|
|
52
|
+
required: false,
|
|
53
|
+
sensitive: true
|
|
54
|
+
})
|
|
55
|
+
},
|
|
56
|
+
AWS_SECRET_ACCESS_KEY: {
|
|
57
|
+
...envString({
|
|
58
|
+
description: "AWS secret access key",
|
|
59
|
+
required: false,
|
|
60
|
+
sensitive: true
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// src/config/index.ts
|
|
66
|
+
var registry = createEnvRegistry(notificationEnvSchema);
|
|
67
|
+
var env = registry.validate();
|
|
68
|
+
var globalConfig = {};
|
|
69
|
+
function configureNotification(config) {
|
|
70
|
+
globalConfig = { ...globalConfig, ...config };
|
|
71
|
+
}
|
|
72
|
+
function getNotificationConfig() {
|
|
73
|
+
return { ...globalConfig };
|
|
74
|
+
}
|
|
75
|
+
function getEmailFrom() {
|
|
76
|
+
return globalConfig.email?.from || env.SPFN_NOTIFICATION_EMAIL_FROM || "noreply@example.com";
|
|
77
|
+
}
|
|
78
|
+
function getEmailReplyTo() {
|
|
79
|
+
return globalConfig.email?.replyTo;
|
|
80
|
+
}
|
|
81
|
+
function getSmsDefaultCountryCode() {
|
|
82
|
+
return globalConfig.sms?.defaultCountryCode || "+82";
|
|
83
|
+
}
|
|
84
|
+
function getAppName() {
|
|
85
|
+
return globalConfig.defaults?.appName || "SPFN";
|
|
86
|
+
}
|
|
87
|
+
function isHistoryEnabled() {
|
|
88
|
+
return globalConfig.enableHistory ?? false;
|
|
89
|
+
}
|
|
90
|
+
export {
|
|
91
|
+
configureNotification,
|
|
92
|
+
env,
|
|
93
|
+
getAppName,
|
|
94
|
+
getEmailFrom,
|
|
95
|
+
getEmailReplyTo,
|
|
96
|
+
getNotificationConfig,
|
|
97
|
+
getSmsDefaultCountryCode,
|
|
98
|
+
isHistoryEnabled,
|
|
99
|
+
notificationEnvSchema
|
|
100
|
+
};
|
|
101
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/config/index.ts","../../src/config/schema.ts"],"sourcesContent":["/**\n * @spfn/notification - Configuration\n */\n\nimport { createEnvRegistry } from '@spfn/core/env';\nimport { notificationEnvSchema } from './schema';\n\nexport { notificationEnvSchema };\n\n/**\n * Environment registry\n */\nconst registry = createEnvRegistry(notificationEnvSchema);\nexport const env = registry.validate();\n\n/**\n * Notification configuration\n */\nexport interface NotificationConfig\n{\n email?: {\n provider?: 'aws-ses' | 'sendgrid' | 'smtp';\n from?: string;\n replyTo?: string;\n };\n sms?: {\n provider?: 'aws-sns' | 'twilio';\n defaultCountryCode?: string;\n };\n slack?: {\n webhookUrl?: string;\n };\n defaults?: {\n appName?: string;\n };\n /**\n * Enable notification history tracking (requires database)\n * @default false\n */\n enableHistory?: boolean;\n}\n\nlet globalConfig: NotificationConfig = {};\n\n/**\n * Configure notification settings\n */\nexport function configureNotification(config: NotificationConfig): void\n{\n globalConfig = { ...globalConfig, ...config };\n}\n\n/**\n * Get current notification configuration\n */\nexport function getNotificationConfig(): NotificationConfig\n{\n return { ...globalConfig };\n}\n\n/**\n * Get email from address\n */\nexport function getEmailFrom(): string\n{\n return globalConfig.email?.from || env.SPFN_NOTIFICATION_EMAIL_FROM || 'noreply@example.com';\n}\n\n/**\n * Get email reply-to address\n */\nexport function getEmailReplyTo(): string | undefined\n{\n return globalConfig.email?.replyTo;\n}\n\n/**\n * Get SMS default country code\n */\nexport function getSmsDefaultCountryCode(): string\n{\n return globalConfig.sms?.defaultCountryCode || '+82';\n}\n\n/**\n * Get app name for templates\n */\nexport function getAppName(): string\n{\n return globalConfig.defaults?.appName || 'SPFN';\n}\n\n/**\n * Check if history tracking is enabled\n */\nexport function isHistoryEnabled(): boolean\n{\n return globalConfig.enableHistory ?? false;\n}\n","/**\n * @spfn/notification - Environment Schema\n */\n\nimport { defineEnvSchema, envString } from '@spfn/core/env';\n\nexport const notificationEnvSchema = defineEnvSchema({\n // Email\n SPFN_NOTIFICATION_EMAIL_PROVIDER: {\n ...envString({\n description: 'Email provider (aws-ses, sendgrid, smtp)',\n default: 'aws-ses',\n required: false,\n examples: ['aws-ses', 'sendgrid', 'smtp'],\n }),\n },\n\n SPFN_NOTIFICATION_EMAIL_FROM: {\n ...envString({\n description: 'Default sender email address',\n required: false,\n examples: ['noreply@example.com'],\n }),\n },\n\n // SMS\n SPFN_NOTIFICATION_SMS_PROVIDER: {\n ...envString({\n description: 'SMS provider (aws-sns, twilio)',\n default: 'aws-sns',\n required: false,\n examples: ['aws-sns', 'twilio'],\n }),\n },\n\n // Slack\n SPFN_NOTIFICATION_SLACK_WEBHOOK_URL: {\n ...envString({\n description: 'Slack webhook URL',\n required: false,\n examples: ['https://hooks.slack.com/services/xxx/xxx/xxx'],\n }),\n },\n\n // AWS (shared with other AWS services)\n AWS_REGION: {\n ...envString({\n description: 'AWS region',\n default: 'ap-northeast-2',\n required: false,\n examples: ['ap-northeast-2', 'us-east-1'],\n }),\n },\n\n AWS_ACCESS_KEY_ID: {\n ...envString({\n description: 'AWS access key ID',\n required: false,\n sensitive: true,\n }),\n },\n\n AWS_SECRET_ACCESS_KEY: {\n ...envString({\n description: 'AWS secret access key',\n required: false,\n sensitive: true,\n }),\n },\n});\n"],"mappings":";AAIA,SAAS,yBAAyB;;;ACAlC,SAAS,iBAAiB,iBAAiB;AAEpC,IAAM,wBAAwB,gBAAgB;AAAA;AAAA,EAEjD,kCAAkC;AAAA,IAC9B,GAAG,UAAU;AAAA,MACT,aAAa;AAAA,MACb,SAAS;AAAA,MACT,UAAU;AAAA,MACV,UAAU,CAAC,WAAW,YAAY,MAAM;AAAA,IAC5C,CAAC;AAAA,EACL;AAAA,EAEA,8BAA8B;AAAA,IAC1B,GAAG,UAAU;AAAA,MACT,aAAa;AAAA,MACb,UAAU;AAAA,MACV,UAAU,CAAC,qBAAqB;AAAA,IACpC,CAAC;AAAA,EACL;AAAA;AAAA,EAGA,gCAAgC;AAAA,IAC5B,GAAG,UAAU;AAAA,MACT,aAAa;AAAA,MACb,SAAS;AAAA,MACT,UAAU;AAAA,MACV,UAAU,CAAC,WAAW,QAAQ;AAAA,IAClC,CAAC;AAAA,EACL;AAAA;AAAA,EAGA,qCAAqC;AAAA,IACjC,GAAG,UAAU;AAAA,MACT,aAAa;AAAA,MACb,UAAU;AAAA,MACV,UAAU,CAAC,8CAA8C;AAAA,IAC7D,CAAC;AAAA,EACL;AAAA;AAAA,EAGA,YAAY;AAAA,IACR,GAAG,UAAU;AAAA,MACT,aAAa;AAAA,MACb,SAAS;AAAA,MACT,UAAU;AAAA,MACV,UAAU,CAAC,kBAAkB,WAAW;AAAA,IAC5C,CAAC;AAAA,EACL;AAAA,EAEA,mBAAmB;AAAA,IACf,GAAG,UAAU;AAAA,MACT,aAAa;AAAA,MACb,UAAU;AAAA,MACV,WAAW;AAAA,IACf,CAAC;AAAA,EACL;AAAA,EAEA,uBAAuB;AAAA,IACnB,GAAG,UAAU;AAAA,MACT,aAAa;AAAA,MACb,UAAU;AAAA,MACV,WAAW;AAAA,IACf,CAAC;AAAA,EACL;AACJ,CAAC;;;ADzDD,IAAM,WAAW,kBAAkB,qBAAqB;AACjD,IAAM,MAAM,SAAS,SAAS;AA6BrC,IAAI,eAAmC,CAAC;AAKjC,SAAS,sBAAsB,QACtC;AACI,iBAAe,EAAE,GAAG,cAAc,GAAG,OAAO;AAChD;AAKO,SAAS,wBAChB;AACI,SAAO,EAAE,GAAG,aAAa;AAC7B;AAKO,SAAS,eAChB;AACI,SAAO,aAAa,OAAO,QAAQ,IAAI,gCAAgC;AAC3E;AAKO,SAAS,kBAChB;AACI,SAAO,aAAa,OAAO;AAC/B;AAKO,SAAS,2BAChB;AACI,SAAO,aAAa,KAAK,sBAAsB;AACnD;AAKO,SAAS,aAChB;AACI,SAAO,aAAa,UAAU,WAAW;AAC7C;AAKO,SAAS,mBAChB;AACI,SAAO,aAAa,iBAAiB;AACzC;","names":[]}
|