@proteinjs/server 1.1.1 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/.eslintrc.js +20 -0
  2. package/.prettierignore +3 -0
  3. package/.prettierrc +8 -0
  4. package/CHANGELOG.md +11 -44
  5. package/LICENSE +21 -0
  6. package/dist/generated/index.js +1 -1
  7. package/dist/generated/index.js.map +1 -1
  8. package/dist/jest.config.d.ts +1 -1
  9. package/dist/jest.config.js +6 -15
  10. package/dist/jest.config.js.map +1 -1
  11. package/dist/src/NodeSessionDataStorage.d.ts.map +1 -1
  12. package/dist/src/NodeSessionDataStorage.js +13 -7
  13. package/dist/src/NodeSessionDataStorage.js.map +1 -1
  14. package/dist/src/loadRoutes.d.ts.map +1 -1
  15. package/dist/src/loadRoutes.js +14 -7
  16. package/dist/src/loadRoutes.js.map +1 -1
  17. package/dist/src/routes/healthCheck.d.ts.map +1 -1
  18. package/dist/src/routes/healthCheck.js +1 -1
  19. package/dist/src/routes/healthCheck.js.map +1 -1
  20. package/dist/src/routes/reactApp.d.ts.map +1 -1
  21. package/dist/src/routes/reactApp.js +7 -4
  22. package/dist/src/routes/reactApp.js.map +1 -1
  23. package/dist/src/startServer.d.ts.map +1 -1
  24. package/dist/src/startServer.js +25 -12
  25. package/dist/src/startServer.js.map +1 -1
  26. package/dist/webpack.config.js +15 -15
  27. package/dist/webpack.config.js.map +1 -1
  28. package/generated/index.ts +5 -8
  29. package/index.ts +1 -1
  30. package/jest.config.js +8 -17
  31. package/package.json +76 -70
  32. package/src/NodeSessionDataStorage.ts +35 -29
  33. package/src/loadRoutes.ts +124 -103
  34. package/src/nodeModulesPath.ts +1 -1
  35. package/src/routes/healthCheck.ts +7 -7
  36. package/src/routes/reactApp.ts +43 -36
  37. package/src/startServer.ts +164 -132
  38. package/tsconfig.json +17 -17
  39. package/webpack.config.js +20 -20
package/src/loadRoutes.ts CHANGED
@@ -1,126 +1,147 @@
1
1
  import express from 'express';
2
2
  import passport from 'passport';
3
- import { ServerConfig, Route, getRequestListeners, Session, SessionData, getSessionDataCaches } from '@proteinjs/server-api';
3
+ import {
4
+ ServerConfig,
5
+ Route,
6
+ getRequestListeners,
7
+ Session,
8
+ SessionData,
9
+ getSessionDataCaches,
10
+ } from '@proteinjs/server-api';
4
11
  import { createReactApp } from './routes/reactApp';
5
12
  import { Logger } from '@proteinjs/util';
6
13
 
7
14
  const logger = new Logger('Server');
8
15
 
