@proteinjs/server 1.1.2 → 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 +11 -5
  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
@@ -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
+ }
@@ -18,173 +18,205 @@ const staticContentPath = '/static/';
18
18
  const logger = new Logger('Server');
19
19
 
20
20
  export async function startServer(config: ServerConfig) {
21
- const routes = getRoutes();
22
- await runStartupEvents(config);
23
- const server = express();
24
- configureRequests(server);
25
- initializeHotReloading(server, config);
26
- beforeRequest(server, config);
27
- loadRoutes(routes.filter(route => route.useHttp), server, config);
28
- configureHttps(server); // registering here forces static content to be redirected to https
29
- configureStaticContentRouter(server, config); // registering here prevents sessions from being created on static content requests
30
- configureSession(server, config);
31
- loadRoutes(routes.filter(route => !route.useHttp), server, config);
32
- loadDefaultStarRoute(routes, server, config);
33
- afterRequest(server, config);
34
- start(server, config);
21
+ const routes = getRoutes();
22
+ await runStartupEvents(config);
23
+ const server = express();
24
+ configureRequests(server);
25
+ initializeHotReloading(server, config);
26
+ beforeRequest(server, config);
27
+ loadRoutes(
28
+ routes.filter((route) => route.useHttp),
29
+ server,
30
+ config
31
+ );
32
+ configureHttps(server); // registering here forces static content to be redirected to https
33
+ configureStaticContentRouter(server, config); // registering here prevents sessions from being created on static content requests
34
+ configureSession(server, config);
35
+ loadRoutes(
36
+ routes.filter((route) => !route.useHttp),
37
+ server,
38
+ config
39
+ );
40
+ loadDefaultStarRoute(routes, server, config);
41
+ afterRequest(server, config);
42
+ start(server, config);
35
43
  }
36
44
 
37
45
  async function runStartupEvents(config: ServerConfig) {
38
- await new Db().init();
46
+ await new Db().init();
39
47
 
40
- if (config.onStartup)
41
- await config.onStartup();
48
+ if (config.onStartup) {
49
+ await config.onStartup();
50
+ }
42
51
  }
43
52
 
44
53
  function configureRequests(server: express.Express) {
45
- server.use(compression());
46
- server.use(cookieParser());
47
- server.use(bodyParser.json({ limit: '100mb' }));
48
- server.use(bodyParser.urlencoded({
49
- extended: true,
50
- limit: '100mb'
51
- }));
52
- server.disable('x-powered-by');
54
+ server.use(compression());
55
+ server.use(cookieParser());
56
+ server.use(bodyParser.json({ limit: '100mb' }));
57
+ server.use(
58
+ bodyParser.urlencoded({
59
+ extended: true,
60
+ limit: '100mb',
61
+ })
62
+ );
63
+ server.disable('x-powered-by');
53
64
  }
54
65
 
55
66
  function initializeHotReloading(server: express.Express, config: ServerConfig) {
56
- if (!process.env.DEVELOPMENT || process.env.DISABLE_HOT_CLIENT_BUILDS || !config.hotClientBuilds || !config.staticContent?.staticContentDir || !config.staticContent?.appEntryPath)
57
- return;
58
-
59
- let wpConfig = Object.assign({}, getWebpackConfig(config));
60
- wpConfig['entry'] = { app: ['webpack-hot-middleware/client', config.staticContent.appEntryPath] };
61
- wpConfig['output']['path'] = config.staticContent.staticContentDir;
62
- wpConfig['output']['publicPath'] = staticContentPath;
63
- const webpackCompiler = webpack(wpConfig);
64
- server.use(webpackDevMiddleware(webpackCompiler, {
65
- publicPath: staticContentPath,
66
- }));
67
- server.use(webpackHotMiddleware(webpackCompiler));
67
+ if (
68
+ !process.env.DEVELOPMENT ||
69
+ process.env.DISABLE_HOT_CLIENT_BUILDS ||
70
+ !config.hotClientBuilds ||
71
+ !config.staticContent?.staticContentDir ||
72
+ !config.staticContent?.appEntryPath
73
+ ) {
74
+ return;
75
+ }
76
+
77
+ const wpConfig = Object.assign({}, getWebpackConfig(config));
78
+ wpConfig['entry'] = { app: ['webpack-hot-middleware/client', config.staticContent.appEntryPath] };
79
+ wpConfig['output']['path'] = config.staticContent.staticContentDir;
80
+ wpConfig['output']['publicPath'] = staticContentPath;
81
+ const webpackCompiler = webpack(wpConfig);
82
+ server.use(
83
+ webpackDevMiddleware(webpackCompiler, {
84
+ publicPath: staticContentPath,
85
+ })
86
+ );
87
+ server.use(webpackHotMiddleware(webpackCompiler));
68
88
  }
