@dnax/core 0.66.3 → 0.67.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/app/hono.ts CHANGED
@@ -15,7 +15,6 @@ import { consola } from "consola";
15
15
 
16
16
  import { cors } from "hono/cors";
17
17
  import { asyncLocalStorage, sessionStorage } from "../lib/asyncLocalStorage";
18
- import { localSession } from "../lib/session";
19
18
  import { crypt } from "../lib/crypto";
20
19
  import {
21
20
  cleanPath,
@@ -32,7 +31,6 @@ import { useRest } from "../driver/mongo/rest";
32
31
  import moment from "moment";
33
32
  import { Cfg } from "../config";
34
33
  import { getService } from "../lib/service";
35
- import { bentoCache, bentoKey } from "../lib/bento";
36
34
  import { MediaDrive } from "../lib/media";
37
35
  import { isStudio } from "../lib/studio";
38
36
 
@@ -45,14 +43,13 @@ import { csrf } from "hono/csrf";
45
43
  import { v4 } from "uuid";
46
44
  import type { SearchParams } from "meilisearch";
47
45
  import { utils } from "..";
48
- const cache = bentoCache.namespace("DNAX_API");
49
46
  const app = new Hono();
50
47
  const API_PATH = "/api";
51
48
 
52
49
  function HonoInstance(): typeof app {
53
50
  app.use(
54
51
  cors({
55
- origin: Cfg.server?.cors?.origin || ["*"],
52
+ origin: (Cfg.server?.cors?.origin as string[]) || ["*"],
56
53
  credentials: Cfg.server?.cors?.credentials ?? false,
57
54
  allowMethods: Cfg.server?.cors?.allowMethods || [
58
55
  "GET",
@@ -73,6 +70,9 @@ function HonoInstance(): typeof app {
73
70
  "X-Requested-With",
74
71
  "Access-Control-Request-Method",
75
72
  "Access-Control-Request-Headers",
73
+ "X-Forwarded-For",
74
+ "Cookie",
75
+ "X-Forwarded-Host",
76
76
  ],
77
77
  })
78
78
  );
@@ -126,8 +126,17 @@ function HonoInstance(): typeof app {
126
126
  reqAt: moment().format().toString(),
127
127
  setAt: sessionData?._v?.setAt || null,
128
128
  };
129
+ let tenantId =
130
+ c.req.header()["tenant-id"] ||
131
+ c.req.query("tenant-id") ||
132
+ c.req.query("tenantId") ||
133
+ c.req.query("tenant_id") ||
134
+ null;
135
+
136
+ tenantId = tenantId ? String(tenantId) : null;
137
+
129
138
  c.set("_v", _v);
130
- c.set("tenant-id", c.req.header()["tenant-id"]);
139
+ c.set("tenant-id", tenantId);
131
140
 
132
141
  //console.log("_v", _v);
133
142
 
@@ -566,38 +575,12 @@ function HonoInstance(): typeof app {
566
575
  });
567
576
  }
568
577
  }
578
+
569
579
  // find
570
580
  if (action == "find") {
571
- if (col?.cache?.enabled && useCache) {
572
- let keyCache = crypt.AES.generateKey({
573
- body: body,
574
- query: c?.req?.query,
575
- });
576
-
577
- // if customCache
578
- if (col?.cache?.fetch) {
579
- let fetchFromCache = await col?.cache?.fetch({
580
- key: keyCache,
581
- action: action,
582
- params: body?.params,
583
- rest: rest,
584
- session: sessionStorage(),
585
- state: col?.cache?.state || {},
586
- c: c,
587
- });
588
- if (!fetchFromCache?.isStale) {
589
- response = fetchFromCache.data;
590
- } else {
591
- response = await rest.find(collection, body?.params || {}, {
592
- withMeta: body?.withMeta || false,
593
- });
594
- }
595
- }
596
- } else {
597
- response = await rest.find(collection, body?.params || {}, {
598
- withMeta: body?.withMeta || false,
599
- });
600
- }
581
+ response = await rest.find(collection, body?.params || {}, {
582
+ withMeta: body?.withMeta || false,
583
+ });
601
584
  }
602
585
 
