hazo_notify 1.1.2 → 1.1.4

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 CHANGED
@@ -1,17 +1,28 @@
1
1
  # Hazo Notify
2
2
 
3
- A reusable component library for sending email notifications with support for multiple integration methods. Currently implements Zeptomail API integration with support for text and HTML emails, multiple attachments, and comprehensive security features.
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
- - **Test UI**: Optional test UI at `/hazo_notify/emailer_test` for testing email functionality
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**: Comprehensive test coverage with Jest
25
+ - **Testing**: Test coverage with Jest
15
26
 
16
27
  ## Installation
17
28
 
@@ -45,6 +56,115 @@ 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 create the required tables (`hazo_notify_template_cat` and `hazo_notify_templates`) by running the appropriate SQL below for your database. The same SQL is also packaged at `node_modules/hazo_notify/migrations/001_create_template_tables.sql`.
68
+
69
+ If `hazo_connect` is not installed, the emailer module still works independently.
70
+
71
+ #### Database Tables
72
+
73
+ The template manager requires two tables:
74
+
75
+ | Table | Purpose |
76
+ |-------|---------|
77
+ | `hazo_notify_template_cat` | Template categories (groups templates per organization) |
78
+ | `hazo_notify_templates` | Email templates with HTML, text, and variable definitions |
79
+
80
+ Both tables are scoped by `org_id` and `root_org_id` for multi-tenant isolation. `hazo_notify_templates.template_category_id` references `hazo_notify_template_cat.id`.
81
+
82
+ #### PostgreSQL Schema
83
+
84
+ ```sql
85
+ CREATE TABLE IF NOT EXISTS hazo_notify_template_cat (
86
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
87
+ org_id UUID NOT NULL,
88
+ root_org_id UUID NOT NULL,
89
+ template_category_name VARCHAR(100) NOT NULL,
90
+ created_at TIMESTAMPTZ DEFAULT NOW(),
91
+ changed_at TIMESTAMPTZ
92
+ );
93
+
94
+ CREATE INDEX IF NOT EXISTS idx_notify_template_cat_org
95
+ ON hazo_notify_template_cat (org_id);
96
+
97
+ CREATE TABLE IF NOT EXISTS hazo_notify_templates (
98
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
99
+ org_id UUID NOT NULL,
100
+ root_org_id UUID NOT NULL,
101
+ template_category_id UUID NOT NULL REFERENCES hazo_notify_template_cat(id),
102
+ template_variables JSONB DEFAULT '{}',
103
+ template_name VARCHAR(100) NOT NULL,
104
+ template_html TEXT NOT NULL DEFAULT '',
105
+ template_text TEXT NOT NULL DEFAULT '',
106
+ email_type VARCHAR(10) NOT NULL DEFAULT 'user',
107
+ created_at TIMESTAMPTZ DEFAULT NOW(),
108
+ changed_at TIMESTAMPTZ
109
+ );
110
+
111
+ CREATE INDEX IF NOT EXISTS idx_notify_templates_org
112
+ ON hazo_notify_templates (org_id);
113
+
114
+ CREATE INDEX IF NOT EXISTS idx_notify_templates_category
115
+ ON hazo_notify_templates (template_category_id);
116
+
117
+ CREATE INDEX IF NOT EXISTS idx_notify_templates_name
118
+ ON hazo_notify_templates (org_id, template_name);
119
+ ```
120
+
121
+ #### SQLite Schema
122
+
123
+ ```sql
124
+ CREATE TABLE IF NOT EXISTS hazo_notify_template_cat (
125
+ id TEXT PRIMARY KEY,
126
+ org_id TEXT NOT NULL,
127
+ root_org_id TEXT NOT NULL,
128
+ template_category_name TEXT NOT NULL,
129
+ created_at TEXT DEFAULT (datetime('now')),
130
+ changed_at TEXT
131
+ );
132
+
133
+ CREATE INDEX IF NOT EXISTS idx_notify_template_cat_org
134
+ ON hazo_notify_template_cat (org_id);
135
+
136
+ CREATE TABLE IF NOT EXISTS hazo_notify_templates (
137
+ id TEXT PRIMARY KEY,
138
+ org_id TEXT NOT NULL,
139
+ root_org_id TEXT NOT NULL,
140
+ template_category_id TEXT NOT NULL REFERENCES hazo_notify_template_cat(id),
141
+ template_variables TEXT DEFAULT '{}',
142
+ template_name TEXT NOT NULL,
143
+ template_html TEXT NOT NULL DEFAULT '',
144
+ template_text TEXT NOT NULL DEFAULT '',
145
+ email_type TEXT NOT NULL DEFAULT 'user',
146
+ created_at TEXT DEFAULT (datetime('now')),
147
+ changed_at TEXT
148
+ );
149
+
150
+ CREATE INDEX IF NOT EXISTS idx_notify_templates_org
151
+ ON hazo_notify_templates (org_id);
152
+
153
+ CREATE INDEX IF NOT EXISTS idx_notify_templates_category
154
+ ON hazo_notify_templates (template_category_id);
155
+
156
+ CREATE INDEX IF NOT EXISTS idx_notify_templates_name
157
+ ON hazo_notify_templates (org_id, template_name);
158
+ ```
159
+
160
+ #### Type Mapping (PostgreSQL ↔ SQLite)
161
+
162
+ | Concept | PostgreSQL | SQLite |
163
+ |---------|------------|--------|
164
+ | Primary / foreign keys | `UUID` (with `gen_random_uuid()` default) | `TEXT` (UUID string supplied by app) |
165
+ | JSON column (`template_variables`) | `JSONB` | `TEXT` (serialized JSON) |
166
+ | Timestamps | `TIMESTAMPTZ` with `NOW()` default | `TEXT` with `datetime('now')` default |
167
+
48
168
  ## Quick Start
