5htp 0.2.3 → 0.3.0-3

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "5htp",
3
3
  "description": "Convenient TypeScript framework designed for Performance and Productivity.",
4
- "version": "0.2.3",
4
+ "version": "0.3.0-3",
5
5
  "author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
6
6
  "repository": "git://github.com/gaetanlegac/5htp.git",
7
7
  "license": "MIT",
@@ -41,7 +41,7 @@
41
41
  "@types/webpack-env": "^1.16.2",
42
42
  "@types/ws": "^7.4.7",
43
43
  "babel-loader": "^8.2.2",
44
- "babel-plugin-glob-import": "^0.0.6-3",
44
+ "babel-plugin-glob-import": "^0.0.7",
45
45
  "babel-plugin-transform-imports": "^2.0.0",
46
46
  "babel-plugin-transform-react-remove-prop-types": "^0.4.24",
47
47
  "brotli-webpack-plugin": "^1.1.0",
@@ -73,7 +73,6 @@
73
73
  "terser-webpack-plugin": "^5.2.4",
74
74
  "ts-alias": "^0.0.7",
75
75
  "ts-node": "^10.9.1",
76
- "tslog": "^3.3.4",
77
76
  "webfont": "^11.2.26",
78
77
  "webpack": "^5.56.0",
79
78
  "webpack-assets-manifest": "^5.0.6",
package/readme.md CHANGED
@@ -41,16 +41,20 @@ Full Stack Typescript framework designed for **developers and users experience**
41
41
  ## To be done:
42
42
 
43
43
  - [ ] Update templates & documentation
44
- - [ ] Improved debugability & debug tools
45
- - Cleaner logs (tweak ts-logs settings)
46
- - Cleaner stacktraces
47
- - export all default exports as classical functions instead of arrow funcs
44
+ - [ ] HMR
45
+ - [ ] Debugging / Monitoring UI
46
+ - All services and status: installed / paused / running
47
+ - Router:
48
+ - list of registered files
49
+ - list of pages / api / error routes / layouts
50
+ - latest requests + performance
51
+ - Logs: recent logs terminal
52
+ - Database: recent queries + performance
53
+ - Page rendering: performance
54
+ - Socket: who is connected
55
+ - [ ] Add testing tools
56
+ - [ ] Possibility to generate static pages
57
+ - [ ] Improve ORM: make definition based on code instead of database structure
48
58
  - [ ] Automatically generates types that associate api routes urls to their return types
49
- - [ ] Fix forms system
50
59
  - [ ] Allow to create CLI apps
