5htp-core 0.3.1 → 0.3.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.
- package/package.json +1 -1
- package/src/client/services/router/components/Link.tsx +1 -1
- package/src/client/services/router/components/Page.tsx +2 -1
- package/src/client/services/router/index.tsx +17 -26
- package/src/client/services/router/request/api.ts +12 -4
- package/src/client/services/router/response/page.ts +5 -7
- package/src/common/router/index.ts +2 -1
- package/src/common/router/register.ts +5 -8
- package/src/common/router/response/page.ts +31 -17
- package/src/server/app/index.ts +12 -3
- package/src/server/app/service/container.ts +1 -1
- package/src/server/app/service/index.ts +24 -7
- package/src/server/services/database/datatypes.ts +14 -2
- package/src/server/services/disks/index.ts +1 -2
- package/src/server/services/email/index.ts +2 -5
- package/src/server/services/email/transporter.ts +19 -6
- package/src/server/services/router/http/index.ts +2 -2
- package/src/server/services/router/index.ts +14 -13
- package/src/server/services/router/request/api.ts +8 -1
- package/src/server/services/router/response/index.ts +2 -2
- package/src/server/services/router/response/page/index.tsx +4 -5
- package/src/server/services/schema/router/index.ts +1 -2
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.3.
|
|
4
|
+
"version": "0.3.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",
|
|
@@ -19,7 +19,7 @@ export const Link = ({ to, ...props }: {
|
|
|
19
19
|
} & React.HTMLProps<HTMLAnchorElement>) => {
|
|
20
20
|
|
|
21
21
|
// External = open in new tab by default
|
|
22
|
-
if (to[0] !== '/' || to.startsWith('//'))
|
|
22
|
+
if (to && (to[0] !== '/' || to.startsWith('//')))
|
|
23
23
|
props.target = '_blank';
|
|
24
24
|
// Otherwise, propagate to the router
|
|
25
25
|
else
|
|
@@ -22,6 +22,7 @@ export default ({ page, isCurrent }: { page: Page, isCurrent?: boolean }) => {
|
|
|
22
22
|
page.loading ? null : page.data
|
|
23
23
|
);
|
|
24
24
|
page.setAllData = setApiData;
|
|
25
|
+
context.data = apiData;
|
|
25
26
|
|
|
26
27
|
React.useEffect(() => {
|
|
27
28
|
|
|
@@ -50,7 +51,7 @@ export default ({ page, isCurrent }: { page: Page, isCurrent?: boolean }) => {
|
|
|
50
51
|
// URL params
|
|
51
52
|
{...context.request.data}
|
|
52
53
|
// API data
|
|
53
|
-
{
|
|
54
|
+
data={apiData}
|
|
54
55
|
/>
|
|
55
56
|
|
|
56
57
|
) : null
|
|
@@ -20,7 +20,7 @@ import BaseRouter, {
|
|
|
20
20
|
import { getLayout } from '@common/router/layouts';
|
|
21
21
|
import { getRegisterPageArgs, buildRegex } from '@common/router/register';
|
|
22
22
|
import { TFetcherList } from '@common/router/request/api';
|
|
23
|
-
import type { TFrontRenderer
|
|
23
|
+
import type { TFrontRenderer } from '@common/router/response/page';
|
|
24
24
|
|
|
25
25
|
import App from '@client/app/component';
|
|
26
26
|
import type ClientApplication from '@client/app';
|
|
@@ -61,21 +61,18 @@ export type Response = ClientResponse<ClientRouter> | ServerResponse<ServerRoute
|
|
|
61
61
|
- TYPES: ROUTES LOADING
|
|
62
62
|
----------------------------------*/
|
|
63
63
|
|
|
64
|
-
// WARN: To be updated with the mplemenations list of Router.page
|
|
64
|
+
// WARN: To be updated with the mplemenations list of Router.page AND the routes babel plugin
|
|
65
65
|
// (both server and client side)
|
|
66
|
-
export type TRegisterPageArgs<
|
|
66
|
+
export type TRegisterPageArgs<
|
|
67
|
+
TProvidedData extends TFetcherList = TFetcherList,
|
|
68
|
+
TRouter extends Router = Router
|
|
69
|
+
> = ([
|
|
67
70
|
path: string,
|
|
68
|
-
controller: TDataProvider<TProvidedData> | null,
|
|
69
71
|
renderer: TFrontRenderer<TProvidedData>
|
|
70
72
|
] | [
|
|
71
73
|
path: string,
|
|
72
74
|
options: Partial<TRoute["options"]>,
|
|
73
75
|
renderer: TFrontRenderer<TProvidedData>
|
|
74
|
-
] | [
|
|
75
|
-
path: string,
|
|
76
|
-
options: Partial<TRoute["options"]>,
|
|
77
|
-
controller: TDataProvider<TProvidedData> | null,
|
|
78
|
-
renderer: TFrontRenderer<TProvidedData>
|
|
79
76
|
])
|
|
80
77
|
|
|
81
78
|
// Route definition passed by the server
|
|
@@ -221,28 +218,20 @@ export default class ClientRouter<
|
|
|
221
218
|
return currentRoute;
|
|
222
219
|
}
|
|
223
220
|
|
|
224
|
-
public page(
|
|
221
|
+
public page<TProvidedData extends TFetcherList = TFetcherList>(
|
|
225
222
|
path: string,
|
|
226
|
-
|
|
227
|
-
renderer: TFrontRenderer<{}>
|
|
223
|
+
renderer: TFrontRenderer<TProvidedData>
|
|
228
224
|
): TRoute;
|
|
229
225
|
|
|
230
|
-
public page(
|
|
226
|
+
public page<TProvidedData extends TFetcherList = TFetcherList>(
|
|
231
227
|
path: string,
|
|
232
228
|
options: Partial<TRoute["options"]>,
|
|
233
|
-
renderer: TFrontRenderer<
|
|
234
|
-
): TRoute;
|
|
235
|
-
|
|
236
|
-
public page(
|
|
237
|
-
path: string,
|
|
238
|
-
options: Partial<TRoute["options"]>,
|
|
239
|
-
controller: TDataProvider<{}> | null,
|
|
240
|
-
renderer: TFrontRenderer<{}>
|
|
229
|
+
renderer: TFrontRenderer<TProvidedData>
|
|
241
230
|
): TRoute;
|
|
242
231
|
|
|
243
232
|
public page(...args: TRegisterPageArgs): TRoute {
|
|
244
233
|
|
|
245
|
-
const { path, options,
|
|
234
|
+
const { path, options, renderer, layout } = getRegisterPageArgs(...args);
|
|
246
235
|
|
|
247
236
|
// S'il s'agit d'une page, son id doit avoir été injecté via le plugin babel
|
|
248
237
|
const id = options["id"];
|
|
@@ -260,7 +249,7 @@ export default class ClientRouter<
|
|
|
260
249
|
...defaultOptions,
|
|
261
250
|
...options
|
|
262
251
|
},
|
|
263
|
-
controller: (context: TClientOrServerContext) => new ClientPage(
|
|
252
|
+
controller: (context: TClientOrServerContext) => new ClientPage(route, renderer, context, layout)
|
|
264
253
|
};
|
|
265
254
|
|
|
266
255
|
this.routes.push(route);
|
|
@@ -275,7 +264,7 @@ export default class ClientRouter<
|
|
|
275
264
|
|
|
276
265
|
const route: TErrorRoute = {
|
|
277
266
|
code,
|
|
278
|
-
controller: (context: TClientOrServerContext) => new ClientPage(
|
|
267
|
+
controller: (context: TClientOrServerContext) => new ClientPage(route, renderer, context, layout),
|
|
279
268
|
options
|
|
280
269
|
};
|
|
281
270
|
|
|
@@ -391,7 +380,9 @@ export default class ClientRouter<
|
|
|
391
380
|
|
|
392
381
|
const response = await this.createResponse(route, request, apiData)
|
|
393
382
|
|
|
394
|
-
ReactDOM.hydrate(
|
|
383
|
+
ReactDOM.hydrate((
|
|
384
|
+
<App context={response.context} />
|
|
385
|
+
), document.body, () => {
|
|
395
386
|
|
|
396
387
|
console.log(`Render complete`);
|
|
397
388
|
|
|
@@ -404,7 +395,7 @@ export default class ClientRouter<
|
|
|
404
395
|
pageData: {} = {}
|
|
405
396
|
): Promise<ClientPage> {
|
|
406
397
|
|
|
407
|
-
// Load if not done before
|
|
398
|
+
// Load the route if not done before
|
|
408
399
|
if ('load' in route)
|
|
409
400
|
route = this.routes[route.index] = await this.load(route);
|
|
410
401
|
|
|
@@ -9,7 +9,8 @@ import axios, { AxiosResponse, AxiosError, AxiosRequestConfig } from 'axios';
|
|
|
9
9
|
import type { TApiResponseData } from '@server/services/router';
|
|
10
10
|
import ApiClientService, {
|
|
11
11
|
TPostData,
|
|
12
|
-
TApiFetchOptions, TFetcherList, TFetcherArgs, TFetcher
|
|
12
|
+
TApiFetchOptions, TFetcherList, TFetcherArgs, TFetcher,
|
|
13
|
+
TDataReturnedByFetchers
|
|
13
14
|
} from '@common/router/request/api';
|
|
14
15
|
import { instancierViaCode, NetworkError } from '@common/errors';
|
|
15
16
|
import type ClientApplication from '@client/app';
|
|
@@ -46,6 +47,13 @@ export default class ApiClient implements ApiClientService {
|
|
|
46
47
|
/*----------------------------------
|
|
47
48
|
- HIGH LEVEL
|
|
48
49
|
----------------------------------*/
|
|
50
|
+
|
|
51
|
+
public fetch<TProvidedData extends TFetcherList = TFetcherList>(
|
|
52
|
+
fetchers: TFetcherList
|
|
53
|
+
): TDataReturnedByFetchers<TProvidedData> {
|
|
54
|
+
throw new Error("api.fetch shouldn't be called here.");
|
|
55
|
+
}
|
|
56
|
+
|
|
49
57
|
public get = <TData extends unknown = unknown>(path: string, data?: TPostData, opts?: TApiFetchOptions) =>
|
|
50
58
|
this.createFetcher<TData>('GET', path, data, opts);
|
|
51
59
|
|
|
@@ -120,7 +128,7 @@ export default class ApiClient implements ApiClientService {
|
|
|
120
128
|
/*if (options?.captcha !== undefined)
|
|
121
129
|
await this.gui.captcha.check(options?.captcha);*/
|
|
122
130
|
|
|
123
|
-
return await this.
|
|
131
|
+
return await this.execute<TData>(method, path, data, options).catch((e) => {
|
|
124
132
|
this.app.handleError(e);
|
|
125
133
|
throw e; // Throw to break the loop
|
|
126
134
|
})
|
|
@@ -141,7 +149,7 @@ export default class ApiClient implements ApiClientService {
|
|
|
141
149
|
// Fetch all the api data thanks to one http request
|
|
142
150
|
const fetchedData = fetchersCount === 0
|
|
143
151
|
? 0
|
|
144
|
-
: await this.
|
|
152
|
+
: await this.execute("POST", "/api", {
|
|
145
153
|
fetchers: fetchersToRun
|
|
146
154
|
}).then((res) => {
|
|
147
155
|
|
|
@@ -201,7 +209,7 @@ export default class ApiClient implements ApiClientService {
|
|
|
201
209
|
return config;
|
|
202
210
|
}
|
|
203
211
|
|
|
204
|
-
public
|
|
212
|
+
public execute<TData = unknown>(...args: TFetcherArgs): Promise<TData> {
|
|
205
213
|
|
|
206
214
|
const config = this.configure(...args);
|
|
207
215
|
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
import type { ComponentChild } from 'preact';
|
|
7
7
|
|
|
8
8
|
// Core
|
|
9
|
-
import type { TClientOrServerContext, Layout } from '@common/router';
|
|
10
|
-
import PageResponse, {
|
|
9
|
+
import type { TClientOrServerContext, Layout, TRoute, TErrorRoute } from '@common/router';
|
|
10
|
+
import PageResponse, { TFrontRenderer } from "@common/router/response/page";
|
|
11
11
|
|
|
12
12
|
// Specific
|
|
13
13
|
import type ClientRouter from '..';
|
|
@@ -29,15 +29,13 @@ export default class ClientPage<TRouter = ClientRouter> extends PageResponse<TRo
|
|
|
29
29
|
public scrollToId: string;
|
|
30
30
|
|
|
31
31
|
public constructor(
|
|
32
|
-
public
|
|
32
|
+
public route: TRoute | TErrorRoute,
|
|
33
33
|
public component: TFrontRenderer,
|
|
34
34
|
public context: TClientOrServerContext,
|
|
35
|
-
public layout?: Layout
|
|
36
|
-
|
|
37
|
-
public route = context.route
|
|
35
|
+
public layout?: Layout
|
|
38
36
|
) {
|
|
39
37
|
|
|
40
|
-
super(
|
|
38
|
+
super(route, component, context);
|
|
41
39
|
|
|
42
40
|
this.bodyId = context.route.options.bodyId;
|
|
43
41
|
this.scrollToId = context.request.hash;
|
|
@@ -20,7 +20,7 @@ import type { TUserRole } from '@server/services/users';
|
|
|
20
20
|
import type { TAppArrowFunction } from '@common/app';
|
|
21
21
|
|
|
22
22
|
// Specfic
|
|
23
|
-
import type { default as Page, TFrontRenderer } from './response/page';
|
|
23
|
+
import type { default as Page, TFrontRenderer, TDataProvider } from './response/page';
|
|
24
24
|
|
|
25
25
|
/*----------------------------------
|
|
26
26
|
- TYPES: ROUTES
|
|
@@ -81,6 +81,7 @@ export type TRouteOptions = {
|
|
|
81
81
|
|
|
82
82
|
// Injected by the page plugin
|
|
83
83
|
filepath?: string,
|
|
84
|
+
data?: TDataProvider
|
|
84
85
|
|
|
85
86
|
// Indexing
|
|
86
87
|
bodyId?: string,
|
|
@@ -10,7 +10,7 @@ import { getLayout } from './layouts';
|
|
|
10
10
|
|
|
11
11
|
// types
|
|
12
12
|
import type { TRouteOptions } from '.';
|
|
13
|
-
import type {
|
|
13
|
+
import type { TFrontRenderer } from './response/page';
|
|
14
14
|
import type { TRegisterPageArgs } from '@client/services/router';
|
|
15
15
|
|
|
16
16
|
/*----------------------------------
|
|
@@ -21,20 +21,17 @@ export const getRegisterPageArgs = (...args: TRegisterPageArgs) => {
|
|
|
21
21
|
|
|
22
22
|
let path: string;
|
|
23
23
|
let options: Partial<TRouteOptions> = {};
|
|
24
|
-
let controller: TDataProvider|null;
|
|
25
24
|
let renderer: TFrontRenderer;
|
|
26
25
|
|
|
27
|
-
if (args.length ===
|
|
28
|
-
([path,
|
|
29
|
-
else if (typeof args[1] === 'object')
|
|
30
|
-
([path, options, renderer] = args)
|
|
26
|
+
if (args.length === 2)
|
|
27
|
+
([path, renderer] = args)
|
|
31
28
|
else
|
|
32
|
-
([path,
|
|
29
|
+
([path, options, renderer] = args)
|
|
33
30
|
|
|
34
31
|
// Automatic layout form the nearest _layout folder
|
|
35
32
|
const layout = getLayout(path, options);
|
|
36
33
|
|
|
37
|
-
return { path, options,
|
|
34
|
+
return { path, options, renderer, layout }
|
|
38
35
|
|
|
39
36
|
}
|
|
40
37
|
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
- DEPENDANCES
|
|
3
3
|
----------------------------------*/
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
// Npm
|
|
6
|
+
import type { VNode } from 'preact';
|
|
6
7
|
|
|
7
8
|
// Core libs
|
|
8
|
-
import { ClientOrServerRouter, TClientOrServerContext } from '@common/router';
|
|
9
|
+
import { ClientOrServerRouter, TClientOrServerContext, TRoute, TErrorRoute } from '@common/router';
|
|
9
10
|
import { TFetcherList, TDataReturnedByFetchers } from '@common/router/request/api';
|
|
10
11
|
import { history } from '@client/services/router/request/history';
|
|
11
12
|
|
|
@@ -14,21 +15,30 @@ import { history } from '@client/services/router/request/history';
|
|
|
14
15
|
----------------------------------*/
|
|
15
16
|
|
|
16
17
|
// The function that fetch data from the api before to pass them as context to the renderer
|
|
17
|
-
export type TDataProvider<TProvidedData extends TFetcherList =
|
|
18
|
-
|
|
18
|
+
export type TDataProvider<TProvidedData extends TFetcherList = TFetcherList> = (
|
|
19
|
+
context: TClientOrServerContext & {
|
|
20
|
+
// URL query parameters
|
|
21
|
+
// TODO: typings
|
|
22
|
+
data: {[key: string]: string | number}
|
|
23
|
+
}
|
|
24
|
+
) => TProvidedData
|
|
19
25
|
|
|
20
26
|
// The function that renders routes
|
|
21
27
|
export type TFrontRenderer<
|
|
22
|
-
TProvidedData extends TFetcherList =
|
|
23
|
-
TAdditionnalData = {},
|
|
28
|
+
TProvidedData extends TFetcherList = TFetcherList,
|
|
29
|
+
TAdditionnalData extends {} = {},
|
|
24
30
|
TRouter = ClientOrServerRouter,
|
|
25
|
-
> =
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
> = (
|
|
32
|
+
context: (
|
|
33
|
+
TClientOrServerContext
|
|
34
|
+
&
|
|
35
|
+
TAdditionnalData
|
|
36
|
+
&
|
|
37
|
+
{
|
|
38
|
+
data: TDataReturnedByFetchers<TProvidedData>
|
|
39
|
+
}
|
|
40
|
+
)
|
|
41
|
+
) => VNode<any> | null
|
|
32
42
|
|
|
33
43
|
// Script or CSS resource
|
|
34
44
|
export type TPageResource = {
|
|
@@ -46,7 +56,7 @@ const debug = false;
|
|
|
46
56
|
/*----------------------------------
|
|
47
57
|
- CLASS
|
|
48
58
|
----------------------------------*/
|
|
49
|
-
export default class PageResponse<TRouter extends ClientOrServerRouter = ClientOrServerRouter> {
|
|
59
|
+
export default abstract class PageResponse<TRouter extends ClientOrServerRouter = ClientOrServerRouter> {
|
|
50
60
|
|
|
51
61
|
// Metadata
|
|
52
62
|
public chunkId: string;
|
|
@@ -65,7 +75,7 @@ export default class PageResponse<TRouter extends ClientOrServerRouter = ClientO
|
|
|
65
75
|
public data: TObjetDonnees = {};
|
|
66
76
|
|
|
67
77
|
public constructor(
|
|
68
|
-
public
|
|
78
|
+
public route: TRoute | TErrorRoute,
|
|
69
79
|
public renderer: TFrontRenderer,
|
|
70
80
|
public context: TClientOrServerContext
|
|
71
81
|
) {
|
|
@@ -77,8 +87,12 @@ export default class PageResponse<TRouter extends ClientOrServerRouter = ClientO
|
|
|
77
87
|
public async fetchData() {
|
|
78
88
|
|
|
79
89
|
// Load the fetchers list to load data if needed
|
|
80
|
-
|
|
81
|
-
|
|
90
|
+
const dataFetcher = this.route.options.data;
|
|
91
|
+
if (dataFetcher)
|
|
92
|
+
this.fetchers = dataFetcher({
|
|
93
|
+
...this.context,
|
|
94
|
+
data: this.context.request.data
|
|
95
|
+
});
|
|
82
96
|
|
|
83
97
|
// Execute the fetchers for missing data
|
|
84
98
|
debug && console.log(`[router][page] Fetching api data:` + Object.keys(this.fetchers));
|
package/src/server/app/index.ts
CHANGED
|
@@ -4,9 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
// Core
|
|
6
6
|
import AppContainer from './container';
|
|
7
|
-
import ApplicationService, {
|
|
7
|
+
import ApplicationService, { StartedServicesIndex } from './service';
|
|
8
8
|
import CommandsManager from './commands';
|
|
9
|
-
import ServicesContainer, {
|
|
9
|
+
import ServicesContainer, {
|
|
10
|
+
ServicesContainer as ServicesContainerClass,
|
|
11
|
+
TRegisteredService,
|
|
12
|
+
TServiceMetas
|
|
13
|
+
} from './service/container';
|
|
10
14
|
import type { ServerBug } from '../services/console';
|
|
11
15
|
|
|
12
16
|
// Built-in
|
|
@@ -49,7 +53,12 @@ export const Service = ServicesContainer;
|
|
|
49
53
|
/*----------------------------------
|
|
50
54
|
- FUNCTIONS
|
|
51
55
|
----------------------------------*/
|
|
52
|
-
export class Application
|
|
56
|
+
export class Application<
|
|
57
|
+
TServicesContainer extends ServicesContainerClass = ServicesContainerClass
|
|
58
|
+
> extends ApplicationService<Config, Hooks, /* TODO: this ? */Application, {}> {
|
|
59
|
+
|
|
60
|
+
public app!: this;
|
|
61
|
+
public servicesContainer!: TServicesContainer;
|
|
53
62
|
|
|
54
63
|
/*----------------------------------
|
|
55
64
|
- PROPERTIES
|
|
@@ -53,7 +53,7 @@ export class ServicesContainer<
|
|
|
53
53
|
public registered: TRegisteredServicesIndex = {}
|
|
54
54
|
|
|
55
55
|
// All service instances by service id
|
|
56
|
-
public allServices:
|
|
56
|
+
public allServices: TServicesIndex = {} as TServicesIndex
|
|
57
57
|
|
|
58
58
|
public setup<TServiceId extends keyof TServicesIndex>(
|
|
59
59
|
serviceId: keyof TServicesIndex,
|
|
@@ -12,7 +12,8 @@ import ServicesContainer from './container';
|
|
|
12
12
|
- TYPES: OPTIONS
|
|
13
13
|
----------------------------------*/
|
|
14
14
|
|
|
15
|
-
export type AnyService =
|
|
15
|
+
export type AnyService<TSubServices extends StartedServicesIndex = StartedServicesIndex> =
|
|
16
|
+
Service<{}, {}, Application, TSubServices>
|
|
16
17
|
|
|
17
18
|
type TServiceConfig = {
|
|
18
19
|
debug?: boolean
|
|
@@ -140,10 +141,26 @@ export default abstract class Service<
|
|
|
140
141
|
// this.use immediatly instanciate the subservice for few reasons:
|
|
141
142
|
// - The subservice instance can be accesses from another service in the constructor, no matter the order of loading of the services
|
|
142
143
|
// - Consistency: the subserviuce proprties shouldn't be assogned to two different values according depending on the app lifecycle
|
|
143
|
-
public use<
|
|
144
|
+
public use<
|
|
145
|
+
TInstalledServices extends this["app"]["servicesContainer"]["allServices"],
|
|
146
|
+
TServiceId extends keyof TInstalledServices,
|
|
147
|
+
TServiceClass extends TInstalledServices[TServiceId],
|
|
148
|
+
TSubServices extends TServiceClass["services"],
|
|
149
|
+
>(
|
|
144
150
|
serviceId: TServiceId,
|
|
145
|
-
|
|
146
|
-
|
|
151
|
+
subServices?: TSubServices
|
|
152
|
+
): (
|
|
153
|
+
// We can't pass the services types as a generic to TServiceClass
|
|
154
|
+
// So we overwrite the services property
|
|
155
|
+
ReturnType< TServiceClass["getServiceInstance"] >
|
|
156
|
+
&
|
|
157
|
+
{
|
|
158
|
+
new (...args: any[]): TServiceClass & { services: TSubServices },
|
|
159
|
+
services: TSubServices
|
|
160
|
+
}
|
|
161
|
+
/*Omit<TServiceClass, 'services'> & {
|
|
162
|
+
services: TSubServices
|
|
163
|
+
}*/
|
|
147
164
|
) {
|
|
148
165
|
|
|
149
166
|
// Check of the service has been configurated
|
|
@@ -152,7 +169,7 @@ export default abstract class Service<
|
|
|
152
169
|
throw new Error(`Unable to use service "${serviceId}": This one hasn't been setup.`);
|
|
153
170
|
|
|
154
171
|
// Bind subservices
|
|
155
|
-
registered.subServices = subServices;
|
|
172
|
+
registered.subServices = subServices || {};
|
|
156
173
|
|
|
157
174
|
// Check if not already instanciated
|
|
158
175
|
const existing = ServicesContainer.allServices[ serviceId ];
|
|
@@ -176,7 +193,7 @@ export default abstract class Service<
|
|
|
176
193
|
return service;
|
|
177
194
|
}
|
|
178
195
|
|
|
179
|
-
|
|
196
|
+
public bindService( localName: string, service: AnyService ) {
|
|
180
197
|
|
|
181
198
|
const serviceScope = this.constructor.name + '.' + localName;
|
|
182
199
|
|
|
@@ -196,7 +213,7 @@ export default abstract class Service<
|
|
|
196
213
|
|
|
197
214
|
}
|
|
198
215
|
|
|
199
|
-
|
|
216
|
+
public async startService( localName: string, service: AnyService ) {
|
|
200
217
|
// Service already started
|
|
201
218
|
if (!service.started) {
|
|
202
219
|
|
|
@@ -107,13 +107,16 @@ export const mysqlToJs = {
|
|
|
107
107
|
'POINT': 'float',
|
|
108
108
|
|
|
109
109
|
// Integres
|
|
110
|
-
'
|
|
111
|
-
'BIGINT': 'int',
|
|
110
|
+
'BIT': 'int',
|
|
112
111
|
'LONG': 'int',
|
|
113
112
|
'LONGLONG': 'int',
|
|
113
|
+
|
|
114
114
|
'TINYINT': 'int',
|
|
115
115
|
'SMALLINT': 'int',
|
|
116
116
|
'MEDIUMINT': 'int',
|
|
117
|
+
'INT': 'int',
|
|
118
|
+
'INTEGER': 'int',
|
|
119
|
+
'BIGINT': 'int',
|
|
117
120
|
|
|
118
121
|
// Dates
|
|
119
122
|
'DATE': 'date',
|
|
@@ -121,9 +124,18 @@ export const mysqlToJs = {
|
|
|
121
124
|
|
|
122
125
|
// Strings
|
|
123
126
|
'VARCHAR': 'string',
|
|
127
|
+
'BINARY': 'string',
|
|
128
|
+
'VARBINARY': 'string',
|
|
129
|
+
'TINYBLOB': 'string',
|
|
130
|
+
'TINY_BLOB': 'string',
|
|
131
|
+
'MEDIUM_BLOB': 'string',
|
|
132
|
+
'BLOB': 'string',
|
|
133
|
+
'LONG_BLOB': 'string',
|
|
124
134
|
'CHAR': 'string',
|
|
125
135
|
'VAR_STRING': 'string',
|
|
126
136
|
'LONGTEXT': 'string',
|
|
137
|
+
'TINYTEXT': 'string',
|
|
138
|
+
'MEDIUMTEXT': 'string',
|
|
127
139
|
'TEXT': 'string',
|
|
128
140
|
'ENUM': 'enum',
|
|
129
141
|
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
// Core
|
|
6
6
|
import type { Application } from '@server/app';
|
|
7
7
|
import Service, { AnyService } from '@server/app/service';
|
|
8
|
-
import type { TRegisteredServicesIndex } from '@server/app/service/container';
|
|
9
8
|
|
|
10
9
|
// Specific
|
|
11
10
|
import type Driver from './driver';
|
|
@@ -25,7 +24,7 @@ export type Hooks = {
|
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
export type Services = {
|
|
28
|
-
|
|
27
|
+
[diskId: string]: Driver
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
/*----------------------------------
|
|
@@ -28,9 +28,6 @@ export type Config = {
|
|
|
28
28
|
transporter: string,
|
|
29
29
|
from: TPerson
|
|
30
30
|
},
|
|
31
|
-
transporters: {
|
|
32
|
-
[transporterName: string]: Transporter
|
|
33
|
-
},
|
|
34
31
|
bugReport: {
|
|
35
32
|
from: TPerson,
|
|
36
33
|
to: TPerson
|
|
@@ -111,14 +108,14 @@ type TOptions = {
|
|
|
111
108
|
----------------------------------*/
|
|
112
109
|
export default class Email extends Service<Config, Hooks, Application, Services> {
|
|
113
110
|
|
|
114
|
-
private transporters = this.
|
|
111
|
+
private transporters = this.services;
|
|
115
112
|
|
|
116
113
|
/*----------------------------------
|
|
117
114
|
- LIFECYCLE
|
|
118
115
|
----------------------------------*/
|
|
119
116
|
|
|
120
117
|
public async start() {
|
|
121
|
-
|
|
118
|
+
|
|
122
119
|
}
|
|
123
120
|
|
|
124
121
|
public async ready() {
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
// Core
|
|
8
8
|
import type Application from "@server/app";
|
|
9
|
+
import Service from '@server/app/service';
|
|
9
10
|
import type EmailService from '@server/services/email';
|
|
10
11
|
|
|
11
12
|
// Specific
|
|
@@ -23,16 +24,28 @@ export type TBasicConfig = {
|
|
|
23
24
|
/*----------------------------------
|
|
24
25
|
- CLASS
|
|
25
26
|
----------------------------------*/
|
|
26
|
-
export abstract class Transporter<TConfig extends
|
|
27
|
+
export abstract class Transporter<TConfig extends TBasicConfig = TBasicConfig>
|
|
28
|
+
extends Service<TConfig, {}, Application, {}> {
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
/*----------------------------------
|
|
31
|
+
- LIFECYCLE
|
|
32
|
+
----------------------------------*/
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
protected async start() {
|
|
35
|
+
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
protected async ready() {
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
protected async shutdown() {
|
|
34
43
|
|
|
35
44
|
}
|
|
36
45
|
|
|
46
|
+
/*----------------------------------
|
|
47
|
+
- ACTIONS
|
|
48
|
+
----------------------------------*/
|
|
49
|
+
|
|
37
50
|
public abstract send( emails: TCompleteEmail[] ): Promise<void>;
|
|
38
51
|
}
|
|
@@ -194,7 +194,7 @@ export default class HttpServer {
|
|
|
194
194
|
----------------------------------*/
|
|
195
195
|
|
|
196
196
|
// TODO: Migrer dans app
|
|
197
|
-
routes.use('/chrome', cors());
|
|
197
|
+
//routes.use('/chrome', cors());
|
|
198
198
|
// TODO: Trouver une solution pour n'autoriser les requetes que depuis l'application & dopamyn.io
|
|
199
199
|
// https://www.google.com/search?q=http+cors+from+android%7Cwindows%7Cdesktop%7Cmodile+app
|
|
200
200
|
//routes.use('/auth', cors());
|
|
@@ -225,7 +225,7 @@ export default class HttpServer {
|
|
|
225
225
|
// Impossible donc de créer un serveur http ici, on le fera dans start.js
|
|
226
226
|
console.info("Lancement du serveur web");
|
|
227
227
|
this.http.listen(this.config.port, () => {
|
|
228
|
-
console.info(`
|
|
228
|
+
console.info(`Web server ready on ${this.publicUrl}`);
|
|
229
229
|
});
|
|
230
230
|
|
|
231
231
|
}
|
|
@@ -95,8 +95,6 @@ export type Config<
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
export type Services = {
|
|
98
|
-
disks?: DisksManager
|
|
99
|
-
} & {
|
|
100
98
|
[routerServiceId: string]: RouterService
|
|
101
99
|
}
|
|
102
100
|
|
|
@@ -113,14 +111,15 @@ export type Hooks = {
|
|
|
113
111
|
- CLASSE
|
|
114
112
|
----------------------------------*/
|
|
115
113
|
export default class ServerRouter<
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
> extends Service<TConfig, Hooks, TApplication, Services> implements BaseRouter {
|
|
114
|
+
TSubservices extends Services = Services
|
|
115
|
+
> extends Service<Config, Hooks, Application, TSubservices> implements BaseRouter {
|
|
119
116
|
|
|
117
|
+
public disks = this.use('Core/Disks') as unknown as DisksManager;
|
|
118
|
+
|
|
120
119
|
// Services
|
|
121
120
|
public http: HTTP;
|
|
122
121
|
public render: DocumentRenderer<this>;
|
|
123
|
-
protected routerServices:
|
|
122
|
+
protected routerServices: TSubservices = {} as TSubservices
|
|
124
123
|
|
|
125
124
|
// Indexed
|
|
126
125
|
public routes: TRoute[] = []; // API + pages front front
|
|
@@ -133,9 +132,9 @@ export default class ServerRouter<
|
|
|
133
132
|
|
|
134
133
|
public constructor(
|
|
135
134
|
parent: AnyService,
|
|
136
|
-
config:
|
|
137
|
-
services:
|
|
138
|
-
app:
|
|
135
|
+
config: Config,
|
|
136
|
+
services: TSubservices,
|
|
137
|
+
app: Application,
|
|
139
138
|
) {
|
|
140
139
|
|
|
141
140
|
super(parent, config, services, app);
|
|
@@ -217,7 +216,7 @@ export default class ServerRouter<
|
|
|
217
216
|
|
|
218
217
|
public page(...args: TRegisterPageArgs) {
|
|
219
218
|
|
|
220
|
-
const { path, options,
|
|
219
|
+
const { path, options, renderer, layout } = getRegisterPageArgs(...args);
|
|
221
220
|
|
|
222
221
|
const { regex, keys } = buildRegex(path);
|
|
223
222
|
|
|
@@ -226,7 +225,7 @@ export default class ServerRouter<
|
|
|
226
225
|
path,
|
|
227
226
|
regex,
|
|
228
227
|
keys,
|
|
229
|
-
controller: (context: TRouterContext<this>) => new Page(
|
|
228
|
+
controller: (context: TRouterContext<this>) => new Page(route, renderer, context, layout),
|
|
230
229
|
options: {
|
|
231
230
|
...defaultOptions,
|
|
232
231
|
accept: 'html', // Les pages retournent forcémment du html
|
|
@@ -249,11 +248,13 @@ export default class ServerRouter<
|
|
|
249
248
|
// Automatic layout form the nearest _layout folder
|
|
250
249
|
const layout = getLayout('Error ' + code, options);
|
|
251
250
|
|
|
252
|
-
|
|
251
|
+
const route = {
|
|
253
252
|
code,
|
|
254
|
-
controller: (context: TRouterContext<this>) => new Page(
|
|
253
|
+
controller: (context: TRouterContext<this>) => new Page(route, renderer, context, layout),
|
|
255
254
|
options
|
|
256
255
|
};
|
|
256
|
+
|
|
257
|
+
this.errors[code] = route;
|
|
257
258
|
}
|
|
258
259
|
|
|
259
260
|
public all = (...args: TApiRegisterArgs<this>) => this.registerApi('*', ...args);
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
import RequestService from './service';
|
|
8
8
|
|
|
9
9
|
import ApiClientService, {
|
|
10
|
-
TApiFetchOptions, TFetcherList, TFetcherArgs, TFetcher
|
|
10
|
+
TApiFetchOptions, TFetcherList, TFetcherArgs, TFetcher,
|
|
11
|
+
TDataReturnedByFetchers
|
|
11
12
|
} from '@common/router/request/api';
|
|
12
13
|
|
|
13
14
|
/*----------------------------------
|
|
@@ -28,6 +29,12 @@ export default class ApiClientRequest extends RequestService implements ApiClien
|
|
|
28
29
|
- HIGH LEVEL
|
|
29
30
|
----------------------------------*/
|
|
30
31
|
|
|
32
|
+
public fetch<TProvidedData extends TFetcherList = TFetcherList>(
|
|
33
|
+
fetchers: TFetcherList
|
|
34
|
+
): TDataReturnedByFetchers<TProvidedData> {
|
|
35
|
+
throw new Error("api.fetch shouldn't be called here.");
|
|
36
|
+
}
|
|
37
|
+
|
|
31
38
|
public get = <TData extends unknown = unknown>(path: string, data?: TObjetDonnees, opts?: TApiFetchOptions) =>
|
|
32
39
|
this.createFetcher<TData>('GET', path, data, opts);
|
|
33
40
|
|
|
@@ -242,11 +242,11 @@ export default class ServerResponse<
|
|
|
242
242
|
// ? this.app.path.root + '/bin' + fichier
|
|
243
243
|
// : this.app.path.data + '/' + fichier;
|
|
244
244
|
// Disk not provided = file response disabled
|
|
245
|
-
if (this.router.
|
|
245
|
+
if (this.router.disks === undefined)
|
|
246
246
|
throw new Anomaly("Router: Unable to return file response in router, because no disk has been given in the router config.");
|
|
247
247
|
|
|
248
248
|
// Retirve disk driver
|
|
249
|
-
const disk = this.router.
|
|
249
|
+
const disk = this.router.disks.get('default');
|
|
250
250
|
|
|
251
251
|
// Verif existance
|
|
252
252
|
const fileExists = await disk.exists('data', fichier);
|
|
@@ -9,8 +9,8 @@ const safeStringify = require('fast-safe-stringify'); // remplace les référenc
|
|
|
9
9
|
|
|
10
10
|
// Core
|
|
11
11
|
import { default as Router, TRouterContext } from "@server/services/router";
|
|
12
|
-
import type { Layout } from '@common/router';
|
|
13
|
-
import PageResponse, {
|
|
12
|
+
import type { Layout, TRoute, TErrorRoute } from '@common/router';
|
|
13
|
+
import PageResponse, { TFrontRenderer } from "@common/router/response/page";
|
|
14
14
|
|
|
15
15
|
// Composants UI
|
|
16
16
|
import App from '@client/app/component';
|
|
@@ -34,18 +34,17 @@ const seoLimits = {
|
|
|
34
34
|
export default class Page<TRouter extends Router = Router> extends PageResponse<TRouter> {
|
|
35
35
|
|
|
36
36
|
public constructor(
|
|
37
|
-
public
|
|
37
|
+
public route: TRoute | TErrorRoute,
|
|
38
38
|
public renderer: TFrontRenderer,
|
|
39
39
|
public context: TRouterContext,
|
|
40
40
|
public layout?: Layout,
|
|
41
41
|
|
|
42
|
-
public route = context.route,
|
|
43
42
|
public app = context.app,
|
|
44
43
|
public router = context.request.router,
|
|
45
44
|
|
|
46
45
|
) {
|
|
47
46
|
|
|
48
|
-
super(
|
|
47
|
+
super(route, renderer, context)
|
|
49
48
|
|
|
50
49
|
}
|
|
51
50
|
|
|
@@ -14,7 +14,6 @@ import RequestValidator, { TConfig } from '../request';
|
|
|
14
14
|
- TYPES
|
|
15
15
|
----------------------------------*/
|
|
16
16
|
|
|
17
|
-
type TRouterWithSchema<TAuthService extends SchemaRouterService> = Router<RouterConfig<{ auth: TAuthService }>>
|
|
18
17
|
|
|
19
18
|
/*----------------------------------
|
|
20
19
|
- SERVICE
|
|
@@ -43,7 +42,7 @@ export default class SchemaRouterService<
|
|
|
43
42
|
- ROUTER SERVICE LIFECYCLE
|
|
44
43
|
----------------------------------*/
|
|
45
44
|
|
|
46
|
-
public requestService( request: ServerRequest
|
|
45
|
+
public requestService( request: ServerRequest ): RequestValidator {
|
|
47
46
|
return new RequestValidator( request, this.config );
|
|
48
47
|
}
|
|
49
48
|
}
|