5htp-core 0.5.9-1 → 0.5.9-2

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.
@@ -7,8 +7,7 @@ import React from 'react';
7
7
  import type { ComponentChild } from 'preact';
8
8
 
9
9
  // Core components
10
- import { Logo } from '@client/components';
11
- import { Link } from '@client/services/router';
10
+ import { Logo, Link } from '@client/components';
12
11
 
13
12
  // Resources
14
13
  import './index.less';
package/client/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import Application from '@/client';
2
2
 
3
3
  const app = new Application();
4
+ app.app = app;
4
5
 
5
6
  app.start();
@@ -55,7 +55,6 @@ const LogPrefix = '[router]'
55
55
 
56
56
  // Client router can handle Client requests AND Server requests (for pages only)
57
57
  export type { default as ClientResponse, TRouterContext } from "./response";
58
- export { Link } from './components/Link';
59
58
 
60
59
  export type Router = ClientRouter | ServerRouter;
61
60
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "5htp-core",
3
3
  "description": "Convenient TypeScript framework designed for Performance and Productivity.",
4
- "version": "0.5.9-1",
4
+ "version": "0.5.9-2",
5
5
  "author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
6
6
  "repository": "git://github.com/gaetanlegac/5htp-core.git",
7
7
  "license": "MIT",
@@ -53,26 +53,7 @@ export default class CommandsManager extends Service<Config, Hooks, Application,
53
53
  public priority = 2 as 2;
54
54
 
55
55
  public commandsIndex: CommandsList = {}
