@dnax/core 0.18.4 → 0.18.6
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 +10 -2
- package/define/index.ts +2 -0
- package/index.ts +8 -0
- package/lib/index.ts +4 -0
- package/lib/media/SyncAdapter.ts +22 -0
- package/lib/{media.ts → media/index.ts} +3 -1
- package/lib/media/sftp.ts +123 -0
- package/lib/schema.ts +2 -2
- package/package.json +6 -5
- package/types/index.ts +7 -1
package/app/hono.ts
CHANGED
|
@@ -251,6 +251,8 @@ function HonoInstance(): typeof app {
|
|
|
251
251
|
}
|
|
252
252
|
});
|
|
253
253
|
|
|
254
|
+
//
|
|
255
|
+
|
|
254
256
|
// API REST
|
|
255
257
|
app.post(cleanPath(API_PATH), async (c) => {
|
|
256
258
|
try {
|
|
@@ -262,7 +264,7 @@ function HonoInstance(): typeof app {
|
|
|
262
264
|
var response;
|
|
263
265
|
var parseBody;
|
|
264
266
|
var body;
|
|
265
|
-
var { action, collection, cleanDeep, useCache, name } =
|
|
267
|
+
var { action, collection, cleanDeep, useCache, name, toolkit } =
|
|
266
268
|
c.req.query() as Q;
|
|
267
269
|
if (
|
|
268
270
|
c.req.raw?.headers
|
|
@@ -297,8 +299,14 @@ function HonoInstance(): typeof app {
|
|
|
297
299
|
throw new contextError(`Action ${action} not found`, 400);
|
|
298
300
|
}
|
|
299
301
|
|
|
300
|
-
|
|
302
|
+
if (action == "execToolkit") {
|
|
303
|
+
let tookit = toolkit;
|
|
304
|
+
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
301
308
|
if (action == "execService") {
|
|
309
|
+
// Exec service
|
|
302
310
|
if (!service) return fn.error("Service not found", 404);
|
|
303
311
|
let fx = service?.exec || service?.fx;
|
|
304
312
|
if (fx) {
|
package/define/index.ts
CHANGED
package/index.ts
CHANGED
|
@@ -7,9 +7,16 @@ import { $ } from "bun";
|
|
|
7
7
|
import define from "./define";
|
|
8
8
|
import * as utils from "./utils";
|
|
9
9
|
import { dataCache } from "./lib/bento";
|
|
10
|
+
import { FilesystemSftpAdapter } from "./lib/media";
|
|
10
11
|
import { crypt } from "./lib/crypto";
|
|
11
12
|
import { contextStorage } from "./lib/asyncLocalStorage";
|
|
12
13
|
|
|
14
|
+
// Adapter
|
|
15
|
+
|
|
16
|
+
const Adapter = {
|
|
17
|
+
FilesystemSftpAdapter,
|
|
18
|
+
};
|
|
19
|
+
|
|
13
20
|
/**
|
|
14
21
|
* v is internal data validation and based of Joi validation.
|
|
15
22
|
* Note : v is an alias of Joi object API .
|
|
@@ -27,4 +34,5 @@ export {
|
|
|
27
34
|
crypt,
|
|
28
35
|
$,
|
|
29
36
|
contextStorage,
|
|
37
|
+
Adapter,
|
|
30
38
|
};
|
package/lib/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { loadPermissions } from "./permissions";
|
|
|
7
7
|
import { loadSocket } from "../lib/socket";
|
|
8
8
|
import { loadAutoRoutes } from "./routes";
|
|
9
9
|
import { initScript } from "../lib/scripts";
|
|
10
|
+
import { syncAdapterFileSystem } from "./media";
|
|
10
11
|
// load all ressource
|
|
11
12
|
async function init(cf = { app: null }) {
|
|
12
13
|
await loadSocket();
|
|
@@ -24,6 +25,9 @@ async function init(cf = { app: null }) {
|
|
|
24
25
|
// load Service
|
|
25
26
|
loadServices();
|
|
26
27
|
|
|
28
|
+
// sync all adapter file system
|
|
29
|
+
syncAdapterFileSystem();
|
|
30
|
+
|
|
27
31
|
// load all loadEndpoints
|
|
28
32
|
await loadEndpoints();
|
|
29
33
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Cfg } from "../../config";
|
|
2
|
+
import { FilesystemSftpAdapter } from "../media/sftp";
|
|
3
|
+
async function syncAdapterFileSystem() {
|
|
4
|
+
const mediaCollections = Cfg.collections?.filter(
|
|
5
|
+
(col) => col.type == "media" && col?.media?.enabled
|
|
6
|
+
);
|
|
7
|
+
|
|
8
|
+
mediaCollections?.map((col) => {
|
|
9
|
+
if (col?.media?.filesystemAdapter) {
|
|
10
|
+
let currentAdapter = col?.media?.filesystemAdapter;
|
|
11
|
+
// for sftp
|
|
12
|
+
if (currentAdapter?.type == "sftp") {
|
|
13
|
+
let setAdapter = col?.media?.filesystemAdapter as InstanceType<
|
|
14
|
+
typeof FilesystemSftpAdapter
|
|
15
|
+
>;
|
|
16
|
+
setAdapter.init(col);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { syncAdapterFileSystem };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { cleanDoubleSlashes } from "ufo";
|
|
2
|
+
import { FilesystemSftpAdapter } from "./sftp";
|
|
3
|
+
import { syncAdapterFileSystem } from "./SyncAdapter";
|
|
2
4
|
import fs from "fs";
|
|
3
5
|
import { v4 } from "uuid";
|
|
4
6
|
type driverOptions = {
|
|
@@ -71,4 +73,4 @@ class MediaDrive {
|
|
|
71
73
|
}
|
|
72
74
|
}
|
|
73
75
|
|
|
74
|
-
export { MediaDrive };
|
|
76
|
+
export { MediaDrive, FilesystemSftpAdapter, syncAdapterFileSystem };
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
type args = "--delete";
|
|
2
|
+
type config = {
|
|
3
|
+
host: string;
|
|
4
|
+
port?: number;
|
|
5
|
+
username: string;
|
|
6
|
+
password: string;
|
|
7
|
+
remoteDir: string;
|
|
8
|
+
ignorePatterns?: string[];
|
|
9
|
+
args?: args[];
|
|
10
|
+
};
|
|
11
|
+
import Client from "ssh2-sftp-client";
|
|
12
|
+
import chokidar from "chokidar";
|
|
13
|
+
import fs from "fs-extra";
|
|
14
|
+
import path from "path";
|
|
15
|
+
import { cleanDoubleSlashes } from "ufo";
|
|
16
|
+
import type { Collection } from "../../types";
|
|
17
|
+
|
|
18
|
+
class FilesystemSftpAdapter {
|
|
19
|
+
#sftp;
|
|
20
|
+
type: "sftp" = "sftp";
|
|
21
|
+
#connected: Boolean = false;
|
|
22
|
+
config;
|
|
23
|
+
constructor(config: config) {
|
|
24
|
+
this.config = config;
|
|
25
|
+
this.config.port = config?.port || 22;
|
|
26
|
+
this.#sftp = new Client();
|
|
27
|
+
this.type = "sftp";
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async connect() {
|
|
32
|
+
await this.#sftp
|
|
33
|
+
.connect(this.config)
|
|
34
|
+
.then((e) => {
|
|
35
|
+
this.#connected = true;
|
|
36
|
+
})
|
|
37
|
+
.catch((err) => {
|
|
38
|
+
console.log(err, "error");
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async sync(
|
|
43
|
+
p: string,
|
|
44
|
+
type: "add" | "change" | "unlink" | "addDir" | "unlinkDir"
|
|
45
|
+
) {
|
|
46
|
+
try {
|
|
47
|
+
let remotePathDest =
|
|
48
|
+
this.config.remoteDir + p?.replace(process.cwd(), "");
|
|
49
|
+
let remoteDir = path.dirname(remotePathDest);
|
|
50
|
+
|
|
51
|
+
//let remoteFile = remotePathDest.replace(/\\/g, "/");
|
|
52
|
+
|
|
53
|
+
if (fs.existsSync(p)) {
|
|
54
|
+
let stats = fs.statSync(p);
|
|
55
|
+
if (stats.isFile()) {
|
|
56
|
+
await this.#sftp.mkdir(remoteDir, true).catch();
|
|
57
|
+
// Téléverser le fichier
|
|
58
|
+
let alreadyExists = await this.#sftp.exists(remotePathDest);
|
|
59
|
+
if (!alreadyExists) {
|
|
60
|
+
await this.#sftp.put(p, remotePathDest, {}).catch((err) => {
|
|
61
|
+
console.error("Fichier televerser", err?.message);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
} else {
|
|
66
|
+
// Supprimer le fichier
|
|
67
|
+
this.#sftp.delete(remotePathDest);
|
|
68
|
+
}
|
|
69
|
+
} catch (err: any) {
|
|
70
|
+
console.error(err?.message);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
watchDir(dir: string) {
|
|
75
|
+
try {
|
|
76
|
+
let local_dir = cleanDoubleSlashes(dir);
|
|
77
|
+
const watcher = chokidar.watch(path.resolve(local_dir), {
|
|
78
|
+
persistent: true,
|
|
79
|
+
ignoreInitial: false,
|
|
80
|
+
ignored: this?.config?.ignorePatterns || [],
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
watcher
|
|
84
|
+
.on("add", (path) => this.sync(path, "add"))
|
|
85
|
+
.on("change", (path) => this.sync(path, "change"))
|
|
86
|
+
.on("unlink", (path) => this.sync(path, "unlink"))
|
|
87
|
+
.on("addDir", (path) => this.sync(path, "addDir"))
|
|
88
|
+
.on("unlinkDir", (path) => this.sync(path, "unlinkDir"));
|
|
89
|
+
} catch (err: any) {
|
|
90
|
+
console.error(err?.message);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async init(col: Collection) {
|
|
95
|
+
let buildPath = "/uploads/";
|
|
96
|
+
if (!col?.media?.visibility && col?.media?.enabled) {
|
|
97
|
+
col.media.visibility = "public";
|
|
98
|
+
}
|
|
99
|
+
buildPath += col?.slug + "/" + col?.media?.visibility;
|
|
100
|
+
let watchLocalDir = path.resolve(process.cwd() + "/" + buildPath);
|
|
101
|
+
|
|
102
|
+
await this.connect().then(async (ops) => {
|
|
103
|
+
let remoteDir = this.config.remoteDir + buildPath;
|
|
104
|
+
|
|
105
|
+
let remoteDirExisis = await this.#sftp.exists(remoteDir);
|
|
106
|
+
|
|
107
|
+
//console.log("remoteDirExisis", remoteDir, remoteDirExisis);
|
|
108
|
+
|
|
109
|
+
if (!remoteDirExisis) {
|
|
110
|
+
await this.#sftp.mkdir(remoteDir, true).catch((err) => {});
|
|
111
|
+
// console.log("Watch", watchLocalDir);
|
|
112
|
+
|
|
113
|
+
setTimeout(() => {
|
|
114
|
+
this.watchDir(watchLocalDir);
|
|
115
|
+
}, 1000);
|
|
116
|
+
} else {
|
|
117
|
+
this.watchDir(watchLocalDir);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export { FilesystemSftpAdapter };
|
package/lib/schema.ts
CHANGED
|
@@ -19,7 +19,7 @@ function buildSchema(col: Collection) {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
if (f?.type == "uuid") {
|
|
22
|
-
propertySchema[f.name] = v.string();
|
|
22
|
+
propertySchema[f.name] = v.string().uuid();
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
if (f?.type == "random") {
|
|
@@ -33,7 +33,7 @@ function buildSchema(col: Collection) {
|
|
|
33
33
|
propertySchema[f.name] = v.string().optional();
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
if (f?.type.match(/(string|richText|textarea|markdown)/)) {
|
|
36
|
+
if (f?.type.match(/(string|richText|textarea|markdown|color)/)) {
|
|
37
37
|
propertySchema[f.name] = v.string();
|
|
38
38
|
}
|
|
39
39
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dnax/core",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.6",
|
|
4
4
|
"module": "index.ts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,13 +8,14 @@
|
|
|
8
8
|
},
|
|
9
9
|
"devDependencies": {
|
|
10
10
|
"@types/bun": "latest",
|
|
11
|
+
"@types/dot-object": "^2.1.6",
|
|
11
12
|
"@types/fs-extra": "^11.0.4",
|
|
13
|
+
"@types/jsonwebtoken": "9.0.6",
|
|
12
14
|
"@types/mime-types": "^2.1.4",
|
|
13
15
|
"@types/nodemailer": "^6.4.15",
|
|
14
16
|
"@types/pidusage": "^2.0.5",
|
|
15
|
-
"@types/
|
|
16
|
-
"@types/
|
|
17
|
-
"@types/jsonwebtoken": "9.0.6"
|
|
17
|
+
"@types/ssh2-sftp-client": "^9.0.4",
|
|
18
|
+
"@types/uuid": "^10.0.0"
|
|
18
19
|
},
|
|
19
20
|
"peerDependencies": {
|
|
20
21
|
"typescript": "^5.0.0"
|
|
@@ -23,7 +24,6 @@
|
|
|
23
24
|
"@clack/prompts": "^0.7.0",
|
|
24
25
|
"@colors/colors": "^1.6.0",
|
|
25
26
|
"@lukeed/ms": "^2.0.2",
|
|
26
|
-
"@orama/orama": "^2.0.23",
|
|
27
27
|
"bentocache": "^1.0.0-beta.9",
|
|
28
28
|
"boxen": "^7.1.1",
|
|
29
29
|
"chokidar": "3.6.0",
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
"rfc6902": "^5.1.2",
|
|
55
55
|
"sharp": "^0.33.5",
|
|
56
56
|
"signaldb": "^0.24.0",
|
|
57
|
+
"ssh2-sftp-client": "^11.0.0",
|
|
57
58
|
"ufo": "^1.5.3",
|
|
58
59
|
"urlencode": "^2.0.0",
|
|
59
60
|
"uuid": "^10.0.0"
|
package/types/index.ts
CHANGED
|
@@ -69,6 +69,7 @@ export type Field = {
|
|
|
69
69
|
| "number"
|
|
70
70
|
| "integer"
|
|
71
71
|
| "password"
|
|
72
|
+
| "color"
|
|
72
73
|
| "random"
|
|
73
74
|
| "relationship"
|
|
74
75
|
| "string"
|
|
@@ -238,6 +239,7 @@ export type Collection = {
|
|
|
238
239
|
* Mimie type to accept
|
|
239
240
|
*/
|
|
240
241
|
accept?: Array<string> | string;
|
|
242
|
+
filesystemAdapter?: any;
|
|
241
243
|
};
|
|
242
244
|
customApi?: {
|
|
243
245
|
insertOne?: (ctx: ctxApi) => object | null | undefined;
|
|
@@ -428,7 +430,10 @@ export type Config = {
|
|
|
428
430
|
io?: any;
|
|
429
431
|
};
|
|
430
432
|
|
|
433
|
+
export type Toolkit = "database" | "activity" | "tasks" | "server";
|
|
434
|
+
|
|
431
435
|
export type Q = {
|
|
436
|
+
toolkit: Toolkit;
|
|
432
437
|
name: string;
|
|
433
438
|
useCache: boolean;
|
|
434
439
|
cleanDeep: boolean;
|
|
@@ -449,7 +454,8 @@ export type Q = {
|
|
|
449
454
|
| "upload"
|
|
450
455
|
| "execService"
|
|
451
456
|
| "batch"
|
|
452
|
-
| "count"
|
|
457
|
+
| "count"
|
|
458
|
+
| "execToolkit";
|
|
453
459
|
};
|
|
454
460
|
|
|
455
461
|
export type routeOption = {
|