5htp-core 0.1.2 → 0.2.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/changelog.md +5 -0
- package/doc/TODO.md +71 -0
- package/package.json +5 -4
- package/src/client/{App.tsx → app/component.tsx} +15 -11
- package/src/client/app/index.ts +128 -0
- package/src/client/app/service.ts +34 -0
- package/src/client/app.tsconfig.json +0 -4
- package/src/client/assets/css/components.less +52 -0
- package/src/client/assets/css/core.less +7 -28
- package/src/client/assets/css/theme.less +1 -1
- package/src/client/assets/css/{borders.less → utils/borders.less} +0 -0
- package/src/client/assets/css/{layouts.less → utils/layouts.less} +0 -0
- package/src/client/assets/css/{medias.less → utils/medias.less} +14 -1
- package/src/client/assets/css/{sizing.less → utils/sizing.less} +0 -0
- package/src/client/assets/css/{spacing.less → utils/spacing.less} +0 -0
- package/src/client/components/Card/index.tsx +13 -7
- package/src/client/components/Dialog/Manager.tsx +41 -14
- package/src/client/components/Dialog/index.less +2 -4
- package/src/client/components/Form/index.tsx +1 -1
- package/src/client/components/Row/index.less +0 -2
- package/src/client/components/Table/index.tsx +3 -2
- package/src/client/components/button.tsx +2 -2
- package/src/client/components/containers/Popover/index.tsx +1 -1
- package/src/client/components/containers/champs.less +0 -2
- package/src/client/components/data/spintext/index.tsx +1 -1
- package/src/client/components/dropdown/index.tsx +1 -1
- package/src/client/components/index.ts +23 -0
- package/src/client/components/input/BaseV2/index.less +0 -2
- package/src/client/components/input/BaseV2/index.tsx +1 -1
- package/src/client/components/input/Date/index.less +0 -2
- package/src/client/components/input/Periode/index.less +0 -2
- package/src/client/components/input/Radio/index.less +0 -2
- package/src/client/components/input/UploadImage/index.less +0 -2
- package/src/client/components/input/UploadImage/index.tsx +1 -1
- package/src/client/hooks/index.ts +5 -0
- package/src/client/hooks/useState/index.tsx +2 -2
- package/src/client/hooks.ts +22 -0
- package/src/client/index.ts +5 -0
- package/src/client/pages/_layout/landing/index.tsx +0 -2
- package/src/client/pages/_messages/400.tsx +2 -2
- package/src/client/pages/_messages/401.tsx +2 -2
- package/src/client/pages/_messages/403.tsx +2 -2
- package/src/client/pages/_messages/404.tsx +2 -2
- package/src/client/pages/_messages/500.tsx +2 -2
- package/src/client/pages/bug.tsx +1 -1
- package/src/client/pages/useHeader.tsx +1 -1
- package/src/client/{context/captcha.ts → services/captcha/index.ts} +0 -0
- package/src/client/services/metrics/index.ts +37 -0
- package/src/client/{router → services/router/components}/Link.tsx +1 -1
- package/src/client/services/router/components/Page.tsx +59 -0
- package/src/client/{router/component.tsx → services/router/components/router.tsx} +52 -74
- package/src/client/services/router/index.tsx +453 -0
- package/src/client/services/router/request/api.ts +227 -0
- package/src/client/{router → services/router}/request/history.ts +0 -0
- package/src/client/services/router/request/index.ts +52 -0
- package/src/client/services/router/response/index.tsx +107 -0
- package/src/client/services/router/response/page.ts +90 -0
- package/src/client/{context/socket.ts → services/socket/index.ts} +2 -2
- package/src/client/utils/dom.ts +1 -1
- package/src/common/app/index.ts +9 -0
- package/src/common/data/chaines/index.ts +9 -6
- package/src/common/data/input/validate.ts +3 -166
- package/src/common/data/objets.ts +25 -0
- package/src/common/data/tableaux.ts +8 -0
- package/src/common/errors/index.ts +3 -1
- package/src/common/router/index.ts +67 -88
- package/src/common/router/layouts.ts +50 -0
- package/src/common/router/register.ts +62 -0
- package/src/common/router/request/api.ts +72 -0
- package/src/common/router/request/index.ts +31 -0
- package/src/common/router/{response.ts → response/index.ts} +9 -13
- package/src/common/router/response/page.ts +46 -54
- package/src/common/validation/index.ts +3 -0
- package/src/common/validation/schema.ts +185 -0
- package/src/common/validation/validator.ts +95 -0
- package/src/common/validation/validators.ts +313 -0
- package/src/server/app/config.ts +9 -27
- package/src/server/app/index.ts +81 -124
- package/src/server/app/service.ts +98 -0
- package/src/server/app.tsconfig.json +0 -8
- package/src/server/index.ts +5 -0
- package/src/server/patch.ts +0 -6
- package/src/server/{data/Cache.ts → services/cache/index.ts} +79 -47
- package/src/server/services/console/bugReporter.ts +26 -16
- package/src/server/services/console/index.ts +59 -51
- package/src/server/services/cron/index.ts +12 -26
- package/src/server/services/database/bucket.ts +40 -0
- package/src/server/services/database/connection.ts +213 -80
- package/src/server/services/database/datatypes.ts +63 -40
- package/src/server/services/database/debug.ts +20 -0
- package/src/server/services/database/index.ts +295 -272
- package/src/server/services/database/metas.ts +246 -135
- package/src/server/services/database/stats.ts +151 -126
- package/src/server/services/email/index.ts +30 -62
- package/src/server/services/email/transporter.ts +38 -0
- package/src/server/services/{router/request/services → metrics}/detect.ts +8 -10
- package/src/server/services/{router/request/services/tracking.ts → metrics/index.ts} +68 -45
- package/src/server/services/{http → router/http}/index.ts +28 -70
- package/src/server/services/{http → router/http}/multipart.ts +0 -0
- package/src/server/services/{http → router/http}/session.ts.old +0 -0
- package/src/server/services/router/index.ts +273 -202
- package/src/server/services/router/request/api.ts +76 -0
- package/src/server/services/router/request/index.ts +16 -97
- package/src/server/services/router/request/service.ts +21 -0
- package/src/server/services/router/response/index.ts +131 -65
- package/src/server/services/router/response/{filter → mask}/Filter.ts +0 -0
- package/src/server/services/router/response/{filter → mask}/index.ts +0 -2
- package/src/server/services/router/response/{filter → mask}/selecteurs.ts +0 -0
- package/src/server/services/router/response/page/document.tsx +194 -0
- package/src/server/services/router/response/page/index.tsx +157 -0
- package/src/server/{libs/pages → services/router/response/page}/schemaGenerator.ts +0 -0
- package/src/server/services/router/service.ts +48 -0
- package/src/server/services/schema/index.ts +47 -0
- package/src/server/services/schema/request.ts +55 -0
- package/src/server/services/schema/router.ts +33 -0
- package/src/server/services/socket/index.ts +38 -43
- package/src/server/services/socket/scope.ts +6 -4
- package/src/server/services/users/index.ts +203 -0
- package/src/server/services/{auth/base.ts → users/old.ts} +28 -112
- package/src/server/services/users/router/index.ts +72 -0
- package/src/server/services/users/router/request.ts +49 -0
- package/src/server/{data → services_old}/SocketClient.ts +0 -0
- package/src/server/{data/Token.olg.ts → services_old/Token.old.ts} +0 -0
- package/src/server/{data → services_old}/aes.ts +0 -0
- package/src/types/aliases.d.ts +43 -2
- package/templates/composant.tsx +1 -1
- package/templates/modal.tsx +1 -1
- package/templates/page.tsx +1 -1
- package/tsconfig.common.json +0 -4
- package/src/client/assets/css/components/components.less +0 -31
- package/src/client/context/api.ts +0 -92
- package/src/client/context/index.ts +0 -246
- package/src/client/index.tsx +0 -129
- package/src/client/router/index.ts +0 -286
- package/src/client/router/request/index.ts +0 -106
- package/src/client/router/response/index.ts +0 -38
- package/src/client/router/route.ts +0 -75
- package/src/common/data/input/validators/basic.ts +0 -299
- package/src/common/data/input/validators/build.ts +0 -63
- package/src/common/router/request.ts +0 -83
- package/src/server/data/ApiClient.ts +0 -119
- package/src/server/data/input.ts +0 -41
- package/src/server/libs/pages/document.static.tsx +0 -41
- package/src/server/libs/pages/document.tsx +0 -203
- package/src/server/libs/pages/render.tsx +0 -90
- package/src/server/routes/auth.ts +0 -151
- package/src/server/services/redis/index.ts +0 -71
- package/src/server/services/router/request/services/auth.ts +0 -177
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
import Application from ".";
|
|
6
|
+
|
|
7
|
+
/*----------------------------------
|
|
8
|
+
- TYPES: OPTIONS
|
|
9
|
+
----------------------------------*/
|
|
10
|
+
|
|
11
|
+
export type AnyService = Service<{}, {}, Application>
|
|
12
|
+
|
|
13
|
+
type THookCallback<THookArgs extends THookOptions> = (...args: THookArgs["args"]) => Promise<void>;
|
|
14
|
+
|
|
15
|
+
type THooksList = {
|
|
16
|
+
[hookName: string]: THookOptions
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type THookOptions = {
|
|
20
|
+
args: any[]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type TPriority = -2 | -1 | 0 | 1 | 2
|
|
24
|
+
|
|
25
|
+
/*----------------------------------
|
|
26
|
+
- CONFIG
|
|
27
|
+
----------------------------------*/
|
|
28
|
+
|
|
29
|
+
const LogPrefix = '[service]';
|
|
30
|
+
|
|
31
|
+
/*----------------------------------
|
|
32
|
+
- CLASS
|
|
33
|
+
----------------------------------*/
|
|
34
|
+
export default abstract class Service<
|
|
35
|
+
TConfig extends {},
|
|
36
|
+
THooks extends THooksList,
|
|
37
|
+
TApplication extends Application
|
|
38
|
+
> {
|
|
39
|
+
|
|
40
|
+
public priority: TPriority = 0;
|
|
41
|
+
public started?: Promise<void>;
|
|
42
|
+
|
|
43
|
+
public constructor(
|
|
44
|
+
public app: TApplication,
|
|
45
|
+
public config: TConfig,
|
|
46
|
+
) {
|
|
47
|
+
|
|
48
|
+
if (!( this instanceof Application ))
|
|
49
|
+
// Make the app aware of his services
|
|
50
|
+
app.registerService(this);
|
|
51
|
+
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public abstract register?(): Promise<void>;
|
|
55
|
+
|
|
56
|
+
public abstract start?(): Promise<void>;
|
|
57
|
+
|
|
58
|
+
/*----------------------------------
|
|
59
|
+
- HOOKS
|
|
60
|
+
----------------------------------*/
|
|
61
|
+
public hooks: {[name in keyof THooks]?: THookCallback< THooks[name] >[]} = {}
|
|
62
|
+
|
|
63
|
+
public on<THookName extends keyof THooksList>(
|
|
64
|
+
name: THookName,
|
|
65
|
+
callback: THookCallback<THooksList[THookName]>
|
|
66
|
+
) {
|
|
67
|
+
|
|
68
|
+
const callbacks = this.hooks[ name ];
|
|
69
|
+
if (callbacks)
|
|
70
|
+
callbacks.push( callback );
|
|
71
|
+
else
|
|
72
|
+
this.hooks[ name ] = [callback]
|
|
73
|
+
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public runHook<THookName extends keyof THooksList>(
|
|
78
|
+
name: THookName,
|
|
79
|
+
...args: THooksList[THookName]["args"]
|
|
80
|
+
) {
|
|
81
|
+
|
|
82
|
+
const callbacks = this.hooks[name];
|
|
83
|
+
if (!callbacks)
|
|
84
|
+
return console.info(LogPrefix, `No ${name} hook defined in the current service instance.`);
|
|
85
|
+
|
|
86
|
+
console.info(`[hook] Run all ${name} hook (${callbacks.length}).`);
|
|
87
|
+
return Promise.all(
|
|
88
|
+
callbacks.map(
|
|
89
|
+
cb => cb(...args).catch(e => {
|
|
90
|
+
console.error(`[hook] Error while executing hook ${name}:`, e);
|
|
91
|
+
})
|
|
92
|
+
)
|
|
93
|
+
).then(() => {
|
|
94
|
+
console.info(`[hook] Hooks ${name} executed with success.`);
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
}
|
|
@@ -5,18 +5,10 @@
|
|
|
5
5
|
"baseUrl": "..",
|
|
6
6
|
"paths": {
|
|
7
7
|
|
|
8
|
-
// RAPPEL: Mettre à jour webpack externals
|
|
9
|
-
|
|
10
8
|
"@client/*": ["../node_modules/5htp-core/src/client/*"],
|
|
11
9
|
"@common/*": ["../node_modules/5htp-core/src/common/*"],
|
|
12
10
|
"@server/*": ["../node_modules/5htp-core/src/server/*"],
|
|
13
11
|
|
|
14
|
-
"@validator": ["../node_modules/5htp-core/src/server/data/input"],
|
|
15
|
-
"@router": ["../node_modules/5htp-core/src/server/services/router"],
|
|
16
|
-
"@errors": ["../node_modules/5htp-core/src/common/errors"],
|
|
17
|
-
|
|
18
|
-
"@models": ["../server/models"],
|
|
19
|
-
|
|
20
12
|
"@/*": ["./*"],
|
|
21
13
|
|
|
22
14
|
// ATTENTION: Les références à preact doivent toujours pointer vers la même instance
|
package/src/server/patch.ts
CHANGED
|
@@ -10,7 +10,7 @@ import hInterval from 'human-interval';
|
|
|
10
10
|
import fs from 'fs-extra';
|
|
11
11
|
|
|
12
12
|
// Core
|
|
13
|
-
import
|
|
13
|
+
import Application, { Service } from '@server/app';
|
|
14
14
|
|
|
15
15
|
// Libs
|
|
16
16
|
|
|
@@ -18,15 +18,17 @@ import app from '@server/app';
|
|
|
18
18
|
- CONFIG
|
|
19
19
|
----------------------------------*/
|
|
20
20
|
|
|
21
|
-
const
|
|
21
|
+
const LogPrefix = '[cache]';
|
|
22
22
|
|
|
23
23
|
/*----------------------------------
|
|
24
24
|
- TYPES
|
|
25
25
|
----------------------------------*/
|
|
26
26
|
|
|
27
|
-
type TPrimitiveValue = string | boolean | number | undefined |
|
|
27
|
+
type TPrimitiveValue = string | boolean | number | undefined | TPrimitiveValue[] | {
|
|
28
|
+
[key: string]: TPrimitiveValue
|
|
29
|
+
}
|
|
28
30
|
|
|
29
|
-
type TExpirationDelay = string | number | Date
|
|
31
|
+
type TExpirationDelay = 'never' | string | number | Date;
|
|
30
32
|
|
|
31
33
|
type CacheEntry = {
|
|
32
34
|
// Value
|
|
@@ -35,47 +37,70 @@ type CacheEntry = {
|
|
|
35
37
|
expiration?: number
|
|
36
38
|
};
|
|
37
39
|
|
|
40
|
+
/*----------------------------------
|
|
41
|
+
- TYPES
|
|
42
|
+
----------------------------------*/
|
|
43
|
+
|
|
44
|
+
export type Config = {
|
|
45
|
+
debug: boolean
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type Hooks = {
|
|
49
|
+
|
|
50
|
+
}
|
|
51
|
+
|
|
38
52
|
/*----------------------------------
|
|
39
53
|
- SERVICE
|
|
40
54
|
----------------------------------*/
|
|
41
|
-
class Cache {
|
|
55
|
+
export default class Cache extends Service<Config, Hooks, Application> {
|
|
42
56
|
|
|
43
|
-
private cacheFile = path.join(app.path.data, 'cache/mem.json');
|
|
57
|
+
private cacheFile = path.join(this.app.path.data, 'cache/mem.json');
|
|
44
58
|
|
|
45
59
|
private data: {[key: string]: CacheEntry | undefined} = {};
|
|
46
60
|
|
|
47
61
|
private changes: number = 0;
|
|
48
62
|
|
|
49
|
-
public
|
|
63
|
+
public async register() {
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public async start() {
|
|
50
69
|
|
|
51
70
|
setInterval(() => this.cleanMem(), 10000);
|
|
52
71
|
|
|
72
|
+
// Restore persisted data
|
|
53
73
|
if (fs.existsSync(this.cacheFile))
|
|
54
74
|
this.data = fs.readJSONSync(this.cacheFile)
|
|
55
75
|
}
|
|
56
76
|
|
|
57
77
|
private cleanMem() {
|
|
58
78
|
|
|
59
|
-
|
|
60
|
-
|
|
79
|
+
// Remove expired data
|
|
61
80
|
const now = Date.now();
|
|
62
81
|
for (const key in this.data) {
|
|
63
82
|
const entry = this.data[ key ];
|
|
64
|
-
if (entry?.expiration && entry.expiration < now)
|
|
83
|
+
if (entry?.expiration && entry.expiration < now) {
|
|
84
|
+
this.config.debug && console.log(LogPrefix, `Delete expired data: ${key}`);
|
|
65
85
|
this.del(key);
|
|
86
|
+
}
|
|
66
87
|
}
|
|
67
88
|
|
|
68
|
-
|
|
89
|
+
// Write changes
|
|
90
|
+
if (this.changes > 0) {
|
|
69
91
|
fs.outputJSONSync(this.cacheFile, this.data);
|
|
92
|
+
this.config.debug && console.log(LogPrefix, `Flush ${this.changes} changes`);
|
|
93
|
+
this.changes = 0;
|
|
94
|
+
}
|
|
70
95
|
}
|
|
71
96
|
|
|
72
97
|
// Expiration = Durée de vie en secondes ou date max
|
|
73
98
|
// Retourne null quand pas de valeur
|
|
74
99
|
public get<TValeur extends TPrimitiveValue>(
|
|
75
100
|
cle: string,
|
|
76
|
-
func
|
|
77
|
-
expiration
|
|
78
|
-
avecDetails
|
|
101
|
+
func: (() => Promise<TValeur>),
|
|
102
|
+
expiration: TExpirationDelay,
|
|
103
|
+
avecDetails: true
|
|
79
104
|
): Promise<CacheEntry>;
|
|
80
105
|
|
|
81
106
|
public get<TValeur extends TPrimitiveValue>(
|
|
@@ -83,47 +108,44 @@ class Cache {
|
|
|
83
108
|
func: (() => Promise<TValeur>),
|
|
84
109
|
expiration?: TExpirationDelay,
|
|
85
110
|
avecDetails?: false
|
|
86
|
-
): Promise<
|
|
111
|
+
): Promise<TValeur>;
|
|
87
112
|
|
|
88
113
|
public async get<TValeur extends TPrimitiveValue>(
|
|
89
114
|
cle: string,
|
|
90
|
-
func
|
|
91
|
-
expiration
|
|
115
|
+
func: (() => Promise<TValeur>),
|
|
116
|
+
expiration: TExpirationDelay = 'never',
|
|
92
117
|
avecDetails?: boolean
|
|
93
|
-
): Promise<
|
|
118
|
+
): Promise<TValeur | CacheEntry> {
|
|
94
119
|
|
|
95
|
-
let
|
|
96
|
-
|
|
97
|
-
debug && console.log(`[cache] Get "${cle}".`);
|
|
120
|
+
let entry: CacheEntry | undefined = this.data[cle];
|
|
98
121
|
|
|
99
122
|
// Expired
|
|
100
|
-
if (
|
|
101
|
-
debug && console.log(`
|
|
102
|
-
|
|
123
|
+
if (entry?.expiration && entry.expiration < Date.now()){
|
|
124
|
+
this.config.debug && console.log(LogPrefix, `Key ${cle} expired.`);
|
|
125
|
+
entry = undefined;
|
|
103
126
|
}
|
|
104
127
|
|
|
105
128
|
// Donnée inexistante
|
|
106
|
-
if (
|
|
129
|
+
if (entry === undefined) {
|
|
130
|
+
|
|
131
|
+
this.config.debug && console.log(LogPrefix, `Get "${cle}": refresh value`);
|
|
107
132
|
|
|
108
133
|
// Rechargement
|
|
109
|
-
|
|
134
|
+
entry = {
|
|
110
135
|
value: await func(),
|
|
111
|
-
expiration: expiration
|
|
112
|
-
? this.delayToTimestamp(expiration)
|
|
113
|
-
: undefined
|
|
136
|
+
expiration: this.delayToTimestamp(expiration)
|
|
114
137
|
}
|
|
115
138
|
|
|
116
139
|
// undefined retourné = pas d'enregistrement
|
|
117
|
-
if (
|
|
118
|
-
await this.set(cle,
|
|
119
|
-
}
|
|
140
|
+
//if (entry.value !== undefined)
|
|
141
|
+
await this.set(cle, entry.value, expiration);
|
|
120
142
|
|
|
121
|
-
|
|
122
|
-
|
|
143
|
+
} else
|
|
144
|
+
this.config.debug && console.log(LogPrefix, `Get "${cle}": restored via cache`);
|
|
123
145
|
|
|
124
146
|
return avecDetails
|
|
125
|
-
?
|
|
126
|
-
:
|
|
147
|
+
? entry
|
|
148
|
+
: entry.value as TValeur;
|
|
127
149
|
};
|
|
128
150
|
|
|
129
151
|
/**
|
|
@@ -137,9 +159,9 @@ class Cache {
|
|
|
137
159
|
* - null: no expiration (default)
|
|
138
160
|
* @returns A void promise
|
|
139
161
|
*/
|
|
140
|
-
public set( cle: string, val: TPrimitiveValue, expiration: TExpirationDelay =
|
|
162
|
+
public set( cle: string, val: TPrimitiveValue, expiration: TExpirationDelay = 'never' ): void {
|
|
141
163
|
|
|
142
|
-
debug && console.log("
|
|
164
|
+
this.config.debug && console.log(LogPrefix, "Updating cache " + cle);
|
|
143
165
|
this.data[ cle ] = {
|
|
144
166
|
value: val,
|
|
145
167
|
expiration: this.delayToTimestamp(expiration)
|
|
@@ -157,24 +179,34 @@ class Cache {
|
|
|
157
179
|
/*----------------------------------
|
|
158
180
|
- UTILS
|
|
159
181
|
----------------------------------*/
|
|
160
|
-
|
|
182
|
+
/**
|
|
183
|
+
*
|
|
184
|
+
* @param delay
|
|
185
|
+
* @returns number (timestamp when the data expired) or undefined (never expires)
|
|
186
|
+
*/
|
|
187
|
+
private delayToTimestamp( delay: TExpirationDelay ): number | undefined {
|
|
188
|
+
|
|
189
|
+
if (delay === 'now') {
|
|
190
|
+
|
|
191
|
+
return Date.now();
|
|
192
|
+
|
|
193
|
+
} else if (delay === 'never') {
|
|
194
|
+
|
|
195
|
+
return undefined;
|
|
161
196
|
|
|
162
197
|
// H expression
|
|
163
|
-
if (typeof delay === 'string') {
|
|
198
|
+
} else if (typeof delay === 'string') {
|
|
164
199
|
|
|
165
200
|
const ms = hInterval(delay);
|
|
166
201
|
if (ms === undefined) throw new Error(`Invalid period string: ` + delay);
|
|
167
202
|
return Date.now() + ms;
|
|
168
203
|
|
|
169
|
-
//
|
|
204
|
+
// Lifetime in seconds
|
|
170
205
|
} else if (typeof delay === 'number')
|
|
171
206
|
return Date.now() + delay;
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
return delay.getTime();
|
|
207
|
+
|
|
208
|
+
// Date limit
|
|
175
209
|
else
|
|
176
|
-
return
|
|
210
|
+
return delay.getTime();
|
|
177
211
|
}
|
|
178
212
|
}
|
|
179
|
-
|
|
180
|
-
export default new Cache;
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
import { v4 as uuid } from 'uuid';
|
|
7
7
|
|
|
8
8
|
// Core
|
|
9
|
-
import
|
|
10
|
-
import type
|
|
9
|
+
import { SqlError } from '@server/services/database/debug';
|
|
10
|
+
import type Console from '.';
|
|
11
11
|
|
|
12
12
|
// Types
|
|
13
13
|
import type ServerRequest from '@server/services/router/request';
|
|
@@ -72,8 +72,6 @@ export type ApplicationBug = {
|
|
|
72
72
|
stacktrace: string
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
const config = app.config.console;
|
|
76
|
-
|
|
77
75
|
/*----------------------------------
|
|
78
76
|
- CONFIG
|
|
79
77
|
----------------------------------*/
|
|
@@ -110,7 +108,8 @@ export default class BugReporter {
|
|
|
110
108
|
private sentBugs: {[bugId: string]: number} = {};
|
|
111
109
|
|
|
112
110
|
public constructor(
|
|
113
|
-
private console: Console
|
|
111
|
+
private console: Console,
|
|
112
|
+
public app = console.app,
|
|
114
113
|
) {
|
|
115
114
|
|
|
116
115
|
}
|
|
@@ -133,7 +132,16 @@ export default class BugReporter {
|
|
|
133
132
|
|
|
134
133
|
public async server( error: Error, request?: ServerRequest ) {
|
|
135
134
|
|
|
136
|
-
//
|
|
135
|
+
// Print the error so it's accessible via logs
|
|
136
|
+
if (error instanceof SqlError) {
|
|
137
|
+
let printedQuery: string;
|
|
138
|
+
try {
|
|
139
|
+
printedQuery = this.console.printSql( error.query );
|
|
140
|
+
} catch (error) {
|
|
141
|
+
printedQuery = 'Failed to print query:' + (error || 'unknown error');
|
|
142
|
+
}
|
|
143
|
+
console.error(`Error caused by this query:`, printedQuery);
|
|
144
|
+
}
|
|
137
145
|
console.error(LogPrefix, `Sending bug report for the following error:`, error);
|
|
138
146
|
|
|
139
147
|
// Prevent duplicates
|
|
@@ -172,6 +180,7 @@ export default class BugReporter {
|
|
|
172
180
|
|
|
173
181
|
await this.sendToTransporters(bugReport);
|
|
174
182
|
|
|
183
|
+
// TODO: Move on App side
|
|
175
184
|
/*if (app.isLoaded('sql'))
|
|
176
185
|
// Memorize
|
|
177
186
|
$.sql.insert('BugServer', {
|
|
@@ -192,7 +201,7 @@ export default class BugReporter {
|
|
|
192
201
|
error.message = "A bug report has been sent to my personal mailbox. Sorry for the inconvenience.";
|
|
193
202
|
}
|
|
194
203
|
|
|
195
|
-
public async
|
|
204
|
+
public async application( report: AppBugInfos ) {
|
|
196
205
|
|
|
197
206
|
// Prevent duplicates
|
|
198
207
|
if (!this.shouldSendReport(report.side, report.user, report.action, report.message))
|
|
@@ -224,17 +233,12 @@ export default class BugReporter {
|
|
|
224
233
|
stacktrace: report.stacktrace,
|
|
225
234
|
}
|
|
226
235
|
|
|
227
|
-
await this.sendToTransporters(bugReport);
|
|
228
|
-
|
|
229
|
-
/* // Send notification
|
|
230
|
-
$.email.send({
|
|
231
|
-
to: app.identity.author.email,
|
|
232
|
-
subject: "Bug app: " + report.message,
|
|
233
|
-
html: report
|
|
234
|
-
});
|
|
235
236
|
|
|
237
|
+
// TODO:
|
|
236
238
|
// Memorize
|
|
237
|
-
|
|
239
|
+
//$.sql.insert('BugApp', );
|
|
240
|
+
|
|
241
|
+
await this.sendToTransporters(bugReport);
|
|
238
242
|
}
|
|
239
243
|
|
|
240
244
|
private async sendToTransporters( bugReport: Bug, error?: Error ) {
|
|
@@ -245,6 +249,12 @@ export default class BugReporter {
|
|
|
245
249
|
return false;
|
|
246
250
|
}
|
|
247
251
|
|
|
252
|
+
// Don't send if we're in local (avoid to use credits: ex: email, sms)
|
|
253
|
+
if (this.app.env.name === 'local'){
|
|
254
|
+
console.warn(LogPrefix, `Error report sending aborted since we're local.`);
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
|
|
248
258
|
// Send report to trabporters
|
|
249
259
|
await Promise.all(
|
|
250
260
|
this.transporters.map( transport => {
|
|
@@ -8,30 +8,31 @@ import { format as formatSql } from 'sql-formatter';
|
|
|
8
8
|
import highlight from 'cli-highlight';
|
|
9
9
|
|
|
10
10
|
// Core libs
|
|
11
|
-
import
|
|
12
|
-
import logToHTML from './html';
|
|
11
|
+
import Application, { Service, TPriority } from '@server/app';
|
|
13
12
|
import context from '@server/context';
|
|
13
|
+
import type ServerRequest from '@server/services/router/request';
|
|
14
|
+
|
|
15
|
+
// Specific
|
|
16
|
+
import logToHTML from './html';
|
|
14
17
|
import BugReporter from "./bugReporter";
|
|
15
18
|
|
|
16
19
|
/*----------------------------------
|
|
17
20
|
- SERVICE CONFIG
|
|
18
21
|
----------------------------------*/
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
type TLogProfile = 'silly' | 'info' | 'warn' | 'error'
|
|
21
24
|
|
|
22
|
-
export type
|
|
23
|
-
|
|
25
|
+
export type Config = {
|
|
26
|
+
dev: {
|
|
27
|
+
level: TLogProfile,
|
|
28
|
+
},
|
|
29
|
+
prod: {
|
|
30
|
+
level: TLogProfile
|
|
31
|
+
}
|
|
24
32
|
}
|
|
25
33
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
interface EmailTransporters { }
|
|
29
|
-
namespace Config {
|
|
30
|
-
interface Services {
|
|
31
|
-
console: ConsoleConfig
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
34
|
+
export type Hooks = {
|
|
35
|
+
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
/*----------------------------------
|
|
@@ -103,7 +104,10 @@ const logFields = [
|
|
|
103
104
|
/*----------------------------------
|
|
104
105
|
- LOGGER
|
|
105
106
|
----------------------------------*/
|
|
106
|
-
export class Console {
|
|
107
|
+
export default class Console extends Service<Config, Hooks, Application> {
|
|
108
|
+
|
|
109
|
+
// Load before all
|
|
110
|
+
public priority: TPriority = 2;
|
|
107
111
|
|
|
108
112
|
// Services
|
|
109
113
|
public logger!: Logger;
|
|
@@ -115,34 +119,50 @@ export class Console {
|
|
|
115
119
|
public requests: TRequestLogs[] = [];
|
|
116
120
|
public sqlQueries: TQueryLogs[] = [];
|
|
117
121
|
|
|
122
|
+
// Adapters
|
|
123
|
+
public log = console.log;
|
|
124
|
+
public warn = console.warn;
|
|
125
|
+
public info = console.info;
|
|
126
|
+
public error = console.error;
|
|
127
|
+
|
|
118
128
|
/*----------------------------------
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
public
|
|
129
|
+
- INSTANCE
|
|
130
|
+
----------------------------------*/
|
|
131
|
+
public async register() {
|
|
132
|
+
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public async start() {
|
|
136
|
+
|
|
137
|
+
const envConfig = this.config[ this.app.env.profile ];
|
|
122
138
|
|
|
123
139
|
this.logger = new Logger({
|
|
124
140
|
overwriteConsole: true,
|
|
125
|
-
//type: app.env.profile === 'dev' ? 'pretty' : 'hidden',
|
|
141
|
+
//type: this.app.env.profile === 'dev' ? 'pretty' : 'hidden',
|
|
126
142
|
requestId: (): string => {
|
|
127
143
|
const { channelType, channelId } = this.getChannel();
|
|
128
144
|
return channelId === undefined ? channelType : channelType + ':' + channelId;
|
|
129
145
|
},
|
|
130
146
|
displayRequestId: false,
|
|
147
|
+
prettyInspectOptions: {
|
|
148
|
+
depth: 2
|
|
149
|
+
}
|
|
131
150
|
});
|
|
132
151
|
|
|
133
152
|
this.logger.attachTransport({
|
|
134
|
-
silly: this.
|
|
135
|
-
debug: this.
|
|
136
|
-
trace: this.
|
|
137
|
-
info: this.
|
|
138
|
-
warn: this.
|
|
139
|
-
error: this.
|
|
140
|
-
fatal: this.
|
|
141
|
-
},
|
|
153
|
+
silly: this.logEntry.bind(this),
|
|
154
|
+
debug: this.logEntry.bind(this),
|
|
155
|
+
trace: this.logEntry.bind(this),
|
|
156
|
+
info: this.logEntry.bind(this),
|
|
157
|
+
warn: this.logEntry.bind(this),
|
|
158
|
+
error: this.logEntry.bind(this),
|
|
159
|
+
fatal: this.logEntry.bind(this),
|
|
160
|
+
}, envConfig.level);
|
|
142
161
|
|
|
143
162
|
setInterval(() => this.clean(), 60000);
|
|
144
163
|
|
|
145
|
-
|
|
164
|
+
// Send email report
|
|
165
|
+
this.app.on('error', (error: Error, request?: ServerRequest) => this.bugReport.server(error, request));
|
|
146
166
|
}
|
|
147
167
|
|
|
148
168
|
private clean() {
|
|
@@ -160,7 +180,7 @@ export class Console {
|
|
|
160
180
|
}
|
|
161
181
|
}
|
|
162
182
|
|
|
163
|
-
private
|
|
183
|
+
private logEntry(entry: ILogObject) {
|
|
164
184
|
|
|
165
185
|
const [channelType, channelId] = entry.requestId?.split(':') || ['master'];
|
|
166
186
|
if (entry.requestId === 'admin')
|
|
@@ -175,10 +195,10 @@ export class Console {
|
|
|
175
195
|
// remove webpack path
|
|
176
196
|
if (miniLog.filePath !== undefined) {
|
|
177
197
|
|
|
178
|
-
const appPrefix = '/webpack:/' + app.pkg.name + '/src/';
|
|
198
|
+
const appPrefix = '/webpack:/' + this.app.pkg.name + '/src/';
|
|
179
199
|
const appPrefixIndex = miniLog.filePath.indexOf(appPrefix);
|
|
180
200
|
|
|
181
|
-
const corePrefix = '/webpack:/' + app.pkg.name + '/node_modules/5htp-core/src/';
|
|
201
|
+
const corePrefix = '/webpack:/' + this.app.pkg.name + '/node_modules/5htp-core/src/';
|
|
182
202
|
const corePrefixIndex = miniLog.filePath.indexOf(corePrefix);
|
|
183
203
|
|
|
184
204
|
if (appPrefixIndex !== -1)
|
|
@@ -207,8 +227,8 @@ export class Console {
|
|
|
207
227
|
- READ
|
|
208
228
|
----------------------------------*/
|
|
209
229
|
|
|
210
|
-
public getClients() {
|
|
211
|
-
return
|
|
230
|
+
/*public getClients() {
|
|
231
|
+
return sql`
|
|
212
232
|
SELECT * FROM logs.Clients
|
|
213
233
|
ORDER BY activity DESC
|
|
214
234
|
LIMIT 100
|
|
@@ -219,7 +239,7 @@ export class Console {
|
|
|
219
239
|
return (
|
|
220
240
|
this.clients.find(c => c.id === clientId)
|
|
221
241
|
||
|
|
222
|
-
await
|
|
242
|
+
await sql`
|
|
223
243
|
SELECT * FROM logs.Clients
|
|
224
244
|
WHERE id = ${clientId}
|
|
225
245
|
`.first()
|
|
@@ -227,7 +247,7 @@ export class Console {
|
|
|
227
247
|
}
|
|
228
248
|
|
|
229
249
|
public getRequests(clientId?: string) {
|
|
230
|
-
return
|
|
250
|
+
return sql`
|
|
231
251
|
SELECT * FROM logs.Requests
|
|
232
252
|
ORDER BY date DESC
|
|
233
253
|
LIMIT 100
|
|
@@ -238,7 +258,7 @@ export class Console {
|
|
|
238
258
|
return (
|
|
239
259
|
this.requests.find(r => r.id === requestId)
|
|
240
260
|
||
|
|
241
|
-
await
|
|
261
|
+
await sql`
|
|
242
262
|
SELECT * FROM logs.Requests
|
|
243
263
|
WHERE id = ${requestId}
|
|
244
264
|
`.first()
|
|
@@ -251,13 +271,13 @@ export class Console {
|
|
|
251
271
|
if (channelId !== undefined)
|
|
252
272
|
filters.channelId = channelId;
|
|
253
273
|
|
|
254
|
-
return
|
|
274
|
+
return sql`
|
|
255
275
|
SELECT * FROM logs.Queries
|
|
256
276
|
WHERE :${filters}
|
|
257
277
|
ORDER BY date DESC
|
|
258
278
|
LIMIT 100
|
|
259
279
|
`.all();
|
|
260
|
-
}
|
|
280
|
+
}*/
|
|
261
281
|
|
|
262
282
|
public async getLogs( channelType: ChannelInfos["channelType"], channelId?: string ) {
|
|
263
283
|
|
|
@@ -274,7 +294,7 @@ export class Console {
|
|
|
274
294
|
|
|
275
295
|
public printHtml(logs: TLog[], full: boolean = false): string {
|
|
276
296
|
|
|
277
|
-
let html = logs.map(
|
|
297
|
+
let html = logs.map( logEntry => logToHTML( logEntry, this )).join('\n');
|
|
278
298
|
|
|
279
299
|
if (full) {
|
|
280
300
|
const consoleCss = `background: #000; padding: 20px; font-family: 'Fira Mono', 'monospace', 'Monaco'; font-size: 12px; line-height: 20px;`
|
|
@@ -289,16 +309,4 @@ export class Console {
|
|
|
289
309
|
{ language: 'sql', ignoreIllegals: true }
|
|
290
310
|
)
|
|
291
311
|
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/*----------------------------------
|
|
295
|
-
- REGISTER SERVICE
|
|
296
|
-
----------------------------------*/
|
|
297
|
-
app.register('console', Console);
|
|
298
|
-
declare global {
|
|
299
|
-
namespace Core {
|
|
300
|
-
interface Services {
|
|
301
|
-
console: Console;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
312
|
}
|