49
169
 
50
170
  1. **Create `.env.local` file** with your Zeptomail API key:
@@ -677,6 +797,43 @@ console.log('Emailer module:', config.emailer_module);
677
797
  console.log('From email:', config.from_email);
678
798
  ```
679
799
 
800
+ ### Template Manager API
801
+
802
+ #### `send_template_email(options, hazo_connect, org_id, config?): Promise<SendTemplateEmailResponse>`
803
+
804
+ Render a named template and send it as an email.
805
+
806
+ ```typescript
807
+ import { send_template_email } from 'hazo_notify/template_manager';
808
+
809
+ const result = await send_template_email({
810
+ template_name: 'welcome_email',
811
+ variables: { user_name: 'John', login_url: 'https://example.com/login' },
812
+ to: 'john@example.com',
813
+ subject: 'Welcome!'
814
+ }, hazo_connect, org_id);
815
+ ```
816
+
817
+ #### `render_template(template_name, variables, hazo_connect, org_id, config?, logger?): Promise<TemplateRenderResult>`
818
+
819
+ Render a template without sending (useful for previews).
820
+
821
+ #### `seed_default_templates(hazo_connect, org_id, root_org_id): Promise<TemplateOperationResponse>`
822
+
823
+ Seed the database with default templates (welcome, verification, password reset, signature).
824
+
825
+ #### Template CRUD
826
+
827
+ ```typescript
828
+ import {
829
+ list_categories, create_category, update_category, delete_category,
830
+ list_templates, create_template, update_template, delete_template,
831
+ get_template_by_name, seed_default_templates,
832
+ } from 'hazo_notify/template_manager';
833
+ ```
834
+
835
+ All CRUD functions take a `hazo_connect` instance as their first argument.
836
+
680
837
  ## Test UI
681
838
 
682
839
  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`.
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Type definitions for the emailer service
3
3
  */
4
- export type EmailerModule = 'zeptoemail_api' | 'smtp' | 'pop3';
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":"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"}
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.2",
3
+ "version": "1.1.4",
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
@@ -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"}