@dnax/core 0.1.20 → 0.2.0

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/app/index.ts CHANGED
@@ -1,39 +1,43 @@
1
1
  import consola from "consola";
2
2
  import { Cfg, loadCfg } from "../config";
3
3
  import { init } from "../lib";
4
+ import { hookDatabase } from "../lib/database";
5
+ import killPort from "kill-port";
4
6
  import boxen from "boxen";
5
7
  import "@colors/colors";
6
8
  import pkg from "../package.json";
7
9
  import findPort from "find-open-port";
8
10
  import { HonoInstance } from "./hono";
9
11
  type configRunApp = {
10
- register?: Array<Function>,
11
- beforeStart?: Array<Function>,
12
- afterStart?: Array<Function>,
13
- onError?: Array<Function>,
14
- destroy?: Array<Function>,
15
- }
12
+ register?: Array<Function>;
13
+ beforeStart?: Array<Function>;
14
+ afterStart?: Array<Function>;
15
+ onError?: Array<Function>;
16
+ destroy?: Array<Function>;
17
+ dbSync?: Array<Function>;
18
+ };
16
19
  async function runApp(config?: configRunApp, clb?: Function) {
17
- console.log("\n");
18
-
19
- await loadCfg();
20
- //
21
-
22
- // Load all ressouce
23
- await init();
24
-
25
- // Register all plugins
26
-
27
- // Load Hono App and route api
20
+ hookDatabase.cb = config?.dbSync || [];
21
+ await loadCfg(); // Load Config
28
22
  const HonoApp = HonoInstance();
29
23
  const PORT = Cfg.server?.port || process.env?.PORT || 4000;
24
+ const PORT_SOCKET = Cfg.server?.socket?.port || 9000;
25
+
26
+ // available port Socket
27
+ await findPort.isAvailable(PORT_SOCKET).then(async (available: boolean) => {
28
+ if (!available) {
29
+ console.error(`⚠️ Socket Port ${PORT_SOCKET} is not available`);
30
+ console.log("");
31
+ process.exit();
32
+ }
33
+ });
30
34
 
35
+ // available port Server
31
36
  await findPort.isAvailable(PORT).then(async (available: boolean) => {
32
37
  // Start App server
33
-
34
38
  if (available) {
35
-
36
-
39
+ // Load all ressouce
40
+ await init();
37
41
  //BeforeStart
38
42
  if (config?.beforeStart) {
39
43
  for (const fn of config?.beforeStart) {
@@ -45,7 +49,6 @@ async function runApp(config?: configRunApp, clb?: Function) {
45
49
  port: PORT,
46
50
  fetch: HonoApp.fetch,
47
51
  maxRequestBodySize: 1024 * 1024 * 900,
48
-
49
52
  });
50
53
 
51
54
  console.log();
@@ -54,8 +57,9 @@ async function runApp(config?: configRunApp, clb?: Function) {
54
57
  info += `\n`;
55
58
  info += `\n`;
56
59
  info +=
57
- `Env: ${process.env.NODE_ENV === "production" ? "production" : "development"
58
- }`.italic.blue.green + "\n";
60
+ `Env: ${
61
+ process.env.NODE_ENV === "production" ? "production" : "development"
62
+ }`.italic.blue.green + "\n";
59
63
  info += `Server: http://localhost:${PORT}\n`.italic.blue;
60
64
  info += `\n`;
61
65
  info += "TENANTS DETAILS :".gray.italic.underline;
@@ -86,7 +90,6 @@ async function runApp(config?: configRunApp, clb?: Function) {
86
90
  await fn();
87
91
  }
88
92
  }
89
-
90
93
  } else {
91
94
  console.error(`⚠️ Port ${PORT} is not available`);
92
95
  console.log("");
@@ -95,4 +98,6 @@ async function runApp(config?: configRunApp, clb?: Function) {
95
98
  });
96
99
  }
97
100
 
101
+ process.on("exit", async () => {});
102
+
98
103
  export { runApp };
package/bin/index.ts ADDED
@@ -0,0 +1,74 @@
1
+ #! /usr/bin/env bun
2
+
3
+ import ch from "chokidar";
4
+ import { spinner } from "@clack/prompts";
5
+ var exec;
6
+ var s = spinner();
7
+ function runPkg(
8
+ opts = {
9
+ stopSpinner: false,
10
+ }
11
+ ) {
12
+ if (opts?.stopSpinner) {
13
+ s.stop();
14
+ }
15
+
16
+ exec = Bun.spawn([`bun`, `index.ts`], {
17
+ stdio: ["inherit", "inherit", "inherit"],
18
+ serialization: "json",
19
+ stdin: "inherit",
20
+ ipc(message, subprocess) {
21
+ console.log(message);
22
+ },
23
+ });
24
+ }
25
+
26
+ // Écoutez le signal SIGINT (Ctrl + C)
27
+ process.on("SIGINT", () => {
28
+ if (exec?.kill) exec.kill();
29
+ process.exit(); // Terminez le processus principal
30
+ });
31
+
32
+ ch.watch(".", {
33
+ ignored: [
34
+ /^(?!.*\.(ts|js|env)$).*/,
35
+ /.*\.(jpg|jpeg|png|gif|bmp|svg|webp)$/i,
36
+ /node_modules|node_modules\/.*/,
37
+ /node_modules/,
38
+ /(^|[\/\\])\../,
39
+ "*/node_modules",
40
+ "*/dist",
41
+ "*.zip",
42
+ "*.tar",
43
+ "*.tar.gz",
44
+ "build",
45
+ "coverage",
46
+ "packages/*/dist",
47
+ "packages/*/build",
48
+ "packages/*/coverage",
49
+ "packages/*/node_modules",
50
+ ],
51
+ })
52
+ .on("change", (path) => {
53
+ let dev = process.argv.includes("--dev");
54
+
55
+ if (dev) {
56
+ s.start("Restarting due to changes ...");
57
+ if (exec?.kill) {
58
+ exec.kill();
59
+ }
60
+ setTimeout(() => {
61
+ runPkg({ stopSpinner: true });
62
+ }, 600);
63
+ }
64
+ })
65
+ .on("ready", () => {
66
+ let dev = process.argv.includes("--dev");
67
+ let start = process.argv.includes("--start");
68
+
69
+ if (dev || start) {
70
+ runPkg();
71
+ } else {
72
+ process.exit();
73
+ }
74
+ });
@@ -10,7 +10,7 @@ async function connectToMongo(t: Tenant) {
10
10
  await client
11
11
  .connect()
12
12
  .then((e) => {
13
- consola.log(`[${t.id}] : Connected to db ✅`.green);
13
+ //consola.log(`[${t.id}] : Connected to db ✅`.green);
14
14
  t.database.isConnected = true;
15
15
  t.database.client = client;
16
16
  t.database.db = client.db();
package/lib/collection.ts CHANGED
@@ -7,6 +7,7 @@ import { Cfg } from "../config";
7
7
  import { useRest } from "../driver/mongo/rest";
8
8
  import { buildSchema } from "./schema";
9
9
  import { cleanPath, resolvePath } from "../utils";
10
+ import { hookDatabase } from "../lib/database";
10
11
 
11
12
  import path from "path";
12
13
  import consola from "consola";
@@ -180,7 +181,13 @@ async function syncCollectionDatabase() {
180
181
  //
181
182
  console.error(err?.message || err);
182
183
  }
183
- consola.success("Database synchronized ");
184
+
185
+ // Data sync
186
+ if (hookDatabase?.cb?.length) {
187
+ for (const fn of hookDatabase.cb) {
188
+ fn();
189
+ }
190
+ }
184
191
  }
185
192
 
186
193
  export {
@@ -0,0 +1,5 @@
1
+ const hookDatabase = {
2
+ cb: [] as Array<Function>,
3
+ };
4
+
5
+ export { hookDatabase };
package/lib/index.ts CHANGED
@@ -17,7 +17,7 @@ async function init(cf = { app: null }) {
17
17
  loadServices();
18
18
 
19
19
  // load Socket
20
- loadSocket();
20
+ await loadSocket();
21
21
 
22
22
  // load all loadEndpoints
23
23
  await loadEndpoints();
package/lib/mail.ts ADDED
@@ -0,0 +1,120 @@
1
+ import { createTransport } from "nodemailer";
2
+ import { Cfg } from "../config/index";
3
+ import type { emailConfigType } from "../types";
4
+ function sendLocalEmail(
5
+ mailOptions: {
6
+ from?: string;
7
+ text?: string;
8
+ html?: string;
9
+ subject?: string;
10
+ to?: string | Array<string> | null | undefined;
11
+ replyTo?: string;
12
+ cc?: string | Array<string> | null | undefined;
13
+ bcc?: string | Array<string> | null | undefined;
14
+ } = {}
15
+ ) {
16
+ return new Promise(async (resolve, reject) => {
17
+ try {
18
+ const smtp = Cfg.email?.smtpOptions;
19
+ const transport = createTransport({
20
+ host: smtp?.host,
21
+ port: Number(smtp?.port),
22
+ secure: smtp?.secure,
23
+ requireTLS: smtp?.requireTLS || true,
24
+ from: `${Cfg.email?.fromName || ""} <${Cfg?.email?.fromAddress || ""}>`,
25
+ });
26
+
27
+ var response = await transport.sendMail({
28
+ from:
29
+ mailOptions.from ||
30
+ `${Cfg.email?.fromName || ""} <${Cfg?.email?.fromAddress || ""}>`,
31
+ to: mailOptions?.to || undefined,
32
+ subject: mailOptions?.subject || "",
33
+ text: mailOptions?.text || "",
34
+ html: mailOptions?.html || "",
35
+ replyTo: mailOptions?.replyTo || undefined,
36
+ cc: mailOptions?.cc || undefined,
37
+ bcc: mailOptions?.bcc || undefined,
38
+ });
39
+ resolve(response);
40
+ } catch (err) {
41
+ reject(err);
42
+ }
43
+ });
44
+ }
45
+ function sendEmail(
46
+ emailConfig: emailConfigType,
47
+ mailOptions: {
48
+ from?: string;
49
+ text?: string;
50
+ html?: string;
51
+ subject?: string;
52
+ to?: string | Array<string> | null | undefined;
53
+ replyTo?: string;
54
+ cc?: string | Array<string> | null | undefined;
55
+ bcc?: string | Array<string> | null | undefined;
56
+ } = {}
57
+ ) {
58
+ return new Promise(async (resolve, reject) => {
59
+ try {
60
+ const smtp = Cfg.email?.smtpOptions;
61
+ const transport = createTransport(emailConfig.smtpOptions);
62
+
63
+ var response = await transport.sendMail({
64
+ from:
65
+ mailOptions.from ||
66
+ `${emailConfig?.fromName || ""} <${emailConfig?.fromAddress || ""}>`,
67
+ to: mailOptions?.to || undefined,
68
+ subject: mailOptions?.subject || "",
69
+ text: mailOptions?.text || "",
70
+ html: mailOptions?.html || "",
71
+ replyTo: mailOptions?.replyTo || undefined,
72
+ cc: mailOptions?.cc || undefined,
73
+ bcc: mailOptions?.bcc || undefined,
74
+ });
75
+ resolve(response);
76
+ } catch (err) {
77
+ reject(err);
78
+ }
79
+ });
80
+ }
81
+
82
+ function updateLocalEmailConfig(options: emailConfigType) {
83
+ Cfg.email = options;
84
+ }
85
+
86
+ function verifyLocalSmtpConnection(smtpConfig: emailConfigType["smtpOptions"]) {
87
+ return new Promise((resolve, reject) => {
88
+ let transport = createTransport(smtpConfig);
89
+ transport.verify((error, success) => {
90
+ if (error) {
91
+ reject(error);
92
+ } else {
93
+ resolve(success);
94
+ }
95
+ });
96
+ });
97
+ }
98
+
99
+ function verifySmtpConnection(smtpConfig: emailConfigType["smtpOptions"]) {
100
+ return new Promise((resolve, reject) => {
101
+ let transport = createTransport(smtpConfig);
102
+ transport.verify((error, success) => {
103
+ if (error) {
104
+ reject(error);
105
+ } else {
106
+ resolve(success);
107
+ }
108
+ });
109
+ });
110
+ }
111
+
112
+ const email = {
113
+ sendEmail,
114
+ sendLocalEmail,
115
+ updateLocalEmailConfig,
116
+ verifySmtpConnection,
117
+ verifyLocalSmtpConnection,
118
+ };
119
+
120
+ export { email };
package/lib/opt.ts ADDED
@@ -0,0 +1,55 @@
1
+ import { parse } from "@lukeed/ms";
2
+ import generateUniqueId from "generate-unique-id";
3
+ type otpOptions = {
4
+ length?: number;
5
+ useLetters?: boolean;
6
+ useNumbers?: boolean;
7
+ includeSymbols?: Array<any>;
8
+ excludeSymbols?: Array<any>;
9
+ expireIn?: string;
10
+ };
11
+
12
+ class Otp {
13
+ #otps: Map<string, number> = new Map();
14
+ #options: otpOptions;
15
+ constructor(options: otpOptions) {
16
+ this.#options = options;
17
+ }
18
+
19
+ generate(options: { id?: string; data?: any } = {}): string | number {
20
+ setTimeout(() => {}, parse(String(this.#options.expireIn) || "1m"));
21
+ let otpCode = generateUniqueId({
22
+ length: this.#options.length || 6,
23
+ includeSymbols: this.#options.includeSymbols || [],
24
+ useLetters: this.#options.useLetters || true,
25
+ useNumbers: this.#options.useNumbers || true,
26
+ excludeSymbols: this.#options.excludeSymbols || [],
27
+ });
28
+ this.#otps.set(options?.id, {
29
+ otp: otpCode,
30
+ data: options?.data,
31
+ });
32
+
33
+ setTimeout(() => {
34
+ this.#otps.delete(options?.id);
35
+ }, parse(String(this.#options?.expireIn) || "1m"));
36
+ return otpCode;
37
+ }
38
+
39
+ delete(id: string): boolean {
40
+ return this.#otps.delete(id) ? true : false;
41
+ }
42
+ verify(id: string, otp: string): { valid: boolean; data: any } {
43
+ // verify otp
44
+ let otpData = this.#otps.get(id);
45
+ if (!otpData) return { valid: false, data: null };
46
+ if (otpData.otp === otp) {
47
+ this.#otps.delete(id);
48
+ return { valid: true, data: otpData?.data };
49
+ } else {
50
+ return { valid: false, data: null };
51
+ }
52
+ }
53
+ }
54
+
55
+ export { Otp };
package/package.json CHANGED
@@ -1,21 +1,28 @@
1
1
  {
2
2
  "name": "@dnax/core",
3
- "version": "0.1.20",
3
+ "version": "0.2.0",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
+ "bin": {
7
+ "dnax": "./bin/index.ts"
8
+ },
6
9
  "devDependencies": {
7
- "@types/bun": "latest"
10
+ "@types/bun": "latest",
11
+ "@types/nodemailer": "^6.4.15"
8
12
  },
9
13
  "peerDependencies": {
10
14
  "typescript": "^5.0.0"
11
15
  },
12
16
  "dependencies": {
17
+ "@clack/prompts": "^0.7.0",
13
18
  "@colors/colors": "^1.6.0",
14
19
  "@google/generative-ai": "0.14.0",
15
20
  "@lukeed/ms": "^2.0.2",
16
21
  "@types/jsonwebtoken": "^9.0.6",
17
22
  "boxen": "^7.1.1",
23
+ "chokidar": "^3.6.0",
18
24
  "clean-deep": "^3.4.0",
25
+ "collect.js": "^4.36.1",
19
26
  "consola": "^3.2.3",
20
27
  "cookie": "^0.6.0",
21
28
  "croner": "^8.0.2",
@@ -29,6 +36,7 @@
29
36
  "mingo": "^6.4.15",
30
37
  "moment": "^2.30.1",
31
38
  "mongodb": "^6.7.0",
39
+ "nodemailer": "^6.9.14",
32
40
  "radash": "^12.1.0",
33
41
  "signaldb": "^0.9.0",
34
42
  "socket.io": "^4.7.5",
package/types/index.ts CHANGED
@@ -252,6 +252,21 @@ export type Collection = {
252
252
  };
253
253
 
254
254
  export type Config = {
255
+ email?: {
256
+ provider: "smtp";
257
+ fromName: string;
258
+ fromAddress: string;
259
+ smtpOptions?: {
260
+ host: string;
261
+ port: number;
262
+ secure?: boolean;
263
+ requireTLS?: boolean;
264
+ auth: {
265
+ user: string;
266
+ pass: string;
267
+ };
268
+ };
269
+ };
255
270
  studio?: {
256
271
  /**
257
272
  * Enable or disable the studio
@@ -386,3 +401,30 @@ export type Service = {
386
401
  io: Io;
387
402
  }) => any;
388
403
  };
404
+
405
+ export type emailConfigType = {
406
+ provider: "smtp";
407
+ fromName: string;
408
+ fromAddress: string;
409
+ smtpOptions?: {
410
+ host: string;
411
+ port: number;
412
+ secure?: boolean;
413
+ requireTLS?: boolean;
414
+ auth: {
415
+ user: string;
416
+ pass: string;
417
+ };
418
+ };
419
+ };
420
+
421
+ export type smtpConfigType = {
422
+ host: string;
423
+ port: number;
424
+ secure?: boolean;
425
+ requireTLS?: boolean;
426
+ auth: {
427
+ user: string;
428
+ pass: string;
429
+ };
430
+ };
package/utils/index.ts CHANGED
@@ -7,8 +7,12 @@ import { parse, format } from "@lukeed/ms";
7
7
  import jwto from "jsonwebtoken";
8
8
  import generateUniqueId from "generate-unique-id";
9
9
  import dayjs from "dayjs";
10
+ import { Otp } from "../lib/opt";
11
+ import collect from "collect.js";
12
+
10
13
  const JWT_SECRET = process?.env?.JWT_SECRET || "secret-libv";
11
14
  import * as _ from "radash";
15
+ import { email } from "../lib/mail";
12
16
 
13
17
  const jwt = {
14
18
  verify: (token: string): { decode: any; valid: boolean; error: any } => {
@@ -241,23 +245,31 @@ const fn = {
241
245
  };
242
246
 
243
247
  const $ = Bun.$;
248
+ const password = {
249
+ hash: hashPassword,
250
+ verify: verifyHashPassword,
251
+ };
244
252
 
245
253
  export {
254
+ password, // Hash and verify Password utils
255
+ email, // smtp utils
246
256
  moment,
247
- $,
248
- fn,
249
- deepMerge,
250
- toDate,
251
- toJson,
257
+ $, // $ Bun utils
258
+ fn, // fn global error dispatch
259
+ deepMerge, // DeepMerge
260
+ toDate, // transform to date
261
+ toJson, // to Json
252
262
  hashPassword,
253
263
  verifyHashPassword,
254
264
  cleanPath,
255
- freeze,
265
+ freeze, // Lock object properties
256
266
  resolvePath,
257
- isDate,
267
+ isDate, // Check if date
258
268
  contextError,
259
- jwt,
260
- _,
261
- generateUniqueId,
262
- omit,
269
+ jwt, // Jwt utils
270
+ _, // Moment utils
271
+ generateUniqueId, // Generate unique id
272
+ omit, // Omit utils
273
+ collect, // Collect utils
274
+ Otp, // Otp utils
263
275
  };