69
89
 
70
90
  function getWebpackConfig(config: ServerConfig) {
71
- setNodeModulesPath(config.hotClientBuilds?.nodeModulesPath as string);
72
- const webpackConfig = require('../webpack.config');
73
- return webpackConfig;
91
+ setNodeModulesPath(config.hotClientBuilds?.nodeModulesPath as string);
92
+ const webpackConfig = require('../webpack.config');
93
+ return webpackConfig;
74
94
  }
75
95
 
76
96
  function configureHttps(server: express.Express) {
77
- server.use((request: express.Request, response: express.Response, next: express.NextFunction) => {
78
- if (request.protocol == 'https' || response.headersSent || process.env.DEVELOPMENT) {
79
- next();
80
- return;
81
- }
97
+ server.use((request: express.Request, response: express.Response, next: express.NextFunction) => {
98
+ if (request.protocol == 'https' || response.headersSent || process.env.DEVELOPMENT) {
99
+ next();
100
+ return;
101
+ }
82
102
 
83
- logger.debug(`Redirecting to https: ${request.headers.host + request.url}`);
84
- response.redirect('https://' + request.headers.host + request.url);
85
- });
103
+ logger.debug(`Redirecting to https: ${request.headers.host + request.url}`);
104
+ response.redirect('https://' + request.headers.host + request.url);
105
+ });
86
106
  }
87
107
 
88
108
  function configureStaticContentRouter(server: express.Express, config: ServerConfig) {
89
- if (!config.staticContent?.staticContentDir)
90
- return;
91
-
92
- server.use(staticContentPath, express.static(config.staticContent.staticContentDir));
93
- logger.info(`Serving static content on path: ${staticContentPath}, serving from directory: ${config.staticContent.staticContentDir}`);
109
+ if (!config.staticContent?.staticContentDir) {
110
+ return;
111
+ }
112
+
113
+ server.use(staticContentPath, express.static(config.staticContent.staticContentDir));
114
+ logger.info(
115
+ `Serving static content on path: ${staticContentPath}, serving from directory: ${config.staticContent.staticContentDir}`
116
+ );
94
117
  }
95
118
 