9
16
  export function loadRoutes(routes: Route[], server: express.Express, config: ServerConfig) {
10
- let starRoute: Route|null = null;
11
- const wildcardRoutes: Route[] = [];
12
- for (const route of routes) {
13
- logger.info(`Loading route: ${route.path}`);
14
- if (route.path == '*') {
15
- starRoute = route;
16
- continue;
17
- }
18
-
19
- if (route.path.includes('*')) {
20
- wildcardRoutes.push(route);
21
- continue;
22
- }
23
-
24
- server[route.method](getPath(route.path), wrapRoute(route.onRequest.bind(route), config));
17
+ let starRoute: Route | null = null;
18
+ const wildcardRoutes: Route[] = [];
19
+ for (const route of routes) {
20
+ logger.info(`Loading route: ${route.path}`);
21
+ if (route.path == '*') {
22
+ starRoute = route;
23
+ continue;
25
24
  }
26
25
 
27
- for (const wildcardRoute of wildcardRoutes)
28
- server[wildcardRoute.method](getPath(wildcardRoute.path), wrapRoute(wildcardRoute.onRequest.bind(wildcardRoute), config));
26
+ if (route.path.includes('*')) {
27
+ wildcardRoutes.push(route);
28
+ continue;
29
+ }
30
+
31
+ server[route.method](getPath(route.path), wrapRoute(route.onRequest.bind(route), config));
32
+ }
33
+
34
+ for (const wildcardRoute of wildcardRoutes) {
35
+ server[wildcardRoute.method](
36
+ getPath(wildcardRoute.path),
37
+ wrapRoute(wildcardRoute.onRequest.bind(wildcardRoute), config)
38
+ );
39
+ }
29
40
 
30
- if (starRoute)
31
- server[starRoute.method](starRoute.path, wrapRoute(starRoute.onRequest.bind(starRoute), config));
41
+ if (starRoute) {
42
+ server[starRoute.method](starRoute.path, wrapRoute(starRoute.onRequest.bind(starRoute), config));
43
+ }
32
44
  }
33
45
 
34
46
  export function loadDefaultStarRoute(routes: Route[], server: express.Express, config: ServerConfig) {
35
- let starRouteSpecified = false;
36
- for (const route of routes) {
37
- if (route.path == '*') {
38
- starRouteSpecified = true;
39
- break;
40
- }
41
- }
42
-
43
- if (!starRouteSpecified && (config.staticContent?.bundlePaths || config.staticContent?.bundlesDir)) {
44
- const reactApp = createReactApp(config);
45
- server[reactApp.method](reactApp.path, wrapRoute(reactApp.onRequest, config));
47
+ let starRouteSpecified = false;
48
+ for (const route of routes) {
49
+ if (route.path == '*') {
50
+ starRouteSpecified = true;
51
+ break;
46
52
  }
53
+ }
54
+
55
+ if (!starRouteSpecified && (config.staticContent?.bundlePaths || config.staticContent?.bundlesDir)) {
56
+ const reactApp = createReactApp(config);
57
+ server[reactApp.method](reactApp.path, wrapRoute(reactApp.onRequest, config));
58
+ }
47
59
  }
48
60
 
49
61
  function getPath(path: string) {
50
- return path.startsWith('/') ? path : `/${path}`;
62
+ return path.startsWith('/') ? path : `/${path}`;
51
63
  }
52
64
 
53
- function wrapRoute(route: (request: express.Request, response: express.Response) => Promise<void>, config: ServerConfig) {
54
- return async function (request: express.Request, response: express.Response, next: express.NextFunction) {
55
- if (response.locals['responseHandled']) {
56
- next();
57
- return;
58
- }
59
-
60
- if (config.authenticate) {
61
- await new Promise<void>((resolve, reject) => {
62
- passport.authenticate('local', function (err, user, info) {
63
- if (err)
64
- reject(err);
65
-
66
- resolve();
67
- })(request, response, next);
68
- });
69
- }
70
-
71
- const sessionData: SessionData = { sessionId: request.sessionID, user: request.user as string, data: {} };
72
- for (const sessionDataCache of getSessionDataCaches())
73
- sessionData.data[sessionDataCache.key] = await sessionDataCache.create(sessionData.sessionId, sessionData.user);
74
- Session.setData(sessionData);
75
-
76
- const requestListeners = getRequestListeners();
77
- for (const listener of requestListeners) {
78
- if (!listener.beforeRequest)
79
- continue;
80
-
81
- try {
82
- await listener.beforeRequest(request, response);
83
- } catch (error: any) {
84
- logger.error(`Caught error when running listener before request`, error);
85
- }
86
- }
87
-
88
- const sixtyMinutes = 1000 * 60 * 60;
89
- const timeout = typeof config.request?.timeoutMs !== 'undefined' ? config.request.timeoutMs : sixtyMinutes;
90
- request.setTimeout(timeout, () => {
91
- if (response.locals.requestNumber)
92
- logger.warn(`[#${response.locals.requestNumber}] Timed out ${request.originalUrl}`);
93
- else
94
- logger.warn(`Timed out ${request.originalUrl}`);
95
- });
96
-
97
- try {
98
- await route(request, response);
99
- } catch(error) {
100
- console.error(error);
101
- }
102
- response.locals['responseHandled'] = true;
103
-
104
- for (const listener of requestListeners) {
105
- if (!listener.afterRequest)
106
- continue;
107
-
108
- try {
109
- await listener.afterRequest(request, response);
110
- } catch (error: any) {
111
- logger.error(`Caught error when running listener after request`, error);
112
- }
113
- }
114
-
115
- next();
116
- };
65
+ function wrapRoute(
66
+ route: (request: express.Request, response: express.Response) => Promise<void>,
67
+ config: ServerConfig
68
+ ) {
69
+ return async function (request: express.Request, response: express.Response, next: express.NextFunction) {
70
+ if (response.locals['responseHandled']) {
71
+ next();
72
+ return;
73
+ }
74
+
75
+ if (config.authenticate) {
76
+ await new Promise<void>((resolve, reject) => {
77
+ passport.authenticate('local', function (err, user, info) {
78
+ if (err) {
79
+ reject(err);
80
+ }
81
+
82
+ resolve();
83
+ })(request, response, next);
84
+ });
85
+ }
86
+
87
+ const sessionData: SessionData = { sessionId: request.sessionID, user: request.user as string, data: {} };
88
+ for (const sessionDataCache of getSessionDataCaches()) {
89
+ sessionData.data[sessionDataCache.key] = await sessionDataCache.create(sessionData.sessionId, sessionData.user);
90
+ }
91
+ Session.setData(sessionData);
92
+
93
+ const requestListeners = getRequestListeners();
94
+ for (const listener of requestListeners) {
95
+ if (!listener.beforeRequest) {
96
+ continue;
97
+ }
98
+
99
+ try {
100
+ await listener.beforeRequest(request, response);
101
+ } catch (error: any) {
102
+ logger.error(`Caught error when running listener before request`, error);
103
+ }
104
+ }
105
+
106
+ const sixtyMinutes = 1000 * 60 * 60;
107
+ const timeout = typeof config.request?.timeoutMs !== 'undefined' ? config.request.timeoutMs : sixtyMinutes;
108
+ request.setTimeout(timeout, () => {
109
+ if (response.locals.requestNumber) {
110
+ logger.warn(`[#${response.locals.requestNumber}] Timed out ${request.originalUrl}`);
111
+ } else {
112
+ logger.warn(`Timed out ${request.originalUrl}`);
113
+ }
114
+ });
115
+
116
+ try {
117
+ await route(request, response);
118
+ } catch (error) {
119
+ console.error(error);
120
+ }
121
+ response.locals['responseHandled'] = true;
122
+
123
+ for (const listener of requestListeners) {
124
+ if (!listener.afterRequest) {
125
+ continue;
126
+ }
127
+
128
+ try {
129
+ await listener.afterRequest(request, response);
130
+ } catch (error: any) {
131
+ logger.error(`Caught error when running listener after request`, error);
132
+ }
133
+ }
134
+
135
+ next();
136
+ };
117
137
  }
118
138
 
119
- function basicAuthCredentials(request: express.Request): { username: string, password: string } | null {
120
- const b64auth = (request.headers.authorization || '').split(' ')[1] || '';
121
- const [username, password] = Buffer.from(b64auth, 'base64').toString().split(':');
122
- if (!username || !password)
123
- return null;
139
+ function basicAuthCredentials(request: express.Request): { username: string; password: string } | null {
140
+ const b64auth = (request.headers.authorization || '').split(' ')[1] || '';
141
+ const [username, password] = Buffer.from(b64auth, 'base64').toString().split(':');
142
+ if (!username || !password) {
143
+ return null;
144
+ }
124
145
 
125
- return { username, password };
126
- }
146
+ return { username, password };
147
+ }
@@ -2,4 +2,4 @@ export let nodeModulesPath: string;
2
2
 
3
3
  export function setNodeModulesPath(path: string) {
4
4
  nodeModulesPath = path;
5
- }
5
+ }
@@ -1,10 +1,10 @@
1
1
  import { Route } from '@proteinjs/server-api';
2
2
 
3
3
  export const healthCheck: Route = {
4
- path: 'health-check',
5
- method: 'get',
6
- useHttp: true,
7
- onRequest: async (request, response): Promise<void> => {
8
- response.send();
9
- }
10
- }
4
+ path: 'health-check',
5
+ method: 'get',
6
+ useHttp: true,
7
+ onRequest: async (request, response): Promise<void> => {
8
+ response.send();
9
+ },
10
+ };
@@ -4,18 +4,20 @@ import { ServerConfig, getServerRenderedScripts } from '@proteinjs/server-api';
4
4
  import { Fs } from '@proteinjs/util-node';
5
5
 
6
6
  export const createReactApp = (serverConfig: ServerConfig) => {
7
- return {
8
- path: '*',
9
- method: 'get' as 'get',
10
- onRequest: async (request: any, response: any): Promise<void> => {
11
- if (request.path.startsWith('/static'))
12
- return;
7
+ return {
8
+ path: '*',
9
+ method: 'get' as 'get',
10
+ onRequest: async (request: any, response: any): Promise<void> => {
11
+ if (request.path.startsWith('/static')) {
12
+ return;
13
+ }
13
14
 
14
- if (!(serverConfig.staticContent?.bundlePaths || serverConfig.staticContent?.bundlesDir))
15
- throw new Error(`ServerConfig.bundlePath or ServerConfig.bundlesDir must be provided to serve a react app`);
15
+ if (!(serverConfig.staticContent?.bundlePaths || serverConfig.staticContent?.bundlesDir)) {
16
+ throw new Error(`ServerConfig.bundlePath or ServerConfig.bundlesDir must be provided to serve a react app`);
17
+ }
16
18
 
17
- const helmet = ReactHelmet.renderStatic();
18
- response.send(`<!DOCTYPE html>
19
+ const helmet = ReactHelmet.renderStatic();
20
+ response.send(`<!DOCTYPE html>
19
21
  <html ${helmet.htmlAttributes}>
20
22
  <head>
21
23
  <meta charset='utf-8' />
@@ -31,37 +33,42 @@ export const createReactApp = (serverConfig: ServerConfig) => {
31
33
  ${await serverRenderedScriptTags()}
32
34
  ${await bundleScriptTags(serverConfig)}
33
35
  </body>
34
- </html>`
35
- );
36
- }
37
- }
38
- }
36
+ </html>`);
37
+ },
38
+ };
39
+ };
39
40
 
40
41
  async function bundleScriptTags(serverConfig: ServerConfig) {
41
- if (!(serverConfig.staticContent?.bundlePaths || serverConfig.staticContent?.bundlesDir))
42
- return;
42
+ if (!(serverConfig.staticContent?.bundlePaths || serverConfig.staticContent?.bundlesDir)) {
43
+ return;
44
+ }
43
45
 
44
- const scriptTags: string[] = [];
45
- if (serverConfig.staticContent?.bundlePaths) {
46
- for (const bundlePath of serverConfig.staticContent.bundlePaths)
47
- scriptTags.push(`<script src='${path.join('/static/', bundlePath)}'></script>`);
48
- } else if (serverConfig.staticContent?.bundlesDir && serverConfig.staticContent?.staticContentDir) {
49
- const resolvedBundlesDir = path.join(serverConfig.staticContent.staticContentDir, serverConfig.staticContent.bundlesDir);
50
- const filePaths = await Fs.getFilePathsMatchingGlob(resolvedBundlesDir, '**/*.js');
51
- for (const filePath of filePaths) {
52
- const relativePath = path.relative(serverConfig.staticContent.staticContentDir, filePath);
53
- scriptTags.push(`<script src='${path.join('/static/', relativePath)}'></script>`);
54
- }
55
- }
46
+ const scriptTags: string[] = [];
47
+ if (serverConfig.staticContent?.bundlePaths) {
48
+ for (const bundlePath of serverConfig.staticContent.bundlePaths) {
49
+ scriptTags.push(`<script src='${path.join('/static/', bundlePath)}'></script>`);
50
+ }
51
+ } else if (serverConfig.staticContent?.bundlesDir && serverConfig.staticContent?.staticContentDir) {
52
+ const resolvedBundlesDir = path.join(
53
+ serverConfig.staticContent.staticContentDir,
54
+ serverConfig.staticContent.bundlesDir
55
+ );
56
+ const filePaths = await Fs.getFilePathsMatchingGlob(resolvedBundlesDir, '**/*.js');
57
+ for (const filePath of filePaths) {
58
+ const relativePath = path.relative(serverConfig.staticContent.staticContentDir, filePath);
59
+ scriptTags.push(`<script src='${path.join('/static/', relativePath)}'></script>`);
60
+ }
61
+ }
56
62
 
57
- return scriptTags.join('\n');
63
+ return scriptTags.join('\n');
58
64
  }
59
65
 
60
66
  async function serverRenderedScriptTags() {
61
- const scripts = getServerRenderedScripts();
62
- const scriptTags: string[] = [];
63
- for (const script of scripts)
64
- scriptTags.push(`<script>${await script.script()}</script>`);
67
+ const scripts = getServerRenderedScripts();
68
+ const scriptTags: string[] = [];
69
+ for (const script of scripts) {
70
+ scriptTags.push(`<script>${await script.script()}</script>`);
71
+ }
65
72
 
66
- return scriptTags.join('\n');
67
- }
73
+ return scriptTags.join('\n');
74
+ }