lamix 4.2.13 → 4.2.15
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/README.md +4 -16
- package/bin/cli.js +60 -1
- package/lib/index.d.ts +26 -0
- package/lib/index.js +221 -99
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -288,21 +288,9 @@ class User extends BaseModel {
|
|
|
288
288
|
return this.hasMany(Post', 'user_id', 'id').onDelete('cascade');
|
|
289
289
|
}
|
|
290
290
|
|
|
291
|
-
#
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
data TEXT NOT NULL,
|
|
295
|
-
expires BIGINT NOT NULL
|
|
296
|
-
);
|
|
297
|
-
CREATE INDEX idx_sessions_expires ON sessions (expires);
|
|
298
|
-
|
|
299
|
-
# Create sessions Table sqlite sql
|
|
300
|
-
CREATE TABLE sessions (
|
|
301
|
-
sid TEXT PRIMARY KEY,
|
|
302
|
-
data TEXT NOT NULL,
|
|
303
|
-
expires INTEGER NOT NULL
|
|
304
|
-
);
|
|
305
|
-
CREATE INDEX idx_sessions_expires ON sessions (expires);
|
|
291
|
+
# migrate sessions Table(whenever migration is run session is auto generated if missing)
|
|
292
|
+
npx lamix migrate
|
|
293
|
+
➡️ sessions table + index are guaranteed to exist.
|
|
306
294
|
|
|
307
295
|
# Session setup
|
|
308
296
|
const express = require('express');
|
|
@@ -340,4 +328,4 @@ class User extends BaseModel {
|
|
|
340
328
|
});
|
|
341
329
|
|
|
342
330
|
app.listen(3000);
|
|
343
|
-
}
|
|
331
|
+
}
|
package/bin/cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
@@ -274,6 +274,8 @@ async function runMigrations() {
|
|
|
274
274
|
DB.initFromEnv();
|
|
275
275
|
await DB.connect();
|
|
276
276
|
|
|
277
|
+
await ensureSessionsTable();
|
|
278
|
+
|
|
277
279
|
const applied = await getAppliedMigrations();
|
|
278
280
|
const files = fs.readdirSync(MIGRATIONS_DIR)
|
|
279
281
|
.filter(f => f.endsWith('.js'))
|
|
@@ -348,6 +350,63 @@ async function tableExists(tableName) {
|
|
|
348
350
|
return false;
|
|
349
351
|
}
|
|
350
352
|
|
|
353
|
+
// ------------------ SESSION hELPER ------------------
|
|
354
|
+
|
|
355
|
+
async function ensureSessionsTable() {
|
|
356
|
+
const exists = await tableExists('sessions');
|
|
357
|
+
if (exists) {
|
|
358
|
+
log.info('ℹ️ sessions table already exists. Skipping.');
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
log.info('⚙️ Creating sessions table...');
|
|
363
|
+
|
|
364
|
+
if (DB.driver === 'mysql') {
|
|
365
|
+
await DB.raw(`
|
|
366
|
+
CREATE TABLE sessions (
|
|
367
|
+
sid VARCHAR(255) PRIMARY KEY,
|
|
368
|
+
data TEXT NOT NULL,
|
|
369
|
+
expires BIGINT NOT NULL
|
|
370
|
+
)
|
|
371
|
+
`);
|
|
372
|
+
|
|
373
|
+
await DB.raw(`
|
|
374
|
+
CREATE INDEX idx_sessions_expires ON sessions (expires)
|
|
375
|
+
`);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (DB.driver === 'sqlite') {
|
|
379
|
+
await DB.raw(`
|
|
380
|
+
CREATE TABLE sessions (
|
|
381
|
+
sid TEXT PRIMARY KEY,
|
|
382
|
+
data TEXT NOT NULL,
|
|
383
|
+
expires INTEGER NOT NULL
|
|
384
|
+
)
|
|
385
|
+
`);
|
|
386
|
+
|
|
387
|
+
await DB.raw(`
|
|
388
|
+
CREATE INDEX idx_sessions_expires ON sessions (expires)
|
|
389
|
+
`);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (DB.driver === 'pg') {
|
|
393
|
+
await DB.raw(`
|
|
394
|
+
CREATE TABLE sessions (
|
|
395
|
+
sid VARCHAR(255) PRIMARY KEY,
|
|
396
|
+
data TEXT NOT NULL,
|
|
397
|
+
expires BIGINT NOT NULL
|
|
398
|
+
)
|
|
399
|
+
`);
|
|
400
|
+
|
|
401
|
+
await DB.raw(`
|
|
402
|
+
CREATE INDEX idx_sessions_expires ON sessions (expires)
|
|
403
|
+
`);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
log.success('✅ sessions table created successfully.');
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
|
|
351
410
|
|
|
352
411
|
async function rollbackLastMigration() {
|
|
353
412
|
DB.initFromEnv();
|
package/lib/index.d.ts
CHANGED
|
@@ -488,6 +488,31 @@ export class DBError extends Error {
|
|
|
488
488
|
constructor(message: any, meta?: {});
|
|
489
489
|
meta: {};
|
|
490
490
|
}
|
|
491
|
+
export class LamixSessionStore {
|
|
492
|
+
constructor(options?: {});
|
|
493
|
+
ttl: any;
|
|
494
|
+
cleanupInterval: any;
|
|
495
|
+
logger: any;
|
|
496
|
+
compress: any;
|
|
497
|
+
cache: LRU<any, any>;
|
|
498
|
+
redisEnabled: boolean;
|
|
499
|
+
redisRetryAt: number;
|
|
500
|
+
redisCooldown: any;
|
|
501
|
+
redis: any;
|
|
502
|
+
_safeCb(cb: any, err: any, result?: any): void;
|
|
503
|
+
_hasSessionModel(): boolean;
|
|
504
|
+
_canUseRedis(): boolean;
|
|
505
|
+
_markRedisFailure(err: any): void;
|
|
506
|
+
_serialize(data: any): string;
|
|
507
|
+
_deserialize(raw: any): any;
|
|
508
|
+
_checkRedisHealth(): Promise<void>;
|
|
509
|
+
get(sid: any, cb: any): Promise<void>;
|
|
510
|
+
set(sid: any, sessionData: any, cb: any): Promise<void>;
|
|
511
|
+
destroy(sid: any, cb: any): Promise<void>;
|
|
512
|
+
touch(sid: any, sessionData: any, cb: any): Promise<void>;
|
|
513
|
+
_startCleanup(): void;
|
|
514
|
+
_cleanupTimer: any;
|
|
515
|
+
}
|
|
491
516
|
export class BaseModel extends Model {
|
|
492
517
|
static passwordField: string;
|
|
493
518
|
static hashRounds: number;
|
|
@@ -586,4 +611,5 @@ declare class Relation {
|
|
|
586
611
|
deleteBehavior: any;
|
|
587
612
|
onDelete(behavior: any): this;
|
|
588
613
|
}
|
|
614
|
+
import LRU = require("lru-cache");
|
|
589
615
|
export {};
|
package/lib/index.js
CHANGED
|
@@ -135,31 +135,6 @@ class DB {
|
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
/* ---------- Driver ---------- */
|
|
138
|
-
|
|
139
|
-
// static _ensureModule() {
|
|
140
|
-
// if (!this.driver) this.initFromEnv();
|
|
141
|
-
|
|
142
|
-
// if (this.driver === 'mysql') {
|
|
143
|
-
// const m = tryRequire('mysql2/promise');
|
|
144
|
-
// if (!m) throw new DBError('Missing mysql2');
|
|
145
|
-
// return m;
|
|
146
|
-
// }
|
|
147
|
-
|
|
148
|
-
// if (this.driver === 'pg') {
|
|
149
|
-
// const m = tryRequire('pg');
|
|
150
|
-
// if (!m) throw new DBError('Missing pg');
|
|
151
|
-
// return m;
|
|
152
|
-
// }
|
|
153
|
-
|
|
154
|
-
// if (this.driver === 'sqlite') {
|
|
155
|
-
// const m = tryRequire('sqlite3');
|
|
156
|
-
// if (!m) throw new DBError('Missing sqlite3');
|
|
157
|
-
// return m;
|
|
158
|
-
// }
|
|
159
|
-
|
|
160
|
-
// throw new DBError(`Unsupported driver: ${this.driver}`);
|
|
161
|
-
// }
|
|
162
|
-
|
|
163
138
|
static _ensureModule() {
|
|
164
139
|
if (!this.driver) this.initFromEnv();
|
|
165
140
|
|
|
@@ -3916,6 +3891,12 @@ class Model {
|
|
|
3916
3891
|
}
|
|
3917
3892
|
}
|
|
3918
3893
|
|
|
3894
|
+
const session = require('express-session');
|
|
3895
|
+
const Redis = require('ioredis');
|
|
3896
|
+
const LRU = require('lru-cache');
|
|
3897
|
+
const zlib = require('zlib');
|
|
3898
|
+
|
|
3899
|
+
/* -------------------- DB Model -------------------- */
|
|
3919
3900
|
class Session extends Model {
|
|
3920
3901
|
static table = 'sessions';
|
|
3921
3902
|
static primaryKey = 'sid';
|
|
@@ -3925,44 +3906,159 @@ class Session extends Model {
|
|
|
3925
3906
|
static fillable = ['sid', 'data', 'expires'];
|
|
3926
3907
|
}
|
|
3927
3908
|
|
|
3928
|
-
|
|
3909
|
+
/* -------------------- Optional Session Model -------------------- */
|
|
3910
|
+
let SessionModel = null;
|
|
3911
|
+
|
|
3912
|
+
try {
|
|
3913
|
+
// If this throws, DB-backed sessions are simply disabled
|
|
3914
|
+
SessionModel = Session;
|
|
3915
|
+
} catch (err) {
|
|
3916
|
+
SessionModel = null;
|
|
3917
|
+
}
|
|
3929
3918
|
|
|
3919
|
+
/* -------------------- Store -------------------- */
|
|
3930
3920
|
class LamixSessionStore extends session.Store {
|
|
3931
3921
|
constructor(options = {}) {
|
|
3932
3922
|
super();
|
|
3933
3923
|
|
|
3934
|
-
this.ttl = options.ttl || 86400;
|
|
3924
|
+
this.ttl = options.ttl || 86400;
|
|
3935
3925
|
this.cleanupInterval = options.cleanupInterval || 60000;
|
|
3926
|
+
this.logger = options.logger || console;
|
|
3927
|
+
this.compress = options.compress ?? true;
|
|
3928
|
+
|
|
3929
|
+
/* -------- In-memory cache -------- */
|
|
3930
|
+
this.cache = new LRU({
|
|
3931
|
+
max: options.cacheSize || 1000,
|
|
3932
|
+
ttl: options.cacheTTL || 60000,
|
|
3933
|
+
});
|
|
3934
|
+
|
|
3935
|
+
/* -------- Redis -------- */
|
|
3936
|
+
this.redisEnabled = false;
|
|
3937
|
+
this.redisRetryAt = 0;
|
|
3938
|
+
this.redisCooldown = options.redisCooldown || 30000;
|
|
3939
|
+
|
|
3940
|
+
if (options.redis) {
|
|
3941
|
+
this.redis =
|
|
3942
|
+
options.redis instanceof Redis
|
|
3943
|
+
? options.redis
|
|
3944
|
+
: new Redis(options.redis);
|
|
3945
|
+
|
|
3946
|
+
this._checkRedisHealth();
|
|
3947
|
+
}
|
|
3936
3948
|
|
|
3937
3949
|
this._startCleanup();
|
|
3938
3950
|
}
|
|
3939
3951
|
|
|
3940
|
-
/*
|
|
3952
|
+
/* -------------------- Safety Helpers -------------------- */
|
|
3953
|
+
_safeCb(cb, err, result = null) {
|
|
3954
|
+
try {
|
|
3955
|
+
cb(err, result);
|
|
3956
|
+
} catch (e) {
|
|
3957
|
+
this.logger.error('Session callback threw', e);
|
|
3958
|
+
}
|
|
3959
|
+
}
|
|
3941
3960
|
|
|
3942
|
-
|
|
3961
|
+
_hasSessionModel() {
|
|
3962
|
+
return !!SessionModel;
|
|
3963
|
+
}
|
|
3964
|
+
|
|
3965
|
+
_canUseRedis() {
|
|
3966
|
+
return this.redisEnabled && Date.now() > this.redisRetryAt;
|
|
3967
|
+
}
|
|
3968
|
+
|
|
3969
|
+
_markRedisFailure(err) {
|
|
3970
|
+
this.redisEnabled = false;
|
|
3971
|
+
this.redisRetryAt = Date.now() + this.redisCooldown;
|
|
3972
|
+
this.logger.warn('Redis disabled temporarily', err);
|
|
3973
|
+
}
|
|
3974
|
+
|
|
3975
|
+
/* -------------------- Serialization -------------------- */
|
|
3976
|
+
_serialize(data) {
|
|
3943
3977
|
try {
|
|
3944
|
-
const
|
|
3978
|
+
const json = JSON.stringify(data);
|
|
3979
|
+
return this.compress
|
|
3980
|
+
? zlib.deflateSync(Buffer.from(json)).toString('base64')
|
|
3981
|
+
: json;
|
|
3982
|
+
} catch (err) {
|
|
3983
|
+
this.logger.warn('Serialize failed, skipping persistence', err);
|
|
3984
|
+
return null;
|
|
3985
|
+
}
|
|
3986
|
+
}
|
|
3945
3987
|
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
.where('sid', sid)
|
|
3949
|
-
.where('expires', '>', now)
|
|
3950
|
-
.first();
|
|
3988
|
+
_deserialize(raw) {
|
|
3989
|
+
if (!raw) return null;
|
|
3951
3990
|
|
|
3952
|
-
|
|
3991
|
+
try {
|
|
3992
|
+
const str = this.compress
|
|
3993
|
+
? zlib.inflateSync(Buffer.from(raw, 'base64')).toString()
|
|
3994
|
+
: raw;
|
|
3953
3995
|
|
|
3954
|
-
|
|
3996
|
+
return JSON.parse(str);
|
|
3955
3997
|
} catch (err) {
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
operation: 'get',
|
|
3959
|
-
err
|
|
3960
|
-
}));
|
|
3998
|
+
this.logger.warn('Deserialize failed, dropping session', err);
|
|
3999
|
+
return null;
|
|
3961
4000
|
}
|
|
3962
4001
|
}
|
|
3963
4002
|
|
|
3964
|
-
/*
|
|
4003
|
+
/* -------------------- Redis Health -------------------- */
|
|
4004
|
+
async _checkRedisHealth() {
|
|
4005
|
+
try {
|
|
4006
|
+
await this.redis.ping();
|
|
4007
|
+
this.redisEnabled = true;
|
|
4008
|
+
this.logger.info('Redis session store active');
|
|
4009
|
+
|
|
4010
|
+
this.redis.on('error', (err) => this._markRedisFailure(err));
|
|
4011
|
+
this.redis.on('connect', () => {
|
|
4012
|
+
this.redisEnabled = true;
|
|
4013
|
+
this.logger.info('Redis reconnected');
|
|
4014
|
+
});
|
|
4015
|
+
} catch (err) {
|
|
4016
|
+
this.redisEnabled = false;
|
|
4017
|
+
this.logger.warn('Redis unavailable', err);
|
|
4018
|
+
}
|
|
4019
|
+
}
|
|
4020
|
+
|
|
4021
|
+
/* -------------------- GET -------------------- */
|
|
4022
|
+
async get(sid, cb) {
|
|
4023
|
+
let sessionData = null;
|
|
4024
|
+
|
|
4025
|
+
try {
|
|
4026
|
+
if (this.cache.has(sid)) {
|
|
4027
|
+
return this._safeCb(cb, null, this.cache.get(sid));
|
|
4028
|
+
}
|
|
4029
|
+
|
|
4030
|
+
if (this._canUseRedis()) {
|
|
4031
|
+
try {
|
|
4032
|
+
const raw = await this.redis.get(`sess:${sid}`);
|
|
4033
|
+
sessionData = this._deserialize(raw);
|
|
4034
|
+
} catch (err) {
|
|
4035
|
+
this._markRedisFailure(err);
|
|
4036
|
+
}
|
|
4037
|
+
}
|
|
4038
|
+
|
|
4039
|
+
if (!sessionData && this._hasSessionModel()) {
|
|
4040
|
+
try {
|
|
4041
|
+
const row = await SessionModel.query()
|
|
4042
|
+
.where('sid', sid)
|
|
4043
|
+
.where('expires', '>', Date.now())
|
|
4044
|
+
.first();
|
|
4045
|
+
|
|
4046
|
+
if (row) sessionData = this._deserialize(row.data);
|
|
4047
|
+
} catch (err) {
|
|
4048
|
+
this.logger.warn('DB GET failed, disabling DB sessions', err);
|
|
4049
|
+
SessionModel = null;
|
|
4050
|
+
}
|
|
4051
|
+
}
|
|
4052
|
+
|
|
4053
|
+
if (sessionData) this.cache.set(sid, sessionData);
|
|
4054
|
+
this._safeCb(cb, null, sessionData);
|
|
4055
|
+
} catch (err) {
|
|
4056
|
+
this.logger.error('GET failed safely', err);
|
|
4057
|
+
this._safeCb(cb, null, null);
|
|
4058
|
+
}
|
|
4059
|
+
}
|
|
3965
4060
|
|
|
4061
|
+
/* -------------------- SET -------------------- */
|
|
3966
4062
|
async set(sid, sessionData, cb) {
|
|
3967
4063
|
try {
|
|
3968
4064
|
const expires =
|
|
@@ -3970,58 +4066,75 @@ class LamixSessionStore extends session.Store {
|
|
|
3970
4066
|
? new Date(sessionData.cookie.expires).getTime()
|
|
3971
4067
|
: Date.now() + this.ttl * 1000;
|
|
3972
4068
|
|
|
3973
|
-
const
|
|
3974
|
-
|
|
3975
|
-
data: JSON.stringify(sessionData),
|
|
3976
|
-
expires
|
|
3977
|
-
};
|
|
4069
|
+
const data = this._serialize(sessionData);
|
|
4070
|
+
if (!data) return this._safeCb(cb, null);
|
|
3978
4071
|
|
|
3979
|
-
|
|
3980
|
-
const existing = await Session
|
|
3981
|
-
.query()
|
|
3982
|
-
.where('sid', sid)
|
|
3983
|
-
.first();
|
|
4072
|
+
this.cache.set(sid, sessionData);
|
|
3984
4073
|
|
|
3985
|
-
if (
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
4074
|
+
if (this._hasSessionModel()) {
|
|
4075
|
+
try {
|
|
4076
|
+
const existing = await SessionModel.query()
|
|
4077
|
+
.where('sid', sid)
|
|
4078
|
+
.first();
|
|
4079
|
+
|
|
4080
|
+
if (existing) {
|
|
4081
|
+
await existing.update({ data, expires });
|
|
4082
|
+
} else {
|
|
4083
|
+
await new SessionModel({ sid, data, expires }, false).saveNew();
|
|
4084
|
+
}
|
|
4085
|
+
} catch (err) {
|
|
4086
|
+
this.logger.warn('DB SET failed, disabling DB sessions', err);
|
|
4087
|
+
SessionModel = null;
|
|
4088
|
+
}
|
|
3990
4089
|
}
|
|
3991
4090
|
|
|
3992
|
-
|
|
4091
|
+
if (this._canUseRedis()) {
|
|
4092
|
+
try {
|
|
4093
|
+
await this.redis.set(`sess:${sid}`, data, 'PX', expires - Date.now());
|
|
4094
|
+
} catch (err) {
|
|
4095
|
+
this._markRedisFailure(err);
|
|
4096
|
+
}
|
|
4097
|
+
}
|
|
4098
|
+
|
|
4099
|
+
this._safeCb(cb, null);
|
|
3993
4100
|
} catch (err) {
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
operation: 'set',
|
|
3997
|
-
err
|
|
3998
|
-
}));
|
|
4101
|
+
this.logger.error('SET failed safely', err);
|
|
4102
|
+
this._safeCb(cb, null);
|
|
3999
4103
|
}
|
|
4000
4104
|
}
|
|
4001
4105
|
|
|
4002
|
-
/*
|
|
4003
|
-
|
|
4106
|
+
/* -------------------- DESTROY -------------------- */
|
|
4004
4107
|
async destroy(sid, cb) {
|
|
4005
4108
|
try {
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4109
|
+
this.cache.delete(sid);
|
|
4110
|
+
|
|
4111
|
+
if (this._hasSessionModel()) {
|
|
4112
|
+
try {
|
|
4113
|
+
await SessionModel.query().where('sid', sid).delete();
|
|
4114
|
+
} catch (err) {
|
|
4115
|
+
this.logger.warn('DB DESTROY failed, disabling DB sessions', err);
|
|
4116
|
+
SessionModel = null;
|
|
4117
|
+
}
|
|
4118
|
+
}
|
|
4010
4119
|
|
|
4011
|
-
|
|
4120
|
+
if (this._canUseRedis()) {
|
|
4121
|
+
try {
|
|
4122
|
+
await this.redis.del(`sess:${sid}`);
|
|
4123
|
+
} catch (err) {
|
|
4124
|
+
this._markRedisFailure(err);
|
|
4125
|
+
}
|
|
4126
|
+
}
|
|
4127
|
+
|
|
4128
|
+
this._safeCb(cb, null);
|
|
4012
4129
|
} catch (err) {
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
operation: 'destroy',
|
|
4016
|
-
err
|
|
4017
|
-
}));
|
|
4130
|
+
this.logger.error('DESTROY failed safely', err);
|
|
4131
|
+
this._safeCb(cb, null);
|
|
4018
4132
|
}
|
|
4019
4133
|
}
|
|
4020
4134
|
|
|
4021
|
-
/*
|
|
4022
|
-
|
|
4135
|
+
/* -------------------- TOUCH -------------------- */
|
|
4023
4136
|
async touch(sid, sessionData, cb) {
|
|
4024
|
-
if (!sessionData) return cb
|
|
4137
|
+
if (!sessionData) return this._safeCb(cb, null);
|
|
4025
4138
|
|
|
4026
4139
|
try {
|
|
4027
4140
|
const expires =
|
|
@@ -4029,45 +4142,54 @@ class LamixSessionStore extends session.Store {
|
|
|
4029
4142
|
? new Date(sessionData.cookie.expires).getTime()
|
|
4030
4143
|
: Date.now() + this.ttl * 1000;
|
|
4031
4144
|
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4145
|
+
this.cache.set(sid, sessionData);
|
|
4146
|
+
|
|
4147
|
+
if (this._hasSessionModel()) {
|
|
4148
|
+
try {
|
|
4149
|
+
await SessionModel.query().where('sid', sid).update({ expires });
|
|
4150
|
+
} catch (err) {
|
|
4151
|
+
this.logger.warn('DB TOUCH failed, disabling DB sessions', err);
|
|
4152
|
+
SessionModel = null;
|
|
4153
|
+
}
|
|
4154
|
+
}
|
|
4036
4155
|
|
|
4037
|
-
|
|
4156
|
+
if (this._canUseRedis()) {
|
|
4157
|
+
try {
|
|
4158
|
+
await this.redis.pexpire(`sess:${sid}`, expires - Date.now());
|
|
4159
|
+
} catch (err) {
|
|
4160
|
+
this._markRedisFailure(err);
|
|
4161
|
+
}
|
|
4162
|
+
}
|
|
4163
|
+
|
|
4164
|
+
this._safeCb(cb, null);
|
|
4038
4165
|
} catch (err) {
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
operation: 'touch',
|
|
4042
|
-
err
|
|
4043
|
-
}));
|
|
4166
|
+
this.logger.error('TOUCH failed safely', err);
|
|
4167
|
+
this._safeCb(cb, null);
|
|
4044
4168
|
}
|
|
4045
4169
|
}
|
|
4046
4170
|
|
|
4047
|
-
/*
|
|
4048
|
-
|
|
4171
|
+
/* -------------------- Cleanup -------------------- */
|
|
4049
4172
|
_startCleanup() {
|
|
4173
|
+
if (!this._hasSessionModel()) return;
|
|
4174
|
+
|
|
4050
4175
|
this._cleanupTimer = setInterval(async () => {
|
|
4051
4176
|
try {
|
|
4052
|
-
await
|
|
4053
|
-
.query()
|
|
4177
|
+
await SessionModel.query()
|
|
4054
4178
|
.where('expires', '<', Date.now())
|
|
4055
4179
|
.delete();
|
|
4056
4180
|
} catch (err) {
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
err
|
|
4061
|
-
});
|
|
4181
|
+
this.logger.warn('Cleanup failed, disabling DB sessions', err);
|
|
4182
|
+
SessionModel = null;
|
|
4183
|
+
clearInterval(this._cleanupTimer);
|
|
4062
4184
|
}
|
|
4063
4185
|
}, this.cleanupInterval);
|
|
4064
4186
|
|
|
4065
4187
|
this._cleanupTimer.unref();
|
|
4066
4188
|
}
|
|
4067
|
-
|
|
4068
4189
|
}
|
|
4069
4190
|
|
|
4070
4191
|
|
|
4192
|
+
|
|
4071
4193
|
// --- BaseModel with bcrypt hashing ---
|
|
4072
4194
|
const bcrypt = tryRequire('bcrypt');
|
|
4073
4195
|
class BaseModel extends Model {
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lamix",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.15",
|
|
4
4
|
"description": "lamix - ORM for Node-express js",
|
|
5
5
|
"main": "./lib",
|
|
6
|
+
"type": "commonjs",
|
|
6
7
|
"exports": {
|
|
7
8
|
".": {
|
|
8
9
|
"require": "./lib/index.js",
|
|
@@ -31,6 +32,9 @@
|
|
|
31
32
|
"dependencies": {
|
|
32
33
|
"bcrypt": "^6.0.0",
|
|
33
34
|
"express-session": "^1.19.0",
|
|
35
|
+
"lru-cache": "^7.18.3",
|
|
36
|
+
"zlib": "^1.0.5",
|
|
37
|
+
"ioredis": "^5.9.2",
|
|
34
38
|
"chalk": "^4.1.2",
|
|
35
39
|
"dotenv": "^17.2.2"
|
|
36
40
|
},
|
|
@@ -39,6 +43,7 @@
|
|
|
39
43
|
"orm",
|
|
40
44
|
"nodejs",
|
|
41
45
|
"database",
|
|
46
|
+
"express",
|
|
42
47
|
"sql"
|
|
43
48
|
],
|
|
44
49
|
"author": {
|