96
119
  function configureSession(server: express.Express, config: ServerConfig) {
97
- const sixtyDays = 1000 * 60 * 60 * 24 * 60;
98
- let sessionOptions: expressSession.SessionOptions = {
99
- secret: config.session.secret,
100
- store: config.session.store,
101
- resave: false,
102
- saveUninitialized: false,
103
- cookie: {
104
- maxAge: sixtyDays
105
- },
106
- rolling: true
107
- };
108
-
109
- if (!process.env.DEVELOPMENT) {
110
- server.set('trust proxy', 1);
111
- if (!sessionOptions.cookie)
112
- sessionOptions.cookie = {};
113
- sessionOptions.cookie.secure = true;
120
+ const sixtyDays = 1000 * 60 * 60 * 24 * 60;
121
+ let sessionOptions: expressSession.SessionOptions = {
122
+ secret: config.session.secret,
123
+ store: config.session.store,
124
+ resave: false,
125
+ saveUninitialized: false,
126
+ cookie: {
127
+ maxAge: sixtyDays,
128
+ },
129
+ rolling: true,
130
+ };
131
+
132
+ if (!process.env.DEVELOPMENT) {
133
+ server.set('trust proxy', 1);
134
+ if (!sessionOptions.cookie) {
135
+ sessionOptions.cookie = {};
114
136
  }
115
-
116
- if (config.session)
117
- sessionOptions = Object.assign(sessionOptions, config.session);
118
-
119
- server.use(expressSession(sessionOptions));
120
- server.use(passport.initialize());
121
- server.use(passport.session());
122
- if (config.authenticate)
123
- initializeAuthentication(config.authenticate);
137
+ sessionOptions.cookie.secure = true;
138
+ }
139
+
140
+ if (config.session) {
141
+ sessionOptions = Object.assign(sessionOptions, config.session);
142
+ }
143
+
144
+ server.use(expressSession(sessionOptions));
145
+ server.use(passport.initialize());
146
+ server.use(passport.session());
147
+ if (config.authenticate) {
148
+ initializeAuthentication(config.authenticate);
149
+ }
124
150
  }
125
151
 
126
152
  function initializeAuthentication(authenticate: (username: string, password: string) => Promise<true | string>) {
127
- passport.use(new passportLocal.Strategy(async function (username, password, done) {
128
- logger.info(`Authenticating`);
129
- const result = await authenticate(username, password);
130
- if (result === true)
131
- return done(null, { username });
132
-
133
- return done(new Error(result));
134
- }));
153
+ passport.use(
154
+ new passportLocal.Strategy(async function (username, password, done) {
155
+ logger.info(`Authenticating`);
156
+ const result = await authenticate(username, password);
157
+ if (result === true) {
158
+ return done(null, { username });
159
+ }
160
+
161
+ return done(new Error(result));
162
+ })
163
+ );
164
+
165
+ passport.serializeUser(function (user, done) {
166
+ done(null, user);
167
+ });
168
+
169
+ passport.deserializeUser(function (id, done) {
170
+ done(null, id);
171
+ });
172
+ }
135
173
 
136
- passport.serializeUser(function (user, done) {
137
- done(null, user);
138
- });
174
+ function beforeRequest(server: express.Express, config: ServerConfig) {
175
+ let requestCounter: number = 0;
176
+ if (config.request?.disableRequestLogging == false || typeof config.request?.disableRequestLogging === 'undefined') {
177
+ server.use((request: express.Request, response: express.Response, next: express.NextFunction) => {
178
+ if (request.path.startsWith('/static') || request.path.startsWith('/favicon.ico')) {
179
+ next();
180
+ return;
181
+ }
139
182
 
140
- passport.deserializeUser(function (id, done) {
141
- done(null, id);
183
+ const requestNumber = ++requestCounter;
184
+ logger.info(`[#${requestNumber}] Started ${request.originalUrl}`);
185
+ response.locals = { requestNumber };
186
+ next();
142
187
  });
143
- }
188
+ }
144
189
 
145
- function beforeRequest(server: express.Express, config: ServerConfig) {
146
- let requestCounter: number = 0;
147
- if (config.request?.disableRequestLogging == false || typeof config.request?.disableRequestLogging === 'undefined') {
148
- server.use((request: express.Request, response: express.Response, next: express.NextFunction) => {
149
- if (request.path.startsWith('/static') || request.path.startsWith('/favicon.ico')) {
150
- next();
151
- return;
152
- }
153
-
154
- const requestNumber = ++requestCounter;
155
- logger.info(`[#${requestNumber}] Started ${request.originalUrl}`);
156
- response.locals = { requestNumber };
157
- next();
158
- });
159
- }
160
-
161
- if (config.request?.beforeRequest)
162
- server.use(config.request.beforeRequest);
190
+ if (config.request?.beforeRequest) {
191
+ server.use(config.request.beforeRequest);
192
+ }
163
193
  }
164
194
 
165
195
  function afterRequest(server: express.Express, config: ServerConfig) {
166
- if (config.request?.afterRequest)
167
- server.use(config.request.afterRequest);
168
-
169
- if (config.request?.disableRequestLogging == false || typeof config.request?.disableRequestLogging === 'undefined') {
170
- server.use((request: express.Request, response: express.Response, next: express.NextFunction) => {
171
- if (request.path.startsWith('/static') || request.path.startsWith('/favicon.ico')) {
172
- next();
173
- return;
174
- }
175
-
176
- logger.info(`[#${response.locals.requestNumber}] Finished ${request.originalUrl}`);
177
- next();
178
- });
179
- }
196
+ if (config.request?.afterRequest) {
197
+ server.use(config.request.afterRequest);
198
+ }
199
+
200
+ if (config.request?.disableRequestLogging == false || typeof config.request?.disableRequestLogging === 'undefined') {
201
+ server.use((request: express.Request, response: express.Response, next: express.NextFunction) => {
202
+ if (request.path.startsWith('/static') || request.path.startsWith('/favicon.ico')) {
203
+ next();
204
+ return;
205
+ }
206
+
207
+ logger.info(`[#${response.locals.requestNumber}] Finished ${request.originalUrl}`);
208
+ next();
209
+ });
210
+ }
180
211
  }
181
212
 
182
213
  function start(server: express.Express, config: ServerConfig) {
183
- const port = config.port ? config.port : 3000;
184
- server.listen(port, () => {
185
- if (process.env.DEVELOPMENT)
186
- logger.info(`Starting in development mode`);
214
+ const port = config.port ? config.port : 3000;
215
+ server.listen(port, () => {
216
+ if (process.env.DEVELOPMENT) {
217
+ logger.info(`Starting in development mode`);
218
+ }
187
219
 
188
- logger.info(`Server listening on port: ${port}`);
189
- });
190
- }
220
+ logger.info(`Server listening on port: ${port}`);
221
+ });
222
+ }
package/tsconfig.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
- "compilerOptions": {
3
- "rootDir": "./",
4
- "target": "es5",
5
- "module": "commonjs",
6
- "declaration": true,
7
- "declarationMap": true,
8
- "sourceMap": true,
9
- "outDir": "./dist/",
10
- "strict": true,
11
- "noImplicitAny": true,
12
- "esModuleInterop": true,
13
- "skipLibCheck": true,
14
- "forceConsistentCasingInFileNames": true,
15
- "resolveJsonModule": true,
16
- "allowJs": true
17
- }
18
- }
2
+ "compilerOptions": {
3
+ "rootDir": "./",
4
+ "target": "es5",
5
+ "module": "commonjs",
6
+ "declaration": true,
7
+ "declarationMap": true,
8
+ "sourceMap": true,
9
+ "outDir": "./dist/",
10
+ "strict": true,
11
+ "noImplicitAny": true,
12
+ "esModuleInterop": true,
13
+ "skipLibCheck": true,
14
+ "forceConsistentCasingInFileNames": true,
15
+ "resolveJsonModule": true,
16
+ "allowJs": true
17
+ }
18
+ }
package/webpack.config.js CHANGED
@@ -13,8 +13,8 @@ const { nodeModulesPath } = require('./src/nodeModulesPath');
13
13
  const webpack5esmInteropRule = {
14
14
  test: /\.m?js/,
15
15
  resolve: {
16
- fullySpecified: false
17
- }
16
+ fullySpecified: false,
17
+ },
18
18
  };
