lamix 4.2.19 → 4.2.21

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/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');
package/lib/index.d.ts CHANGED
@@ -67,6 +67,7 @@ export class Model {
67
67
  static whereNot(...args: any[]): QueryBuilder;
68
68
  static whereNotIn(col: any, arr: any): QueryBuilder;
69
69
  static whereNull(col: any): QueryBuilder;
70
+ static filter(...args: any[]): QueryBuilder;
70
71
  static find(value: any): Promise<any>;
71
72
  static findOrFail(value: any): Promise<any>;
72
73
  static findBy(col: any, value: any): Promise<any>;
@@ -212,7 +213,15 @@ export class Collection extends Array<any> {
212
213
  clone(): Collection;
213
214
  each(fn: any): Promise<this>;
214
215
  mapAsync(fn: any): Promise<Collection>;
215
- where(key: any, value: any): Collection;
216
+ /**
217
+ * Enhanced filter:
218
+ * - filter(fn)
219
+ * - filter({ key: value })
220
+ * - filter('key', value)
221
+ * - filter('key', '>', value)
222
+ */
223
+ filter(condition: any, operator?: any, value?: any): Collection;
224
+ where(key: any, operator: any, value?: any): Collection;
216
225
  whereNot(key: any, value: any): Collection;
217
226
  filterNull(): Collection;
218
227
  onlyKeys(keys: any): Collection;
@@ -492,26 +501,12 @@ export class LamixSessionStore {
492
501
  constructor(options?: {});
493
502
  ttl: any;
494
503
  cleanupInterval: any;
495
- logger: any;
496
- compress: any;
497
- cache: 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>;
504
+ get(sid: any, cb: any): Promise<any>;
510
505
  set(sid: any, sessionData: any, cb: any): Promise<void>;
511
506
  destroy(sid: any, cb: any): Promise<void>;
512
- touch(sid: any, sessionData: any, cb: any): Promise<void>;
507
+ touch(sid: any, sessionData: any, cb: any): Promise<any>;
513
508
  _startCleanup(): void;
514
- _cleanupTimer: any;
509
+ _cleanupTimer: NodeJS.Timeout;
515
510
  }
516
511
  export class BaseModel extends Model {
517
512
  static passwordField: string;
@@ -548,23 +543,36 @@ export class BaseModel extends Model {
548
543
  }
549
544
  declare class SimpleCache {
550
545
  constructor(options?: {});
551
- cache: any;
552
- get(key: any): any;
553
- set(key: any, value: any, ttl?: any): void;
554
- has(key: any): any;
555
- delete(key: any): any;
556
- clear(): void;
546
+ cache: LRUCache<{}, {}, unknown>;
547
+ /**
548
+ * Get cached value
549
+ * @param {string} key
550
+ * @returns {*} value or null
551
+ */
552
+ get(key: string): any;
557
553
  /**
558
- * Get value or compute + store it
559
- * Supports async functions
554
+ * Set cache value
555
+ * @param {string} key
556
+ * @param {*} value
557
+ * @param {number} ttl Optional TTL in ms
560
558
  */
561
- getOrSet(key: any, fetchFn: any, ttl?: any): Promise<any>;
559
+ set(key: string, value: any, ttl?: number): void;
560
+ /**
561
+ * Delete a key
562
+ * @param {string} key
563
+ */
564
+ del(key: string): void;
565
+ /**
566
+ * Clear entire cache
567
+ */
568
+ clear(): void;
562
569
  /**
563
- * Basic cache stats
570
+ * Get cache stats (optional utility)
564
571
  */
565
572
  stats(): {
566
- size: any;
567
- calculatedSize: any;
573
+ size: number;
574
+ calculatedSize: number;
575
+ maxSize: number;
568
576
  };
569
577
  }
570
578
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -625,4 +633,5 @@ declare class Relation {
625
633
  deleteBehavior: any;
626
634
  onDelete(behavior: any): this;
627
635
  }
636
+ import { LRUCache } from "lru-cache";
628
637
  export {};
package/lib/index.js CHANGED
@@ -5,7 +5,6 @@ const { performance } = require('perf_hooks');
5
5
  const { AsyncLocalStorage } = require('async_hooks');
6
6
  require('dotenv').config();
7
7
  const session = require('express-session');
8
- const Redis = require('ioredis');
9
8
  const { LRUCache } = require('lru-cache');
10
9
  const zlib = require('zlib');
11
10
 
@@ -32,68 +31,75 @@ class DBError extends Error {
32
31
  class SimpleCache {
33
32
  constructor(options = {}) {
34
33
  const {
35
- max = 1000, // max number of items
36
- ttl = 0, // default TTL (ms)
37
- maxSize, // optional size-based eviction
38
- sizeCalculation, // function(value, key)
34
+ maxSizeMB = 50, // total memory cap
35
+ defaultTTL = 1000 * 60 * 5, // 5 minutes
39
36
  } = options;
40
37
 
41
38
  this.cache = new LRUCache({
42
- max,
43
- ttl,
39
+ maxSize: maxSizeMB * 1024 * 1024, // convert MB → bytes
40
+ ttl: defaultTTL,
44
41
  ttlAutopurge: true,
45
- maxSize,
46
- sizeCalculation,
47
42
  allowStale: false,
48
- updateAgeOnGet: false,
43
+
44
+ // Estimate memory usage per entry
45
+ sizeCalculation: (value, key) => {
46
+ try {
47
+ return Buffer.byteLength(JSON.stringify(value));
48
+ } catch (err) {
49
+ // fallback small size if stringify fails
50
+ return 1024;
51
+ }
52
+ },
49
53
  });
50
54
  }
51
55
 
56
+ /**
57
+ * Get cached value
58
+ * @param {string} key
59
+ * @returns {*} value or null
60
+ */
52
61
  get(key) {
53
62
  const value = this.cache.get(key);
54
63
  return value === undefined ? null : value;
55
64
  }
56
65
 
57
- set(key, value, ttl = null) {
58
- if (ttl !== null) {
66
+ /**
67
+ * Set cache value
68
+ * @param {string} key
69
+ * @param {*} value
70
+ * @param {number} ttl Optional TTL in ms
71
+ */
72
+ set(key, value, ttl = 0) {
73
+ if (ttl > 0) {
59
74
  this.cache.set(key, value, { ttl });
60
75
  } else {
61
76
  this.cache.set(key, value);
62
77
  }
63
78
  }
64
79
 
65
- has(key) {
66
- return this.cache.has(key);
67
- }
68
-
69
- delete(key) {
70
- return this.cache.delete(key);
71
- }
72
-
73
- clear() {
74
- this.cache.clear();
80
+ /**
81
+ * Delete a key
82
+ * @param {string} key
83
+ */
84
+ del(key) {
85
+ this.cache.delete(key);
75
86
  }
76
87
 
77
88
  /**
78
- * Get value or compute + store it
79
- * Supports async functions
89
+ * Clear entire cache
80
90
  */
81
- async getOrSet(key, fetchFn, ttl = null) {
82
- const existing = this.get(key);
83
- if (existing !== null) return existing;
84
-
85
- const value = await fetchFn();
86
- this.set(key, value, ttl);
87
- return value;
91
+ clear() {
92
+ this.cache.clear();
88
93
  }
89
94
 
90
95
  /**
91
- * Basic cache stats
96
+ * Get cache stats (optional utility)
92
97
  */
93
98
  stats() {
94
99
  return {
95
100
  size: this.cache.size,
96
101
  calculatedSize: this.cache.calculatedSize,
102
+ maxSize: this.cache.maxSize,
97
103
  };
98
104
  }
99
105
  }
@@ -124,7 +130,7 @@ class DB {
124
130
  static config = null;
125
131
  static pool = null;
126
132
 
127
- static cache = new SimpleCache({ max: 1000, ttl: 60_000 });
133
+ static cache = new SimpleCache({ maxSizeMB: 500, defaultTTL: 1000 * 60 * 2});
128
134
  static retryAttempts = 1;
129
135
 
130
136
  static eventHandlers = { query: [], error: [], reconnect: [] };
@@ -929,16 +935,78 @@ class Collection extends Array {
929
935
  // -------------------------
930
936
  // Filtering
931
937
  // -------------------------
932
- where(key, value) {
933
- return new Collection(this.filter(item => item?.[key] === value));
938
+ /**
939
+ * Enhanced filter:
940
+ * - filter(fn)
941
+ * - filter({ key: value })
942
+ * - filter('key', value)
943
+ * - filter('key', '>', value)
944
+ */
945
+ filter(condition, operator = null, value = null) {
946
+
947
+ // 1️⃣ Callback style
948
+ if (typeof condition === 'function') {
949
+ return new Collection(
950
+ Array.prototype.filter.call(this, condition)
951
+ );
952
+ }
953
+
954
+ // 2️⃣ Object style
955
+ if (typeof condition === 'object' && !Array.isArray(condition)) {
956
+ return new Collection(
957
+ Array.prototype.filter.call(this, item =>
958
+ Object.entries(condition).every(
959
+ ([k, v]) => item?.[k] === v
960
+ )
961
+ )
962
+ );
963
+ }
964
+
965
+ // 3️⃣ Key/value or key/operator/value
966
+ if (typeof condition === 'string') {
967
+
968
+ // If only 2 args → assume "="
969
+ if (value === null) {
970
+ value = operator;
971
+ operator = '=';
972
+ }
973
+
974
+ return new Collection(
975
+ Array.prototype.filter.call(this, item => {
976
+ const field = item?.[condition];
977
+
978
+ switch (operator) {
979
+ case '=':
980
+ case '==': return field == value;
981
+ case '===': return field === value;
982
+ case '!=': return field != value;
983
+ case '!==': return field !== value;
984
+ case '>': return field > value;
985
+ case '>=': return field >= value;
986
+ case '<': return field < value;
987
+ case '<=': return field <= value;
988
+ case 'in': return Array.isArray(value) && value.includes(field);
989
+ case 'not in': return Array.isArray(value) && !value.includes(field);
990
+ default: return false;
991
+ }
992
+ })
993
+ );
994
+ }
995
+
996
+ return new Collection();
997
+ }
998
+
999
+ // Laravel-style aliases
1000
+ where(key, operator, value = null) {
1001
+ return this.filter(key, operator, value);
934
1002
  }
935
1003
 
936
1004
  whereNot(key, value) {
937
- return new Collection(this.filter(item => item?.[key] !== value));
1005
+ return this.filter(item => item?.[key] !== value);
938
1006
  }
939
1007
 
940
1008
  filterNull() {
941
- return new Collection(this.filter(v => v !== null && v !== undefined));
1009
+ return this.filter(v => v !== null && v !== undefined);
942
1010
  }
943
1011
 
944
1012
  onlyKeys(keys) {
@@ -3217,22 +3285,31 @@ class Model {
3217
3285
  // ──────────────────────────────
3218
3286
  static async all() { return await this.query().get(); }
3219
3287
  static where(...args) { return this.query().where(...args); }
3288
+ // static filter(...args) { return this.query().where(...args); }
3220
3289
  static whereIn(col, arr) { return this.query().whereIn(col, arr); }
3221
3290
  static whereNot(...args) { return this.query().whereNot(...args); }
3222
3291
  static whereNotIn(col, arr) { return this.query().whereNotIn(col, arr); }
3223
3292
  static whereNull(col) { return this.query().whereNull(col); }
3224
3293
 
3294
+ static filter(...args) {
3295
+ const qb = this.query();
3296
+ if (args.length === 1 && typeof args[0] === 'object' && !Array.isArray(args[0])) {
3297
+ for (const [key, value] of Object.entries(args[0])) {
3298
+ qb.where(key, value);
3299
+ }
3300
+ return qb;
3301
+ }
3302
+ return qb.where(...args);
3303
+ }
3304
+
3225
3305
  static async find(value) {
3226
3306
  if (value === undefined || value === null) return null;
3227
-
3228
3307
  const query = this.query();
3229
-
3230
3308
  // If numeric → try primary key first
3231
3309
  if (!isNaN(value)) {
3232
3310
  const row = await query.where(this.primaryKey, value).first();
3233
3311
  if (row) return row;
3234
3312
  }
3235
-
3236
3313
  // Fallback or non-numeric → try slug
3237
3314
  return await this.query()
3238
3315
  .where(this.slugKey, value)
@@ -3965,155 +4042,79 @@ class Session extends Model {
3965
4042
  let SessionModel = null;
3966
4043
 
3967
4044
  try {
3968
- // If this throws, DB-backed sessions are simply disabled
3969
4045
  SessionModel = Session;
3970
4046
  } catch (err) {
3971
4047
  SessionModel = null;
3972
4048
  }
3973
4049
 
3974
4050
  /* -------------------- Store -------------------- */
4051
+ const { promisify } = require('util');
4052
+
4053
+ const gzip = promisify(zlib.gzip);
4054
+ const gunzip = promisify(zlib.gunzip);
4055
+
3975
4056
  class LamixSessionStore extends session.Store {
3976
4057
  constructor(options = {}) {
3977
4058
  super();
3978
4059
 
3979
- this.ttl = options.ttl || 86400;
4060
+ this.ttl = options.ttl || 86400; // seconds
3980
4061
  this.cleanupInterval = options.cleanupInterval || 60000;
3981
- this.logger = options.logger || console;
3982
- this.compress = options.compress ?? true;
3983
-
3984
- /* -------- In-memory cache -------- */
3985
- this.cache = new LRUCache({
3986
- max: options.cacheSize || 1000,
3987
- ttl: options.cacheTTL || 60000,
3988
- });
3989
-
3990
- /* -------- Redis -------- */
3991
- this.redisEnabled = false;
3992
- this.redisRetryAt = 0;
3993
- this.redisCooldown = options.redisCooldown || 30000;
3994
-
3995
- if (options.redis) {
3996
- this.redis =
3997
- options.redis instanceof Redis
3998
- ? options.redis
3999
- : new Redis(options.redis);
4000
-
4001
- this._checkRedisHealth();
4002
- }
4003
4062
 
4004
4063
  this._startCleanup();
4005
4064
  }
4006
4065
 
4007
- /* -------------------- Safety Helpers -------------------- */
4008
- _safeCb(cb, err, result = null) {
4009
- try {
4010
- cb(err, result);
4011
- } catch (e) {
4012
- this.logger.error('Session callback threw', e);
4013
- }
4014
- }
4015
-
4016
- _hasSessionModel() {
4017
- return !!SessionModel;
4018
- }
4019
-
4020
- _canUseRedis() {
4021
- return this.redisEnabled && Date.now() > this.redisRetryAt;
4022
- }
4023
-
4024
- _markRedisFailure(err) {
4025
- this.redisEnabled = false;
4026
- this.redisRetryAt = Date.now() + this.redisCooldown;
4027
- this.logger.warn('Redis disabled temporarily', err);
4028
- }
4029
-
4030
- /* -------------------- Serialization -------------------- */
4031
- _serialize(data) {
4032
- try {
4033
- const json = JSON.stringify(data);
4034
- return this.compress
4035
- ? zlib.deflateSync(Buffer.from(json)).toString('base64')
4036
- : json;
4037
- } catch (err) {
4038
- this.logger.warn('Serialize failed, skipping persistence', err);
4039
- return null;
4040
- }
4041
- }
4042
-
4043
- _deserialize(raw) {
4044
- if (!raw) return null;
4066
+ /* ---------- Get ---------- */
4045
4067
 
4068
+ async get(sid, cb) {
4046
4069
  try {
4047
- const str = this.compress
4048
- ? zlib.inflateSync(Buffer.from(raw, 'base64')).toString()
4049
- : raw;
4070
+ const now = Date.now();
4050
4071
 
4051
- return JSON.parse(str);
4052
- } catch (err) {
4053
- this.logger.warn('Deserialize failed, dropping session', err);
4054
- return null;
4055
- }
4056
- }
4057
-
4058
- /* -------------------- Redis Health -------------------- */
4059
- async _checkRedisHealth() {
4060
- try {
4061
- await this.redis.ping();
4062
- this.redisEnabled = true;
4063
- this.logger.info('Redis session store active');
4064
-
4065
- this.redis.on('error', (err) => this._markRedisFailure(err));
4066
- this.redis.on('connect', () => {
4067
- this.redisEnabled = true;
4068
- this.logger.info('Redis reconnected');
4069
- });
4070
- } catch (err) {
4071
- this.redisEnabled = false;
4072
- this.logger.warn('Redis unavailable', err);
4073
- }
4074
- }
4072
+ const row = await Session
4073
+ .query()
4074
+ .where('sid', sid)
4075
+ .where('expires', '>', now)
4076
+ .first();
4075
4077
 
4076
- /* -------------------- GET -------------------- */
4077
- async get(sid, cb) {
4078
- let sessionData = null;
4078
+ if (!row) return cb(null, null);
4079
4079
 
4080
- try {
4081
- if (this.cache.has(sid)) {
4082
- return this._safeCb(cb, null, this.cache.get(sid));
4083
- }
4080
+ let sessionJSON;
4084
4081
 
4085
- if (this._canUseRedis()) {
4086
- try {
4087
- const raw = await this.redis.get(`sess:${sid}`);
4088
- sessionData = this._deserialize(raw);
4089
- } catch (err) {
4090
- this._markRedisFailure(err);
4091
- }
4082
+ // ---------- Step 1: Decompress ----------
4083
+ try {
4084
+ const buffer = Buffer.from(row.data, 'base64');
4085
+ const decompressed = await gunzip(buffer);
4086
+ sessionJSON = decompressed.toString('utf8');
4087
+ } catch {
4088
+ // fallback to legacy plain JSON
4089
+ sessionJSON = row.data;
4092
4090
  }
4093
4091
 
4094
- if (!sessionData && this._hasSessionModel()) {
4095
- try {
4096
- const row = await SessionModel.query()
4097
- .where('sid', sid)
4098
- .where('expires', '>', Date.now())
4099
- .first();
4092
+ // ---------- Step 2: Parse JSON safely ----------
4093
+ try {
4094
+ const parsed = JSON.parse(sessionJSON);
4095
+ return cb(null, parsed);
4096
+ } catch (parseErr) {
4097
+ console.warn('Corrupted session detected. Destroying:', sid);
4098
+
4099
+ // destroy corrupted session
4100
+ await Session
4101
+ .query()
4102
+ .where('sid', sid)
4103
+ .delete();
4100
4104
 
4101
- if (row) sessionData = this._deserialize(row.data);
4102
- } catch (err) {
4103
- this.logger.warn('DB GET failed, disabling DB sessions', err);
4104
- SessionModel = null;
4105
- }
4105
+ return cb(null, null); // treat as no session
4106
4106
  }
4107
4107
 
4108
- if (sessionData) this.cache.set(sid, sessionData);
4109
- this._safeCb(cb, null, sessionData);
4110
4108
  } catch (err) {
4111
- this.logger.error('GET failed safely', err);
4112
- this._safeCb(cb, null, null);
4109
+ console.error('Session GET failed:', err);
4110
+
4111
+ // IMPORTANT: never pass fatal error to express-session
4112
+ return cb(null, null);
4113
4113
  }
4114
4114
  }
4115
4115
 
4116
- /* -------------------- SET -------------------- */
4116
+ /* ---------- Set ---------- */
4117
+
4117
4118
  async set(sid, sessionData, cb) {
4118
4119
  try {
4119
4120
  const expires =
@@ -4121,75 +4122,63 @@ class LamixSessionStore extends session.Store {
4121
4122
  ? new Date(sessionData.cookie.expires).getTime()
4122
4123
  : Date.now() + this.ttl * 1000;
4123
4124
 
4124
- const data = this._serialize(sessionData);
4125
- if (!data) return this._safeCb(cb, null);
4125
+ const json = JSON.stringify(sessionData);
4126
4126
 
4127
- this.cache.set(sid, sessionData);
4127
+ // Async compression (non-blocking)
4128
+ const compressed = await gzip(json);
4129
+ const base64Data = compressed.toString('base64');
4128
4130
 
4129
- if (this._hasSessionModel()) {
4130
- try {
4131
- const existing = await SessionModel.query()
4132
- .where('sid', sid)
4133
- .first();
4134
-
4135
- if (existing) {
4136
- await existing.update({ data, expires });
4137
- } else {
4138
- await new SessionModel({ sid, data, expires }, false).saveNew();
4139
- }
4140
- } catch (err) {
4141
- this.logger.warn('DB SET failed, disabling DB sessions', err);
4142
- SessionModel = null;
4143
- }
4144
- }
4131
+ const payload = {
4132
+ sid,
4133
+ data: base64Data,
4134
+ expires
4135
+ };
4145
4136
 
4146
- if (this._canUseRedis()) {
4147
- try {
4148
- await this.redis.set(`sess:${sid}`, data, 'PX', expires - Date.now());
4149
- } catch (err) {
4150
- this._markRedisFailure(err);
4151
- }
4137
+ const existing = await Session
4138
+ .query()
4139
+ .where('sid', sid)
4140
+ .first();
4141
+
4142
+ if (existing) {
4143
+ await existing.update(payload);
4144
+ } else {
4145
+ const session = new Session(payload, false);
4146
+ await session.saveNew(payload);
4152
4147
  }
4153
4148
 
4154
- this._safeCb(cb, null);
4149
+ cb(null);
4155
4150
  } catch (err) {
4156
- this.logger.error('SET failed safely', err);
4157
- this._safeCb(cb, null);
4151
+ cb(new DBError('Failed to persist session', {
4152
+ sid,
4153
+ operation: 'set',
4154
+ err
4155
+ }));
4158
4156
  }
4159
4157
  }
4160
4158
 
4161
- /* -------------------- DESTROY -------------------- */
4159
+ /* ---------- Destroy ---------- */
4160
+
4162
4161
  async destroy(sid, cb) {
4163
4162
  try {
4164
- this.cache.delete(sid);
4163
+ await Session
4164
+ .query()
4165
+ .where('sid', sid)
4166
+ .delete();
4165
4167
 
4166
- if (this._hasSessionModel()) {
4167
- try {
4168
- await SessionModel.query().where('sid', sid).delete();
4169
- } catch (err) {
4170
- this.logger.warn('DB DESTROY failed, disabling DB sessions', err);
4171
- SessionModel = null;
4172
- }
4173
- }
4174
-
4175
- if (this._canUseRedis()) {
4176
- try {
4177
- await this.redis.del(`sess:${sid}`);
4178
- } catch (err) {
4179
- this._markRedisFailure(err);
4180
- }
4181
- }
4182
-
4183
- this._safeCb(cb, null);
4168
+ cb(null);
4184
4169
  } catch (err) {
4185
- this.logger.error('DESTROY failed safely', err);
4186
- this._safeCb(cb, null);
4170
+ cb(new DBError('Failed to destroy session', {
4171
+ sid,
4172
+ operation: 'destroy',
4173
+ err
4174
+ }));
4187
4175
  }
4188
4176
  }
4189
4177
 
4190
- /* -------------------- TOUCH -------------------- */
4178
+ /* ---------- Touch ---------- */
4179
+
4191
4180
  async touch(sid, sessionData, cb) {
4192
- if (!sessionData) return this._safeCb(cb, null);
4181
+ if (!sessionData) return cb(null);
4193
4182
 
4194
4183
  try {
4195
4184
  const expires =
@@ -4197,45 +4186,37 @@ class LamixSessionStore extends session.Store {
4197
4186
  ? new Date(sessionData.cookie.expires).getTime()
4198
4187
  : Date.now() + this.ttl * 1000;
4199
4188
 
4200
- this.cache.set(sid, sessionData);
4189
+ await Session
4190
+ .query()
4191
+ .where('sid', sid)
4192
+ .update({ expires });
4201
4193
 
4202
- if (this._hasSessionModel()) {
4203
- try {
4204
- await SessionModel.query().where('sid', sid).update({ expires });
4205
- } catch (err) {
4206
- this.logger.warn('DB TOUCH failed, disabling DB sessions', err);
4207
- SessionModel = null;
4208
- }
4209
- }
4210
-
4211
- if (this._canUseRedis()) {
4212
- try {
4213
- await this.redis.pexpire(`sess:${sid}`, expires - Date.now());
4214
- } catch (err) {
4215
- this._markRedisFailure(err);
4216
- }
4217
- }
4218
-
4219
- this._safeCb(cb, null);
4194
+ cb();
4220
4195
  } catch (err) {
4221
- this.logger.error('TOUCH failed safely', err);
4222
- this._safeCb(cb, null);
4196
+ cb(new DBError('Failed to touch session', {
4197
+ sid,
4198
+ operation: 'touch',
4199
+ err
4200
+ }));
4223
4201
  }
4224
4202
  }
4225
4203
 
4226
- /* -------------------- Cleanup -------------------- */
4227
- _startCleanup() {
4228
- if (!this._hasSessionModel()) return;
4204
+ /* ---------- Cleanup ---------- */
4229
4205
 
4206
+ _startCleanup() {
4230
4207
  this._cleanupTimer = setInterval(async () => {
4231
4208
  try {
4232
- await SessionModel.query()
4209
+ await Session
4210
+ .query()
4233
4211
  .where('expires', '<', Date.now())
4234
4212
  .delete();
4235
4213
  } catch (err) {
4236
- this.logger.warn('Cleanup failed, disabling DB sessions', err);
4237
- SessionModel = null;
4238
- clearInterval(this._cleanupTimer);
4214
+ console.error(
4215
+ new DBError('Session cleanup failed', {
4216
+ operation: 'cleanup',
4217
+ err
4218
+ })
4219
+ );
4239
4220
  }
4240
4221
  }, this.cleanupInterval);
4241
4222
 
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "lamix",
3
- "version": "4.2.19",
3
+ "version": "4.2.21",
4
4
  "description": "lamix - ORM for Node-express js",
5
- "main": "./lib",
5
+ "main": "./lib/index.js",
6
6
  "type": "commonjs",
7
7
  "exports": {
8
8
  ".": {
@@ -32,7 +32,6 @@
32
32
  "bcrypt": "^6.0.0",
33
33
  "express-session": "^1.19.0",
34
34
  "lru-cache": "^11.2.5",
35
- "ioredis": "^5.9.2",
36
35
  "chalk": "^4.1.2",
37
36
  "dotenv": "^17.2.4 "
38
37
  },