603
586
  if (action == "listActivity") {
package/app/index.ts CHANGED
@@ -2,17 +2,16 @@ import consola from "consola";
2
2
  import { Cfg, loadCfg } from "../config";
3
3
  import { init } from "../lib";
4
4
  import { hookDatabase } from "../lib/database";
5
- import killPort from "kill-port";
6
5
  import boxen from "boxen";
7
6
  import { loadSocket } from "../lib/socket";
8
- import pidusage from "pidusage";
9
7
  import "@colors/colors";
10
8
  import pkg from "../package.json";
11
- import findPort from "find-open-port";
9
+ import { findPort } from "../utils/port";
12
10
  import { webSocketServer } from "../lib/socket/instance";
13
11
  import { HonoInstance } from "./hono";
14
12
  import { utils } from "..";
15
13
  import type { Server } from "bun";
14
+ import { getPidUsage } from "../utils/os";
16
15
  type configRunApp = {
17
16
  register?: Array<Function>;
18
17
  beforeStart?: Array<Function>;
@@ -22,125 +21,106 @@ type configRunApp = {
22
21
  dbSync?: Array<Function>;
23
22
  };
24
23
  async function runApp(config?: configRunApp, clb?: Function): Promise<Server> {
25
- hookDatabase.cb = config?.dbSync || [];
26
- await loadCfg(); // Load Config
24
+ try {
25
+ hookDatabase.cb = config?.dbSync || [];
26
+ await loadCfg(); // Load Config
27
27
 
28
- const PORT = Cfg.server?.port || process.env?.PORT || 4000;
29
- const CLUSTER_MODE = Cfg?.clusterMode ?? false;
30
- /* const PORT_SOCKET = Cfg.server?.socket?.port || 9000;
28
+ const PORT = Cfg.server?.port || process.env?.PORT || 4000;
29
+ const CLUSTER_MODE = Cfg?.clusterMode ?? false;
31
30
 
32
- // available port Socket
33
- await findPort.isAvailable(PORT_SOCKET).then(async (available: boolean) => {
34
- if (!available) {
35
- console.error(`⚠️ Socket Port ${PORT_SOCKET} is not available`);
36
- console.log("");
37
- process.exit(1);
38
- }
39
- }); */
40
-
41
- // available port Server
42
- return await findPort
43
- .isAvailable(PORT)
44
- .then(async (available: boolean) => {
45
- // Start App server
46
- if (!available && !Cfg?.clusterMode) {
47
- console.error(`⚠️ Port ${PORT} is not available`);
48
- console.log("");
49
- process.exit();
50
- }
51
-
52
- if (available) {
53
- // Load all ressouce
54
- await init();
55
- const HonoApp = HonoInstance();
56
- //await loadSocket(HonoApp);
57
- //BeforeStart
58
- if (config?.beforeStart) {
59
- for (const fn of config?.beforeStart) {
60
- await fn();
61
- }
31
+ // available port Server
32
+ return await findPort
33
+ .isAvailable(Number(PORT))
34
+ .then(async (available: boolean) => {
35
+ // Start App server
36
+ if (!available && !Cfg?.clusterMode) {
37
+ console.error(`⚠️ Port ${PORT} is not available`);
38
+ console.log("");
39
+ process.exit();
62
40
  }
63
41
 
64
- var server: any = Bun.serve({
65
- port: PORT,
66
- reusePort: CLUSTER_MODE,
67
- fetch: (req, server) => {
68
- if (server.upgrade(req)) {
69
- // handle authentication
70
- return;
42
+ if (available) {
43
+ // Load all ressouce
44
+ await init();
45
+ const HonoApp = HonoInstance();
46
+ //await loadSocket(HonoApp);
47
+ //BeforeStart
48
+ if (config?.beforeStart) {
49
+ for (const fn of config?.beforeStart) {
50
+ await fn();
71
51
  }
52
+ }
72
53
 
73
- return HonoApp.fetch(req, server);
74
- },
75
- maxRequestBodySize: 1024 * 1024 * 900,
76
- websocket: webSocketServer(server),
77
- });
54
+ var server: any = Bun.serve({
55
+ port: PORT,
56
+ reusePort: CLUSTER_MODE,
57
+ fetch: (req, server) => {
58
+ if (server.upgrade(req)) {
59
+ // handle authentication
60
+ return;
61
+ }
78
62
 
79
- let serverName =
80
- process.env.SERVER_NAME || Cfg?.server?.name || "SERVER";
63
+ return HonoApp.fetch(req, server);
64
+ },
65
+ maxRequestBodySize: 1024 * 1024 * 900,
66
+ websocket: webSocketServer(server),
67
+ });
81
68
 
82
- /* console.log(
83
- boxen(`SERVER : ${PORT}`, {
84
- borderStyle: "round",
85
- title: `@dnax/server ${pkg.version}`,
86
- padding: 1,
87
- dimBorder: true,
88
- titleAlignment: "center",
89
- //float: "center",
90
- //margin: 1,
91
- borderColor: "gray",
92
- })
93
- ); */
94
- let info = "";
95
- let envName = process.env?.NODE_ENV || "dev";
96
- info += `${serverName}`.gray.underline.bold;
97
- info += `\n`;
98
- info += `\n`;
99
- info += `Env: ${envName}`.green.bold + "\n";
100
- info += `url: http://localhost:${PORT}\n`.gray.bold;
101
- //info += `Jwt Secret: ${Cfg.server.jwt?.secret}\n`.gray;
102
- info += `\n`;
103
- info += "TENANTS :".gray.underline.bold;
104
- info += `\n`;
105
- Cfg.tenants?.map((t: any) => {
106
- info += `\n${t?.name?.blue || "_"} : ${t?.id?.green}`.bold;
107
- });
108
- info += `\n\n`;
109
- info += `🔄 ${new Date().toLocaleString()}`.gray;
69
+ let serverName =
70
+ process.env.SERVER_NAME || Cfg?.server?.name || "SERVER";
110
71
 
111
- if (clb) clb();
72
+ let info = "";
73
+ let envName = process.env?.NODE_ENV || "dev";
74
+ info += `${serverName}`.gray.underline.bold;
75
+ info += `\n`;
76
+ info += `\n`;
77
+ info += `Env: ${envName}`.green.bold + "\n";
78
+ info += `url: http://localhost:${PORT}\n`.gray.bold;
79
+ //info += `Jwt Secret: ${Cfg.server.jwt?.secret}\n`.gray;
80
+ info += `\n`;
81
+ info += "TENANTS :".gray.underline.bold;
82
+ info += `\n`;
83
+ Cfg.tenants?.map((t: any) => {
84
+ info += `\n${t?.name?.blue || "_"} : ${t?.id?.green}`.bold;
85
+ });
86
+ info += `\n\n`;
87
+ info += `🔄 ${new Date().toLocaleString()}`.gray;
112
88
 
113
- console.log();
114
- console.log(
115
- boxen(info, {
116
- borderStyle: "double",
117
- title: `@dnax/server ${pkg.version}`,
118
- padding: 1.5,
119
- dimBorder: true,
89
+ if (clb) clb();
90
+ console.log(
91
+ boxen(info, {
92
+ borderStyle: "double",
93
+ title: `@dnax/server ${pkg.version}`,
94
+ padding: 1.5,
95
+ dimBorder: true,
120
96
 
121
- titleAlignment: "center",
122
- //float: "center",
123
- //margin: 1,
124
- borderColor: "gray",
125
- })
126
- );
97
+ titleAlignment: "center",
98
+ //float: "center",
99
+ //margin: 1,
100
+ borderColor: "gray",
101
+ })
102
+ );
127
103
 
128
- //AfterStart
129
- if (config?.afterStart) {
130
- for (const fn of config?.afterStart) {
131
- await fn({
132
- config: utils.copy(Cfg),
133
- });
104
+ //AfterStart
105
+ if (config?.afterStart) {
106
+ for (const fn of config?.afterStart) {
107
+ await fn({
108
+ config: utils.copy(Cfg),
109
+ });
110
+ }
134
111
  }
135
112
  }
136
- }
137
113
 
138
- return server;
139
- })
140
- .catch((err: any) => {
141
- console.error("Warning", err?.message);
142
- process.exit(1);
143
- });
114
+ return server;
115
+ })
116
+ .catch((err: any) => {
117
+ console.error(err);
118
+ process.exit(1);
119
+ });
120
+ } catch (err: any) {
121
+ consola.error(err?.message);
122
+ process.exit(1);
123
+ }
144
124
  }
145
125
 
146
126
  //process.on("exit", async () => {});
package/config/index.ts CHANGED
@@ -1,11 +1,10 @@
1
1
  import { cors } from "hono/cors";
2
- import { Config } from "./../types/index";
3
2
  import type { Config } from "../types";
4
3
  import fs from "fs-extra";
5
- import { systemCache } from "../lib/bento";
6
4
  import { Glob } from "bun";
7
5
  import path from "path";
8
6
  import { v4 } from "uuid";
7
+ import { consola } from "consola";
9
8
 
10
9
  const ROOT_PATH = process.cwd();
11
10
  const Cfg: Config = {
@@ -52,22 +51,7 @@ async function setCfg(config: Config) {
52
51
  }
53
52
 
54
53
  if (!Cfg?.server?.jwt?.secret) {
55
- let jwtSecret = await systemCache.get({
56
- key: ".jwt.json",
57
- });
58
- if (!jwtSecret) {
59
- jwtSecret = v4().replaceAll("-", "");
60
- await systemCache.set({
61
- key: ".jwt.json",
62
- value: jwtSecret,
63
- ttl: "2y",
64
- });
65
- }
66
- Cfg.server.jwt.secret = jwtSecret;
67
- }
68
-
69
- if (!Cfg?.server.jwt?.secret) {
70
- console.error("JWT_SECRET is not defined");
54
+ consola.error("JWT_SECRET is not defined".red);
71
55
  process.exit(1);
72
56
  }
73
57
 
@@ -24,6 +24,21 @@ export type findParam = {
24
24
  };
25
25
  };
26
26
 
27
+ export type restEventType = [
28
+ "*",
29
+ "insertOne",
30
+ "insertMany",
31
+ "updateOne",
32
+ "updateMany",
33
+ "deleteOne",
34
+ "deleteMany",
35
+ "find",
36
+ "findOne",
37
+ "findAndUpdate",
38
+ "findOneAndUpdate",
39
+ "aggregate",
40
+ "count"
41
+ ];
27
42
  export type findOneParam = {
28
43
  $match: object;
29
44
  $include?: Array<object>;
@@ -13,8 +13,8 @@ async function connectToMongo(t: Tenant) {
13
13
  await client
14
14
  .connect()
15
15
  .then((e) => {
16
- console.log("\n");
17
- consola.success(`DB connected : [${t.id}] ✅`.green);
16
+ //console.log("\n");
17
+ // consola.success(`DB connected : [${t.id}] ✅`.green);
18
18
  t.database.isConnected = true;
19
19
  t.database.client = client;
20
20
  t.database.db = client.db();
@@ -0,0 +1,85 @@
1
+ type options = {
2
+ uri: string;
3
+ binPath?: string;
4
+ };
5
+ import { consola } from "consola";
6
+ import { $ } from "bun";
7
+ import moment from "moment";
8
+
9
+ class DatabaseTools {
10
+ options: options;
11
+ constructor(options: options) {
12
+ this.options = options;
13
+ }
14
+ /**
15
+ * @param output - path to the output file
16
+ */
17
+ async backup(
18
+ filename: string,
19
+ path: string,
20
+ options?: {
21
+ debug?: boolean;
22
+ }
23
+ ) {
24
+ try {
25
+ consola.log("🔄 Backuping database to", path);
26
+ const { uri, binPath } = this.options;
27
+ const cmdBin = binPath ? `${binPath}/mongodump` : "mongodump";
28
+ let outputPath = path + "/" + filename + ".gz";
29
+ if (options?.debug) {
30
+ const output =
31
+ await $`${cmdBin} --uri ${uri} --archive=${outputPath} --gzip`;
32
+ console.log(output);
33
+ } else {
34
+ const output =
35
+ await $`${cmdBin} --uri ${uri} --archive=${outputPath} --gzip`.quiet();
36
+ }
37
+ console.log();
38
+
39
+ consola.log(`✅ Backup [${filename}] completed to [${path}]`.bold);
40
+ } catch (err: any) {
41
+ consola.error(err?.message);
42
+ }
43
+ }
44
+
45
+ async export(
46
+ collectionName: string,
47
+ databaseName: string,
48
+ path: string,
49
+ options?: {
50
+ debug?: boolean;
51
+ format?: "json" | "gz";
52
+ }
53
+ ) {
54
+ try {
55
+ consola.log(
56
+ `🔄 Exporting collection [${collectionName}] to [${path}]`.bold
57
+ );
58
+ let format = options?.format || "json";
59
+ const { uri, binPath } = this.options;
60
+ const cmdBin = binPath ? `${binPath}/mongoexport` : "mongoexport";
61
+ let outputPath = path + "/" + collectionName + ".json";
62
+ if (options?.debug) {
63
+ const output =
64
+ await $`${cmdBin} --uri ${uri} --db=${databaseName} --collection=${collectionName} --out=${outputPath} --jsonArray --pretty`;
65
+ console.log(output);
66
+ } else {
67
+ const output =
68
+ await $`${cmdBin} --uri ${uri} --db=${databaseName} --collection=${collectionName} --out=${outputPath} --jsonArray --pretty`.quiet();
69
+ }
70
+ console.log();
71
+
72
+ consola.log(
73
+ `✅[${collectionName}]'s collection exported to [${path}]`.bold
74
+ );
75
+ } catch (err: any) {
76
+ consola.error(err?.message);
77
+ }
78
+ }
79
+ }
80
+
81
+ function useDatabaseTools(options: options): DatabaseTools {
82
+ return new DatabaseTools(options);
83
+ }
84
+
85
+ export { useDatabaseTools };
@@ -23,6 +23,7 @@ import type {
23
23
  findOneParam,
24
24
  findParam,
25
25
  queryParam,
26
+ restEventType,
26
27
  updateParams,
27
28
  } from "./@types";
28
29
  import {
@@ -462,17 +463,6 @@ class useRest {
462
463
  });
463
464
  }
464
465
 
465
- try {
466
- col?.cache?.watch({
467
- action: "insertOne",
468
- c: this.#c,
469
- session: sessionStorage(),
470
- rest: this,
471
- state: col?.cache?.state || {},
472
- result: toJson(data),
473
- });
474
- } catch (err) {}
475
-
476
466
  // meilisearch engine
477
467
  if (
478
468
  this.#tenant?.searchEngine?.meilisearch?.enabled &&
@@ -621,16 +611,6 @@ class useRest {
621
611
  });
622
612
  }
623
613
 
624
- try {
625
- col?.cache?.watch({
626
- action: "insertMany",
627
- c: this.#c,
628
- session: sessionStorage(),
629
- rest: this,
630
- state: col?.cache?.state || {},
631
- result: toJson(data),
632
- });
633
- } catch (err) {}
634
614
  if (
635
615
  this.#tenant?.searchEngine?.meilisearch?.enabled &&
636
616
  col?.searchEngine?.meilisearch?.dispatchAction == "auto"
@@ -663,6 +643,8 @@ class useRest {
663
643
  }
664
644
  });
665
645
  }
646
+
647
+ //on(event: restEventType, clb: Function) {}
666
648
  /**
667
649
  *
668
650
  * @param queries
@@ -711,19 +693,14 @@ class useRest {
711
693
  collection: string,
712
694
  params?: findParam,
713
695
  options?: optionCb
714
- ): Promise<
715
- object[] | { data: object[]; meta: { total: number; count: number } }
716
- > {
696
+ ): Promise<{ _id: string; [key: string]: any }[]> {
717
697
  return new Promise(async (resolve, reject) => {
718
698
  try {
719
699
  if (!params) params = {};
720
700
  if (options?.cleanDeep) {
721
701
  params = cleanDeep(params);
722
702
  }
723
- let meta: { total: number; count: number } = {
724
- total: 0,
725
- count: 0,
726
- };
703
+
727
704
  let useHook = options?.useHook ?? this.#useHook;
728
705
  let useCustomApi = options?.useCustomApi ?? this.#useCustomApi;
729
706
  let sharedData = {};
@@ -789,22 +766,6 @@ class useRest {
789
766
 
790
767
  result.docs = toJson(result.docs);
791
768
 
792
- if (options?.withMeta) {
793
- meta.count = await this.#tenant.database.db
794
- ?.collection(collection)
795
- .countDocuments({
796
- ...(params?.$match || {}),
797
- })
798
- .then((e) => e || 0)
799
- .catch((err) => 0);
800
- meta.total = await this.#tenant.database.db
801
- ?.collection(collection)
802
- .estimatedDocumentCount();
803
- } else {
804
- meta.total = result.docs.length;
805
- meta.count = result.docs.length;
806
- }
807
-
808
769
  if (col?.hooks?.afterFind && useHook) {
809
770
  await col.hooks.afterFind({
810
771
  sharedData: sharedData,
@@ -830,13 +791,6 @@ class useRest {
830
791
  resultDocs = resultDocs[options?.elementAt] ?? null;
831
792
  }
832
793
 
833
- if (options?.withMeta) {
834
- return resolve({
835
- data: resultDocs,
836
- meta: meta,
837
- });
838
- }
839
-
840
794
  return resolve(resultDocs);
841
795
  } catch (err) {
842
796
  return reject(err);
@@ -847,10 +801,7 @@ class useRest {
847
801
  async count(
848
802
  collection: string,
849
803
  params: findParam,
850
- options?: Omit<
851
- optionCb,
852
- "useCustomApi" | "withMeta" | "elementAt" | "useHook"
853
- >
804
+ options?: Omit<optionCb, "useCustomApi" | "withMeta" | "elementAt">
854
805
  ): Promise<number> {
855
806
  return new Promise(async (resolve, reject) => {
856
807
  try {
@@ -1264,16 +1215,6 @@ class useRest {
1264
1215
  });
1265
1216
  }
1266
1217
 
1267
- try {
1268
- col?.cache?.watch({
1269
- action: "insertMany",
1270
- c: this.#c,
1271
- session: sessionStorage(),
1272
- rest: this,
1273
- state: col?.cache?.state || {},
1274
- result: toJson(result?.doc || {}),
1275
- });
1276
- } catch (err) {}
1277
1218
  if (
1278
1219
  this.#tenant?.searchEngine?.meilisearch?.enabled &&
1279
1220
  col?.searchEngine?.meilisearch?.dispatchAction == "auto"
@@ -1544,44 +1485,6 @@ class useRest {
1544
1485
  });
1545
1486
  }
1546
1487
 
1547
- async search(
1548
- collection: string,
1549
- term: string,
1550
- searchOptions: SearchParams
1551
- ): Promise<{
1552
- hits: Array<object>;
1553
- limit: number;
1554
- offset: number;
1555
- total: number;
1556
- processingTimeMs: number;
1557
- facetDistribution?: object;
1558
- facetsStats?: object;
1559
- estimatedTotalHits?: number;
1560
- totalHits?: number;
1561
- hitsPerPage?: number;
1562
- page?: number;
1563
- }> {
1564
- return new Promise(async (resolve, reject) => {
1565
- try {
1566
- let index = getCollection(collection, this.#tenant_id)?.searchEngine
1567
- ?.meilisearch?.index!;
1568
-
1569
- if (!index)
1570
- return reject({
1571
- code: 400,
1572
- message: "Search engine Index required",
1573
- });
1574
-
1575
- let result = this.meilisearch.client.index(index).search(term, {
1576
- ...searchOptions,
1577
- });
1578
- resolve(result);
1579
- } catch (err) {
1580
- return reject(err);
1581
- }
1582
- });
1583
- }
1584
-
1585
1488
  async updateMany(
1586
1489
  collection: string,
1587
1490
  ids: Array<string>,
@@ -1746,16 +1649,6 @@ class useRest {
1746
1649
  });
1747
1650
  }
1748
1651
 
1749
- try {
1750
- col?.cache?.watch({
1751
- action: "updateMany",
1752
- c: this.#c,
1753
- session: sessionStorage(),
1754
- rest: this,
1755
- state: col?.cache?.state || {},
1756
- result: toJson(result?.docs || []),
1757
- });
1758
- } catch (err) {}
1759
1652
  if (
1760
1653
  this.#tenant?.searchEngine?.meilisearch?.enabled &&
1761
1654
  col?.searchEngine?.meilisearch?.dispatchAction == "auto"
@@ -1885,16 +1778,6 @@ class useRest {
1885
1778
  });
1886
1779
  }
1887
1780
 
1888
- try {
1889
- col?.cache?.watch({
1890
- action: "deleteOne",
1891
- c: this.#c,
1892
- session: sessionStorage(),
1893
- rest: this,
1894
- state: col?.cache?.state || {},
1895
- result: toJson(doc || {}),
1896
- });
1897
- } catch (err) {}
1898
1781
  if (
1899
1782
  this.#tenant?.searchEngine?.meilisearch?.enabled &&
1900
1783
  col?.searchEngine?.meilisearch?.dispatchAction == "auto"
@@ -2027,16 +1910,6 @@ class useRest {
2027
1910
  });
2028
1911
  }
2029
1912
 
2030
- try {
2031
- col?.cache?.watch({
2032
- action: "deleteMany",
2033
- c: this.#c,
2034
- session: sessionStorage(),
2035
- rest: this,
2036
- state: col?.cache?.state || {},
2037
- result: deletedIds || [],
2038
- });
2039
- } catch (err) {}
2040
1913
  if (
2041
1914
  this.#tenant?.searchEngine?.meilisearch?.enabled &&
2042
1915
  col?.searchEngine?.meilisearch?.dispatchAction == "auto"
package/index.ts CHANGED
@@ -6,13 +6,12 @@ import * as v from "joi";
6
6
  import { $ } from "bun";
7
7
  import define from "./define";
8
8
  import * as utils from "./utils";
9
- import { dataCache } from "./lib/bento";
10
9
  import { FilesystemSftpAdapter, MinioAdapter } from "./lib/media";
11
10
  import { crypt } from "./lib/crypto";
12
11
  import { contextStorage } from "./lib/asyncLocalStorage";
13
12
  import { Cron as Task } from "croner";
14
- import { useWorkflow } from "./lib/workflow";
15
13
  import { serveStatic } from "hono/bun";
14
+ import { useDatabaseTools } from "./driver/mongo/database";
16
15
  // Adapter
17
16
 
18
17
  const Adapter = {
@@ -32,11 +31,10 @@ export {
32
31
  utils,
33
32
  useRest,
34
33
  v,
35
- dataCache,
36
34
  Task,
37
35
  crypt,
38
36
  $,
39
37
  contextStorage,
40
38
  Adapter,
41
- //useWorkflow,
39
+ useDatabaseTools,
42
40
  };
@@ -1,6 +1,5 @@
1
1
  import { AsyncLocalStorage } from "node:async_hooks";
2
2
  import type { sessionCtx } from "../types";
3
- import { localSession } from "./session";
4
3
  import { v4 } from "uuid";
5
4
  import { jwt, uuid } from "../utils";
6
5
  import { Cfg } from "../config";
@@ -19,61 +19,4 @@ if (!fs?.existsSync(path.resolve(cacheDirectoryData + "bentocache"))) {
19
19
  });
20
20
  }
21
21
 
22
- const systemCache = new BentoCache({
23
- default: "systemCache",
24
-
25
- stores: {
26
- systemCache: bentostore().useL2Layer(
27
- fileDriver({
28
- directory: cacheDirectory,
29
- pruneInterval: "1h",
30
- //maxSize: 100 * 1024 * 1024,
31
- })
32
- ),
33
- },
34
- });
35
-
36
- const dataCache = new BentoCache({
37
- default: "dataCache",
38
- stores: {
39
- dataCache: bentostore().useL2Layer(
40
- fileDriver({
41
- directory: cacheDirectoryData,
42
- pruneInterval: false,
43
-
44
- //maxSize: 100 * 1024 * 1024,
45
- })
46
- ),
47
- },
48
- });
49
-
50
- const bentoCache = new BentoCache({
51
- default: "dnaxCache",
52
- stores: {
53
- dnaxCache: bentostore().useL1Layer(
54
- memoryDriver({
55
- maxSize: 100 * 1024 * 1024,
56
- })
57
- ),
58
- },
59
- });
60
-
61
- function bentoKey(data: object | string) {
62
- let key = "";
63
- if (data) {
64
- if (typeof data == "object") {
65
- key = JSON.stringify(data);
66
- key = key.replace(/\s/g, "").trim();
67
- }
68
-
69
- if (typeof data == "string") {
70
- key = data.replace(/\s/g, "").trim();
71
- }
72
- }
73
-
74
- return key;
75
- }
76
-
77
- const sessionCache = systemCache.namespace("tokens");
78
-
79
- export { bentoCache, bentoKey, systemCache, sessionCache, dataCache };
22
+ export {};
package/lib/collection.ts CHANGED
@@ -43,7 +43,7 @@ async function loadAllCollections() {
43
43
 
44
44
  function getCollection(
45
45
  name: string,
46
- tenant_id: string | number
46
+ tenant_id: string
47
47
  ): Collection | undefined | null {
48
48
  if (Cfg?.collections?.length) {
49
49
  return Cfg.collections.find((col: Collection) => {
package/lib/index.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { loadAllCollections, syncCollectionDatabase } from "./collection";
2
- import { syncMeilisearchClientOnTenant } from "./meilisearch";
3
2
  import { connectTenantsDatabase } from "../driver";
4
3
  import { loadEndpoints } from "./endpoint";
5
4
  import { loadServices } from "./service";
@@ -10,41 +9,67 @@ import { loadAutoRoutes } from "./routes";
10
9
  import { initScript } from "../lib/scripts";
11
10
  import { syncAdapterFileSystem } from "./media";
12
11
  import { runGenTypes } from "../types/gen";
12
+ import consola from "consola";
13
+ import ora from "ora";
13
14
 
14
15
  // load all ressource
15
16
  async function init(cf = { app: null }) {
17
+ console.log("\n");
18
+ const spinner = ora("Initializing...").start();
19
+ spinner.color = "green";
20
+
21
+ //console.log("🔄 Initializing...".blue);
16
22
  await loadSocket();
23
+ //consola.success("Loaded socket");
17
24
  // load all tenants database
18
25
  await connectTenantsDatabase();
26
+ // consola.success("Loaded tenants database");
19
27
  // load all collections
20
28
  await loadAllCollections();
29
+ //consola.success("Loaded collections");
21
30
 
22
31
  // load all permissions
23
32
  await loadPermissions();
33
+ //consola.success("Loaded permissions");
24
34
 
25
35
  // sync all collections database ( Indexes)
26
36
  syncCollectionDatabase();
37
+ //consola.success("Synced collections database");
27
38
 
28
- // sync
29
- syncMeilisearchClientOnTenant();
39
+ runGenTypes();
30
40
 
31
41
  // load Service
32
42
  loadServices();
43
+ //consola.success("Loaded services");
33
44
 
34
45
  // sync all adapter file system
35
46
  syncAdapterFileSystem();
47
+ //consola.success(" adapter file system");
36
48
 
37
49
  // load all loadEndpoints
38
50
  await loadEndpoints();
51
+ // consola.success("Loaded endpoints");
39
52
 
40
53
  // load auto routes
41
54
  await loadAutoRoutes();
55
+ //consola.success("Loaded auto routes");
42
56
 
43
57
  await initCron();
44
-
45
- runGenTypes();
58
+ //consola.success("Loaded cron/Tasks");
46
59
 
47
60
  initScript();
61
+ //consola.success("Loaded scripts");
62
+ //spinner.clear();
63
+ spinner.stop();
64
+ spinner.clear();
65
+ console.log(
66
+ "\n---------------------------------------\n".gray +
67
+ "\n✨ Your server is up and running\n".green.bold +
68
+ "---------------------------------------\n".gray +
69
+ `🌍 Environment : ${process.env.NODE_ENV || "development"}\n`.gray +
70
+ `🕒 Started at : ${new Date().toLocaleString()}\n`.gray +
71
+ "---------------------------------------\n".gray
72
+ );
48
73
  }
49
74
 
50
75
  export { init };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dnax/core",
3
- "version": "0.66.3",
3
+ "version": "0.67.1",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "bin": {},
@@ -9,9 +9,9 @@
9
9
  "@types/dot-object": "^2.1.6",
10
10
  "@types/fs-extra": "^11.0.4",
11
11
  "@types/jsonwebtoken": "9.0.9",
12
- "@types/mime-types": "^2.1.4",
12
+ "@types/mime-types": "^3.0.1",
13
13
  "@types/minio": "^7.1.1",
14
- "@types/nodemailer": "^6.4.15",
14
+ "@types/nodemailer": "^6.4.17",
15
15
  "@types/pidusage": "^2.0.5",
16
16
  "@types/ssh2-sftp-client": "^9.0.4",
17
17
  "@types/uuid": "^10.0.0"
@@ -22,7 +22,8 @@
22
22
  "dependencies": {
23
23
  "@colors/colors": "^1.6.0",
24
24
  "@lukeed/ms": "^2.0.2",
25
- "bentocache": "^1.2.1",
25
+ "@types/blessed": "^0.1.25",
26
+ "bentocache": "^1.5.0",
26
27
  "boxen": "^7.1.1",
27
28
  "chokidar": "3.6.0",
28
29
  "clean-deep": "^3.4.0",
@@ -32,22 +33,19 @@
32
33
  "croner": "8.1.1",
33
34
  "deepcopy": "^2.1.0",
34
35
  "dot-object": "2.1.5",
35
- "find-open-port": "^2.0.3",
36
36
  "fs-extra": "^11.2.0",
37
37
  "generate-unique-id": "^2.0.3",
38
- "hono": "4.6.14",
38
+ "hono": "4.8.9",
39
39
  "joi": "17.13.3",
40
40
  "json-joy": "16.8.0",
41
41
  "jsonwebtoken": "^9.0.2",
42
- "meilisearch": "^0.50.0",
43
42
  "mime-types": "^2.1.35",
44
- "mingo": "^6.5.0",
45
43
  "minio": "^8.0.5",
46
44
  "moment": "^2.30.1",
47
- "mongodb": "6.17.0",
48
- "nodemailer": "^6.9.14",
45
+ "mongodb": "6.18.0",
46
+ "nodemailer": "^7.0.5",
47
+ "ora": "^8.2.0",
49
48
  "pidusage": "^4.0.0",
50
- "pizzip": "^3.1.8",
51
49
  "radash": "^12.1.0",
52
50
  "rfc6902": "^5.1.2",
53
51
  "sharp": "^0.33.5",
package/types/index.ts CHANGED
@@ -320,70 +320,7 @@ export type Collection = {
320
320
  findOne?: (ctx: ctxApi) => object;
321
321
  count?: (ctx: ctxApi) => number;
322
322
  };
323
- searchEngine?: {
324
- meilisearch: {
325
- /**
326
- * unique name of the index on meilisearch
327
- */
328
- index: string;
329
- primaryKey?: string;
330
- /**
331
- * default value :auto
332
- */
333
- dispatchAction: "auto" | "manual";
334
- filterableAttributes?: Array<string>;
335
- };
336
- };
337
- /**
338
- * Cache available for action 'find' | 'findOne'
339
- */
340
- cache?: {
341
- enabled?: boolean;
342
- state?: {
343
- [key: string]: any;
344
- };
345
- init?: (ctx: {
346
- rest: InstanceType<typeof useRest>;
347
- state: {
348
- [key: string]: any;
349
- };
350
- }) => void;
351
- watch: (ctx: {
352
- action:
353
- | "insertOne"
354
- | "insertMany"
355
- | "updateOne"
356
- | "updateMany"
357
- | "deleteOne"
358
- | "deleteMany"
359
- | "findOneAndUpdate";
360
- rest: InstanceType<typeof useRest>;
361
- c?: Context;
362
- session?: sessionCtx;
363
- result: any;
364
- state: {
365
- [key: string]: any;
366
- };
367
- }) => void;
368
- fetch?: (ctx: {
369
- state: {
370
- [key: string]: any;
371
- };
372
- body: {
373
- params: findParam;
374
- pipeline: Array<object>;
375
- withMeta: boolean;
376
- };
377
- key: string;
378
- action: "find" | "aggregate";
379
- rest: InstanceType<typeof useRest>;
380
- c: Context;
381
- session: sessionCtx;
382
- }) => {
383
- isStale: boolean;
384
- data: any;
385
- };
386
- };
323
+
387
324
  schema?: object;
388
325
  auth?: {
389
326
  enabled?: boolean;
package/utils/os.ts CHANGED
@@ -1 +1,22 @@
1
- function Os() {}
1
+ import pidusage from "pidusage";
2
+
3
+ /**
4
+ * Retourne les stats CPU/RAM pour un ou plusieurs PIDs.
5
+ * @param {number[]} pids - Liste des PIDs à surveiller.
6
+ * @returns {Promise<{ pid: number, cpu: number, ram: number, elapsed: number }[]>}
7
+ */
8
+ export async function getPidUsage(pids = [process.pid]) {
9
+ try {
10
+ const stats = await pidusage(pids);
11
+
12
+ return Object.entries(stats).map(([pid, usage]) => ({
13
+ pid: Number(pid),
14
+ cpu: usage.cpu, // en %
15
+ ram: usage.memory / 1024 / 1024, // en MB
16
+ elapsed: usage.elapsed / 1000, // uptime en secondes
17
+ }));
18
+ } catch (err) {
19
+ console.error("Erreur getPidUsage:", err.message);
20
+ return [];
21
+ }
22
+ }
package/utils/port.ts ADDED
@@ -0,0 +1,41 @@
1
+ import net from "net";
2
+ import type { AddressInfo } from "net";
3
+ function findPort() {
4
+ return new Promise((resolve, reject) => {
5
+ const server = net.createServer();
6
+ server.on("error", reject);
7
+ server.listen(0, () => {
8
+ const { port, address } = server.address() as AddressInfo;
9
+ server.on("close", resolve.bind(null, port));
10
+ server.close();
11
+ });
12
+ });
13
+ }
14
+
15
+ function isAvailable(port: number): Promise<boolean> {
16
+ return new Promise((resolve, reject) => {
17
+ const socket = net.connect(port);
18
+ socket.setTimeout(500, () => {
19
+ socket.destroy();
20
+ const error = new Error("ETIMEDOUT") as any;
21
+ error.code = "ETIMEDOUT";
22
+ reject(error);
23
+ });
24
+ socket.on("error", (error: any) => {
25
+ if (error.code === "ECONNREFUSED") {
26
+ return resolve(true);
27
+ }
28
+ return reject(error);
29
+ });
30
+ socket.on("connect", () => {
31
+ socket.destroy();
32
+ resolve(false);
33
+ });
34
+ });
35
+ }
36
+
37
+ findPort.findPort = findPort;
38
+ findPort.default = findPort;
39
+ findPort.isAvailable = isAvailable;
40
+
41
+ export { findPort };
package/bin/_.ts DELETED
@@ -1,121 +0,0 @@
1
- #! /usr/bin/env bun
2
-
3
- import ch from "chokidar";
4
- import { spinner } from "@clack/prompts";
5
- import "@colors/colors";
6
- var exec;
7
- var s = spinner();
8
- function runPkg(
9
- opts = {
10
- stopSpinner: false,
11
- }
12
- ) {
13
- if (opts?.stopSpinner) {
14
- s.stop();
15
- }
16
-
17
- exec = Bun.spawn([`bun`, `index.ts`], {
18
- stdio: ["inherit", "inherit", "inherit"],
19
- serialization: "json",
20
- stdin: "inherit",
21
- ipc(message, subprocess) {
22
- console.log(message);
23
- },
24
- });
25
- }
26
-
27
- // Écoutez le signal SIGINT (Ctrl + C)
28
- process.on("SIGINT", () => {
29
- if (exec?.kill) exec.kill();
30
- process.exit(1); // Terminez le processus principal
31
- });
32
-
33
- ch.watch(".", {
34
- cwd: process.cwd(),
35
- ignored: [
36
- /.*\.(jpg|jpeg|png|gif|bmp|svg|webp|dump|zip|rar|.git|.lockb|package.json)$/i,
37
- /node_modules|node_modules\/.*/,
38
- /node_modules/,
39
- /(^|[\/\\])\../,
40
- "node_modules/**/*",
41
- ".env.*",
42
- ".env",
43
- ".nitro",
44
- ".git",
45
- ".output",
46
- ".vscode",
47
- ".idea",
48
- ".DS_Store",
49
- ".env.local",
50
- ".env.development",
51
- ".env.test",
52
- ".env.production",
53
- "node_modules",
54
- "package.json",
55
- "package-lock.json",
56
- "yarn.lock",
57
- "yarn-error.log",
58
- "bun.lockb",
59
- "bun.lock",
60
- "*.docs",
61
- ".docx",
62
- ".pdf",
63
- ".xlsx",
64
- ".pptx",
65
- ".zip",
66
- "package-lock.json",
67
- "yarn.lock",
68
- "tsconfig.json",
69
- "tsconfig.tsbuildinfo",
70
- "*.tsbuildinfo",
71
- "*.log",
72
- "*.tgz",
73
- "/.git",
74
- "/.github",
75
- "/.vscode",
76
- "/.idea",
77
- "/coverage",
78
- "/dist",
79
- "/build",
80
- "/node_modules",
81
- "/package-lock.json",
82
- "/yarn.lock",
83
- ".cache",
84
- "dist",
85
- "*/dist",
86
- "*.zip",
87
- "*.log",
88
- ".DS_Store",
89
- "*.tar",
90
- "*.tar.gz",
91
- "build",
92
- "*.lockb",
93
- "coverage",
94
- "packages/*/dist",
95
- "packages/*/build",
96
- "packages/*/coverage",
97
- "packages/*/node_modules",
98
- ],
99
- })
100
- .on("change", (path) => {
101
- console.log("Changed file:".gray, path.green);
102
- let dev = process.argv.includes("--dev");
103
- if (dev && (path?.endsWith(".ts") || path?.endsWith(".js"))) {
104
- s.start("Restarting due to changes ...");
105
- if (exec?.kill) {
106
- exec.kill();
107
- }
108
- setTimeout(() => {
109
- runPkg({ stopSpinner: true });
110
- }, 1500);
111
- }
112
- })
113
- .on("ready", () => {
114
- let dev = process.argv.includes("--dev");
115
- let start = process.argv.includes("--start");
116
- if (dev || start) {
117
- runPkg();
118
- } else {
119
- process.exit();
120
- }
121
- });
@@ -1,25 +0,0 @@
1
- import { MeiliSearch } from "meilisearch";
2
- import { Cfg } from "../../config";
3
- function getClient(config: {
4
- host: string;
5
- apiKey?: string;
6
- }): InstanceType<typeof MeiliSearch> {
7
- const client = new MeiliSearch({
8
- host: config?.host,
9
- apiKey: config?.apiKey,
10
- });
11
- return client;
12
- }
13
-
14
- async function syncMeilisearchClientOnTenant() {
15
- for await (let t of Cfg.tenants) {
16
- if (t?.searchEngine?.meilisearch?.enabled) {
17
- t.searchEngine.meilisearch.client = getClient({
18
- host: t.searchEngine.meilisearch.host,
19
- apiKey: t.searchEngine.meilisearch.apiKey,
20
- });
21
- }
22
- }
23
- }
24
-
25
- export { MeiliSearch, getClient, syncMeilisearchClientOnTenant };