ztechno_core 0.0.64 → 0.0.66

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.
@@ -1,4 +1,4 @@
1
- import { HashStruct } from './typings/crypto_types';
1
+ import { HashStruct } from './typings';
2
2
  export declare class ZCryptoService {
3
3
  static encrypt(text: string): HashStruct;
4
4
  static decrypt(data: HashStruct): string;
@@ -1,10 +1,10 @@
1
1
  import { ZMailService } from './mail_service';
2
- import { ZSqlService } from './sql_service';
2
+ import { ZSQLService } from './sql_service';
3
3
  import { ZTranslateService } from './translate_service';
4
4
  import { ZUserService } from './user_service';
5
5
  export declare class ZEngineBase {
6
6
  static mailService?: ZMailService;
7
- static sqlService?: ZSqlService;
7
+ static sqlService?: ZSQLService;
8
8
  static translateService?: ZTranslateService;
9
9
  static userService?: ZUserService;
10
10
  protected static start(): any;
package/lib/index.d.ts CHANGED
@@ -1,19 +1,9 @@
1
1
  import { ZEngineBase } from './engine_base';
2
2
  import { ZCryptoService } from './crypto_service';
3
3
  import { ZMailService } from './mail_service';
4
- import { ZSqlService } from './sql_service';
4
+ import { ZSQLService } from './sql_service';
5
5
  import { ZTranslateService } from './translate_service';
6
6
  import { ZUserService } from './user_service';
7
7
  export { middleware } from './express';
8
- export { HashStruct } from './typings/crypto_types';
9
- export {
10
- MailOptions,
11
- MailOptionsBase,
12
- MailOptionsHtml,
13
- MailOptionsText,
14
- MailServiceOptions,
15
- MailResponse,
16
- } from './typings/mail_types';
17
- export { TranslateData, Dom as ZDom, Node as ZNode, ZNodeText, dbTranslationRow } from './typings/translate_types';
18
- export { ZRequiredUserColumns, ZUser, ZUserCredentials, ZUserSession } from './typings/user_types';
19
- export { ZCryptoService, ZMailService, ZSqlService, ZTranslateService, ZUserService, ZEngineBase };
8
+ export * from './typings';
9
+ export { ZEngineBase, ZCryptoService, ZMailService, ZSQLService as ZSqlService, ZTranslateService, ZUserService };
package/lib/index.js CHANGED
@@ -1,13 +1,40 @@
1
1
  'use strict';
2
+ var __createBinding =
3
+ (this && this.__createBinding) ||
4
+ (Object.create
5
+ ? function (o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ('get' in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = {
10
+ enumerable: true,
11
+ get: function () {
12
+ return m[k];
13
+ },
14
+ };
15
+ }
16
+ Object.defineProperty(o, k2, desc);
17
+ }
18
+ : function (o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ });
22
+ var __exportStar =
23
+ (this && this.__exportStar) ||
24
+ function (m, exports) {
25
+ for (var p in m)
26
+ if (p !== 'default' && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
27
+ };
2
28
  Object.defineProperty(exports, '__esModule', { value: true });
3
- exports.ZEngineBase =
4
- exports.ZUserService =
29
+ exports.ZUserService =
5
30
  exports.ZTranslateService =
6
31
  exports.ZSqlService =
7
32
  exports.ZMailService =
8
33
  exports.ZCryptoService =
34
+ exports.ZEngineBase =
9
35
  exports.middleware =
10
36
  void 0;
37
+ // Core services
11
38
  const engine_base_1 = require('./engine_base');
12
39
  Object.defineProperty(exports, 'ZEngineBase', {
13
40
  enumerable: true,
@@ -33,7 +60,7 @@ const sql_service_1 = require('./sql_service');
33
60
  Object.defineProperty(exports, 'ZSqlService', {
34
61
  enumerable: true,
35
62
  get: function () {
36
- return sql_service_1.ZSqlService;
63
+ return sql_service_1.ZSQLService;
37
64
  },
38
65
  });
39
66
  const translate_service_1 = require('./translate_service');
@@ -50,6 +77,7 @@ Object.defineProperty(exports, 'ZUserService', {
50
77
  return user_service_1.ZUserService;
51
78
  },
52
79
  });
80
+ // Express middleware
53
81
  var express_1 = require('./express');
54
82
  Object.defineProperty(exports, 'middleware', {
55
83
  enumerable: true,
@@ -57,3 +85,5 @@ Object.defineProperty(exports, 'middleware', {
57
85
  return express_1.middleware;
58
86
  },
59
87
  });
88
+ // Re-export all types from typings barrel
89
+ __exportStar(require('./typings'), exports);
@@ -1,8 +1,77 @@
1
- import { MailOptions, MailOptionsHtml, MailOptionsText, MailResponse, MailServiceOptions } from './typings/mail_types';
1
+ import {
2
+ MailOptions,
3
+ MailOptionsHtml,
4
+ MailOptionsText,
5
+ MailResponse,
6
+ MailServiceOptions,
7
+ ZMailSendOptTemplate,
8
+ } from './typings';
9
+ import { ZMailBlacklistOrm } from './orm/mail_blacklist_orm';
2
10
  export declare class ZMailService {
3
11
  private opt;
4
- protected get sql(): import('./sql_service').ZSqlService;
12
+ protected get sql(): import('./sql_service').ZSQLService;
13
+ protected blacklistOrm: ZMailBlacklistOrm;
14
+ /**
15
+ * Creates a new ZMailService instance
16
+ * @param opt - Configuration options for the mail service including authentication, sender email, and SQL service
17
+ */
5
18
  constructor(opt: MailServiceOptions);
19
+ /**
20
+ * Checks if an email is allowed to be sent by verifying it's not blacklisted
21
+ * @param mailOpts - Mail options containing the recipient email to check
22
+ * @returns Promise that resolves to true if email is allowed, false if blacklisted
23
+ * @protected
24
+ */
6
25
  protected allowSend(mailOpts: MailOptions): Promise<boolean>;
7
- send(mailOpts: MailOptionsText | MailOptionsHtml): Promise<MailResponse | undefined>;
26
+ /**
27
+ * Sends an email with text content
28
+ * @param mailOpts - Mail options with text body
29
+ * @returns Promise that resolves to mail response or undefined if sending is not allowed
30
+ */
31
+ send(mailOpts: MailOptionsText): Promise<MailResponse | undefined>;
32
+ /**
33
+ * Sends an email with HTML content
34
+ * @param mailOpts - Mail options with HTML body
35
+ * @returns Promise that resolves to mail response or undefined if sending is not allowed
36
+ */
37
+ send(mailOpts: MailOptionsHtml): Promise<MailResponse | undefined>;
38
+ /**
39
+ * Sends an advanced email with text content, supporting templates and variable injection
40
+ * @param mailOpts - Mail options with text body
41
+ * @returns Promise that resolves to mail response
42
+ */
43
+ sendAdvanced(mailOpts: MailOptionsText): Promise<any>;
44
+ /**
45
+ * Sends an advanced email with HTML content, supporting templates and variable injection
46
+ * @param mailOpts - Mail options with HTML body
47
+ * @returns Promise that resolves to mail response
48
+ */
49
+ sendAdvanced(mailOpts: MailOptionsHtml): Promise<any>;
50
+ /**
51
+ * Sends an advanced email using a template file, supporting variable injection
52
+ * @param mailOpts - Mail options with template path and injection variables
53
+ * @returns Promise that resolves to mail response
54
+ */
55
+ sendAdvanced(mailOpts: ZMailSendOptTemplate): Promise<any>;
56
+ /**
57
+ * Fetches the content of a template file from the filesystem
58
+ * @param template - Path to the template file to read
59
+ * @returns Promise that resolves to the template content as a string
60
+ * @throws Will throw an error if the file cannot be read
61
+ * @private
62
+ */
63
+ private fetchTemplate;
64
+ /**
65
+ * Injects variables into a body string by replacing placeholder tokens
66
+ * @param body - The string content where variables should be injected
67
+ * @param inject - Object containing key-value pairs where keys are variable names and values are replacement content
68
+ * @returns Promise that resolves to the body string with all variables injected
69
+ * @example
70
+ * ```typescript
71
+ * const result = await inject('Hello :name from :company', { name: 'John', company: 'ACME' });
72
+ * // Returns: 'Hello John from ACME'
73
+ * ```
74
+ * @private
75
+ */
76
+ private inject;
8
77
  }
@@ -7,16 +7,38 @@ var __importDefault =
7
7
  Object.defineProperty(exports, '__esModule', { value: true });
8
8
  exports.ZMailService = void 0;
9
9
  const nodemailer_1 = __importDefault(require('nodemailer'));
10
+ const promises_1 = __importDefault(require('fs/promises'));
11
+ const mail_blacklist_orm_1 = require('./orm/mail_blacklist_orm');
10
12
  class ZMailService {
11
13
  get sql() {
12
14
  return this.opt.sqlService;
13
15
  }
16
+ /**
17
+ * Creates a new ZMailService instance
18
+ * @param opt - Configuration options for the mail service including authentication, sender email, and SQL service
19
+ */
14
20
  constructor(opt) {
15
21
  this.opt = opt;
22
+ this.blacklistOrm = new mail_blacklist_orm_1.ZMailBlacklistOrm(opt);
16
23
  }
24
+ /**
25
+ * Checks if an email is allowed to be sent by verifying it's not blacklisted
26
+ * @param mailOpts - Mail options containing the recipient email to check
27
+ * @returns Promise that resolves to true if email is allowed, false if blacklisted
28
+ * @protected
29
+ */
17
30
  async allowSend(mailOpts) {
31
+ const blacklistEntry = await this.blacklistOrm.findOne({ email: mailOpts.recipient, is_blacklisted: 1 });
32
+ if (blacklistEntry) {
33
+ return false;
34
+ }
18
35
  return true;
19
36
  }
37
+ /**
38
+ * Sends an email with either text or HTML content
39
+ * @param mailOpts - Mail options containing recipient, subject, and body/html content
40
+ * @returns Promise that resolves to mail response or undefined if sending is not allowed
41
+ */
20
42
  async send(mailOpts) {
21
43
  const allow = await this.allowSend(mailOpts);
22
44
  if (!allow) {
@@ -41,5 +63,64 @@ class ZMailService {
41
63
  });
42
64
  });
43
65
  }
66
+ /**
67
+ * Sends an advanced email with enhanced features including template loading and variable injection.
68
+ * Automatically generates unsubscribe hash and injects common variables like email and hashToUnsubscribe.
69
+ * @param mailOpts - Mail options that can include template path, injection variables, and standard mail fields
70
+ * @returns Promise that resolves to mail response from the underlying send method
71
+ * @example
72
+ * ```typescript
73
+ * await mailService.sendAdvanced({
74
+ * recipient: 'user@example.com',
75
+ * subject: 'Welcome!',
76
+ * template: './templates/welcome.html',
77
+ * inject: { name: 'John', company: 'ACME Corp' }
78
+ * });
79
+ * ```
80
+ */
81
+ async sendAdvanced(mailOpts) {
82
+ const opts = mailOpts;
83
+ const hashToUnsubscribe = await this.blacklistOrm.genEmailUnsubscribeHash({ email: mailOpts.recipient });
84
+ if (opts.template !== undefined) {
85
+ opts.html = await this.fetchTemplate(opts.template);
86
+ }
87
+ if (opts.inject !== undefined) {
88
+ const key = opts.html !== undefined ? 'html' : 'body';
89
+ const baseInject = { email: mailOpts.recipient, hashToUnsubscribe };
90
+ opts[key] = await this.inject(opts[key], Object.assign(baseInject, opts.inject));
91
+ }
92
+ return await this.send(opts);
93
+ }
94
+ /**
95
+ * Fetches the content of a template file from the filesystem
96
+ * @param template - Path to the template file to read
97
+ * @returns Promise that resolves to the template content as a string
98
+ * @throws Will throw an error if the file cannot be read
99
+ * @private
100
+ */
101
+ async fetchTemplate(template) {
102
+ return await promises_1.default.readFile(template, { encoding: 'utf-8' });
103
+ }
104
+ /**
105
+ * Injects variables into a body string by replacing placeholder tokens
106
+ * @param body - The string content where variables should be injected
107
+ * @param inject - Object containing key-value pairs where keys are variable names and values are replacement content
108
+ * @returns Promise that resolves to the body string with all variables injected
109
+ * @example
110
+ * ```typescript
111
+ * const result = await inject('Hello :name from :company', { name: 'John', company: 'ACME' });
112
+ * // Returns: 'Hello John from ACME'
113
+ * ```
114
+ * @private
115
+ */
116
+ async inject(body, inject) {
117
+ Object.keys(inject ?? {}).map((variableName) => {
118
+ const key = `:${variableName}`;
119
+ while (body.indexOf(key) !== -1) {
120
+ body = body.replace(key, inject[variableName].toString());
121
+ }
122
+ });
123
+ return body;
124
+ }
44
125
  }
45
126
  exports.ZMailService = ZMailService;
@@ -0,0 +1,21 @@
1
+ import { ZOrm } from './orm';
2
+ import { ZSQLService } from '../sql_service';
3
+ import { ZMailBlacklist, ZMailBlacklistSearch } from '../typings';
4
+ export declare class ZMailBlacklistOrm extends ZOrm {
5
+ private hashSalt;
6
+ private sqlService;
7
+ constructor(opt: { alias?: string; sqlService: ZSQLService; hashSalt?: string });
8
+ genEmailUnsubscribeHash({ email }: { email: string }): Promise<string>;
9
+ create(
10
+ item: Omit<ZMailBlacklist, 'updated_at' | 'created_at'>,
11
+ ): Promise<Omit<ZMailBlacklist, 'updated_at' | 'created_at'>>;
12
+ findOne(conditions: Partial<ZMailBlacklist>): Promise<ZMailBlacklist>;
13
+ findAll(
14
+ conditions?: Partial<ZMailBlacklistSearch>,
15
+ opt?: {
16
+ limit?: number;
17
+ },
18
+ ): Promise<ZMailBlacklist[]>;
19
+ update({ email, is_blacklisted }: Pick<ZMailBlacklist, 'email' | 'is_blacklisted'>): Promise<boolean>;
20
+ createTable(): Promise<void>;
21
+ }
@@ -0,0 +1,68 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, '__esModule', { value: true });
3
+ exports.ZMailBlacklistOrm = void 0;
4
+ const orm_1 = require('./orm');
5
+ const crypto_service_1 = require('../crypto_service');
6
+ class ZMailBlacklistOrm extends orm_1.ZOrm {
7
+ constructor(opt) {
8
+ super({ alias: opt.alias ?? 'email_blacklist' });
9
+ this.sqlService = opt.sqlService;
10
+ this.hashSalt = opt.hashSalt ?? 'ZTECHNO';
11
+ }
12
+ async genEmailUnsubscribeHash({ email }) {
13
+ const existingHash = await this.findOne({ email });
14
+ if (existingHash !== undefined) {
15
+ return existingHash.hash;
16
+ }
17
+ const hash = crypto_service_1.ZCryptoService.hash('sha512', `${this.hashSalt}-${email}`);
18
+ await this.create({ email, hash, is_blacklisted: 0 });
19
+ return hash;
20
+ }
21
+ async create(item) {
22
+ const res = await this.sqlService.query(
23
+ `
24
+ INSERT INTO \`${this.alias}\` (email, hash, is_blacklisted, updated_at, created_at)
25
+ VALUES (:email, :hash, :is_blacklisted, NOW(), NOW())
26
+ ON DUPLICATE KEY UPDATE hash=:hash, updated_at=NOW()
27
+ `,
28
+ item,
29
+ );
30
+ return item; // return Object.assign(item, { invoice_id: res.insertId }) as ZMailBlacklist
31
+ }
32
+ async findOne(conditions) {
33
+ const rows = await this.findAll(conditions, { limit: 1 });
34
+ return rows[0];
35
+ }
36
+ async findAll(conditions, opt) {
37
+ const whereKeys = Object.keys(conditions ?? {});
38
+ const whereClause = whereKeys.length ? `WHERE ${whereKeys.map((key) => `${key}=:${key}`).join(' AND ')}` : '';
39
+ const limit = opt?.limit ? `LIMIT ${opt.limit}` : '';
40
+ return await this.sqlService.exec({
41
+ query: /*SQL*/ `SELECT * FROM \`${this.alias}\` ${whereClause} ${limit}`,
42
+ params: conditions,
43
+ });
44
+ }
45
+ async update({ email, is_blacklisted }) {
46
+ const res = await this.sqlService.query(
47
+ `
48
+ UPDATE \`${this.alias}\` SET is_blacklisted=:is_blacklisted, updated_at=NOW() WHERE email=:email
49
+ `,
50
+ { email, is_blacklisted },
51
+ );
52
+ return res.affectedRows !== 0;
53
+ }
54
+ async createTable() {
55
+ await this.sqlService.query(/*SQL*/ `
56
+ CREATE TABLE \`${this.alias}\` (
57
+ \`email\` varchar(512) NOT NULL,
58
+ \`hash\` varchar(256) NOT NULL,
59
+ \`is_blacklisted\` tinyint(1) NOT NULL DEFAULT 0,
60
+ \`updated_at\` datetime NOT NULL DEFAULT current_timestamp(),
61
+ \`created_at\` datetime NOT NULL DEFAULT current_timestamp(),
62
+ PRIMARY KEY (\`email\`),
63
+ KEY \`is_blacklisted\` (\`is_blacklisted\`)
64
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
65
+ `);
66
+ }
67
+ }
68
+ exports.ZMailBlacklistOrm = ZMailBlacklistOrm;
@@ -0,0 +1,8 @@
1
+ import { ZSQLService } from '../sql_service';
2
+ export declare class ZOrm {
3
+ readonly alias: string;
4
+ constructor(opt: { alias: string });
5
+ ensureTableExists(sqlService: ZSQLService): Promise<void>;
6
+ private checkTableExists;
7
+ createTable(sqlService: ZSQLService): Promise<void>;
8
+ }
package/lib/orm/orm.js ADDED
@@ -0,0 +1,26 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, '__esModule', { value: true });
3
+ exports.ZOrm = void 0;
4
+ class ZOrm {
5
+ constructor(opt) {
6
+ this.alias = opt.alias;
7
+ }
8
+ async ensureTableExists(sqlService) {
9
+ const exists = await this.checkTableExists(sqlService);
10
+ if (!exists) {
11
+ await this.createTable(sqlService);
12
+ }
13
+ }
14
+ async checkTableExists(sqlService) {
15
+ const res = await sqlService.query(`
16
+ SELECT ENGINE, VERSION, CREATE_TIME FROM information_schema.tables
17
+ WHERE table_schema = '${sqlService.database}' AND table_name = '${this.alias}'
18
+ LIMIT 1
19
+ `);
20
+ return res.length > 0;
21
+ }
22
+ async createTable(sqlService) {
23
+ throw new Error(`${this.alias} Create Table Statement Not Implemented!`);
24
+ }
25
+ }
26
+ exports.ZOrm = ZOrm;
@@ -1,7 +1,7 @@
1
1
  import * as mysql from 'mysql';
2
2
  type ZOnErrorCallback = (err: mysql.MysqlError) => any;
3
3
  type ZOnLogCallback = (log: string) => any;
4
- export declare class ZSqlService {
4
+ export declare class ZSQLService {
5
5
  private options;
6
6
  private pool;
7
7
  private defaultPoolconfig;
@@ -40,9 +40,9 @@ var __importStar =
40
40
  return result;
41
41
  };
42
42
  Object.defineProperty(exports, '__esModule', { value: true });
43
- exports.ZSqlService = void 0;
43
+ exports.ZSQLService = void 0;
44
44
  const mysql = __importStar(require('mysql'));
45
- class ZSqlService {
45
+ class ZSQLService {
46
46
  get database() {
47
47
  return this.databaseName;
48
48
  }
@@ -149,4 +149,4 @@ class ZSqlService {
149
149
  return false;
150
150
  }
151
151
  }
152
- exports.ZSqlService = ZSqlService;
152
+ exports.ZSQLService = ZSQLService;
@@ -1,17 +1,23 @@
1
- import { TranslateData, dbTranslationRow } from './index';
2
- import { ATranslateLang, TranslateServiceOptions } from './typings/translate_types';
1
+ import { TranslateData, dbTranslationRow, ATranslateLang, TranslateServiceOptions } from './typings';
3
2
  export declare class ZTranslateService {
4
3
  private opt;
5
4
  private localCache;
6
5
  private get sql();
7
6
  surpressErrors: boolean;
7
+ private maxRetries;
8
+ private retryDelay;
9
+ private fallbackText;
8
10
  getLanguages(): ATranslateLang[];
9
11
  getSourceLang(): string;
10
12
  getDefaultLang(): string;
11
13
  constructor(opt: TranslateServiceOptions);
12
14
  private codes;
13
15
  getLang(cookies: { [key: string]: string }): string;
16
+ private sleep;
17
+ private logError;
18
+ private retryOperation;
14
19
  translateText(langOrReq: string | any, text: string): Promise<string>;
20
+ private processHtmlEntities;
15
21
  translateHtml(
16
22
  html: string,
17
23
  cookies: {