@rpcbase/server 0.442.0 → 0.444.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/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import session from "express-session";
2
2
  import { RedisStore } from "connect-redis";
3
+ import MongoStore from "connect-mongo";
3
4
  import { createClient } from "redis";
4
5
  import env from "@rpcbase/env";
5
6
  import { initApiClient, SsrErrorFallback, SSR_ERROR_STATE_GLOBAL_KEY, serializeSsrErrorState } from "@rpcbase/client";
@@ -218,26 +219,32 @@ process.env = {
218
219
  ...process.env
219
220
  };
220
221
  const isProduction$1 = process.env.NODE_ENV === "production";
221
- const initServer = async (app, serverEnv) => {
222
- await initApiClient({ app });
223
- app.disable("x-powered-by");
224
- app.set("trust proxy", true);
225
- app.use(requestIp.mw());
226
- app.use((req, res, next) => {
227
- if (req.headers.host?.startsWith("www.")) {
228
- const newHost = req.headers.host.replace("www.", "");
229
- return res.redirect(301, `${req.protocol}://${newHost}${req.originalUrl}`);
230
- }
231
- next();
232
- });
233
- metricsIngestProxyMiddleware(app);
234
- if (!serverEnv.REDIS_URL) {
235
- console.log("WARNING", "missing REDIS_URL, will skip session storage middleware");
236
- return;
237
- } else {
238
- console.log("REDIS_URL:", serverEnv.REDIS_URL);
222
+ const SESSION_MAX_AGE_S = 3600 * 24 * 60;
223
+ const getMongoUrl = (serverEnv) => {
224
+ const explicitUrl = serverEnv.MONGODB_URL || serverEnv.MONGO_URL || serverEnv.MONGODB_URI || serverEnv.DB_URL;
225
+ if (explicitUrl) {
226
+ return explicitUrl;
239
227
  }
240
- const sessionSecret = getDerivedKey(serverEnv.MASTER_KEY, "express_session_key");
228
+ if (serverEnv.DB_PORT) {
229
+ const host = serverEnv.DB_HOST ?? "localhost";
230
+ const dbName = serverEnv.APP_NAME ?? "rb";
231
+ return `mongodb://${host}:${serverEnv.DB_PORT}/${dbName}-sessions`;
232
+ }
233
+ return void 0;
234
+ };
235
+ const createMongoSessionStore = (serverEnv) => {
236
+ const mongoUrl = getMongoUrl(serverEnv);
237
+ if (!mongoUrl) {
238
+ throw new Error("Missing REDIS_URL and Mongo connection details (MONGODB_URL/MONGO_URL/MONGODB_URI/DB_PORT)");
239
+ }
240
+ console.log("Using MongoDB session store");
241
+ return MongoStore.create({
242
+ mongoUrl,
243
+ collectionName: "sessions",
244
+ ttl: SESSION_MAX_AGE_S
245
+ });
246
+ };
247
+ const createRedisSessionStore = async (redisUrl) => {
241
248
  const reconnectStrategy = (retries) => {
242
249
  console.log("redis_client::rb/server reconnectStrategy::retrying with arg", retries);
243
250
  if (retries < 5) {
@@ -248,7 +255,7 @@ const initServer = async (app, serverEnv) => {
248
255
  }
249
256
  };
250
257
  const redisClient = createClient({
251
- url: serverEnv.REDIS_URL,
258
+ url: redisUrl,
252
259
  socket: {
253
260
  reconnectStrategy,
254
261
  connectTimeout: 1e4,
@@ -261,17 +268,41 @@ const initServer = async (app, serverEnv) => {
261
268
  redisClient.on("error", (error) => {
262
269
  console.log("session-storage::redis_client ERROR", error);
263
270
  });
264
- redisClient.connect();
271
+ console.log("Using Redis session store");
272
+ await redisClient.connect();
273
+ return new RedisStore({
274
+ client: redisClient,
275
+ ttl: SESSION_MAX_AGE_S
276
+ });
277
+ };
278
+ const initServer = async (app, serverEnv) => {
279
+ await initApiClient({ app });
280
+ app.disable("x-powered-by");
281
+ app.set("trust proxy", true);
282
+ app.use(requestIp.mw());
283
+ app.use((req, res, next) => {
284
+ if (req.headers.host?.startsWith("www.")) {
285
+ const newHost = req.headers.host.replace("www.", "");
286
+ return res.redirect(301, `${req.protocol}://${newHost}${req.originalUrl}`);
287
+ }
288
+ next();
289
+ });
290
+ metricsIngestProxyMiddleware(app);
291
+ if (!serverEnv.MASTER_KEY) {
292
+ throw new Error("MASTER_KEY must be defined to derive the session secret");
293
+ }
294
+ const sessionSecret = getDerivedKey(serverEnv.MASTER_KEY, "express_session_key");
295
+ const redisUrl = serverEnv.REDIS_URL?.trim();
296
+ const store = redisUrl ? await createRedisSessionStore(redisUrl) : createMongoSessionStore(serverEnv);
265
297
  const sessionConfig = {
266
298
  name: "session",
267
- store: new RedisStore({ client: redisClient }),
299
+ store,
268
300
  proxy: true,
269
301
  resave: false,
270
302
  saveUninitialized: false,
271
303
  secret: sessionSecret,
272
304
  cookie: {
273
- maxAge: 1e3 * 3600 * 24 * 60
274
- // 60 days
305
+ maxAge: SESSION_MAX_AGE_S * 1e3
275
306
  }
276
307
  };
277
308
  if (isProduction$1) {
@@ -421,7 +452,14 @@ async function renderSSR(req, dataRoutes) {
421
452
  throw err;
422
453
  }
423
454
  if (routerContext.errors) {
424
- console.log("SERVER ERRORS", routerContext.errors);
455
+ if (routerContext.statusCode === 404) {
456
+ console.warn(`SSR 404 ${req.method} ${req.originalUrl}`, { errors: routerContext.errors });
457
+ } else {
458
+ console.error(`SSR ${routerContext.statusCode || 500} ${req.method} ${req.originalUrl}`, routerContext.errors);
459
+ const error = new Error("SSR loader error");
460
+ error.details = routerContext.errors;
461
+ throw error;
462
+ }
425
463
  }
426
464
  const router = createStaticRouter(dataRoutes, routerContext);
427
465
  const element = /* @__PURE__ */ jsx(StrictMode, { children: /* @__PURE__ */ jsx(
@@ -1,5 +1,7 @@
1
1
  import { Application } from 'express';
2
- export declare const initServer: (app: Application, serverEnv: {
2
+ type ServerEnv = {
3
3
  [key: string]: string | undefined;
4
- }) => Promise<void>;
4
+ };
5
+ export declare const initServer: (app: Application, serverEnv: ServerEnv) => Promise<void>;
6
+ export {};
5
7
  //# sourceMappingURL=initServer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"initServer.d.ts","sourceRoot":"","sources":["../src/initServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAsBrC,eAAO,MAAM,UAAU,GAAU,KAAK,WAAW,EAAE,WAAW;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;CAAE,kBA6ElG,CAAA"}
1
+ {"version":3,"file":"initServer.d.ts","sourceRoot":"","sources":["../src/initServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAsBrC,KAAK,SAAS,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;CAAE,CAAA;AA8EtD,eAAO,MAAM,UAAU,GAAU,KAAK,WAAW,EAAE,WAAW,SAAS,kBAmDtE,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"renderSSR.d.ts","sourceRoot":"","sources":["../src/renderSSR.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAA;AAClC,OAAO,EAAE,SAAS,EAAc,MAAM,OAAO,CAAA;AAC7C,OAAO,EAGL,aAAa,EACd,MAAM,iBAAiB,CAAA;AAOxB,wBAAsB,SAAS,CAC7B,GAAG,EAAE,OAAO,CAAC,OAAO,EACpB,UAAU,EAAE,aAAa,CAAC,YAAY,CAAC,GACtC,OAAO,CAAC;IAAC,OAAO,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAC,CAAC,CA+BnD"}
1
+ {"version":3,"file":"renderSSR.d.ts","sourceRoot":"","sources":["../src/renderSSR.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAA;AAClC,OAAO,EAAE,SAAS,EAAc,MAAM,OAAO,CAAA;AAC7C,OAAO,EAGL,aAAa,EACd,MAAM,iBAAiB,CAAA;AAOxB,wBAAsB,SAAS,CAC7B,GAAG,EAAE,OAAO,CAAC,OAAO,EACpB,UAAU,EAAE,aAAa,CAAC,YAAY,CAAC,GACtC,OAAO,CAAC;IAAC,OAAO,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAC,CAAC,CAuCnD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpcbase/server",
3
- "version": "0.442.0",
3
+ "version": "0.444.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"
@@ -44,6 +44,7 @@
44
44
  }
45
45
  },
46
46
  "dependencies": {
47
+ "connect-mongo": "6.0.0",
47
48
  "connect-redis": "9.0.0",
48
49
  "express-session": "1.18.2",
49
50
  "http-proxy-middleware": "3.0.5",