hazo_notify 1.1.2 → 1.1.3
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 +63 -3
- package/dist/emailer/types.d.ts +2 -1
- package/dist/emailer/types.d.ts.map +1 -1
- package/migrations/001_create_template_tables.sql +87 -0
- package/package.json +6 -1
- package/dist/utils.d.ts +0 -12
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js +0 -15
- package/dist/utils.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
# Hazo Notify
|
|
2
2
|
|
|
3
|
-
A reusable component library for sending email notifications with
|
|
3
|
+
A reusable component library for sending email notifications with template management. Implements Zeptomail API integration with support for text and HTML emails, Handlebars-based email templates, multiple attachments, and comprehensive security features.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
+
### Emailer
|
|
7
8
|
- **Multiple Integration Methods**: Support for API (Zeptomail - implemented), SMTP (placeholder), and POP3 (placeholder)
|
|
8
9
|
- **Text and HTML Emails**: Send both plain text and HTML formatted emails
|
|
9
10
|
- **Multiple Attachments**: Support for sending multiple file attachments (up to 10, configurable)
|
|
10
11
|
- **Security Features**: HTML sanitization, email injection protection, rate limiting, input validation
|
|
11
12
|
- **Configurable**: Configuration via `config/hazo_notify_config.ini` file using `hazo_config` package
|
|
12
|
-
|
|
13
|
+
|
|
14
|
+
### Template Manager
|
|
15
|
+
- **Handlebars Templates**: Email template rendering with variable substitution
|
|
16
|
+
- **Database-Backed Storage**: Template and category CRUD via `hazo_connect`
|
|
17
|
+
- **System Variables**: Auto-generated date/time variables (11 formats)
|
|
18
|
+
- **Template Composition**: `@template` reference syntax for including templates within templates
|
|
19
|
+
- **Default Templates**: Built-in welcome, verification, password reset, and signature templates
|
|
20
|
+
- **Caching**: Template compilation caching for performance
|
|
21
|
+
|
|
22
|
+
### General
|
|
23
|
+
- **Test UI**: Optional test UI at `/hazo_notify/emailer_test` and `/hazo_notify/template_manager`
|
|
13
24
|
- **TypeScript**: Fully typed with TypeScript
|
|
14
|
-
- **Testing**:
|
|
25
|
+
- **Testing**: Test coverage with Jest
|
|
15
26
|
|
|
16
27
|
## Installation
|
|
17
28
|
|
|
@@ -45,6 +56,18 @@ max_files = 14d
|
|
|
45
56
|
|
|
46
57
|
If `hazo_logs` is not installed, hazo_notify will use a built-in console logger.
|
|
47
58
|
|
|
59
|
+
### Optional: Database-Backed Templates with hazo_connect
|
|
60
|
+
|
|
61
|
+
For the template manager module, install the optional `hazo_connect` peer dependency:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npm install hazo_connect
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Then run the migration in `migrations/001_create_template_tables.sql` against your database to create the required tables (`hazo_notify_template_cat` and `hazo_notify_templates`).
|
|
68
|
+
|
|
69
|
+
If `hazo_connect` is not installed, the emailer module still works independently.
|
|
70
|
+
|
|
48
71
|
## Quick Start
|
|
49
72
|
|
|
50
73
|
1. **Create `.env.local` file** with your Zeptomail API key:
|
|
@@ -677,6 +700,43 @@ console.log('Emailer module:', config.emailer_module);
|
|
|
677
700
|
console.log('From email:', config.from_email);
|
|
678
701
|
```
|
|
679
702
|
|
|
703
|
+
### Template Manager API
|
|
704
|
+
|
|
705
|
+
#### `send_template_email(options, hazo_connect, org_id, config?): Promise<SendTemplateEmailResponse>`
|
|
706
|
+
|
|
707
|
+
Render a named template and send it as an email.
|
|
708
|
+
|
|
709
|
+
```typescript
|
|
710
|
+
import { send_template_email } from 'hazo_notify/template_manager';
|
|
711
|
+
|
|
712
|
+
const result = await send_template_email({
|
|
713
|
+
template_name: 'welcome_email',
|
|
714
|
+
variables: { user_name: 'John', login_url: 'https://example.com/login' },
|
|
715
|
+
to: 'john@example.com',
|
|
716
|
+
subject: 'Welcome!'
|
|
717
|
+
}, hazo_connect, org_id);
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
#### `render_template(template_name, variables, hazo_connect, org_id, config?, logger?): Promise<TemplateRenderResult>`
|
|
721
|
+
|
|
722
|
+
Render a template without sending (useful for previews).
|
|
723
|
+
|
|
724
|
+
#### `seed_default_templates(hazo_connect, org_id, root_org_id): Promise<TemplateOperationResponse>`
|
|
725
|
+
|
|
726
|
+
Seed the database with default templates (welcome, verification, password reset, signature).
|
|
727
|
+
|
|
728
|
+
#### Template CRUD
|
|
729
|
+
|
|
730
|
+
```typescript
|
|
731
|
+
import {
|
|
732
|
+
list_categories, create_category, update_category, delete_category,
|
|
733
|
+
list_templates, create_template, update_template, delete_template,
|
|
734
|
+
get_template_by_name, seed_default_templates,
|
|
735
|
+
} from 'hazo_notify/template_manager';
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
All CRUD functions take a `hazo_connect` instance as their first argument.
|
|
739
|
+
|
|
680
740
|
## Test UI
|
|
681
741
|
|
|
682
742
|
To enable the UI component and all routes, set `enable_ui=true` in the `[ui]` section of `config/hazo_notify_config.ini`. The test UI will be available at `/hazo_notify/emailer_test`.
|
package/dist/emailer/types.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Type definitions for the emailer service
|
|
3
3
|
*/
|
|
4
|
-
|
|
4
|
+
import type { EmailerModule } from './utils/constants.js';
|
|
5
|
+
export type { EmailerModule };
|
|
5
6
|
/**
|
|
6
7
|
* Logger interface compatible with hazo_logs
|
|
7
8
|
* Used for optional structured logging
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/emailer/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/emailer/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
-- hazo_notify template manager database schema
|
|
2
|
+
-- Supports both PostgreSQL and SQLite
|
|
3
|
+
--
|
|
4
|
+
-- Tables:
|
|
5
|
+
-- hazo_notify_template_cat - Template categories
|
|
6
|
+
-- hazo_notify_templates - Email templates
|
|
7
|
+
--
|
|
8
|
+
-- Usage:
|
|
9
|
+
-- Run the appropriate version (PostgreSQL or SQLite) for your database.
|
|
10
|
+
|
|
11
|
+
-- ============================================================
|
|
12
|
+
-- PostgreSQL version (active)
|
|
13
|
+
-- ============================================================
|
|
14
|
+
|
|
15
|
+
CREATE TABLE IF NOT EXISTS hazo_notify_template_cat (
|
|
16
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
17
|
+
org_id UUID NOT NULL,
|
|
18
|
+
root_org_id UUID NOT NULL,
|
|
19
|
+
template_category_name VARCHAR(100) NOT NULL,
|
|
20
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
21
|
+
changed_at TIMESTAMPTZ
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
CREATE INDEX IF NOT EXISTS idx_notify_template_cat_org
|
|
25
|
+
ON hazo_notify_template_cat (org_id);
|
|
26
|
+
|
|
27
|
+
CREATE TABLE IF NOT EXISTS hazo_notify_templates (
|
|
28
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
29
|
+
org_id UUID NOT NULL,
|
|
30
|
+
root_org_id UUID NOT NULL,
|
|
31
|
+
template_category_id UUID NOT NULL REFERENCES hazo_notify_template_cat(id),
|
|
32
|
+
template_variables JSONB DEFAULT '{}',
|
|
33
|
+
template_name VARCHAR(100) NOT NULL,
|
|
34
|
+
template_html TEXT NOT NULL DEFAULT '',
|
|
35
|
+
template_text TEXT NOT NULL DEFAULT '',
|
|
36
|
+
email_type VARCHAR(10) NOT NULL DEFAULT 'user',
|
|
37
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
38
|
+
changed_at TIMESTAMPTZ
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
CREATE INDEX IF NOT EXISTS idx_notify_templates_org
|
|
42
|
+
ON hazo_notify_templates (org_id);
|
|
43
|
+
|
|
44
|
+
CREATE INDEX IF NOT EXISTS idx_notify_templates_category
|
|
45
|
+
ON hazo_notify_templates (template_category_id);
|
|
46
|
+
|
|
47
|
+
CREATE INDEX IF NOT EXISTS idx_notify_templates_name
|
|
48
|
+
ON hazo_notify_templates (org_id, template_name);
|
|
49
|
+
|
|
50
|
+
-- ============================================================
|
|
51
|
+
-- SQLite version (commented)
|
|
52
|
+
-- ============================================================
|
|
53
|
+
--
|
|
54
|
+
-- CREATE TABLE IF NOT EXISTS hazo_notify_template_cat (
|
|
55
|
+
-- id TEXT PRIMARY KEY,
|
|
56
|
+
-- org_id TEXT NOT NULL,
|
|
57
|
+
-- root_org_id TEXT NOT NULL,
|
|
58
|
+
-- template_category_name TEXT NOT NULL,
|
|
59
|
+
-- created_at TEXT DEFAULT (datetime('now')),
|
|
60
|
+
-- changed_at TEXT
|
|
61
|
+
-- );
|
|
62
|
+
--
|
|
63
|
+
-- CREATE INDEX IF NOT EXISTS idx_notify_template_cat_org
|
|
64
|
+
-- ON hazo_notify_template_cat (org_id);
|
|
65
|
+
--
|
|
66
|
+
-- CREATE TABLE IF NOT EXISTS hazo_notify_templates (
|
|
67
|
+
-- id TEXT PRIMARY KEY,
|
|
68
|
+
-- org_id TEXT NOT NULL,
|
|
69
|
+
-- root_org_id TEXT NOT NULL,
|
|
70
|
+
-- template_category_id TEXT NOT NULL REFERENCES hazo_notify_template_cat(id),
|
|
71
|
+
-- template_variables TEXT DEFAULT '{}',
|
|
72
|
+
-- template_name TEXT NOT NULL,
|
|
73
|
+
-- template_html TEXT NOT NULL DEFAULT '',
|
|
74
|
+
-- template_text TEXT NOT NULL DEFAULT '',
|
|
75
|
+
-- email_type TEXT NOT NULL DEFAULT 'user',
|
|
76
|
+
-- created_at TEXT DEFAULT (datetime('now')),
|
|
77
|
+
-- changed_at TEXT
|
|
78
|
+
-- );
|
|
79
|
+
--
|
|
80
|
+
-- CREATE INDEX IF NOT EXISTS idx_notify_templates_org
|
|
81
|
+
-- ON hazo_notify_templates (org_id);
|
|
82
|
+
--
|
|
83
|
+
-- CREATE INDEX IF NOT EXISTS idx_notify_templates_category
|
|
84
|
+
-- ON hazo_notify_templates (template_category_id);
|
|
85
|
+
--
|
|
86
|
+
-- CREATE INDEX IF NOT EXISTS idx_notify_templates_name
|
|
87
|
+
-- ON hazo_notify_templates (org_id, template_name);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hazo_notify",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Email that acts as a notification center as well for schedules too",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"dist",
|
|
39
39
|
"data",
|
|
40
40
|
"config",
|
|
41
|
+
"migrations",
|
|
41
42
|
"README.md"
|
|
42
43
|
],
|
|
43
44
|
"repository": {
|
|
@@ -66,9 +67,13 @@
|
|
|
66
67
|
"isomorphic-dompurify": "^2.9.0"
|
|
67
68
|
},
|
|
68
69
|
"peerDependencies": {
|
|
70
|
+
"hazo_connect": ">=2.4.0",
|
|
69
71
|
"hazo_logs": "^1.0.10"
|
|
70
72
|
},
|
|
71
73
|
"peerDependenciesMeta": {
|
|
74
|
+
"hazo_connect": {
|
|
75
|
+
"optional": true
|
|
76
|
+
},
|
|
72
77
|
"hazo_logs": {
|
|
73
78
|
"optional": true
|
|
74
79
|
}
|
package/dist/utils.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utility functions for UI components
|
|
3
|
-
* Provides className merging with Tailwind CSS support
|
|
4
|
-
*/
|
|
5
|
-
import { type ClassValue } from 'clsx';
|
|
6
|
-
/**
|
|
7
|
-
* Merge class names with Tailwind CSS conflict resolution
|
|
8
|
-
* @param inputs - Class names to merge
|
|
9
|
-
* @returns Merged class name string
|
|
10
|
-
*/
|
|
11
|
-
export declare function cn(...inputs: ClassValue[]): string;
|
|
12
|
-
//# sourceMappingURL=utils.d.ts.map
|
package/dist/utils.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/lib/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAG7C;;;;GAIG;AACH,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,UAEzC"}
|
package/dist/utils.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utility functions for UI components
|
|
3
|
-
* Provides className merging with Tailwind CSS support
|
|
4
|
-
*/
|
|
5
|
-
import { clsx } from 'clsx';
|
|
6
|
-
import { twMerge } from 'tailwind-merge';
|
|
7
|
-
/**
|
|
8
|
-
* Merge class names with Tailwind CSS conflict resolution
|
|
9
|
-
* @param inputs - Class names to merge
|
|
10
|
-
* @returns Merged class name string
|
|
11
|
-
*/
|
|
12
|
-
export function cn(...inputs) {
|
|
13
|
-
return twMerge(clsx(inputs));
|
|
14
|
-
}
|
|
15
|
-
//# sourceMappingURL=utils.js.map
|
package/dist/utils.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/lib/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAmB,MAAM,MAAM,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEzC;;;;GAIG;AACH,MAAM,UAAU,EAAE,CAAC,GAAG,MAAoB;IACxC,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AAC/B,CAAC"}
|