56
-
57
- /*----------------------------------
58
- - LIFECYCLE
59
- ----------------------------------*/
60
-
61
- protected async start() {
62
-
63
- }
64
-
65
- protected async ready() {
66
-
67
- }
68
-
69
- protected async shutdown() {
70
-
71
- }
72
-
73
- /*----------------------------------
74
- - DEFINITIONS
75
- ----------------------------------*/
56
+
76
57
  public command<TArgs extends any[]>(
77
58
  ...args: (
78
59
  [name: string, description: string, childrens: Command[]]
@@ -206,11 +206,6 @@ export default class Console {
206
206
  this.enableLogging(origLog);
207
207
  }
208
208
 
209
- // Avoid to use lifecycle functions
210
- protected async start() {}
211
- public async ready() {}
212
- public async shutdown() {}
213
-
214
209
  private enableLogging( origLog: typeof console.log ) {
215
210
 
216
211
  const minLogLevel = logLevels[this.config.level];
@@ -7,7 +7,7 @@ import type express from 'express';
7
7
 
8
8
  // Core
9
9
  import AppContainer from './container';
10
- import ApplicationService, { StartedServicesIndex } from './service';
10
+ import ApplicationService, { AnyService, StartedServicesIndex } from './service';
11
11
  import CommandsManager from './commands';
12
12
  import ServicesContainer, {
13
13
  ServicesContainer as ServicesContainerClass,
@@ -82,8 +82,12 @@ export abstract class Application<
82
82
  public debug: boolean = false;
83
83
  public launched: boolean = false;
84
84
 
85
- protected abstract serviceNames: string[];
86
- protected abstract servicesIdToName: { [serviceId: string]: string };
85
+ protected abstract registered: {
86
+ [serviceId: string]: {
87
+ name: string,
88
+ start: () => AnyService
89
+ }
90
+ };
87
91
 
88
92
  /*----------------------------------
89
93
  - INIT
@@ -132,6 +136,8 @@ export abstract class Application<
132
136
  console.log("Core version", CORE_VERSION);
133
137
  const startTime = Date.now();
134
138
 
139
+ this.startServices();
140
+
135
141
  await this.ready();
136
142
  await this.runHook('ready');
137
143
 
@@ -151,16 +157,48 @@ export abstract class Application<
151
157
 
152
158
  }
153
159
 
160
+ private startServices() {
161
+
162
+ // Print services
163
+ console.log('----------------------------------');
164
+ console.log('- SERVICES');
165
+ console.log('----------------------------------');
166
+ const printService = (service, level: number = 0) => {
167
+
168
+ console.log('-' + '-'.repeat(level * 4), service.name, '(' + service.priority + ')');
169
+
170
+ if (service.subservices) for (const subservice of service.subservices)
171
+ printService(subservice, level + 1);
172
+ }
173
+
174
+ // Satrt services
175
+ for (const serviceId in this.registered) {
176
+
177
+ const service = this.registered[serviceId];
178
+ printService(service, 0);
179
+ const instance = service.start();
180
+ this[service.name] = instance.getServiceInstance();
181
+ }
182
+ }
183
+
154
184
  protected async ready() {
155
185
 
156
- console.info(`[boot] Prepare services`);
157
- for (const serviceName of this.serviceNames) {
186
+ const processService = (service: AnyService) => {
158
187
 
159
- const service = this[serviceName];
188
+ service.ready();
189
+
190
+ // Subservices
191
+ for (const serviceId in service.services)
192
+ processService(service.services[serviceId]);
193
+ }
194
+
195
+ for (const serviceId in this.registered) {
160
196
 
161
- if (typeof service.getServices === 'function')
162
- service.services = service.getServices();
197
+ const registeredService = this.registered[serviceId];
198
+ const service = this[registeredService.name];
163
199
 
200
+ // TODO: move to router
201
+ // Application.on('service.ready')
164
202
  const routes = service.__routes;
165
203
  if (routes) for (const route of routes) {
166
204
 
@@ -182,7 +220,7 @@ export abstract class Application<
182
220
  this.Router.controllers[ route.path ] = route;
183
221
  }
184
222
 
185
- service.ready();
223
+ processService(service);
186
224
  }
187
225
  }
188
226
 
@@ -110,7 +110,7 @@ export default abstract class Service<
110
110
  public config: TConfig,
111
111
  // Make this argument appear as instanciated sercices index
112
112
  // But actually, Setup.use returns a registered service, not yet launched
113
- public getServices: TServicesIndex,
113
+ getServices: (instance: AnyService) => TServicesIndex,
114
114
  app: TApplication | 'self'
115
115
  ) {
116
116
 
@@ -120,6 +120,9 @@ export default abstract class Service<
120
120
  this.app = app === 'self'
121
121
  ? this as unknown as TApplication
122
122
  : app
123
+
124
+ if (typeof getServices === 'function')
125
+ this.services = getServices(this);
123
126
 
124
127
  }
125
128
 
@@ -143,11 +146,11 @@ export default abstract class Service<
143
146
 
144
147
  public use( serviceId: string ) {
145
148
 
146
- const serviceName = this.app.servicesIdToName[serviceId];
147
- if (serviceName === undefined)
148
- throw new Error(`Service ${serviceName} not found.`);
149
+ const registeredService = this.app.registered[serviceId];
150
+ if (registeredService === undefined)
151
+ throw new Error(`Service ${registeredService} not found.`);
149
152
 
150
- return this.app[ serviceName ];
153
+ return this.app[ registeredService.name ];
151
154
  }
152
155
 
153
156
  /*----------------------------------
@@ -13,7 +13,7 @@ type AuthResponse = {
13
13
  export default class {
14
14
 
15
15
 
16
- protected async start() {
16
+ protected async ready() {
17
17
 
18
18
  // Google auth client
19
19
  if (this.config.google) {
@@ -37,9 +37,15 @@ export default class AuthenticationRouterService<
37
37
  - LIFECYCLE
38
38
  ----------------------------------*/
39
39
 
40
- public users = this.services.users;
40
+ public users;
41
41
 
42
- protected async start() {
42
+ public constructor(...args) {
43
+ super(...args);
44
+
45
+ this.users = this.services.users;
46
+ }
47
+
48
+ protected async ready() {
43
49
 
44
50
  // Decode current user
45
51
  this.parent.on('request', async (request: TRequest) => {
@@ -59,10 +65,6 @@ export default class AuthenticationRouterService<
59
65
  })
60
66
  }
61
67
 
62
- protected async ready() {
63
-
64
- }
65
-
66
68
  protected async shutdown() {
67
69
 
68
70
  }
@@ -96,16 +96,9 @@ export default class Cache extends Service<Config, Hooks, Application, Services>
96
96
  - LIFECYCLE
97
97
  ----------------------------------*/
98
98
 
99
- protected async start() {
100
-
101
- setInterval(() => this.cleanMem(), 10000);
102
-
103
- // Restore persisted data
104
- //await this.restore();
105
- }
106
-
107
99
  public async ready() {
108
100
 
101
+ setInterval(() => this.cleanMem(), 10000);
109
102
  }
110
103
 
111
104
  public async shutdown() {
@@ -45,7 +45,7 @@ export default class CronManager extends Service<Config, Hooks, Application, Ser
45
45
  - LIFECICLE
46
46
  ----------------------------------*/
47
47
 
48
- protected async start() {
48
+ public async ready() {
49
49
 
50
50
  clearInterval(CronManager.timer);
51
51
  CronManager.timer = setInterval(() => {
@@ -54,13 +54,6 @@ export default class CronManager extends Service<Config, Hooks, Application, Ser
54
54
  CronManager.taches[id].run();
55
55
 
56
56
  }, 10000);
57
- }
58
-
59
- public async ready() {
60
-
61
- }
62
-
63
- public async shutdown() {
64
57
 
65
58
  }
66
59
 
@@ -98,7 +98,7 @@ export default class SQL extends Service<Config, Hooks, Application, Services> {
98
98
  public constructor(
99
99
  parent: AnyService,
100
100
  config: Config,
101
- drivers: TRegisteredServicesIndex,
101
+ drivers: () => TRegisteredServicesIndex,
102
102
  app: Application,
103
103
  ) {
104
104
 
@@ -77,8 +77,6 @@ export default class StatsService extends Service<TStatsServiceConfig> {
77
77
 
78
78
  }
79
79
 
80
- protected async start() {}
81
-
82
80
  public async fetchStats<TDonnees extends TObjDonneesStats>(
83
81
 
84
82
  table: string, columns: (string | [string, string])[], {
@@ -4,7 +4,7 @@
4
4
 
5
5
  // Core
6
6
  import type { Application } from '@server/app';
7
- import Service, { AnyService } from '@server/app/service';
7
+ import Service, { AnyService, TRegisteredServicesIndex } from '@server/app/service';
8
8
 
9
9
  // Specific
10
10
  import type Driver from './driver';
@@ -44,15 +44,20 @@ export default class DisksManager<
44
44
  - LIFECYCLE
45
45
  ----------------------------------*/
46
46
 
47
- public async ready() {
47
+ public constructor(
48
+ parent: AnyService,
49
+ config: TConfig,
50
+ services: () => TRegisteredServicesIndex,
51
+ app: Application,
52
+ ) {
53
+
54
+ super(parent, config, services, app);
48
55
 
49
56
  const drivers = this.services;
50
57
 
51
58
  if (Object.keys( drivers ).length === 0)
52
59
  throw new Error("At least one disk driver should be mounted.");
53
60
 
54
- console.log('start disks service', Object.keys( drivers ), Object.keys( this.mounted ), Object.keys( this.services ));
55
-
56
61
  const defaultDisk = drivers[ this.config.default ];
57
62
  if (defaultDisk === undefined)
58
63
  console.log(`Default disk "${this.config.default as string}" not mounted.`);
@@ -27,25 +27,5 @@ export type TBasicConfig = {
27
27
  export abstract class Transporter<TConfig extends TBasicConfig = TBasicConfig>
28
28
  extends Service<TConfig, {}, Application, {}> {
29
29
 
30
- /*----------------------------------
31
- - LIFECYCLE
32
- ----------------------------------*/
33
-
34
- protected async start() {
35
-
36
- }
37
-
38
- protected async ready() {
39
-
40
- }
41
-
42
- protected async shutdown() {
43
-
44
- }
45
-
46
- /*----------------------------------
47
- - ACTIONS
48
- ----------------------------------*/
49
-
50
30
  public abstract send( emails: TCompleteEmail[] ): Promise<void>;
51
31
  }
@@ -37,19 +37,6 @@ export type Services = {
37
37
  export default class ModelsManager extends Service<Config, Hooks, Application, Services> {
38
38
 
39
39
  public client = new PrismaClient();
40
-
41
- /*----------------------------------
42
- - LIFECICLE
43
- ----------------------------------*/
44
-
45
- protected async start() {
46
-
47
-
48
- }
49
-
50
- public async ready() {
51
-
52
- }
53
40
 
54
41
  public async shutdown() {
55
42
  await this.client.$disconnect()
@@ -147,7 +147,7 @@ export default class ServerRouter<
147
147
  public constructor(
148
148
  parent: AnyService,
149
149
  config: Config,
150
- services: TSubservices,
150
+ services: () => TSubservices,
151
151
  app: Application,
152
152
  ) {
153
153
 
@@ -174,8 +174,8 @@ export default class ServerRouter<
174
174
  // Use require to avoid circular references
175
175
  this.registerRoutes([
176
176
  ...require("metas:@/server/routes/**/*.ts"),
177
- ...require("metas:@/client/pages/**/*.tsx"),
178
- ...require("metas:@client/pages/**/*.tsx")
177
+ ...require("metas:@/client/pages/**/([a-z0-9]*).tsx"),
178
+ ...require("metas:@/client/pages/**/([a-z0-9]*).tsx")
179
179
  ]);
180
180
 
181
181
  // Start HTTP server
@@ -192,7 +192,6 @@ export default class ServerRouter<
192
192
  ----------------------------------*/
193
193
 
194
194
  private registerRoutes(defModules: GlobImportedWithMetas<TRouteModule>) {
195
-
196
195
  for (const routeModule of defModules) {
197
196
 
198
197
  const register = routeModule.exports.__register;
@@ -21,10 +21,6 @@ import ApiClientService, {
21
21
  ----------------------------------*/
22
22
  export default class ApiClientRequest extends RequestService implements ApiClientService {
23
23
 
24
- protected async start() {
25
-
26
- }
27
-
28
24
  /*----------------------------------
29
25
  - HIGH LEVEL
30
26
  ----------------------------------*/
@@ -66,9 +62,8 @@ export default class ApiClientRequest extends RequestService implements ApiClien
66
62
  public createFetcher<TData extends unknown = unknown>(...[method, path, data, options]: TFetcherArgs): TFetcher<TData> {
67
63
  return {
68
64
  method, path, data, options,
69
- then: () => { throw new Error("Async resolvers should not be run from server side."); },
70
- run: () => { throw new Error("Async resolvers should not be run from server side."); },
71
- };
65
+ // We don't put the then and catch methods so the api consumer on server side will know it's a fetcher and not a promize to wait
66
+ } as TFetcher<TData>;
72
67
  }
73
68
 
74
69
  public async fetchSync(fetchers: TFetcherList, alreadyLoadedData: {}): Promise<TObjetDonnees> {
@@ -72,7 +72,7 @@ export default class WebSocketCommander<
72
72
  ----------------------------------*/
73
73
 
74
74
  public loading: Promise<void> | undefined = undefined;
75
- protected async start() {
75
+ protected async ready() {
76
76
 
77
77
  this.users.on('disconnect', async (userId: string) => {
78
78
  this.disconnect(userId, 'Logout');
@@ -120,10 +120,6 @@ export default class WebSocketCommander<
120
120
  console.info(`Socket commander bound to http server.`);
121
121
  }
122
122
 
123
- public async ready() {
124
-
125
- }
126
-
127
123
  public async shutdown() {
128
124
  this.closeAll();
129
125
  }
@@ -55,6 +55,51 @@ declare type Routes = {
55
55
 
56
56
  declare type PrimitiveValue = string | number | boolean;
57
57
 
58
+ /*----------------------------------
59
+ - COPY FROM CLI/APP/INDEX.TS
60
+ ----------------------------------*/
61
+
62
+ type TEnvConfig = {
63
+ name: 'local' | 'server',
64
+ profile: 'dev' | 'prod',
65
+ version: string,
66
+ }
67
+
68
+ type TServiceSetup = {
69
+ id: string,
70
+ name: string,
71
+ config: {},
72
+ subservices: TServiceSubservices
73
+ }
74
+
75
+ type TServiceRef = {
76
+ refTo: string
77
+ }
78
+
79
+ type TServiceSubservices = {
80
+ [key: string]: TServiceSetup | TServiceRef
81
+ }
82
+
58
83
  declare module '@cli/app' {
59
- export const app: 'test';
84
+ type App = {
85
+
86
+ env: TEnvConfig;
87
+
88
+ use: (referenceName: string) => TServiceRef;
89
+
90
+ setup: (...args: [
91
+ // { user: app.setup('Core/User') }
92
+ servicePath: string,
93
+ serviceConfig?: {},
94
+ serviceSubservices?: TServiceSubservices
95
+ ] | [
96
+ // app.setup('User', 'Core/User')
97
+ serviceName: string,
98
+ servicePath: string,
99
+ serviceConfig?: {},
100
+ serviceSubservices?: TServiceSubservices
101
+ ]) => TServiceSetup;
102
+ }
103
+ const app: App;
104
+ export = app;
60
105
  }
package/types/icons.d.ts CHANGED
@@ -1 +1 @@
1
- export type TIcones = "solid/spinner-third"|"at"|"bell"|"times-circle"|"info-circle"|"check-circle"|"exclamation-circle"|"times"|"map-marker-alt"|"bullhorn"|"angle-down"|"search"|"check"|"eye"|"trash"|"meh-rolling-eyes"|"arrow-left"|"arrow-right"|"bold"|"italic"|"underline"|"strikethrough"|"subscript"|"superscript"|"code"|"link"|"unlink"|"pen"|"file"|"font"|"empty-set"|"horizontal-rule"|"page-break"|"image"|"table"|"poll"|"columns"|"sticky-note"|"caret-right"|"plus"|"list-ul"|"check-square"|"h1"|"h2"|"h3"|"h4"|"list-ol"|"paragraph"|"quote-left"|"align-left"|"align-center"|"align-right"|"align-justify"|"indent"|"outdent"
1
+ export type TIcones = "long-arrow-right"|"times"|"solid/spinner-third"|"sack-dollar"|"bell"|"bullseye"|"project-diagram"|"user-friends"|"eye"|"lock"|"comments"|"phone"|"chalkboard-teacher"|"chart-bar"|"at"|"arrow-right"|"rocket"|"magnet"|"search"|"file-excel"|"plus-circle"|"plus"|"user-plus"|"mouse-pointer"|"thumbs-up"|"dollar-sign"|"map-marker"|"link"|"industry"|"users"|"calendar-alt"|"file-invoice"|"binoculars"|"brands/linkedin"|"lightbulb"|"long-arrow-left"|"key"|"user"|"building"|"briefcase"|"times-circle"|"suitcase"|"brands/linkedin-in"|"phone-plus"|"envelope"|"home-alt"|"planet-ringed"|"user-circle"|"crosshairs"|"comments-alt"|"paper-plane"|"user-shield"|"shield-alt"|"chart-line"|"money-bill-wave"|"star"|"file-alt"|"angle-up"|"angle-down"|"solid/crown"|"brands/discord"|"pen"|"file"|"info-circle"|"check-circle"|"exclamation-circle"|"check"|"meh-rolling-eyes"|"arrow-left"|"trash"|"solid/star"|"solid/star-half-alt"|"regular/star"|"chevron-left"|"cog"|"power-off"|"usd-circle"|"trophy"|"bars"|"chevron-right"|"edit"|"map-marker-alt"|"clock"|"arrow-to-bottom"|"ellipsis-h"|"question-circle"|"play"|"minus-circle"|"plane-departure"|"wind"|"external-link"|"ban"|"heart"|"calendar-check"|"unlink"|"bold"|"italic"|"underline"|"strikethrough"|"subscript"|"superscript"|"code"|"font"|"empty-set"|"horizontal-rule"|"page-break"|"image"|"table"|"poll"|"columns"|"sticky-note"|"caret-right"|"align-left"|"align-center"|"align-right"|"align-justify"|"indent"|"outdent"|"list-ul"|"check-square"|"h1"|"h2"|"h3"|"h4"|"list-ol"|"paragraph"|"quote-left"