19
19
 
20
20
  module.exports = {
@@ -28,26 +28,26 @@ module.exports = {
28
28
  filename: '[name].js',
29
29
  // path and publicPath provided in startServer.initializeHotReloading
30
30
  // path: path.join(__dirname, 'dist'),
31
- library: '[name]'
31
+ library: '[name]',
32
32
  },
33
33
  resolve: {
34
34
  extensions: ['.tsx', '.ts', '.js', '.json'],
35
35
  alias: {
36
- 'react': path.join(nodeModulesPath, 'react'),
37
- 'process': 'process/browser',
36
+ react: path.join(nodeModulesPath, 'react'),
37
+ process: 'process/browser',
38
38
  '@mui/joy': path.join(nodeModulesPath, '@mui/joy'),
39
39
  '@mui/material': path.join(nodeModulesPath, '@mui/material'),
40
40
  '@mui/icons-material': path.join(nodeModulesPath, '@mui/icons-material'),
41
41
  'webpack-hot-middleware': path.join(nodeModulesPath, 'webpack-hot-middleware'),
42
42
  },
43
43
  // provide shims for node libraries for webpack >= 5
44
- fallback: {
45
- 'crypto': require.resolve('crypto-browserify'),
46
- 'util': require.resolve('util/'),
47
- 'events': require.resolve('events/'),
48
- 'url': require.resolve('url/'),
49
- 'buffer': require.resolve('buffer/'),
50
- 'stream': require.resolve('stream-browserify'),
44
+ fallback: {
45
+ crypto: require.resolve('crypto-browserify'),
46
+ util: require.resolve('util/'),
47
+ events: require.resolve('events/'),
48
+ url: require.resolve('url/'),
49
+ buffer: require.resolve('buffer/'),
50
+ stream: require.resolve('stream-browserify'),
51
51
  'process/browser': require.resolve('process/browser'),
52
52
  },
53
53
  },
@@ -95,20 +95,20 @@ module.exports = {
95
95
  splitChunks: {
96
96
  cacheGroups: {
97
97
  vendor: {
98
- test: /[\\/]node_modules[\\/]/, // Matches node_modules folder
98
+ test: /[\\/]node_modules[\\/]/, // Matches node_modules folder
99
99
  name: 'vendor',
100
100
  chunks: 'all',
101
- priority: -10
102
- }
103
- }
104
- }
101
+ priority: -10,
102
+ },
103
+ },
104
+ },
105
105
  },
106
106
  plugins: [
107
107
  new webpack.ProvidePlugin({
108
- process: 'process/browser',
109
- Buffer: ['buffer', 'Buffer'],
108
+ process: 'process/browser',
109
+ Buffer: ['buffer', 'Buffer'],
110
110
  }),
111
111
  new webpack.HotModuleReplacementPlugin(),
112
112
  new ReactRefreshWebpackPlugin(),
113
113
  ],
114
- };
114
+ };