51
- - [ ] Debugging / Monitoring UI
52
- - Admin dashboard
53
- - [ ] Fix Typescript errors
54
- - [ ] Completely replace expressjs
55
- - [ ] Improve stability
56
- - [ ] Improve modularity
60
+ - [ ] Fix Typescript errors
@@ -0,0 +1,117 @@
1
+ export type BugApp = {
2
+ action: string,
3
+ build: string,
4
+ client: string,
5
+ date: Date,
6
+ device?: string,
7
+ hash: string,
8
+ ip: string,
9
+ message?: string,
10
+ side: string,
11
+ solved?: Date,
12
+ stacktrace: string,
13
+ status?: string,
14
+ user?: string
15
+ }
16
+ export type BugGUI = {
17
+ before?: string,
18
+ date: Date,
19
+ device: string,
20
+ guiVersion: string,
21
+ hash: string,
22
+ ip: string,
23
+ observation?: string,
24
+ serverVersion: string,
25
+ solved?: Date,
26
+ context?: object,
27
+ stacktrace?: string,
28
+ url: string,
29
+ user?: string
30
+ }
31
+ export type BugServer = {
32
+ channelId?: string,
33
+ channelType: string,
34
+ date: Date,
35
+ hash: string,
36
+ ip?: string,
37
+ logs: string,
38
+ solved?: Date,
39
+ stacktrace: string,
40
+ user?: string
41
+ }
42
+ export type Countries = {
43
+ id: string,
44
+ name: string
45
+ }
46
+ export type Devices = {
47
+ activity: Date,
48
+ bandwidth: number,
49
+ build: number,
50
+ connectedSince: Date,
51
+ id: string,
52
+ invalid: number,
53
+ ip: string,
54
+ meet: Date,
55
+ name?: string,
56
+ platform: string,
57
+ rewards: number,
58
+ user: string,
59
+ valid: number
60
+ }
61
+ export type Locales = {
62
+ id: string,
63
+ name: string
64
+ }
65
+ export type User = {
66
+ activity: Date,
67
+ balance: number,
68
+ balanceGoal: number,
69
+ balanceGoalReached: number,
70
+ banned?: Date,
71
+ boosterEnd?: Date,
72
+ country?: string,
73
+ donationPc: number,
74
+ email: string,
75
+ emailHash: string,
76
+ exp: number,
77
+ level: number,
78
+ levelsReached: number,
79
+ meet: Date,
80
+ name: string,
81
+ phone?: string,
82
+ referrer?: string,
83
+ refPeriodEnd?: Date,
84
+ roles: string[],
85
+ smscode?: string,
86
+ utm?: string
87
+ }
88
+ export type UserLogin = {
89
+ date: Date,
90
+ device: string,
91
+ id: number,
92
+ ip: string,
93
+ user: string
94
+ }
95
+ export type UserStats = {
96
+ activity: Date,
97
+ balance: number,
98
+ bandwidth: number,
99
+ date: Date,
100
+ failures: number,
101
+ refClics: number,
102
+ refCommission: number,
103
+ refSignups: number,
104
+ success: number,
105
+ user: string
106
+ }
107
+ export type Withdraw = {
108
+ address: string,
109
+ amount: number,
110
+ btcPrice: number,
111
+ date: Date,
112
+ fees: number,
113
+ id: number,
114
+ sent: number,
115
+ transactionId?: string,
116
+ user: string
117
+ }
package/src/app/config.ts CHANGED
@@ -14,6 +14,9 @@
14
14
  import fs from 'fs-extra';
15
15
  import yaml from 'yaml';
16
16
 
17
+ // Types
18
+ import type { TEnvConfig } from '../../../core/src/server/app/container/config';
19
+
17
20
  /*----------------------------------
18
21
  - LOADE
19
22
  ----------------------------------*/
@@ -32,10 +35,9 @@ export default class ConfigParser {
32
35
  return yaml.parse(rawConfig);
33
36
  }
34
37
 
