5htp-core 0.3.4 → 0.3.5
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/app/component.tsx +3 -0
- package/src/client/assets/css/components/button.less +6 -5
- package/src/client/assets/css/components/card.less +0 -22
- package/src/client/assets/css/components.less +0 -25
- package/src/client/assets/css/core.less +62 -3
- package/src/client/assets/css/text/icons.less +3 -2
- package/src/client/assets/css/text/text.less +0 -4
- package/src/client/assets/css/theme.less +69 -39
- package/src/client/assets/css/utils/layouts.less +1 -12
- package/src/client/assets/css/utils/medias.less +2 -15
- package/src/client/components/Dialog/index.less +2 -0
- package/src/client/components/Form.ts +4 -3
- package/src/client/components/Row/index.less +2 -0
- package/src/client/components/Video/index.less +6 -1
- package/src/client/components/containers/Popover/index.tsx +1 -2
- package/src/client/components/containers/Popover/popover.less +2 -0
- package/src/client/components/data/progressbar/index.less +2 -0
- package/src/client/components/inputv3/base.less +6 -0
- package/src/client/components/inputv3/file/index.less +2 -0
- package/src/client/pages/_messages/401.tsx +1 -2
- package/src/client/services/router/components/Page.tsx +1 -0
- package/src/client/services/router/components/router.tsx +37 -13
- package/src/client/services/router/index.tsx +22 -13
- package/src/client/services/router/request/api.ts +21 -13
- package/src/client/services/router/response/index.tsx +26 -12
- package/src/client/services/router/response/page.ts +1 -1
- package/src/common/router/index.ts +41 -0
- package/src/common/router/request/api.ts +2 -0
- package/src/common/router/response/index.ts +2 -2
- package/src/common/router/response/page.ts +1 -0
- package/src/common/validation/validator.ts +12 -2
- package/src/common/validation/validators.ts +5 -5
- package/src/server/app/index.ts +0 -1
- package/src/server/app/service/index.ts +12 -3
- package/src/server/services/console/index.ts +2 -4
- package/src/server/services/router/http/index.ts +5 -7
- package/src/server/services/router/index.ts +9 -10
- package/src/server/services/router/request/api.ts +7 -2
- package/src/server/services/router/response/index.ts +13 -12
- package/src/types/aliases.d.ts +4 -4
|
@@ -15,7 +15,9 @@ import type {
|
|
|
15
15
|
import type { TBasicSSrData } from '@server/services/router/response';
|
|
16
16
|
|
|
17
17
|
import BaseRouter, {
|
|
18
|
-
defaultOptions, TRoute, TErrorRoute,
|
|
18
|
+
defaultOptions, TRoute, TErrorRoute,
|
|
19
|
+
TClientOrServerContext, TRouteModule,
|
|
20
|
+
buildUrl, TDomainsList
|
|
19
21
|
} from '@common/router'
|
|
20
22
|
import { getLayout } from '@common/router/layouts';
|
|
21
23
|
import { getRegisterPageArgs, buildRegex } from '@common/router/register';
|
|
@@ -27,6 +29,7 @@ import type ClientApplication from '@client/app';
|
|
|
27
29
|
import Service from '@client/app/service';
|
|
28
30
|
|
|
29
31
|
// Specific
|
|
32
|
+
import type { ClientContext } from '@/client/context';
|
|
30
33
|
import ClientRequest from './request';
|
|
31
34
|
import { location, history } from './request/history';
|
|
32
35
|
import ClientResponse from './response';
|
|
@@ -122,7 +125,8 @@ type THookName = 'location.change' | 'page.changed'
|
|
|
122
125
|
|
|
123
126
|
type Config<TAdditionnalContext extends {} = {}> = {
|
|
124
127
|
preload: string[], // List of globs
|
|
125
|
-
context: (router: ClientRouter) => TAdditionnalContext
|
|
128
|
+
context: (context: ClientContext, router: ClientRouter) => TAdditionnalContext,
|
|
129
|
+
domains: TDomainsList
|
|
126
130
|
}
|
|
127
131
|
|
|
128
132
|
/*----------------------------------
|
|
@@ -134,8 +138,11 @@ export default class ClientRouter<
|
|
|
134
138
|
> extends Service<Config<TAdditionnalContext>, ClientApplication> implements BaseRouter {
|
|
135
139
|
|
|
136
140
|
// Context data
|
|
137
|
-
public context = window["ssr"] as (TBasicSSrData | undefined);
|
|
138
141
|
public ssrRoutes = window["routes"] as TSsrUnresolvedRoute[];
|
|
142
|
+
public ssrContext = window["ssr"] as (TBasicSSrData | undefined);
|
|
143
|
+
public context!: ClientContext;
|
|
144
|
+
|
|
145
|
+
public setLoading!: React.Dispatch< React.SetStateAction<boolean> >;
|
|
139
146
|
|
|
140
147
|
public constructor(app: TApplication, config: Config<TAdditionnalContext>) {
|
|
141
148
|
|
|
@@ -149,9 +156,13 @@ export default class ClientRouter<
|
|
|
149
156
|
this.initialRender(currentRoute);
|
|
150
157
|
}
|
|
151
158
|
|
|
159
|
+
public url = (path: string, params: {} = {}, absolute: boolean = true) =>
|
|
160
|
+
buildUrl(path, params, this.config.domains, absolute);
|
|
161
|
+
|
|
152
162
|
public go( url: string ) {
|
|
163
|
+
url = this.url(url, {}, false);
|
|
153
164
|
console.log( LogPrefix, "Go to", url);
|
|
154
|
-
history?.replace(url);
|
|
165
|
+
history?.replace( url );
|
|
155
166
|
}
|
|
156
167
|
|
|
157
168
|
/*----------------------------------
|
|
@@ -203,9 +214,9 @@ export default class ClientRouter<
|
|
|
203
214
|
if (currentRoute === undefined) {
|
|
204
215
|
|
|
205
216
|
const isCurrentRoute = (
|
|
206
|
-
this.
|
|
217
|
+
this.ssrContext !== undefined
|
|
207
218
|
&&
|
|
208
|
-
route.chunk === this.
|
|
219
|
+
route.chunk === this.ssrContext.page.chunkId
|
|
209
220
|
);
|
|
210
221
|
|
|
211
222
|
if (isCurrentRoute) {
|
|
@@ -365,20 +376,18 @@ export default class ClientRouter<
|
|
|
365
376
|
|
|
366
377
|
// Restituate SSR response
|
|
367
378
|
let apiData: {} = {}
|
|
368
|
-
if (this.
|
|
369
|
-
|
|
370
|
-
console.log("SSR Response restitution ...");
|
|
379
|
+
if (this.ssrContext) {
|
|
371
380
|
|
|
372
|
-
request.user = this.
|
|
381
|
+
request.user = this.ssrContext.user || null;
|
|
373
382
|
|
|
374
|
-
request.data = this.
|
|
383
|
+
request.data = this.ssrContext.request.data;
|
|
375
384
|
|
|
376
|
-
apiData = this.
|
|
385
|
+
apiData = this.ssrContext.page.data || {};
|
|
377
386
|
}
|
|
378
387
|
|
|
379
388
|
// Replacer api data par ssr data
|
|
380
389
|
|
|
381
|
-
const response = await this.createResponse(route, request, apiData)
|
|
390
|
+
const response = await this.createResponse(route, request, apiData);
|
|
382
391
|
|
|
383
392
|
ReactDOM.hydrate((
|
|
384
393
|
<App context={response.context} />
|
|
@@ -39,7 +39,7 @@ export default class ApiClient implements ApiClientService {
|
|
|
39
39
|
public constructor(
|
|
40
40
|
public app: ClientApplication,
|
|
41
41
|
public request: Request,
|
|
42
|
-
public router = request.router
|
|
42
|
+
public router = request.router,
|
|
43
43
|
) {
|
|
44
44
|
|
|
45
45
|
}
|
|
@@ -66,30 +66,34 @@ export default class ApiClient implements ApiClientService {
|
|
|
66
66
|
public delete = <TData extends unknown = unknown>(path: string, data?: TPostData, opts?: TApiFetchOptions) =>
|
|
67
67
|
this.createFetcher<TData>('DELETE', path, data, opts);
|
|
68
68
|
|
|
69
|
-
|
|
70
69
|
public set( newData: TObjetDonnees ) {
|
|
71
70
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
71
|
+
if (!('context' in this.router))
|
|
72
|
+
throw new Error("api.set is not available on server side.");
|
|
73
|
+
|
|
74
|
+
if (this.router.context.page)
|
|
75
|
+
this.router.context.page.setAllData(curData => ({ ...curData, ...newData }));
|
|
76
|
+
else
|
|
77
|
+
throw new Error(`[api] this.router.context.page undefined`)
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
public reload( ids?: string | string[], params?: TObjetDonnees ) {
|
|
81
|
+
|
|
82
|
+
if (!('context' in this.router))
|
|
83
|
+
throw new Error("api.set is not available on server side.");
|
|
79
84
|
|
|
80
|
-
|
|
81
|
-
throw new Error("context.page is missing");
|
|
85
|
+
const page = this.router.context.page;
|
|
82
86
|
|
|
83
87
|
if (ids === undefined)
|
|
84
|
-
ids = Object.keys(
|
|
88
|
+
ids = Object.keys(page.fetchers);
|
|
85
89
|
else if (typeof ids === 'string')
|
|
86
90
|
ids = [ids];
|
|
87
91
|
|
|
88
|
-
console.log("[api] Reload data", ids, params,
|
|
92
|
+
console.log("[api] Reload data", ids, params, page.fetchers);
|
|
89
93
|
|
|
90
94
|
for (const id of ids) {
|
|
91
95
|
|
|
92
|
-
const fetcher =
|
|
96
|
+
const fetcher = page.fetchers[id];
|
|
93
97
|
if (fetcher === undefined)
|
|
94
98
|
return console.error(`Unable to reload ${id}: Request not found in fetchers list.`);
|
|
95
99
|
|
|
@@ -169,12 +173,15 @@ export default class ApiClient implements ApiClientService {
|
|
|
169
173
|
public configure = (...[method, path, data, options]: TFetcherArgs): AxiosRequestConfig => {
|
|
170
174
|
|
|
171
175
|
const { onProgress, captcha } = options || {};
|
|
176
|
+
|
|
177
|
+
const url = this.router.url( path, {}, false );
|
|
172
178
|
|
|
173
|
-
debug && console.log(`[api] Sending request`, method,
|
|
179
|
+
debug && console.log(`[api] Sending request`, method, url, data);
|
|
174
180
|
|
|
181
|
+
// Create AXIOS config
|
|
175
182
|
const config: AxiosRequestConfig = {
|
|
176
183
|
|
|
177
|
-
url
|
|
184
|
+
url,
|
|
178
185
|
method: method,
|
|
179
186
|
headers: {
|
|
180
187
|
'Content-Type': "application/json",
|
|
@@ -192,6 +199,7 @@ export default class ApiClient implements ApiClientService {
|
|
|
192
199
|
|
|
193
200
|
};
|
|
194
201
|
|
|
202
|
+
// Format request data
|
|
195
203
|
if (data) {
|
|
196
204
|
// URL params
|
|
197
205
|
if (method === "GET") {
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
import type ServerRouter from '@server/services/router';
|
|
7
7
|
import type ServerResponse from '@server/services/router/response';
|
|
8
8
|
|
|
9
|
-
import type {
|
|
10
|
-
import BaseResponse from '@common/router/response';
|
|
9
|
+
import type { TAnyRoute, TErrorRoute } from '@common/router';
|
|
10
|
+
import BaseResponse, { TResponseData } from '@common/router/response';
|
|
11
11
|
|
|
12
12
|
import type ClientApplication from '@client/app';
|
|
13
13
|
import type { default as ClientRouter } from '@client/services/router'
|
|
@@ -15,7 +15,6 @@ import type ClientResponse from '@client/services/router/response'
|
|
|
15
15
|
import ClientRequest from '@client/services/router/request'
|
|
16
16
|
import ClientPage from '@client/services/router/response/page'
|
|
17
17
|
import { history } from '@client/services/router/request/history';
|
|
18
|
-
import CommonPage from '@common/router/response/page';
|
|
19
18
|
|
|
20
19
|
/*----------------------------------
|
|
21
20
|
- TYPES
|
|
@@ -34,12 +33,11 @@ export type TRouterContext<
|
|
|
34
33
|
// ClientPage context
|
|
35
34
|
{
|
|
36
35
|
app: TApplication,
|
|
37
|
-
context: TRouterContext<TRouter, TApplication>,
|
|
38
36
|
request: ClientRequest<TRouter>,
|
|
39
|
-
route:
|
|
37
|
+
route: TAnyRoute<TRouterContext>,
|
|
40
38
|
api: ClientRequest<TRouter>["api"],
|
|
41
39
|
page: ClientPage<TRouter>,
|
|
42
|
-
|
|
40
|
+
data: TObjetDonnees
|
|
43
41
|
}
|
|
44
42
|
&
|
|
45
43
|
// Expose client application services (api, socket, ...)
|
|
@@ -61,7 +59,7 @@ export default class ClientPageResponse<
|
|
|
61
59
|
|
|
62
60
|
public constructor(
|
|
63
61
|
public request: ClientRequest<TRouter>,
|
|
64
|
-
public route:
|
|
62
|
+
public route: TAnyRoute | TErrorRoute,
|
|
65
63
|
|
|
66
64
|
public app = request.app,
|
|
67
65
|
) {
|
|
@@ -76,22 +74,38 @@ export default class ClientPageResponse<
|
|
|
76
74
|
|
|
77
75
|
private createContext(): TRouterContext<TRouter, TRouter["app"]> {
|
|
78
76
|
|
|
79
|
-
const
|
|
77
|
+
const basicContext: TRouterContext<TRouter, TRouter["app"]> = {
|
|
78
|
+
|
|
80
79
|
// App services (TODO: expose only services)
|
|
81
80
|
...this.request.app,
|
|
81
|
+
|
|
82
82
|
// Router context
|
|
83
83
|
app: this.app,
|
|
84
|
-
context: undefined as unknown as TRouterContext<TRouter, TRouter["app"]>,
|
|
85
84
|
request: this.request,
|
|
86
85
|
route: this.route,
|
|
87
86
|
api: this.request.api,
|
|
87
|
+
// Will be assigned when the controller will be runned
|
|
88
|
+
page: undefined as unknown as ClientPage<TRouter>,
|
|
89
|
+
data: {},
|
|
90
|
+
}
|
|
88
91
|
|
|
89
|
-
|
|
92
|
+
const newContext: TRouterContext<TRouter, TRouter["app"]> = {
|
|
93
|
+
...basicContext,
|
|
94
|
+
// Custom context
|
|
95
|
+
...this.request.router.config.context( basicContext, this.request.router )
|
|
90
96
|
}
|
|
91
97
|
|
|
92
|
-
context
|
|
98
|
+
// Update context object if already exists
|
|
99
|
+
// NOTE: we don't create a nex instance of context because we don't want to rereder the full page (inc layout) to update the context given by thr react context provider
|
|
100
|
+
const existingContext = this.request.router.context;
|
|
101
|
+
if (existingContext === undefined) {
|
|
102
|
+
|
|
103
|
+
this.request.router.context = newContext
|
|
104
|
+
|
|
105
|
+
} else for(const key in newContext)
|
|
106
|
+
existingContext[ key ] = newContext[ key ];
|
|
93
107
|
|
|
94
|
-
return
|
|
108
|
+
return newContext
|
|
95
109
|
}
|
|
96
110
|
|
|
97
111
|
public async runController( additionnalData: {} = {} ): Promise<ClientPage> {
|
|
@@ -45,7 +45,7 @@ export default class ClientPage<TRouter = ClientRouter> extends PageResponse<TRo
|
|
|
45
45
|
this.context.page = this;
|
|
46
46
|
|
|
47
47
|
// Data succesfully loaded
|
|
48
|
-
this.data = data || await this.fetchData();
|
|
48
|
+
this.context.data = this.data = data || await this.fetchData();
|
|
49
49
|
|
|
50
50
|
return this;
|
|
51
51
|
}
|
|
@@ -107,10 +107,51 @@ export type TRouteModule<TRegisteredRoute = any> = {
|
|
|
107
107
|
__register?: TAppArrowFunction<TRegisteredRoute>
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
export type TDomainsList = {
|
|
111
|
+
[endpointId: string]: string
|
|
112
|
+
} & {
|
|
113
|
+
current: string
|
|
114
|
+
}
|
|
115
|
+
|
|
110
116
|
export const defaultOptions = {
|
|
111
117
|
priority: 0,
|
|
112
118
|
}
|
|
113
119
|
|
|
120
|
+
/*----------------------------------
|
|
121
|
+
- FUNCTIONS
|
|
122
|
+
----------------------------------*/
|
|
123
|
+
export const buildUrl = (
|
|
124
|
+
path: string,
|
|
125
|
+
params: {} = {},
|
|
126
|
+
domains: TDomainsList,
|
|
127
|
+
absolute: boolean
|
|
128
|
+
) => {
|
|
129
|
+
|
|
130
|
+
// Relative to domain
|
|
131
|
+
if (path[0] === '/' && absolute)
|
|
132
|
+
return domains.current + path;
|
|
133
|
+
// Other domains of the project
|
|
134
|
+
else if (path[0] === '@') {
|
|
135
|
+
|
|
136
|
+
// Extract domain ID from path
|
|
137
|
+
let domainId: string;
|
|
138
|
+
const slackPos = path.indexOf('/');
|
|
139
|
+
domainId = path.substring(1, slackPos);
|
|
140
|
+
path = path.substring(slackPos);
|
|
141
|
+
|
|
142
|
+
// Get domain
|
|
143
|
+
const domain = domains[ domainId ];
|
|
144
|
+
if (domain === undefined)
|
|
145
|
+
throw new Error("Unknown API endpoint ID: " + domainId);
|
|
146
|
+
|
|
147
|
+
// Return full url
|
|
148
|
+
return domain + path;
|
|
149
|
+
|
|
150
|
+
// Absolute URL
|
|
151
|
+
} else
|
|
152
|
+
return path;
|
|
153
|
+
}
|
|
154
|
+
|
|
114
155
|
/*----------------------------------
|
|
115
156
|
- BASE ROUTER
|
|
116
157
|
----------------------------------*/
|
|
@@ -72,6 +72,8 @@ export default abstract class ApiClient {
|
|
|
72
72
|
|
|
73
73
|
public abstract delete<TData extends unknown = unknown>(path: string, data?: TObjetDonnees, opts?: TApiFetchOptions): TFetcher<TData>;
|
|
74
74
|
|
|
75
|
+
public abstract set( newData: TObjetDonnees );
|
|
76
|
+
|
|
75
77
|
/*----------------------------------
|
|
76
78
|
- LOW LEVEL
|
|
77
79
|
----------------------------------*/
|
|
@@ -7,14 +7,14 @@ import { FunctionalComponent } from "preact";
|
|
|
7
7
|
|
|
8
8
|
// Core
|
|
9
9
|
import { TAnyRoute } from "..";
|
|
10
|
-
import type ClientRequest from '@client/services/router';
|
|
10
|
+
import type ClientRequest from '@client/services/router/request';
|
|
11
11
|
import Page from '@client/services/router/response/page'
|
|
12
12
|
|
|
13
13
|
/*----------------------------------
|
|
14
14
|
- TYPES
|
|
15
15
|
----------------------------------*/
|
|
16
16
|
|
|
17
|
-
type TResponseData = Page
|
|
17
|
+
export type TResponseData = Page
|
|
18
18
|
|
|
19
19
|
/*----------------------------------
|
|
20
20
|
- CONTEXT
|
|
@@ -10,6 +10,7 @@ import { InputError } from '@common/errors';
|
|
|
10
10
|
|
|
11
11
|
// Specific
|
|
12
12
|
import type { TValidateOptions } from './schema';
|
|
13
|
+
import type { InputBaseProps } from '@client/components/inputv3/base';
|
|
13
14
|
|
|
14
15
|
/*----------------------------------
|
|
15
16
|
- TYPES
|
|
@@ -64,14 +65,23 @@ export const EXCLUDE_VALUE = "action:exclure" as const;
|
|
|
64
65
|
/*----------------------------------
|
|
65
66
|
- CLASS
|
|
66
67
|
----------------------------------*/
|
|
67
|
-
export default class Validator<
|
|
68
|
+
export default class Validator<
|
|
69
|
+
TValue,
|
|
70
|
+
TOptions extends TValidator<TValue> = TValidator<TValue>,
|
|
71
|
+
TComponent = React.FunctionComponent< InputBaseProps< TValue > >
|
|
72
|
+
> {
|
|
68
73
|
|
|
69
74
|
public constructor(
|
|
70
75
|
public type: string,
|
|
71
76
|
public validateType: TValidationFunction<TValue>,
|
|
72
|
-
public options: TOptions
|
|
77
|
+
public options: TOptions,
|
|
78
|
+
public componentAttributes: Partial<InputBaseProps<TValue>> = {}
|
|
73
79
|
) {
|
|
74
80
|
|
|
81
|
+
// Basic component attriutes
|
|
82
|
+
this.componentAttributes.required = options?.opt !== true;
|
|
83
|
+
//this.componentAttributes.validator = this;
|
|
84
|
+
|
|
75
85
|
}
|
|
76
86
|
|
|
77
87
|
public isEmpty = (val: any) => val === undefined || val === '' || val === null
|
|
@@ -111,22 +111,22 @@ export default class SchemaValidators {
|
|
|
111
111
|
})
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
public choice = (
|
|
114
|
+
public choice = (choices?: any[], opts: TValidator<any> & {} = {}) =>
|
|
115
115
|
new Validator<any>('choice', (val, input, output) => {
|
|
116
116
|
|
|
117
117
|
// Choice object
|
|
118
118
|
if (typeof val === 'object' && ('value' in val) && typeof val.value !== 'object')
|
|
119
119
|
val = val.value;
|
|
120
120
|
|
|
121
|
-
if (
|
|
122
|
-
const isValid =
|
|
121
|
+
if (choices !== undefined) {
|
|
122
|
+
const isValid = choices.some(v => v.value === val);
|
|
123
123
|
if (!isValid)
|
|
124
|
-
throw new InputError("Invalid value. Must be: " +
|
|
124
|
+
throw new InputError("Invalid value. Must be: " + choices.map(v => v.value).join(', '));
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
return val;
|
|
128
128
|
|
|
129
|
-
}, opts)
|
|
129
|
+
}, opts, { choices })
|
|
130
130
|
|
|
131
131
|
/*----------------------------------
|
|
132
132
|
- CHAINES
|
package/src/server/app/index.ts
CHANGED
|
@@ -41,6 +41,10 @@ export type StartedServicesIndex = {
|
|
|
41
41
|
[serviceId: string]: AnyService
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
type TServiceUseOptions = {
|
|
45
|
+
optional?: boolean
|
|
46
|
+
}
|
|
47
|
+
|
|
44
48
|
/*----------------------------------
|
|
45
49
|
- CONFIG
|
|
46
50
|
----------------------------------*/
|
|
@@ -147,7 +151,8 @@ export default abstract class Service<
|
|
|
147
151
|
TSubServices extends TServiceClass["services"],
|
|
148
152
|
>(
|
|
149
153
|
serviceId: TServiceId,
|
|
150
|
-
subServices?: TSubServices
|
|
154
|
+
subServices?: TSubServices,
|
|
155
|
+
serviceUseOptions: TServiceUseOptions = {}
|
|
151
156
|
): (
|
|
152
157
|
// We can't pass the services types as a generic to TServiceClass
|
|
153
158
|
// So we overwrite the services property
|
|
@@ -164,8 +169,12 @@ export default abstract class Service<
|
|
|
164
169
|
|
|
165
170
|
// Check of the service has been configurated
|
|
166
171
|
const registered = ServicesContainer.registered[ serviceId ];
|
|
167
|
-
if (registered === undefined)
|
|
168
|
-
|
|
172
|
+
if (registered === undefined) {
|
|
173
|
+
if (serviceUseOptions.optional)
|
|
174
|
+
return undefined;
|
|
175
|
+
else
|
|
176
|
+
throw new Error(`Unable to use service "${serviceId}": This one hasn't been setup.`);
|
|
177
|
+
}
|
|
169
178
|
|
|
170
179
|
// Bind subservices
|
|
171
180
|
if (subServices !== undefined)
|
|
@@ -137,8 +137,6 @@ export default class Console extends Service<Config, Hooks, Application, Service
|
|
|
137
137
|
|
|
138
138
|
protected async start() {
|
|
139
139
|
|
|
140
|
-
return;
|
|
141
|
-
|
|
142
140
|
const origLog = console.log
|
|
143
141
|
|
|
144
142
|
this.logger = new Logger({
|
|
@@ -352,10 +350,10 @@ export default class Console extends Service<Config, Hooks, Application, Service
|
|
|
352
350
|
|
|
353
351
|
public printHtml( logs: TJsonLog[], full: boolean = false ): string {
|
|
354
352
|
|
|
355
|
-
let html = logs.map( logEntry => logToHTML( logEntry, this )).join('
|
|
353
|
+
let html = logs.map( logEntry => logToHTML( logEntry, this )).join('<br />');
|
|
356
354
|
|
|
357
355
|
if (full) {
|
|
358
|
-
const consoleCss = `background: #000; padding: 20px; font-family: 'Fira Mono', 'monospace', 'Monaco'; font-size: 12px; line-height: 20px;`
|
|
356
|
+
const consoleCss = `background: #000; padding: 20px; font-family: 'Fira Mono', 'monospace', 'Monaco'; font-size: 12px; line-height: 20px;color: #aaa;`
|
|
359
357
|
html = '<div style="' + consoleCss + '">' + html + '</div>';
|
|
360
358
|
}
|
|
361
359
|
|
|
@@ -8,7 +8,7 @@ import express from 'express';
|
|
|
8
8
|
import http from 'http';
|
|
9
9
|
import https from 'https';
|
|
10
10
|
import path from 'path';
|
|
11
|
-
import cors from 'cors';
|
|
11
|
+
import cors, { CorsOptions } from 'cors';
|
|
12
12
|
//var serveStatic = require('serve-static')
|
|
13
13
|
|
|
14
14
|
// Middlewares (npm)
|
|
@@ -52,7 +52,8 @@ export type Config = {
|
|
|
52
52
|
styles?: string[],
|
|
53
53
|
images?: string[],
|
|
54
54
|
scripts: string[],
|
|
55
|
-
}
|
|
55
|
+
},
|
|
56
|
+
cors?: CorsOptions
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
export type Hooks = {
|
|
@@ -200,11 +201,8 @@ export default class HttpServer {
|
|
|
200
201
|
- PAGES / API
|
|
201
202
|
----------------------------------*/
|
|
202
203
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
// TODO: Trouver une solution pour n'autoriser les requetes que depuis l'application & dopamyn.io
|
|
206
|
-
// https://www.google.com/search?q=http+cors+from+android%7Cwindows%7Cdesktop%7Cmodile+app
|
|
207
|
-
//routes.use('/auth', cors());
|
|
204
|
+
if (this.config.cors !== undefined)
|
|
205
|
+
routes.use( cors( this.config.cors ));
|
|
208
206
|
|
|
209
207
|
routes.use( csp.expressCspHeader({
|
|
210
208
|
directives: {
|
|
@@ -24,7 +24,8 @@ import type DisksManager from '@server/services/disks';
|
|
|
24
24
|
import { CoreError, NotFound } from '@common/errors';
|
|
25
25
|
import BaseRouter, {
|
|
26
26
|
TRoute, TErrorRoute, TRouteModule,
|
|
27
|
-
TRouteOptions, defaultOptions
|
|
27
|
+
TRouteOptions, defaultOptions,
|
|
28
|
+
buildUrl, TDomainsList
|
|
28
29
|
} from '@common/router';
|
|
29
30
|
import { buildRegex, getRegisterPageArgs } from '@common/router/register';
|
|
30
31
|
import { layoutsList, getLayout } from '@common/router/layouts';
|
|
@@ -86,6 +87,8 @@ export type Config<
|
|
|
86
87
|
|
|
87
88
|
disk?: string, // Disk driver ID
|
|
88
89
|
|
|
90
|
+
domains: TDomainsList,
|
|
91
|
+
|
|
89
92
|
http: HttpServiceConfig
|
|
90
93
|
|
|
91
94
|
context: (
|
|
@@ -114,7 +117,9 @@ export default class ServerRouter<
|
|
|
114
117
|
TSubservices extends Services = Services
|
|
115
118
|
> extends Service<Config, Hooks, Application, TSubservices> implements BaseRouter {
|
|
116
119
|
|
|
117
|
-
public disks = this.use('Core/Disks'
|
|
120
|
+
public disks = this.use('Core/Disks', undefined, {
|
|
121
|
+
optional: true
|
|
122
|
+
}) as unknown as DisksManager | undefined;
|
|
118
123
|
|
|
119
124
|
// Services
|
|
120
125
|
public http: HTTP;
|
|
@@ -144,7 +149,6 @@ export default class ServerRouter<
|
|
|
144
149
|
|
|
145
150
|
this.http = new HTTP(config.http, this);
|
|
146
151
|
this.render = new DocumentRenderer(this);
|
|
147
|
-
|
|
148
152
|
}
|
|
149
153
|
|
|
150
154
|
/*----------------------------------
|
|
@@ -205,13 +209,8 @@ export default class ServerRouter<
|
|
|
205
209
|
this.afterRegister();
|
|
206
210
|
}
|
|
207
211
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
path: TRoutePath,
|
|
211
|
-
params: Routes[TRoutePath]["params"]
|
|
212
|
-
) {
|
|
213
|
-
return this.http.publicUrl + path;
|
|
214
|
-
}
|
|
212
|
+
public url = (path: string, params: {} = {}, absolute: boolean = true) =>
|
|
213
|
+
buildUrl(path, params, this.config.domains, absolute);
|
|
215
214
|
|
|
216
215
|
/*----------------------------------
|
|
217
216
|
- REGISTER
|
|
@@ -47,6 +47,10 @@ export default class ApiClientRequest extends RequestService implements ApiClien
|
|
|
47
47
|
public delete = <TData extends unknown = unknown>(path: string, data?: TObjetDonnees, opts?: TApiFetchOptions) =>
|
|
48
48
|
this.createFetcher<TData>('DELETE', path, data, opts);
|
|
49
49
|
|
|
50
|
+
public set( newData: TObjetDonnees ) {
|
|
51
|
+
throw new Error("api.set is not available on server side.");
|
|
52
|
+
}
|
|
53
|
+
|
|
50
54
|
/*----------------------------------
|
|
51
55
|
- API CALLS FROM SERVER
|
|
52
56
|
----------------------------------*/
|
|
@@ -65,10 +69,11 @@ export default class ApiClientRequest extends RequestService implements ApiClien
|
|
|
65
69
|
|
|
66
70
|
for (const id in fetchers) {
|
|
67
71
|
|
|
68
|
-
|
|
72
|
+
const fetcher = fetchers[id]
|
|
73
|
+
if (!fetcher)
|
|
69
74
|
continue;
|
|
70
75
|
|
|
71
|
-
const { method, path, data, options } =
|
|
76
|
+
const { method, path, data, options } = fetcher;
|
|
72
77
|
//this.router.config.debug && console.log(`[api] Resolving from internal api`, method, path, data);
|
|
73
78
|
|
|
74
79
|
// We don't fetch the already given data
|
|
@@ -31,7 +31,7 @@ const debug = true;
|
|
|
31
31
|
export type TBasicSSrData = {
|
|
32
32
|
request: { data: TObjetDonnees, id: string },
|
|
33
33
|
page: { chunkId: string, data?: TObjetDonnees },
|
|
34
|
-
|
|
34
|
+
user: User | null
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
export type TRouterContext<TRouter extends ServerRouter = ServerRouter> = (
|
|
@@ -245,17 +245,17 @@ export default class ServerResponse<
|
|
|
245
245
|
}
|
|
246
246
|
|
|
247
247
|
// TODO: https://github.com/adonisjs/http-server/blob/develop/src/Response/index.ts#L430
|
|
248
|
-
public async file(
|
|
248
|
+
public async file( filename: string ) {
|
|
249
249
|
|
|
250
250
|
// Securité
|
|
251
|
-
if (
|
|
251
|
+
if (filename.includes('..'))
|
|
252
252
|
throw new Forbidden("Disallowed");
|
|
253
253
|
|
|
254
254
|
// // Force absolute path
|
|
255
|
-
// if (!
|
|
256
|
-
//
|
|
257
|
-
// ? this.app.path.root + '/bin' +
|
|
258
|
-
// : this.app.path.data + '/' +
|
|
255
|
+
// if (!filename.startsWith( this.app.path.root ))
|
|
256
|
+
// filename = filename[0] === '/'
|
|
257
|
+
// ? this.app.path.root + '/bin' + filename
|
|
258
|
+
// : this.app.path.data + '/' + filename;
|
|
259
259
|
// Disk not provided = file response disabled
|
|
260
260
|
if (this.router.disks === undefined)
|
|
261
261
|
throw new Anomaly("Router: Unable to return file response in router, because no disk has been given in the router config.");
|
|
@@ -264,14 +264,15 @@ export default class ServerResponse<
|
|
|
264
264
|
const disk = this.router.disks.get('default');
|
|
265
265
|
|
|
266
266
|
// Verif existance
|
|
267
|
-
const fileExists = await disk.exists('data',
|
|
267
|
+
const fileExists = await disk.exists('data', filename);
|
|
268
268
|
if (!fileExists) {
|
|
269
|
-
console.log("File " +
|
|
269
|
+
console.log("File " + filename + " was not found.");
|
|
270
270
|
throw new NotFound();
|
|
271
271
|
}
|
|
272
272
|
|
|
273
|
-
// envoi
|
|
274
|
-
|
|
273
|
+
// envoi filename
|
|
274
|
+
const file = await disk.readFile('data', filename, {});
|
|
275
|
+
this.data = file;
|
|
275
276
|
return this.end();
|
|
276
277
|
}
|
|
277
278
|
|
|
@@ -279,7 +280,7 @@ export default class ServerResponse<
|
|
|
279
280
|
|
|
280
281
|
debug && console.log("[routeur][response] Redirect", url);
|
|
281
282
|
this.statusCode = code;
|
|
282
|
-
this.headers['Location'] = url;
|
|
283
|
+
this.headers['Location'] = this.router.url( url );
|
|
283
284
|
return this.end();
|
|
284
285
|
}
|
|
285
286
|
|