5htp-core 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.md +5 -0
- package/doc/TODO.md +71 -0
- package/package.json +5 -4
- package/src/client/{App.tsx → app/component.tsx} +15 -8
- package/src/client/app/index.ts +128 -0
- package/src/client/app/service.ts +34 -0
- package/src/client/app.tsconfig.json +0 -4
- package/src/client/assets/css/medias.less +14 -0
- package/src/client/components/Card/index.tsx +2 -2
- package/src/client/components/Dialog/Manager.tsx +39 -12
- package/src/client/components/Form/index.tsx +1 -1
- package/src/client/components/button.tsx +2 -2
- package/src/client/components/containers/Popover/index.tsx +1 -1
- package/src/client/components/data/spintext/index.tsx +1 -1
- package/src/client/components/dropdown/index.tsx +1 -1
- package/src/client/components/index.ts +8 -0
- package/src/client/components/input/BaseV2/index.tsx +1 -1
- package/src/client/components/input/UploadImage/index.tsx +1 -1
- package/src/client/hooks/index.ts +5 -0
- package/src/client/hooks/useState/index.tsx +2 -2
- package/src/client/hooks.ts +22 -0
- package/src/client/index.ts +5 -0
- package/src/client/pages/_layout/landing/index.tsx +0 -2
- package/src/client/pages/_messages/400.tsx +2 -2
- package/src/client/pages/_messages/401.tsx +2 -2
- package/src/client/pages/_messages/403.tsx +2 -2
- package/src/client/pages/_messages/404.tsx +2 -2
- package/src/client/pages/_messages/500.tsx +2 -2
- package/src/client/pages/bug.tsx +1 -1
- package/src/client/pages/useHeader.tsx +1 -1
- package/src/client/{context/captcha.ts → services/captcha/index.ts} +0 -0
- package/src/client/services/metrics/index.ts +37 -0
- package/src/client/{router → services/router/components}/Link.tsx +1 -1
- package/src/client/services/router/components/Page.tsx +59 -0
- package/src/client/{router/component.tsx → services/router/components/router.tsx} +43 -74
- package/src/client/services/router/index.tsx +448 -0
- package/src/client/services/router/request/api.ts +229 -0
- package/src/client/{router → services/router}/request/history.ts +0 -0
- package/src/client/services/router/request/index.ts +52 -0
- package/src/client/services/router/response/index.tsx +107 -0
- package/src/client/services/router/response/page.ts +95 -0
- package/src/client/{context/socket.ts → services/socket/index.ts} +2 -2
- package/src/client/utils/dom.ts +1 -1
- package/src/common/app/index.ts +9 -0
- package/src/common/data/chaines/index.ts +9 -6
- package/src/common/data/input/validate.ts +3 -166
- package/src/common/data/objets.ts +25 -0
- package/src/common/data/tableaux.ts +8 -0
- package/src/common/errors/index.ts +3 -1
- package/src/common/router/index.ts +67 -88
- package/src/common/router/layouts.ts +50 -0
- package/src/common/router/register.ts +62 -0
- package/src/common/router/request/api.ts +72 -0
- package/src/common/router/request/index.ts +31 -0
- package/src/common/router/{response.ts → response/index.ts} +9 -13
- package/src/common/router/response/page.ts +40 -56
- package/src/common/validation/index.ts +3 -0
- package/src/common/validation/schema.ts +184 -0
- package/src/common/validation/validator.ts +88 -0
- package/src/common/validation/validators.ts +313 -0
- package/src/server/app/config.ts +9 -27
- package/src/server/app/index.ts +81 -124
- package/src/server/app/service.ts +98 -0
- package/src/server/app.tsconfig.json +0 -8
- package/src/server/error/index.ts +13 -0
- package/src/server/index.ts +5 -0
- package/src/server/patch.ts +0 -6
- package/src/server/{data/Cache.ts → services/cache/index.ts} +79 -47
- package/src/server/services/console/bugReporter.ts +26 -16
- package/src/server/services/console/index.ts +59 -51
- package/src/server/services/cron/index.ts +12 -26
- package/src/server/services/database/bucket.ts +40 -0
- package/src/server/services/database/connection.ts +206 -75
- package/src/server/services/database/datatypes.ts +63 -40
- package/src/server/services/database/index.ts +295 -272
- package/src/server/services/database/metas.ts +246 -135
- package/src/server/services/database/stats.ts +151 -126
- package/src/server/services/email/index.ts +28 -52
- package/src/server/services/{router/request/services → metrics}/detect.ts +8 -10
- package/src/server/services/{router/request/services/tracking.ts → metrics/index.ts} +68 -45
- package/src/server/services/{http → router/http}/index.ts +28 -70
- package/src/server/services/{http → router/http}/multipart.ts +0 -0
- package/src/server/services/{http → router/http}/session.ts.old +0 -0
- package/src/server/services/router/index.ts +273 -203
- package/src/server/services/router/request/api.ts +73 -0
- package/src/server/services/router/request/index.ts +16 -97
- package/src/server/services/router/request/service.ts +21 -0
- package/src/server/services/router/response/index.ts +125 -64
- package/src/server/services/router/response/{filter → mask}/Filter.ts +0 -0
- package/src/server/services/router/response/{filter → mask}/index.ts +0 -2
- package/src/server/services/router/response/{filter → mask}/selecteurs.ts +0 -0
- package/src/server/services/router/response/page/document.tsx +194 -0
- package/src/server/services/router/response/page/index.tsx +157 -0
- package/src/server/{libs/pages → services/router/response/page}/schemaGenerator.ts +0 -0
- package/src/server/services/router/service.ts +48 -0
- package/src/server/services/schema/index.ts +47 -0
- package/src/server/services/schema/request.ts +55 -0
- package/src/server/services/schema/router.ts +33 -0
- package/src/server/services/socket/index.ts +38 -43
- package/src/server/services/socket/scope.ts +6 -4
- package/src/server/services/users/index.ts +203 -0
- package/src/server/services/{auth/base.ts → users/old.ts} +28 -112
- package/src/server/services/users/router/index.ts +72 -0
- package/src/server/services/users/router/request.ts +49 -0
- package/src/types/aliases.d.ts +43 -2
- package/templates/composant.tsx +1 -1
- package/templates/modal.tsx +1 -1
- package/templates/page.tsx +1 -1
- package/tsconfig.common.json +0 -4
- package/src/client/context/api.ts +0 -92
- package/src/client/context/index.ts +0 -246
- package/src/client/index.tsx +0 -129
- package/src/client/router/index.ts +0 -286
- package/src/client/router/request/index.ts +0 -106
- package/src/client/router/response/index.ts +0 -38
- package/src/client/router/route.ts +0 -75
- package/src/common/data/input/validators/basic.ts +0 -299
- package/src/common/data/input/validators/build.ts +0 -63
- package/src/common/router/request.ts +0 -83
- package/src/server/data/ApiClient.ts +0 -119
- package/src/server/data/input.ts +0 -41
- package/src/server/libs/pages/document.static.tsx +0 -41
- package/src/server/libs/pages/document.tsx +0 -203
- package/src/server/libs/pages/render.tsx +0 -90
- package/src/server/routes/auth.ts +0 -151
- package/src/server/services/redis/index.ts +0 -71
- package/src/server/services/router/request/services/auth.ts +0 -177
|
@@ -2,70 +2,89 @@
|
|
|
2
2
|
- DEPENDANCES
|
|
3
3
|
----------------------------------*/
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
import { pathToRegexp, Key } from 'path-to-regexp';
|
|
7
|
-
import type { ComponentChild } from 'preact';
|
|
5
|
+
import { Layout } from './layouts';
|
|
8
6
|
|
|
9
7
|
// types
|
|
10
8
|
import type {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
} from '@client/router';
|
|
9
|
+
default as ClientRouter,
|
|
10
|
+
TRouterContext as ClientRouterContext,
|
|
11
|
+
TRegisterPageArgs
|
|
12
|
+
} from '@client/services/router';
|
|
15
13
|
|
|
16
|
-
import type {
|
|
14
|
+
import type {
|
|
15
|
+
default as ServerRouter,
|
|
16
|
+
TRouterContext as ServerRouterContext,
|
|
17
|
+
TRouteHttpMethod
|
|
18
|
+
} from '@server/services/router';
|
|
17
19
|
|
|
18
|
-
import type {
|
|
20
|
+
import type { TUserRole } from '@server/services/users';
|
|
19
21
|
|
|
20
|
-
import type {
|
|
22
|
+
import type { TAppArrowFunction } from '@common/app';
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
// Specfic
|
|
25
|
+
import type ApiClient from './request/api';
|
|
26
|
+
import type Request from './request';
|
|
27
|
+
import type Response from './response';
|
|
28
|
+
import type { default as Page, TFrontRenderer } from './response/page';
|
|
23
29
|
|
|
24
30
|
/*----------------------------------
|
|
25
|
-
- TYPES:
|
|
31
|
+
- TYPES: ROUTES
|
|
26
32
|
----------------------------------*/
|
|
27
33
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
type LayoutComponent = (attributes: { context: ClientContext }) => ComponentChild;
|
|
31
|
-
export type Layout = { path: string, Component: LayoutComponent }
|
|
32
|
-
const getLayout = (routePath: string | undefined): Layout | undefined => {
|
|
33
|
-
|
|
34
|
-
let layout: Layout | undefined = layouts[''];
|
|
35
|
-
if (routePath) {
|
|
36
|
-
for (const layoutPath in layouts)
|
|
37
|
-
if (routePath === layoutPath || routePath.startsWith( layoutPath + '/' ))
|
|
38
|
-
layout = { path: layoutPath, Component: layouts[layoutPath] };
|
|
39
|
-
}
|
|
40
|
-
//layout && console.log(`${routePath}: Using Layout: ${layout.path}`);
|
|
41
|
-
return layout;
|
|
42
|
-
}
|
|
34
|
+
export type { Layout } from './layouts';
|
|
43
35
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
----------------------------------*/
|
|
36
|
+
export type { default as Request } from './request';
|
|
37
|
+
export type { default as Response } from './response';
|
|
47
38
|
|
|
48
|
-
export type
|
|
49
|
-
|
|
39
|
+
export type ClientOrServerRouter = ClientRouter | ServerRouter;
|
|
40
|
+
|
|
41
|
+
export type TRoute<RouterContext extends TClientOrServerContext = TClientOrServerContext> = {
|
|
50
42
|
|
|
43
|
+
// Match
|
|
44
|
+
method: TRouteHttpMethod,
|
|
45
|
+
path: string,
|
|
51
46
|
regex: RegExp,
|
|
52
47
|
keys: (number | string)[],
|
|
53
48
|
|
|
49
|
+
// Execute
|
|
50
|
+
controller: TRouteController<RouterContext>,//TServerController<TRouter> | TFrontRenderer<TRouter>,
|
|
54
51
|
options: TRouteOptions
|
|
55
52
|
}
|
|
56
53
|
|
|
57
|
-
export type
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
renderer: TFrontRenderer,
|
|
62
|
-
options: {}
|
|
54
|
+
export type TErrorRoute<RouterContext extends TClientOrServerContext = TClientOrServerContext> = {
|
|
55
|
+
code,
|
|
56
|
+
controller: TRouteController<RouterContext>,
|
|
57
|
+
options: TRouteOptions
|
|
63
58
|
}
|
|
64
59
|
|
|
60
|
+
export type TClientOrServerContext<
|
|
61
|
+
TClientOnlyContextKeys extends keyof ClientRouterContext = keyof (ClientRouterContext | ServerRouterContext)
|
|
62
|
+
> = (
|
|
63
|
+
(
|
|
64
|
+
{[serverContextKey in keyof ServerRouterContext/*Omit<ClientRouterContext, TClientOnlyContextKeys>*/]: undefined}
|
|
65
|
+
&
|
|
66
|
+
ClientRouterContext
|
|
67
|
+
)
|
|
68
|
+
|
|
|
69
|
+
(
|
|
70
|
+
// Tell that all the keys of client context are existing but undefined
|
|
71
|
+
// This avoids errors: "Property 'page' is optional in type '{ app: Application; ..."
|
|
72
|
+
// When we destructure the context from the page controller
|
|
73
|
+
// While making reference to a key only available in client context
|
|
74
|
+
// So here, we put the
|
|
75
|
+
{[clientContextKey in keyof ClientRouterContext/*Omit<ClientRouterContext, TClientOnlyContextKeys>*/]: undefined}
|
|
76
|
+
&
|
|
77
|
+
ServerRouterContext
|
|
78
|
+
)
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
export type TRouteController<RouterContext extends TClientOrServerContext = TClientOrServerContext> =
|
|
82
|
+
(context: RouterContext) => /* Page to render */Page | /* Any data (html, json) */Promise<any>
|
|
83
|
+
|
|
65
84
|
export type TRouteOptions = {
|
|
66
85
|
|
|
67
86
|
// Injected by the page plugin
|
|
68
|
-
filepath
|
|
87
|
+
filepath?: string,
|
|
69
88
|
|
|
70
89
|
// Indexing
|
|
71
90
|
bodyId?: string,
|
|
@@ -78,7 +97,7 @@ export type TRouteOptions = {
|
|
|
78
97
|
|
|
79
98
|
// Access Restriction
|
|
80
99
|
auth?: TUserRole | boolean,
|
|
81
|
-
form?: TSchema,
|
|
100
|
+
//form?: TSchema,
|
|
82
101
|
layout?: false | Layout,
|
|
83
102
|
|
|
84
103
|
TESTING?: boolean,
|
|
@@ -86,6 +105,11 @@ export type TRouteOptions = {
|
|
|
86
105
|
|
|
87
106
|
}
|
|
88
107
|
|
|
108
|
+
export type TRouteModule<TRegisteredRoute = any> = {
|
|
109
|
+
// exporing __register is a way to know we axport a TAppArrowFunction
|
|
110
|
+
__register?: TAppArrowFunction<TRegisteredRoute>
|
|
111
|
+
}
|
|
112
|
+
|
|
89
113
|
export const defaultOptions = {
|
|
90
114
|
priority: 0,
|
|
91
115
|
}
|
|
@@ -94,55 +118,10 @@ export const defaultOptions = {
|
|
|
94
118
|
- BASE ROUTER
|
|
95
119
|
----------------------------------*/
|
|
96
120
|
|
|
97
|
-
export default abstract class
|
|
98
|
-
|
|
99
|
-
public page = <TControllerData extends TObjetDonnees = {}>(...args: TRegisterPageArgs<TControllerData>) =>
|
|
100
|
-
this.registerPage(...args);
|
|
101
|
-
|
|
102
|
-
public error = (code: number, options, renderer: TFrontRenderer<{ message: string }>) =>
|
|
103
|
-
this.registerErrorPage(code, options, renderer);
|
|
104
|
-
|
|
105
|
-
protected abstract registerPage(...page: TRegisterPageArgs ): any;
|
|
106
|
-
|
|
107
|
-
public errors: { [code: number]: TErrorRoute } = {};
|
|
108
|
-
protected registerErrorPage( code: number, options, renderer: TFrontRenderer ) {
|
|
109
|
-
return this.errors[code] = {
|
|
110
|
-
type: 'PAGE',
|
|
111
|
-
renderer,
|
|
112
|
-
options
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
protected getRegisterPageArgs(...args: TRegisterPageArgs) {
|
|
117
|
-
|
|
118
|
-
const [path, options, controller, renderer] = args;
|
|
119
|
-
|
|
120
|
-
// S'il s'agit d'une page, son id doit avoir été injecté via le plugin babel
|
|
121
|
-
if (options["id"] === undefined)
|
|
122
|
-
throw new Error(`ID not found for the following page route: ${path}`);
|
|
123
|
-
|
|
124
|
-
// Bind layout
|
|
125
|
-
if (options.layout !== false)
|
|
126
|
-
options.layout = getLayout(options.filepath);
|
|
127
|
-
|
|
128
|
-
return { path, options, controller, renderer }
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
protected buildRegex( path: string ) {
|
|
133
|
-
|
|
134
|
-
// pathToRegexp ne supporte plus les wildcards depuis 4.0
|
|
135
|
-
if (path.endsWith('*'))
|
|
136
|
-
path = path.substring(0, path.length - 1) + '(.*)';
|
|
137
|
-
|
|
138
|
-
// path => regex
|
|
139
|
-
const keys: Key[] = []
|
|
140
|
-
const regex = pathToRegexp(path, keys, {
|
|
141
|
-
sensitive: true
|
|
142
|
-
});
|
|
121
|
+
export default abstract class RouterInterface {
|
|
143
122
|
|
|
144
|
-
|
|
123
|
+
public abstract page<TControllerData extends TObjetDonnees = {}>(...args: TRegisterPageArgs<TControllerData>);
|
|
145
124
|
|
|
146
|
-
}
|
|
125
|
+
public abstract error(code: number, options, renderer: TFrontRenderer<{}, { message: string }>);
|
|
147
126
|
|
|
148
127
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Npm
|
|
6
|
+
import type { ComponentChild } from 'preact';
|
|
7
|
+
// Core
|
|
8
|
+
import type { ClientContext } from '@/client/context';
|
|
9
|
+
// App
|
|
10
|
+
import layouts from '@/client/pages/**/_layout/index.tsx';
|
|
11
|
+
|
|
12
|
+
/*----------------------------------
|
|
13
|
+
- CONST
|
|
14
|
+
----------------------------------*/
|
|
15
|
+
|
|
16
|
+
export const layoutsList = layouts as ImportedLayouts;
|
|
17
|
+
|
|
18
|
+
/*----------------------------------
|
|
19
|
+
- TYPES
|
|
20
|
+
----------------------------------*/
|
|
21
|
+
type LayoutComponent = (attributes: { context: ClientContext }) => ComponentChild;
|
|
22
|
+
|
|
23
|
+
export type Layout = { path: string, Component: LayoutComponent }
|
|
24
|
+
|
|
25
|
+
export type ImportedLayouts = {
|
|
26
|
+
[chunkId: string]: Layout["Component"]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/*----------------------------------
|
|
30
|
+
- UTILS
|
|
31
|
+
----------------------------------*/
|
|
32
|
+
// TODO: getLayot only on server side, and pass the layout chunk id
|
|
33
|
+
export const getLayout = (routePath: string | undefined): Layout | undefined => {
|
|
34
|
+
|
|
35
|
+
//console.log(`[router][layouts] Get layout for "${routePath}".`);
|
|
36
|
+
|
|
37
|
+
let layout: Layout | undefined;
|
|
38
|
+
if (routePath) {
|
|
39
|
+
for (const layoutPath in layouts)
|
|
40
|
+
if (routePath === layoutPath || routePath.startsWith( layoutPath + '_' ))
|
|
41
|
+
layout = {
|
|
42
|
+
path: layoutPath,
|
|
43
|
+
Component: layouts[layoutPath]
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
//console.log(`[router][layouts] Get layout for "${routePath}". Found:`, layout);
|
|
48
|
+
|
|
49
|
+
return layout;
|
|
50
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Npm
|
|
6
|
+
import { pathToRegexp, Key } from 'path-to-regexp';
|
|
7
|
+
|
|
8
|
+
// Core
|
|
9
|
+
import { getLayout } from './layouts';
|
|
10
|
+
|
|
11
|
+
// types
|
|
12
|
+
import type { TRouteOptions } from '.';
|
|
13
|
+
import type { TDataProvider, TFrontRenderer } from './response/page';
|
|
14
|
+
import type { TRegisterPageArgs } from '@client/services/router';
|
|
15
|
+
|
|
16
|
+
/*----------------------------------
|
|
17
|
+
- UTILS
|
|
18
|
+
----------------------------------*/
|
|
19
|
+
|
|
20
|
+
export const getRegisterPageArgs = (...args: TRegisterPageArgs) => {
|
|
21
|
+
|
|
22
|
+
let path: string;
|
|
23
|
+
let options: Partial<TRouteOptions> = {};
|
|
24
|
+
let controller: TDataProvider|null;
|
|
25
|
+
let renderer: TFrontRenderer;
|
|
26
|
+
|
|
27
|
+
if (args.length === 3)
|
|
28
|
+
([path, controller, renderer] = args)
|
|
29
|
+
else
|
|
30
|
+
([path, options, controller, renderer] = args)
|
|
31
|
+
|
|
32
|
+
// S'il s'agit d'une page, son id doit avoir été injecté via le plugin babel
|
|
33
|
+
const chunkId = options["id"];
|
|
34
|
+
if (chunkId === undefined)
|
|
35
|
+
throw new Error(`ID has not injected for the following page route: ${path}`);
|
|
36
|
+
|
|
37
|
+
// Bind layout
|
|
38
|
+
if (options.layout !== false)
|
|
39
|
+
options.layout = getLayout(chunkId);
|
|
40
|
+
|
|
41
|
+
return { path, options, controller, renderer }
|
|
42
|
+
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const buildRegex = ( path: string ) => {
|
|
46
|
+
|
|
47
|
+
// pathToRegexp ne supporte plus les wildcards depuis 4.0
|
|
48
|
+
if (path.endsWith('*'))
|
|
49
|
+
path = path.substring(0, path.length - 1) + '(.*)';
|
|
50
|
+
|
|
51
|
+
// path => regex
|
|
52
|
+
const keys: Key[] = []
|
|
53
|
+
const regex = pathToRegexp(path, keys, {
|
|
54
|
+
sensitive: true
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
keys: keys.map(k => k.name),
|
|
59
|
+
regex
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
import type { HttpMethod } from '@server/services/router';
|
|
6
|
+
|
|
7
|
+
/*----------------------------------
|
|
8
|
+
- TYPES
|
|
9
|
+
----------------------------------*/
|
|
10
|
+
|
|
11
|
+
export type TFetcherList = { [id: string]: TFetcher }
|
|
12
|
+
|
|
13
|
+
export type TFetcher<TData extends unknown = unknown> = {
|
|
14
|
+
|
|
15
|
+
// For async calls: api.post(...).then((data) => ...)
|
|
16
|
+
then: (callback: (data: TData) => void) => Promise<TData>,
|
|
17
|
+
run: () => Promise<TData>,
|
|
18
|
+
|
|
19
|
+
method: HttpMethod,
|
|
20
|
+
path: string,
|
|
21
|
+
data?: object,
|
|
22
|
+
options?: TApiFetchOptions
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type TFetcherArgs = [
|
|
26
|
+
method: HttpMethod,
|
|
27
|
+
path: string,
|
|
28
|
+
data?: object,
|
|
29
|
+
options?: TApiFetchOptions
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
export type TApiFetchOptions = {
|
|
33
|
+
captcha?: string, // Action id (required by recaptcha)
|
|
34
|
+
onProgress?: (percent: number) => void
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// https://stackoverflow.com/questions/44851268/typescript-how-to-extract-the-generic-parameter-from-a-type
|
|
38
|
+
type TypeWithGeneric<T> = TFetcher<T>
|
|
39
|
+
type extractGeneric<Type> = Type extends TypeWithGeneric<infer X> ? X : never
|
|
40
|
+
|
|
41
|
+
export type TDataReturnedByFetchers<TProvidedData extends TFetcherList = {}> = {
|
|
42
|
+
[Property in keyof TProvidedData]: undefined | (extractGeneric<TProvidedData[Property]> extends ((...args: any[]) => any)
|
|
43
|
+
? ThenArg<ReturnType< extractGeneric<TProvidedData[Property]> >>
|
|
44
|
+
: extractGeneric<TProvidedData[Property]>
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/*----------------------------------
|
|
49
|
+
- CLASS
|
|
50
|
+
----------------------------------*/
|
|
51
|
+
export default abstract class ApiClient {
|
|
52
|
+
|
|
53
|
+
/*----------------------------------
|
|
54
|
+
- TOP LEVEL
|
|
55
|
+
----------------------------------*/
|
|
56
|
+
|
|
57
|
+
public abstract get<TData extends unknown = unknown>(path: string, data?: TObjetDonnees, opts?: TApiFetchOptions): TFetcher<TData>;
|
|
58
|
+
|
|
59
|
+
public abstract post<TData extends unknown = unknown>(path: string, data?: TObjetDonnees, opts?: TApiFetchOptions): TFetcher<TData>;
|
|
60
|
+
|
|
61
|
+
public abstract put<TData extends unknown = unknown>(path: string, data?: TObjetDonnees, opts?: TApiFetchOptions): TFetcher<TData>;
|
|
62
|
+
|
|
63
|
+
public abstract delete<TData extends unknown = unknown>(path: string, data?: TObjetDonnees, opts?: TApiFetchOptions): TFetcher<TData>;
|
|
64
|
+
|
|
65
|
+
/*----------------------------------
|
|
66
|
+
- LOW LEVEL
|
|
67
|
+
----------------------------------*/
|
|
68
|
+
|
|
69
|
+
public abstract createFetcher<TData extends unknown = unknown>(...args: TFetcherArgs): TFetcher<TData>;
|
|
70
|
+
|
|
71
|
+
public abstract fetchSync(fetchers: TFetcherList): Promise<TObjetDonnees>;
|
|
72
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Core
|
|
6
|
+
import Response from '../response';
|
|
7
|
+
|
|
8
|
+
/*----------------------------------
|
|
9
|
+
- TYPES
|
|
10
|
+
----------------------------------*/
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/*----------------------------------
|
|
14
|
+
- CONTEXT
|
|
15
|
+
----------------------------------*/
|
|
16
|
+
export default abstract class BaseRequest {
|
|
17
|
+
|
|
18
|
+
// Permet d'accèder à l'instance complète via spread
|
|
19
|
+
public request: this = this;
|
|
20
|
+
public host!: string;
|
|
21
|
+
|
|
22
|
+
public data: TObjetDonnees = {};
|
|
23
|
+
public abstract response?: Response;
|
|
24
|
+
public user: User | null = null;
|
|
25
|
+
|
|
26
|
+
public constructor(
|
|
27
|
+
public path: string,
|
|
28
|
+
) {
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -6,30 +6,26 @@
|
|
|
6
6
|
import { FunctionalComponent } from "preact";
|
|
7
7
|
|
|
8
8
|
// Core
|
|
9
|
-
import { TRoute } from "
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import PageResponse from './response/page';
|
|
13
|
-
import { ClientContext } from '@client/context';
|
|
9
|
+
import { TRoute } from "..";
|
|
10
|
+
import type ClientRequest from '@client/services/router';
|
|
11
|
+
import Page from '@client/services/router/response/page'
|
|
14
12
|
|
|
15
13
|
/*----------------------------------
|
|
16
14
|
- TYPES
|
|
17
15
|
----------------------------------*/
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
export type TResponseData = PageResponse | unknown
|
|
17
|
+
type TResponseData = Page
|
|
22
18
|
|
|
23
19
|
/*----------------------------------
|
|
24
20
|
- CONTEXT
|
|
25
21
|
----------------------------------*/
|
|
26
22
|
export default abstract class BaseResponse<
|
|
27
|
-
TData extends TResponseData =
|
|
28
|
-
TRequest extends
|
|
23
|
+
TData extends TResponseData = Page,
|
|
24
|
+
TRequest extends ClientRequest = ClientRequest
|
|
29
25
|
> {
|
|
30
26
|
|
|
31
|
-
public data?:
|
|
32
|
-
public request:
|
|
27
|
+
public data?: TData;
|
|
28
|
+
public request: TRequest;
|
|
33
29
|
public route?: TRoute;
|
|
34
30
|
|
|
35
31
|
public constructor(
|
|
@@ -37,7 +33,7 @@ export default abstract class BaseResponse<
|
|
|
37
33
|
) {
|
|
38
34
|
// ServerResponse et ClientResponse assignent request.response
|
|
39
35
|
request.response = this;
|
|
40
|
-
this.request = request as
|
|
36
|
+
this.request = request as TRequest;
|
|
41
37
|
}
|
|
42
38
|
|
|
43
39
|
public setRoute(route: TRoute) {
|
|
@@ -2,19 +2,38 @@
|
|
|
2
2
|
- DEPENDANCES
|
|
3
3
|
----------------------------------*/
|
|
4
4
|
|
|
5
|
-
import type { ComponentChild } from 'preact';
|
|
5
|
+
import type { ComponentChild, FunctionComponent } from 'preact';
|
|
6
6
|
|
|
7
7
|
// Core libs
|
|
8
|
-
import {
|
|
9
|
-
import { TFetcherList } from '@common/router/request';
|
|
10
|
-
import { history } from '@client/router/request/history';
|
|
11
|
-
import { ClientContext } from '@client/context';
|
|
8
|
+
import { ClientOrServerRouter, TClientOrServerContext } from '@common/router';
|
|
9
|
+
import { TFetcherList, TDataReturnedByFetchers } from '@common/router/request/api';
|
|
10
|
+
import { history } from '@client/services/router/request/history';
|
|
12
11
|
|
|
13
12
|
/*----------------------------------
|
|
14
13
|
- TYPES
|
|
15
14
|
----------------------------------*/
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
// 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
|
+
(context: TClientOrServerContext/* & TUrlData */) => TProvidedData
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
// The function that renders routes
|
|
23
|
+
export type TFrontRenderer<
|
|
24
|
+
TProvidedData extends TFetcherList = {},
|
|
25
|
+
TAdditionnalData = {},
|
|
26
|
+
TRouter = ClientOrServerRouter,
|
|
27
|
+
> = FunctionComponent<(
|
|
28
|
+
TClientOrServerContext
|
|
29
|
+
&
|
|
30
|
+
TDataReturnedByFetchers<TProvidedData>
|
|
31
|
+
&
|
|
32
|
+
TAdditionnalData
|
|
33
|
+
)>;
|
|
34
|
+
|
|
35
|
+
// Script or CSS resource
|
|
36
|
+
export type TPageResource = {
|
|
18
37
|
id: string,
|
|
19
38
|
attrs?: TObjetDonnees
|
|
20
39
|
} & ({
|
|
@@ -27,70 +46,35 @@ type TResource = {
|
|
|
27
46
|
/*----------------------------------
|
|
28
47
|
- CLASS
|
|
29
48
|
----------------------------------*/
|
|
30
|
-
export default class PageResponse {
|
|
31
|
-
|
|
32
|
-
// Render
|
|
33
|
-
public id: string;
|
|
34
|
-
public data: TObjetDonnees = {};
|
|
35
|
-
public loading: ComponentChild = false;
|
|
36
|
-
public component: TFrontRenderer;
|
|
49
|
+
export default class PageResponse<TRouter extends ClientOrServerRouter = ClientOrServerRouter> {
|
|
37
50
|
|
|
38
51
|
// Metadata
|
|
52
|
+
public chunkId: string;
|
|
39
53
|
public title?: string;
|
|
40
54
|
public description?: string;
|
|
41
55
|
public bodyClass: Set<string> = new Set<string>();
|
|
42
56
|
public bodyId?: string;
|
|
43
57
|
|
|
44
|
-
//
|
|
58
|
+
// Resources
|
|
45
59
|
public amp?: boolean;
|
|
46
|
-
public scripts:
|
|
47
|
-
public style:
|
|
48
|
-
|
|
49
|
-
// State
|
|
50
|
-
public hash?: string; // Element id to scroll to
|
|
51
|
-
|
|
52
|
-
public constructor(
|
|
53
|
-
public context: ClientContext,
|
|
54
|
-
public route: TClientRoute,
|
|
55
|
-
data: TObjetDonnees = {},
|
|
56
|
-
) {
|
|
57
|
-
this.id = route.options.id; // Binded by the pages babel plugin
|
|
58
|
-
this.bodyId = route.options.bodyId;
|
|
59
|
-
this.component = route.renderer;
|
|
60
|
-
this.data = data;
|
|
61
|
-
this.hash = context.request.hash;
|
|
62
|
-
}
|
|
60
|
+
public scripts: TPageResource[] = [];
|
|
61
|
+
public style: TPageResource[] = [];
|
|
63
62
|
|
|
64
|
-
//
|
|
63
|
+
// Data
|
|
65
64
|
public fetchers: TFetcherList = {};
|
|
65
|
+
public data: TObjetDonnees = {};
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
public constructor(
|
|
68
|
+
public dataProvider: TDataProvider | null,
|
|
69
|
+
public renderer: TFrontRenderer,
|
|
70
|
+
public context: TClientOrServerContext
|
|
71
|
+
) {
|
|
69
72
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
document.body.className = [...this.bodyClass].join(' ');
|
|
73
|
-
|
|
73
|
+
this.chunkId = context.route.options["id"];
|
|
74
|
+
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
|
|
77
77
|
public async fetchData() {
|
|
78
|
-
this.
|
|
79
|
-
this.data = await this.context.request.fetchSync(this.fetchers);
|
|
80
|
-
return this.data;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
public setAllData( callback: (data: {[k: string]: any}) => void) {
|
|
84
|
-
console.warn(`page.setAllData not yet attached to the page Reatc component.`);
|
|
85
|
-
}
|
|
86
|
-
public setData( key: string, value: ((value: any) => void) | any ) {
|
|
87
|
-
this.setAllData(old => ({
|
|
88
|
-
...old,
|
|
89
|
-
[key]: typeof value === 'function' ? value(old[key]) : value
|
|
90
|
-
}));
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
public go( url: string ) {
|
|
94
|
-
history?.replace(url);
|
|
78
|
+
return await this.context.request.api.fetchSync( this.fetchers );
|
|
95
79
|
}
|
|
96
80
|
}
|