@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 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":[]}