@rpcbase/server 0.465.0 → 0.467.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.
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkInitReplicaSet.d.ts","sourceRoot":"","sources":["../src/checkInitReplicaSet.ts"],"names":[],"mappings":"AAGA,KAAK,SAAS,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;CAAE,CAAA;AAMtD,eAAO,MAAM,mBAAmB,GAAU,WAAW,SAAS,KAAG,OAAO,CAAC,IAAI,CAiH5E,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import session from "express-session";
|
|
|
2
2
|
import { RedisStore } from "connect-redis";
|
|
3
3
|
import MongoStore from "connect-mongo";
|
|
4
4
|
import { createClient } from "redis";
|
|
5
|
+
import { MongoClient } from "mongodb";
|
|
5
6
|
import env from "@rpcbase/env";
|
|
6
7
|
import { initApiClient, SsrErrorFallback, SSR_ERROR_STATE_GLOBAL_KEY, serializeSsrErrorState } from "@rpcbase/client";
|
|
7
8
|
import { dirname, posix, sep } from "path";
|
|
@@ -3278,6 +3279,101 @@ const metricsIngestProxyMiddleware = (app) => {
|
|
|
3278
3279
|
})
|
|
3279
3280
|
);
|
|
3280
3281
|
};
|
|
3282
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
3283
|
+
let hasWarnedNoReplicationEnabled = false;
|
|
3284
|
+
const checkInitReplicaSet = async (serverEnv) => {
|
|
3285
|
+
const port = serverEnv.DB_PORT?.trim();
|
|
3286
|
+
if (!port) return;
|
|
3287
|
+
const host = (serverEnv.DB_HOST ?? "localhost").trim();
|
|
3288
|
+
const replSetName = "rs0";
|
|
3289
|
+
const memberHost = `${host}:${port}`;
|
|
3290
|
+
const maxAttempts = 10;
|
|
3291
|
+
const serverSelectionTimeoutMs = 2e3;
|
|
3292
|
+
const uri = `mongodb://${host}:${port}/?directConnection=true`;
|
|
3293
|
+
const waitForReplicaSetReady = async (admin) => {
|
|
3294
|
+
const maxWaitAttempts = 10;
|
|
3295
|
+
for (let attempt = 1; attempt <= maxWaitAttempts; attempt++) {
|
|
3296
|
+
try {
|
|
3297
|
+
const status = await admin.command({ replSetGetStatus: 1 });
|
|
3298
|
+
const state = Number(status?.myState ?? 0);
|
|
3299
|
+
if (status?.ok && (state === 1 || state === 2)) return;
|
|
3300
|
+
} catch {
|
|
3301
|
+
}
|
|
3302
|
+
await sleep(250 * attempt);
|
|
3303
|
+
}
|
|
3304
|
+
};
|
|
3305
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
3306
|
+
let client2 = null;
|
|
3307
|
+
try {
|
|
3308
|
+
client2 = new MongoClient(uri, {
|
|
3309
|
+
family: 4,
|
|
3310
|
+
serverSelectionTimeoutMS: serverSelectionTimeoutMs,
|
|
3311
|
+
connectTimeoutMS: serverSelectionTimeoutMs
|
|
3312
|
+
});
|
|
3313
|
+
await client2.connect();
|
|
3314
|
+
const admin = client2.db("admin").admin();
|
|
3315
|
+
await admin.command({ ping: 1 });
|
|
3316
|
+
try {
|
|
3317
|
+
await admin.command({ replSetGetStatus: 1 });
|
|
3318
|
+
return;
|
|
3319
|
+
} catch (error) {
|
|
3320
|
+
const codeName = error?.codeName;
|
|
3321
|
+
if (codeName === "NotYetInitialized") {
|
|
3322
|
+
try {
|
|
3323
|
+
const res = await admin.command({
|
|
3324
|
+
replSetInitiate: {
|
|
3325
|
+
_id: replSetName,
|
|
3326
|
+
members: [{ _id: 0, host: memberHost }]
|
|
3327
|
+
}
|
|
3328
|
+
});
|
|
3329
|
+
if (res?.ok) {
|
|
3330
|
+
console.warn(`[rb/server] MongoDB replica set '${replSetName}' initiated (${memberHost}).`);
|
|
3331
|
+
} else {
|
|
3332
|
+
console.warn(`[rb/server] MongoDB replica set initiation returned ok=${String(res?.ok)}.`);
|
|
3333
|
+
}
|
|
3334
|
+
} catch (initError) {
|
|
3335
|
+
const initCodeName = initError?.codeName;
|
|
3336
|
+
if (initCodeName !== "AlreadyInitialized") {
|
|
3337
|
+
const message2 = initError instanceof Error ? initError.message : String(initError);
|
|
3338
|
+
console.warn(`[rb/server] MongoDB replica set initiation failed: ${message2}`);
|
|
3339
|
+
if (initCodeName === "InvalidReplicaSetConfig") {
|
|
3340
|
+
console.warn(
|
|
3341
|
+
`[rb/server] Hint: the replica set member host must match the mongod address/port. If MongoDB runs in Docker with port mapping, ensure the container listens on ${port} (e.g. mongod --port ${port}) instead of the default 27017.`
|
|
3342
|
+
);
|
|
3343
|
+
}
|
|
3344
|
+
}
|
|
3345
|
+
}
|
|
3346
|
+
await waitForReplicaSetReady(admin);
|
|
3347
|
+
return;
|
|
3348
|
+
}
|
|
3349
|
+
if (codeName === "NoReplicationEnabled") {
|
|
3350
|
+
if (!hasWarnedNoReplicationEnabled) {
|
|
3351
|
+
hasWarnedNoReplicationEnabled = true;
|
|
3352
|
+
console.warn(
|
|
3353
|
+
`[rb/server] MongoDB is not started with --replSet ${replSetName} (replication disabled). Change streams require a replica set; start mongod with --replSet.`
|
|
3354
|
+
);
|
|
3355
|
+
}
|
|
3356
|
+
return;
|
|
3357
|
+
}
|
|
3358
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3359
|
+
console.warn(`[rb/server] MongoDB replica set check failed: ${message}`);
|
|
3360
|
+
return;
|
|
3361
|
+
}
|
|
3362
|
+
} catch (error) {
|
|
3363
|
+
if (attempt === maxAttempts) {
|
|
3364
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3365
|
+
console.warn(`[rb/server] MongoDB replica set auto-init skipped (unable to connect to ${host}:${port}): ${message}`);
|
|
3366
|
+
return;
|
|
3367
|
+
}
|
|
3368
|
+
await sleep(250 * attempt);
|
|
3369
|
+
} finally {
|
|
3370
|
+
try {
|
|
3371
|
+
await client2?.close();
|
|
3372
|
+
} catch {
|
|
3373
|
+
}
|
|
3374
|
+
}
|
|
3375
|
+
}
|
|
3376
|
+
};
|
|
3281
3377
|
process.env = {
|
|
3282
3378
|
...env,
|
|
3283
3379
|
...__rb_env__,
|
|
@@ -3297,17 +3393,24 @@ const getMongoUrl = (serverEnv) => {
|
|
|
3297
3393
|
}
|
|
3298
3394
|
return void 0;
|
|
3299
3395
|
};
|
|
3300
|
-
const createMongoSessionStore = (serverEnv) => {
|
|
3396
|
+
const createMongoSessionStore = async (serverEnv) => {
|
|
3301
3397
|
const mongoUrl = getMongoUrl(serverEnv);
|
|
3302
3398
|
if (!mongoUrl) {
|
|
3303
3399
|
throw new Error("Missing REDIS_URL and Mongo connection details (MONGODB_URL/MONGO_URL/MONGODB_URI/DB_PORT)");
|
|
3304
3400
|
}
|
|
3305
3401
|
console.log("Using MongoDB session store");
|
|
3306
|
-
|
|
3307
|
-
|
|
3402
|
+
const client2 = await MongoClient.connect(mongoUrl, {
|
|
3403
|
+
family: 4,
|
|
3404
|
+
serverSelectionTimeoutMS: 2e3,
|
|
3405
|
+
connectTimeoutMS: 2e3
|
|
3406
|
+
});
|
|
3407
|
+
const store = MongoStore.create({
|
|
3408
|
+
client: client2,
|
|
3308
3409
|
collectionName: "sessions",
|
|
3309
3410
|
ttl: SESSION_MAX_AGE_S
|
|
3310
3411
|
});
|
|
3412
|
+
await store.collectionP;
|
|
3413
|
+
return store;
|
|
3311
3414
|
};
|
|
3312
3415
|
const createRedisSessionStore = async (redisUrl) => {
|
|
3313
3416
|
const reconnectStrategy = (retries) => {
|
|
@@ -3342,6 +3445,10 @@ const createRedisSessionStore = async (redisUrl) => {
|
|
|
3342
3445
|
};
|
|
3343
3446
|
const initServer = async (app, serverEnv) => {
|
|
3344
3447
|
await initApiClient({ app });
|
|
3448
|
+
const replicaSetInitPromise = checkInitReplicaSet(serverEnv).catch((error) => {
|
|
3449
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3450
|
+
console.warn(`[rb/server] MongoDB replica set auto-init error: ${message}`);
|
|
3451
|
+
});
|
|
3345
3452
|
app.disable("x-powered-by");
|
|
3346
3453
|
app.set("trust proxy", true);
|
|
3347
3454
|
app.use(requestIp.mw());
|
|
@@ -3364,7 +3471,13 @@ const initServer = async (app, serverEnv) => {
|
|
|
3364
3471
|
}
|
|
3365
3472
|
const sessionSecret = getDerivedKey(serverEnv.MASTER_KEY, "express_session_key");
|
|
3366
3473
|
const redisUrl = serverEnv.REDIS_URL?.trim();
|
|
3367
|
-
|
|
3474
|
+
let store;
|
|
3475
|
+
if (redisUrl) {
|
|
3476
|
+
store = await createRedisSessionStore(redisUrl);
|
|
3477
|
+
} else {
|
|
3478
|
+
await replicaSetInitPromise;
|
|
3479
|
+
store = await createMongoSessionStore(serverEnv);
|
|
3480
|
+
}
|
|
3368
3481
|
const sessionConfig = {
|
|
3369
3482
|
name: "session",
|
|
3370
3483
|
store,
|
|
@@ -3377,7 +3490,7 @@ const initServer = async (app, serverEnv) => {
|
|
|
3377
3490
|
}
|
|
3378
3491
|
};
|
|
3379
3492
|
if (isProduction$1) {
|
|
3380
|
-
sessionConfig.cookie.secure =
|
|
3493
|
+
sessionConfig.cookie.secure = "auto";
|
|
3381
3494
|
}
|
|
3382
3495
|
const sessionMiddleware = session(sessionConfig);
|
|
3383
3496
|
app.locals.rbSessionMiddleware = sessionMiddleware;
|
package/dist/initServer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"initServer.d.ts","sourceRoot":"","sources":["../src/initServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"initServer.d.ts","sourceRoot":"","sources":["../src/initServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAyBrC,KAAK,SAAS,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;CAAE,CAAA;AAuFtD,eAAO,MAAM,UAAU,GAAU,KAAK,WAAW,EAAE,WAAW,SAAS,kBAsEtE,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rpcbase/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.467.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -75,6 +75,7 @@
|
|
|
75
75
|
"connect-redis": "9.0.0",
|
|
76
76
|
"express-session": "1.18.2",
|
|
77
77
|
"http-proxy-middleware": "3.0.5",
|
|
78
|
+
"mongodb": "7.0.0",
|
|
78
79
|
"redis": "5.10.0",
|
|
79
80
|
"resend": "6.5.2",
|
|
80
81
|
"ws": "8.18.0"
|