35
- public env() {
38
+ public env(): TEnvConfig {
36
39
  // We assume that when we run 5htp dev, we're in local
37
40
  // Otherwise, we're in production environment (docker)
38
- console.log("[cli] Using environment:", process.env.NODE_ENV);
39
41
  return process.env.NODE_ENV === 'development' ? {
40
42
  name: 'local',
41
43
  profile: 'dev',
package/src/app/index.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  ----------------------------------*/
4
4
 
5
5
  // npm
6
+ import path from 'path';
6
7
  import TsAlias from 'ts-alias';
7
8
 
8
9
  // Cre
@@ -10,7 +11,7 @@ import cli from '..';
10
11
 
11
12
  // Specific
12
13
  import ConfigParser from './config';
13
- import type { } from '../../../core/src/server/app/config';
14
+ import type { TEnvConfig } from '../../../core/src/server/app/container/config';
14
15
 
15
16
  /*----------------------------------
16
17
  - TYPES
@@ -21,21 +22,32 @@ export type TAppSide = 'server' | 'client'
21
22
  /*----------------------------------
22
23
  - SERVICE
23
24
  ----------------------------------*/
24
- export default class App {
25
+ export class App {
25
26
 
26
27
  // config
27
28
  // WARNING: High level config files (env and services) shouldn't be loaded from the CLI
28
29
  // The CLI will be run on CircleCI, and no env file should be sent to this service
29
30
  public identity: Config.Identity;
30
31
 
32
+ public env: TEnvConfig;
33
+
31
34
  public paths = {
35
+
32
36
  root: cli.paths.appRoot,
33
- src: cli.paths.appRoot + '/src',
34
- bin: cli.paths.appRoot + '/bin',
35
- data: cli.paths.appRoot + '/var/data',
36
- public: cli.paths.appRoot + '/public',
37
- pages: cli.paths.appRoot + '/src/client/pages',
38
- cache: cli.paths.appRoot + '/src/.cache',
37
+ src: path.join( cli.paths.appRoot, 'src'),
38
+ bin: path.join( cli.paths.appRoot, 'bin'),
39
+ data: path.join( cli.paths.appRoot, 'var', 'data'),
40
+ public: path.join( cli.paths.appRoot, 'public'),
41
+ pages: path.join( cli.paths.appRoot, 'src', 'client', 'pages'),
42
+ cache: path.join( cli.paths.appRoot, 'src', '.cache'),
43
+
44
+ client: {
45
+ generated: path.join( cli.paths.appRoot, 'src', 'client', '.generated')
46
+ },
47
+ server: {
48
+ generated: path.join( cli.paths.appRoot, 'src', 'server', '.generated'),
49
+ configs: path.join( cli.paths.appRoot, 'src', 'server', 'app')
50
+ },
39
51
 
40
52
  withAlias: (filename: string, side: TAppSide) =>
41
53
  this.aliases[side].apply(filename),
@@ -44,11 +56,21 @@ export default class App {
44
56
  this.aliases[side].realpath(filename),
45
57
  }
46
58
 
59
+ public containerServices = [
60
+ 'Services',
61
+ 'Environment',
62
+ 'Identity',
63
+ /*'Application',
64
+ 'Path',
65
+ 'Event'*/
66
+ ]
67
+
47
68
  public constructor() {
48
69
 
49
- console.log(`[cli] Loading app config ...`);
70
+ cli.debug && console.log(`[cli] Loading app config ...`);
50
71
  const configParser = new ConfigParser( cli.paths.appRoot );
51
72
  this.identity = configParser.identity();
73
+ this.env = configParser.env();
52
74
  }
53
75
 
54
76
  /*----------------------------------
@@ -73,4 +95,8 @@ export default class App {
73
95
  debug: false
74
96
  }),
75
97
  }
76
- }
98
+ }
99
+
100
+ export const app = new App
101
+
102
+ export default app
@@ -6,10 +6,7 @@
6
6
  import prompts from 'prompts';
7
7
 
8
8
  // Configs
9
- import createCompilers from '../compiler';
10
-
11
- // Core
12
- import App from '../app';
9
+ import Compiler from '../compiler';
13
10
 
14
11
  /*----------------------------------
15
12
  - TYPES
@@ -20,9 +17,9 @@ import App from '../app';
20
17
  ----------------------------------*/
21
18
  export const run = (): Promise<void> => new Promise(async (resolve) => {
22
19
 
23
- const app = new App();
20
+ const compiler = new Compiler('prod');
24
21
 
25
- const multiCompiler = await createCompilers(app, 'prod');
22
+ const multiCompiler = await compiler.create();
26
23
 
27
24
  multiCompiler.run((error, stats) => {
28
25
 
@@ -11,19 +11,17 @@ import cli from '../';
11
11
  import Keyboard from '../utils/keyboard';
12
12
 
13
13
  // Configs
14
- import createCompilers, { compiling } from '../compiler';
14
+ import Compiler from '../compiler';
15
15
 
16
16
  // Core
17
- import App from '../app';
17
+ import { app, App } from '../app';
18
18
 
19
19
  /*----------------------------------
20
20
  - COMMANDE
21
21
  ----------------------------------*/
22
22
  export const run = () => new Promise<void>(async () => {
23
-
24
- const app = new App();
25
23
 
26
- const multiCompiler = await createCompilers(app, 'dev', {
24
+ const compiler = new Compiler('dev', {
27
25
  before: () => {
28
26
 
29
27
  stopApp();
@@ -35,6 +33,8 @@ export const run = () => new Promise<void>(async () => {
35
33
  }
36
34
  });
37
35
 
36
+ const multiCompiler = await compiler.create();
37
+
38
38
  multiCompiler.watch({
39
39
 
40
40
  // https://webpack.js.org/configuration/watch/#watchoptions
@@ -60,8 +60,8 @@ export const run = () => new Promise<void>(async () => {
60
60
 
61
61
  Keyboard.input('ctrl+r', async () => {
62
62
 
63
- console.log(`Waiting for compilers to be ready ...`, Object.keys(compiling));
64
- await Promise.all(Object.values(compiling));
63
+ console.log(`Waiting for compilers to be ready ...`, Object.keys(compiler.compiling));
64
+ await Promise.all(Object.values(compiler.compiling));
65
65
 
66
66
  console.log(`Reloading app ...`);
67
67
  startApp(app);
@@ -178,7 +178,7 @@ export default function createCompiler( app: App, mode: TCompileMode ): webpack.
178
178
  ...c.chunks.reduce(
179
179
  (files, cc) => [
180
180
  ...files,
181
- ...cc.files.filter(fileFilter).map(addPath),
181
+ ...[...cc.files].filter(fileFilter).map(addPath),
182
182
  ],
183
183
  [],
184
184
  ),
@@ -124,12 +124,11 @@ module.exports = (app: App, side: TAppSide, dev: boolean): webpack.RuleSetRule[]
124
124
 
125
125
  //require("./plugins/pages")({ side }),
126
126
 
127
- require('./routes/routes')({ side, app }),
127
+ require('./routes/routes')({ side, app, debug: false }),
128
128
 
129
129
  ...(side === 'client' ? [] : [
130
130
 
131
- // Dependancies injection
132
- //require('./plugins/services')({ side }),
131
+ require('./plugins/services')({ side, app, debug: false }),
133
132
 
134
133
  ]),
135
134
 
@@ -4,157 +4,202 @@
4
4
 
5
5
  // Npm
6
6
  import * as types from '@babel/types'
7
- import type { PluginObj, NodePath } from '@babel/core';
8
- import generate from '@babel/generator';
7
+ import type { PluginObj } from '@babel/core';
9
8
 
10
9
  // Core
11
10
  import cli from '@cli';
12
- import App, { TAppSide } from '../../../../app';
11
+ import { App, TAppSide } from '../../../../app';
13
12
 
14
13
  /*----------------------------------
15
14
  - WEBPACK RULE
16
15
  ----------------------------------*/
17
16
 
18
17
  type TOptions = {
19
- side: TAppSide
18
+ side: TAppSide,
19
+ app: App,
20
+ debug?: boolean
20
21
  }
21
22
 
22
- const filenamePrefix = cli.paths.appRoot + '/src/server/services';
23
- const processFile = (filename: string) => (
24
- filename.startsWith( cli.paths.appRoot + '/src/server/services' )
25
- |
26
- filename.startsWith( cli.paths.appRoot + '/src/server/routes' )
27
- )
23
+ type TImportSource = 'container' | 'application';
28
24
 
29
25
  module.exports = (options: TOptions) => (
30
26
  [Plugin, options]
31
27
  )
32
28
 
33
- const debug = true;
34
29
 
35
30
  /*----------------------------------
36
31
  - PLUGIN
37
32
  ----------------------------------*/
38
- function Plugin(babel, { side }: TOptions) {
33
+ function Plugin(babel, { app, side, debug }: TOptions) {
39
34
 
40
35
  const t = babel.types as typeof types;
41
- let program: NodePath<types.Program>;
36
+
37
+ /*
38
+ Transforms:
39
+ import { MyService, Environment } from '@app';
40
+ ...
41
+ MyService.method()
42
+ Environment.name
43
+
44
+ To:
45
+ import app from '@app';
46
+ import Container from '@server/app/container';
47
+ ...
48
+ app.services.MyService.method()
49
+ Container.Environment.name
50
+
51
+ Processed files:
52
+ @/server/config
53
+ @/server/routes
54
+ @/server/services
55
+ */
42
56
 
43
57
  const plugin: PluginObj<{
44
58
 
45
- filename: string,
59
+ debug: boolean,
46
60
 
47
- appImport: string | null,
61
+ filename: string,
62
+ processFile: boolean,
48
63
 
49
64
  // Identifier => Name
50
- importedServices: {[identifier: string]: string}
65
+ importedServicesCount: number,
66
+ importedServices: {
67
+ [local: string]: {
68
+ imported: string,
69
+ bindings: any, // TODO: Scope.Binding[] type
70
+ source: TImportSource
71
+ }
72
+ },
73
+ bySource: {[importSource in TImportSource] : number}
51
74
  }> = {
52
75
  pre(state) {
53
76
 
54
77
  this.filename = state.opts.filename as string;
78
+ this.processFile = (
79
+ this.filename.startsWith( cli.paths.appRoot + '/src/server/config' )
80
+ ||
81
+ this.filename.startsWith( cli.paths.appRoot + '/src/server/routes' )
82
+ ||
83
+ this.filename.startsWith( cli.paths.appRoot + '/src/server/services' )
84
+ )
55
85
 
56
- this.appImport = null
57
86
  this.importedServices = {}
87
+ this.bySource = {
88
+ container: 0,
89
+ application: 0
90
+ }
91
+ this.importedServicesCount = 0
92
+ this.debug = debug || false;
58
93
 
59
94
  },
60
95
  visitor: {
61
96
 
62
- Program(path) {
63
- program = path;
64
- },
65
-
66
- // Transform imports
97
+ // Find @app imports
98
+ // Test: import { router } from '@app';
99
+ // Replace by: nothing
67
100
  ImportDeclaration(path) {
68
101
 
69
- if (!this.filename.startsWith( cli.paths.appRoot + '/src/server' ))
102
+ if (!this.processFile)
70
103
  return;
71
104
 
72
- if (path.node.source.value !== '@server/app')
105
+ if (path.node.source.value !== '@app')
73
106
  return;
74
107
 
75
- const importedServices: { local: string, imported: string }[] = []
76
- let appName: string = 'app';
77
-
78
108
  for (const specifier of path.node.specifiers) {
79
- /*
80
- import app from '@server/app';
81
- */
82
- if (specifier.type === 'ImportDefaultSpecifier') {
109
+
110
+ if (specifier.type !== 'ImportSpecifier')
111
+ continue;
83
112
 
84
- appName = specifier.local.name;
113
+ if (specifier.imported.type !== 'Identifier')
114
+ continue;
85
115
 
86
- /*
87
- import { sql } from '@server/app';
88
- =>
89
- import app from '@server/app';
90
- app.use('sql');
91
- */
92
- } else if (specifier.type === 'ImportSpecifier') {
116
+ this.importedServicesCount++;
93
117
 
94
- if (specifier.imported.type !== 'Identifier')
95
- continue;
118
+ let importSource: TImportSource;
119
+ if (app.containerServices.includes(specifier.imported.name))
120
+ importSource = 'container';
121
+ else
122
+ importSource = 'application';
96
123
 
97
- importedServices.push({
98
- local: specifier.local.name,
99
- imported: specifier.imported.name
100
- });
124
+ this.importedServices[ specifier.local.name ] = {
125
+ imported: specifier.imported.name,
126
+ bindings: path.scope.bindings[ specifier.local.name ].referencePaths,
127
+ source: importSource
128
+ }
101
129
 
102
- /*
103
- import * as templates from '@server/app';
104
- =>
130
+ this.bySource[ importSource ]++;
131
+ }
105
132
 
106
- */
107
- } else if (specifier.type === 'ImportNamespaceSpecifier') {
133
+ // Replace by simple import
134
+ this.debug && console.log("[babel][services] Replace importation");
135
+ const replaceWith: any[] = []
108
136
 
109
- //importDefault = specifier.local.name;
110
- //importAll = true;
137
+ if (this.bySource.container > 0)
138
+ replaceWith.push(
139
+ t.importDeclaration(
140
+ [t.importDefaultSpecifier( t.identifier('container') )],
141
+ t.stringLiteral( cli.paths.core.src + '/server/app/container')
142
+ )
143
+ );
111
144
 
112
- }
113
- }
145
+ if (this.bySource.application > 0)
146
+ replaceWith.push(
147
+ t.importDeclaration(
148
+ [t.importDefaultSpecifier( t.identifier('application') )],
149
+ t.stringLiteral( cli.paths.core.src + '/server/app/instance')
150
+ )
151
+ );
114
152
 
115
- // No service imported
116
- // This verification avoids ininite loop
117
- if (importedServices.length === 0)
153
+ path.replaceWithMultiple(replaceWith);
154
+ },
155
+
156
+ Identifier(path) {
157
+
158
+ if (!this.processFile || this.importedServicesCount === 0)
118
159
  return;
119
160
 
120
- const replacements: types.Statement[] = [
121
- t.importDeclaration(
122
- [
123
- t.importDefaultSpecifier( t.identifier( appName )),
124
- ],
125
- t.stringLiteral('@server/app')
126
- )
127
- ]
128
-
129
- for (const { imported, local } of importedServices) {
130
-
131
- replacements.push(
132
- t.expressionStatement(
133
- t.callExpression(
134
- t.memberExpression(
135
- t.identifier( appName ),
136
- t.identifier('use')
137
- ),
138
- [
139
- t.stringLiteral( imported )
140
- ]
141
- )
142
- )
143
- );
161
+ // Get service the identifier makes rfeerence to
162
+ const name = path.node.name;
163
+ const service = this.importedServices[ name ];
164
+ if (service === undefined)
165
+ return;
166
+
167
+ // sometimes not iterable
168
+ if (!service.bindings)
169
+ return;
144
170
 
145
- this.importedServices[ local ] = imported;
171
+ // Replace by app.services.name
172
+ let serviceBinding: any;
173
+ for (const binding of service.bindings) {
174
+ if (binding.replaced !== true && path.getPathLocation() === binding.getPathLocation()) {
175
+
176
+ serviceBinding = binding;
177
+
178
+ break;
179
+ }
146
180
  }
147
181
 
148
- debug && console.log(`############ [compilation][babel][services] Remplacement: `,
149
- generate(t.program(replacements)).code
150
- );
182
+ // This identifier is a binding to a service
183
+ if (serviceBinding === undefined)
184
+ return;
151
185
 
152
- path.replaceWithMultiple(replacements);
153
- },
186
+ // Replace to reference to app.services.serviceName
187
+ path.replaceWith(
188
+ t.memberExpression(
189
+ service.source === 'container'
190
+ // container.Environment
191
+ ? t.identifier( service.source )
192
+ // application.services.Disks
193
+ : t.memberExpression(
194
+ t.identifier( service.source ),
195
+ t.identifier('services'),
196
+ ),
197
+ path.node
198
+ )
199
+ );
154
200
 
155
- // transform accesses
156
- Identifier() {
157
-
201
+ // Avoid circular loop
202
+ serviceBinding.replaced = true;
158
203
  }
159
204
  }
160
205
  }