@arikajs/session 0.0.5
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 +429 -0
- package/dist/Contracts/SessionDriver.d.ts +33 -0
- package/dist/Contracts/SessionDriver.d.ts.map +1 -0
- package/dist/Contracts/SessionDriver.js +3 -0
- package/dist/Contracts/SessionDriver.js.map +1 -0
- package/dist/CookieSessionId.d.ts +35 -0
- package/dist/CookieSessionId.d.ts.map +1 -0
- package/dist/CookieSessionId.js +129 -0
- package/dist/CookieSessionId.js.map +1 -0
- package/dist/Drivers/DatabaseDriver.d.ts +19 -0
- package/dist/Drivers/DatabaseDriver.d.ts.map +1 -0
- package/dist/Drivers/DatabaseDriver.js +90 -0
- package/dist/Drivers/DatabaseDriver.js.map +1 -0
- package/dist/Drivers/FileDriver.d.ts +18 -0
- package/dist/Drivers/FileDriver.d.ts.map +1 -0
- package/dist/Drivers/FileDriver.js +170 -0
- package/dist/Drivers/FileDriver.js.map +1 -0
- package/dist/Drivers/MemoryDriver.d.ts +16 -0
- package/dist/Drivers/MemoryDriver.d.ts.map +1 -0
- package/dist/Drivers/MemoryDriver.js +53 -0
- package/dist/Drivers/MemoryDriver.js.map +1 -0
- package/dist/Drivers/RedisDriver.d.ts +20 -0
- package/dist/Drivers/RedisDriver.d.ts.map +1 -0
- package/dist/Drivers/RedisDriver.js +54 -0
- package/dist/Drivers/RedisDriver.js.map +1 -0
- package/dist/Middleware/StartSession.d.ts +19 -0
- package/dist/Middleware/StartSession.d.ts.map +1 -0
- package/dist/Middleware/StartSession.js +109 -0
- package/dist/Middleware/StartSession.js.map +1 -0
- package/dist/Session.d.ts +88 -0
- package/dist/Session.d.ts.map +1 -0
- package/dist/Session.js +232 -0
- package/dist/Session.js.map +1 -0
- package/dist/SessionManager.d.ts +51 -0
- package/dist/SessionManager.d.ts.map +1 -0
- package/dist/SessionManager.js +117 -0
- package/dist/SessionManager.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DatabaseDriver = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* DatabaseDriver — stores sessions using a SQL database table.
|
|
6
|
+
* Depends on the application's database instance implementing basic
|
|
7
|
+
* table(), where(), update(), insert(), and delete() methods.
|
|
8
|
+
*/
|
|
9
|
+
class DatabaseDriver {
|
|
10
|
+
constructor(database, table = 'sessions', connection) {
|
|
11
|
+
this.database = database;
|
|
12
|
+
this.table = table;
|
|
13
|
+
this.connection = connection;
|
|
14
|
+
}
|
|
15
|
+
async load(sessionId) {
|
|
16
|
+
const session = await this.database.table(this.table, this.connection)
|
|
17
|
+
.where('id', sessionId)
|
|
18
|
+
.first();
|
|
19
|
+
if (!session)
|
|
20
|
+
return null;
|
|
21
|
+
if (session.expiration && session.expiration <= Math.floor(Date.now() / 1000)) {
|
|
22
|
+
await this.destroy(sessionId);
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(session.payload);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async save(sessionId, data, ttlSeconds) {
|
|
33
|
+
const payload = JSON.stringify(data);
|
|
34
|
+
const expiration = Math.floor(Date.now() / 1000) + ttlSeconds;
|
|
35
|
+
const exists = await this.database.table(this.table, this.connection)
|
|
36
|
+
.where('id', sessionId)
|
|
37
|
+
.exists();
|
|
38
|
+
if (exists) {
|
|
39
|
+
await this.database.table(this.table, this.connection)
|
|
40
|
+
.where('id', sessionId)
|
|
41
|
+
.update({ payload, expiration });
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
// Need to insert user_id into the table as well if this is a framework user
|
|
45
|
+
let userId = null;
|
|
46
|
+
if (data['auth_user_id']) {
|
|
47
|
+
userId = data['auth_user_id'];
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
await this.database.table(this.table, this.connection).insert({
|
|
51
|
+
id: sessionId,
|
|
52
|
+
user_id: userId,
|
|
53
|
+
ip_address: null, // these could be populated via middleware later
|
|
54
|
+
user_agent: null,
|
|
55
|
+
payload,
|
|
56
|
+
expiration,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Ignore duplicate key errors if two requests spawn here due to race
|
|
61
|
+
await this.database.table(this.table, this.connection)
|
|
62
|
+
.where('id', sessionId)
|
|
63
|
+
.update({ payload, expiration });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async destroy(sessionId) {
|
|
68
|
+
await this.database.table(this.table, this.connection)
|
|
69
|
+
.where('id', sessionId)
|
|
70
|
+
.delete();
|
|
71
|
+
}
|
|
72
|
+
async gc(maxLifetimeSeconds) {
|
|
73
|
+
// Collect everything <= current time
|
|
74
|
+
const now = Math.floor(Date.now() / 1000);
|
|
75
|
+
await this.database.table(this.table, this.connection)
|
|
76
|
+
.where('expiration', '<=', now)
|
|
77
|
+
.delete();
|
|
78
|
+
}
|
|
79
|
+
async acquireLock(sessionId, timeoutSeconds) {
|
|
80
|
+
// Simple pessimistic locking in a separate locks table, or just use DB transactions.
|
|
81
|
+
// For simplicity and to avoid creating a new table, we attempt to save a lock flag or rely on DB timeouts.
|
|
82
|
+
// Returning true here as a simple mock; true database locking requires named locks or a dedicated lock column.
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
async releaseLock(sessionId) {
|
|
86
|
+
// Release logic goes here.
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
exports.DatabaseDriver = DatabaseDriver;
|
|
90
|
+
//# sourceMappingURL=DatabaseDriver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DatabaseDriver.js","sourceRoot":"","sources":["../../src/Drivers/DatabaseDriver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { SessionDriver } from '../Contracts/SessionDriver';
|
|
2
|
+
/**
|
|
3
|
+
* FileDriver — stores sessions as JSON files on disk.
|
|
4
|
+
* Suitable for single-server applications. Supports GC via file scanning.
|
|
5
|
+
*/
|
|
6
|
+
export declare class FileDriver implements SessionDriver {
|
|
7
|
+
private readonly directory;
|
|
8
|
+
constructor(directory: string);
|
|
9
|
+
private ensureDirectory;
|
|
10
|
+
private filePath;
|
|
11
|
+
load(sessionId: string): Promise<Record<string, any> | null>;
|
|
12
|
+
save(sessionId: string, data: Record<string, any>, ttlSeconds: number): Promise<void>;
|
|
13
|
+
destroy(sessionId: string): Promise<void>;
|
|
14
|
+
gc(maxLifetimeSeconds: number): Promise<void>;
|
|
15
|
+
acquireLock(sessionId: string, timeoutSeconds: number): Promise<boolean>;
|
|
16
|
+
releaseLock(sessionId: string): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=FileDriver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileDriver.d.ts","sourceRoot":"","sources":["../../src/Drivers/FileDriver.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAO3D;;;GAGG;AACH,qBAAa,UAAW,YAAW,aAAa;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,MAAM;IAI9C,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,QAAQ;IAWH,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IAmB5D,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAcrF,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOzC,EAAE,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4B7C,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAuBxE,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAM7D"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.FileDriver = void 0;
|
|
37
|
+
const fs = __importStar(require("node:fs"));
|
|
38
|
+
const path = __importStar(require("node:path"));
|
|
39
|
+
const crypto = __importStar(require("node:crypto"));
|
|
40
|
+
/**
|
|
41
|
+
* FileDriver — stores sessions as JSON files on disk.
|
|
42
|
+
* Suitable for single-server applications. Supports GC via file scanning.
|
|
43
|
+
*/
|
|
44
|
+
class FileDriver {
|
|
45
|
+
constructor(directory) {
|
|
46
|
+
this.directory = directory;
|
|
47
|
+
this.ensureDirectory();
|
|
48
|
+
}
|
|
49
|
+
ensureDirectory() {
|
|
50
|
+
if (!fs.existsSync(this.directory)) {
|
|
51
|
+
fs.mkdirSync(this.directory, { recursive: true });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
filePath(sessionId) {
|
|
55
|
+
// Use a simple hash-based subdirectory to avoid huge flat folders
|
|
56
|
+
const hash = crypto.createHash('md5').update(sessionId).digest('hex');
|
|
57
|
+
const sub = hash.slice(0, 2);
|
|
58
|
+
const dir = path.join(this.directory, sub);
|
|
59
|
+
if (!fs.existsSync(dir)) {
|
|
60
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
61
|
+
}
|
|
62
|
+
return path.join(dir, `${sessionId}.json`);
|
|
63
|
+
}
|
|
64
|
+
async load(sessionId) {
|
|
65
|
+
const file = this.filePath(sessionId);
|
|
66
|
+
if (!fs.existsSync(file))
|
|
67
|
+
return null;
|
|
68
|
+
try {
|
|
69
|
+
const raw = fs.readFileSync(file, 'utf8');
|
|
70
|
+
const entry = JSON.parse(raw);
|
|
71
|
+
if (Date.now() > entry.expiresAt) {
|
|
72
|
+
fs.unlinkSync(file);
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
return entry.data;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async save(sessionId, data, ttlSeconds) {
|
|
82
|
+
const file = this.filePath(sessionId);
|
|
83
|
+
const entry = {
|
|
84
|
+
data,
|
|
85
|
+
expiresAt: Date.now() + ttlSeconds * 1000,
|
|
86
|
+
};
|
|
87
|
+
try {
|
|
88
|
+
fs.writeFileSync(file, JSON.stringify(entry), 'utf8');
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// Silently fail — don't crash the request
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async destroy(sessionId) {
|
|
95
|
+
const file = this.filePath(sessionId);
|
|
96
|
+
if (fs.existsSync(file)) {
|
|
97
|
+
try {
|
|
98
|
+
fs.unlinkSync(file);
|
|
99
|
+
}
|
|
100
|
+
catch { }
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async gc(maxLifetimeSeconds) {
|
|
104
|
+
const now = Date.now();
|
|
105
|
+
const maxMs = maxLifetimeSeconds * 1000;
|
|
106
|
+
const scanDir = (dir) => {
|
|
107
|
+
if (!fs.existsSync(dir))
|
|
108
|
+
return;
|
|
109
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
110
|
+
const fullPath = path.join(dir, entry.name);
|
|
111
|
+
if (entry.isDirectory()) {
|
|
112
|
+
scanDir(fullPath);
|
|
113
|
+
}
|
|
114
|
+
else if (entry.name.endsWith('.json')) {
|
|
115
|
+
try {
|
|
116
|
+
const raw = fs.readFileSync(fullPath, 'utf8');
|
|
117
|
+
const session = JSON.parse(raw);
|
|
118
|
+
if (now > session.expiresAt) {
|
|
119
|
+
fs.unlinkSync(fullPath);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// Corrupt file — remove it
|
|
124
|
+
try {
|
|
125
|
+
fs.unlinkSync(fullPath);
|
|
126
|
+
}
|
|
127
|
+
catch { }
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
scanDir(this.directory);
|
|
133
|
+
}
|
|
134
|
+
async acquireLock(sessionId, timeoutSeconds) {
|
|
135
|
+
const lockPath = this.filePath(sessionId) + '.lock';
|
|
136
|
+
if (fs.existsSync(lockPath)) {
|
|
137
|
+
try {
|
|
138
|
+
const stat = fs.statSync(lockPath);
|
|
139
|
+
// If it's stale, break it
|
|
140
|
+
if (Date.now() - stat.mtimeMs > timeoutSeconds * 1000) {
|
|
141
|
+
fs.unlinkSync(lockPath);
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
try {
|
|
152
|
+
fs.writeFileSync(lockPath, '', { flag: 'wx' });
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
async releaseLock(sessionId) {
|
|
160
|
+
const lockPath = this.filePath(sessionId) + '.lock';
|
|
161
|
+
if (fs.existsSync(lockPath)) {
|
|
162
|
+
try {
|
|
163
|
+
fs.unlinkSync(lockPath);
|
|
164
|
+
}
|
|
165
|
+
catch { }
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
exports.FileDriver = FileDriver;
|
|
170
|
+
//# sourceMappingURL=FileDriver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileDriver.js","sourceRoot":"","sources":["../../src/Drivers/FileDriver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { SessionDriver } from '../Contracts/SessionDriver';
|
|
2
|
+
/**
|
|
3
|
+
* MemoryDriver — stores sessions in a JavaScript Map.
|
|
4
|
+
* ⚠️ Development only. Data is lost on server restart and not shared across processes.
|
|
5
|
+
*/
|
|
6
|
+
export declare class MemoryDriver implements SessionDriver {
|
|
7
|
+
private store;
|
|
8
|
+
load(sessionId: string): Promise<Record<string, any> | null>;
|
|
9
|
+
save(sessionId: string, data: Record<string, any>, ttlSeconds: number): Promise<void>;
|
|
10
|
+
destroy(sessionId: string): Promise<void>;
|
|
11
|
+
gc(maxLifetimeSeconds: number): Promise<void>;
|
|
12
|
+
private lockedSessions;
|
|
13
|
+
acquireLock(sessionId: string, timeoutSeconds: number): Promise<boolean>;
|
|
14
|
+
releaseLock(sessionId: string): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=MemoryDriver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MemoryDriver.d.ts","sourceRoot":"","sources":["../../src/Drivers/MemoryDriver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAE3D;;;GAGG;AACH,qBAAa,YAAa,YAAW,aAAa;IAC9C,OAAO,CAAC,KAAK,CAA4E;IAE5E,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IAU5D,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOrF,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC,EAAE,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS1D,OAAO,CAAC,cAAc,CAA0B;IAEnC,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IASxE,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG7D"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MemoryDriver = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* MemoryDriver — stores sessions in a JavaScript Map.
|
|
6
|
+
* ⚠️ Development only. Data is lost on server restart and not shared across processes.
|
|
7
|
+
*/
|
|
8
|
+
class MemoryDriver {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.store = new Map();
|
|
11
|
+
this.lockedSessions = new Set();
|
|
12
|
+
}
|
|
13
|
+
async load(sessionId) {
|
|
14
|
+
const entry = this.store.get(sessionId);
|
|
15
|
+
if (!entry)
|
|
16
|
+
return null;
|
|
17
|
+
if (Date.now() > entry.expiresAt) {
|
|
18
|
+
this.store.delete(sessionId);
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return entry.data;
|
|
22
|
+
}
|
|
23
|
+
async save(sessionId, data, ttlSeconds) {
|
|
24
|
+
this.store.set(sessionId, {
|
|
25
|
+
data,
|
|
26
|
+
expiresAt: Date.now() + ttlSeconds * 1000,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
async destroy(sessionId) {
|
|
30
|
+
this.store.delete(sessionId);
|
|
31
|
+
}
|
|
32
|
+
async gc(maxLifetimeSeconds) {
|
|
33
|
+
const now = Date.now();
|
|
34
|
+
for (const [id, entry] of this.store.entries()) {
|
|
35
|
+
if (now > entry.expiresAt) {
|
|
36
|
+
this.store.delete(id);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async acquireLock(sessionId, timeoutSeconds) {
|
|
41
|
+
if (this.lockedSessions.has(sessionId))
|
|
42
|
+
return false;
|
|
43
|
+
this.lockedSessions.add(sessionId);
|
|
44
|
+
// Auto-release after timeout just in case it crashes
|
|
45
|
+
setTimeout(() => this.lockedSessions.delete(sessionId), timeoutSeconds * 1000);
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
async releaseLock(sessionId) {
|
|
49
|
+
this.lockedSessions.delete(sessionId);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.MemoryDriver = MemoryDriver;
|
|
53
|
+
//# sourceMappingURL=MemoryDriver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MemoryDriver.js","sourceRoot":"","sources":["../../src/Drivers/MemoryDriver.ts"],"names":[],"mappings":";;;AAEA;;;GAGG;AACH,MAAa,YAAY;IAAzB;QACY,UAAK,GAAkE,IAAI,GAAG,EAAE,CAAC;QAgCjF,mBAAc,GAAgB,IAAI,GAAG,EAAE,CAAC;IAcpD,CAAC;IA5CU,KAAK,CAAC,IAAI,CAAC,SAAiB;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACxC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;YAC/B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAC7B,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC;IACtB,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,SAAiB,EAAE,IAAyB,EAAE,UAAkB;QAC9E,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE;YACtB,IAAI;YACJ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI;SAC5C,CAAC,CAAC;IACP,CAAC;IAEM,KAAK,CAAC,OAAO,CAAC,SAAiB;QAClC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC;IAEM,KAAK,CAAC,EAAE,CAAC,kBAA0B;QACtC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YAC7C,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;gBACxB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC1B,CAAC;QACL,CAAC;IACL,CAAC;IAIM,KAAK,CAAC,WAAW,CAAC,SAAiB,EAAE,cAAsB;QAC9D,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC;YAAE,OAAO,KAAK,CAAC;QACrD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAEnC,qDAAqD;QACrD,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC,CAAC;QAC/E,OAAO,IAAI,CAAC;IAChB,CAAC;IAEM,KAAK,CAAC,WAAW,CAAC,SAAiB;QACtC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC1C,CAAC;CACJ;AA/CD,oCA+CC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { SessionDriver } from '../Contracts/SessionDriver';
|
|
2
|
+
import Redis, { Cluster } from 'ioredis';
|
|
3
|
+
/**
|
|
4
|
+
* RedisDriver — stores sessions using Redis.
|
|
5
|
+
* Supports native TTL (no GC needed) and excellent session locking.
|
|
6
|
+
*/
|
|
7
|
+
export declare class RedisDriver implements SessionDriver {
|
|
8
|
+
private readonly redis;
|
|
9
|
+
private readonly prefix;
|
|
10
|
+
constructor(redis: Redis | Cluster, prefix?: string);
|
|
11
|
+
private key;
|
|
12
|
+
private lockKey;
|
|
13
|
+
load(sessionId: string): Promise<Record<string, any> | null>;
|
|
14
|
+
save(sessionId: string, data: Record<string, any>, ttlSeconds: number): Promise<void>;
|
|
15
|
+
destroy(sessionId: string): Promise<void>;
|
|
16
|
+
gc(maxLifetimeSeconds: number): Promise<void>;
|
|
17
|
+
acquireLock(sessionId: string, timeoutSeconds: number): Promise<boolean>;
|
|
18
|
+
releaseLock(sessionId: string): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=RedisDriver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RedisDriver.d.ts","sourceRoot":"","sources":["../../src/Drivers/RedisDriver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzC;;;GAGG;AACH,qBAAa,WAAY,YAAW,aAAa;IAEzC,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,KAAK,EAAE,KAAK,GAAG,OAAO,EACtB,MAAM,GAAE,MAAyB;IAGtD,OAAO,CAAC,GAAG;IAIX,OAAO,CAAC,OAAO;IAIF,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IAU5D,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASrF,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC,EAAE,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7C,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKxE,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG7D"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RedisDriver = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* RedisDriver — stores sessions using Redis.
|
|
6
|
+
* Supports native TTL (no GC needed) and excellent session locking.
|
|
7
|
+
*/
|
|
8
|
+
class RedisDriver {
|
|
9
|
+
constructor(redis, prefix = 'arika_session:') {
|
|
10
|
+
this.redis = redis;
|
|
11
|
+
this.prefix = prefix;
|
|
12
|
+
}
|
|
13
|
+
key(sessionId) {
|
|
14
|
+
return this.prefix + sessionId;
|
|
15
|
+
}
|
|
16
|
+
lockKey(sessionId) {
|
|
17
|
+
return this.prefix + 'lock:' + sessionId;
|
|
18
|
+
}
|
|
19
|
+
async load(sessionId) {
|
|
20
|
+
const raw = await this.redis.get(this.key(sessionId));
|
|
21
|
+
if (!raw)
|
|
22
|
+
return null;
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(raw);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async save(sessionId, data, ttlSeconds) {
|
|
31
|
+
const raw = JSON.stringify(data);
|
|
32
|
+
if (ttlSeconds > 0) {
|
|
33
|
+
await this.redis.set(this.key(sessionId), raw, 'EX', ttlSeconds);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
await this.redis.set(this.key(sessionId), raw);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async destroy(sessionId) {
|
|
40
|
+
await this.redis.del(this.key(sessionId));
|
|
41
|
+
}
|
|
42
|
+
async gc(maxLifetimeSeconds) {
|
|
43
|
+
// Redis handles TTL automatically — no-op.
|
|
44
|
+
}
|
|
45
|
+
async acquireLock(sessionId, timeoutSeconds) {
|
|
46
|
+
const result = await this.redis.set(this.lockKey(sessionId), '1', 'EX', timeoutSeconds, 'NX');
|
|
47
|
+
return result === 'OK';
|
|
48
|
+
}
|
|
49
|
+
async releaseLock(sessionId) {
|
|
50
|
+
await this.redis.del(this.lockKey(sessionId));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.RedisDriver = RedisDriver;
|
|
54
|
+
//# sourceMappingURL=RedisDriver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RedisDriver.js","sourceRoot":"","sources":["../../src/Drivers/RedisDriver.ts"],"names":[],"mappings":";;;AAGA;;;GAGG;AACH,MAAa,WAAW;IACpB,YACqB,KAAsB,EACtB,SAAiB,gBAAgB;QADjC,UAAK,GAAL,KAAK,CAAiB;QACtB,WAAM,GAAN,MAAM,CAA2B;IAClD,CAAC;IAEG,GAAG,CAAC,SAAiB;QACzB,OAAO,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;IACnC,CAAC;IAEO,OAAO,CAAC,SAAiB;QAC7B,OAAO,IAAI,CAAC,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;IAC7C,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,SAAiB;QAC/B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;QACtD,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QACtB,IAAI,CAAC;YACD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,SAAiB,EAAE,IAAyB,EAAE,UAAkB;QAC9E,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACjB,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;QACrE,CAAC;aAAM,CAAC;YACJ,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC;QACnD,CAAC;IACL,CAAC;IAEM,KAAK,CAAC,OAAO,CAAC,SAAiB;QAClC,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;IAC9C,CAAC;IAEM,KAAK,CAAC,EAAE,CAAC,kBAA0B;QACtC,2CAA2C;IAC/C,CAAC;IAEM,KAAK,CAAC,WAAW,CAAC,SAAiB,EAAE,cAAsB;QAC9D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,CAAC,CAAC;QAC9F,OAAO,MAAM,KAAK,IAAI,CAAC;IAC3B,CAAC;IAEM,KAAK,CAAC,WAAW,CAAC,SAAiB;QACtC,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;IAClD,CAAC;CACJ;AAjDD,kCAiDC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { SessionManager } from '../SessionManager';
|
|
2
|
+
/**
|
|
3
|
+
* StartSession middleware.
|
|
4
|
+
*
|
|
5
|
+
* Lifecycle:
|
|
6
|
+
* 1. Read session ID from the request cookie (or generate a new one)
|
|
7
|
+
* 2. Create a Session instance (lazy — does NOT hit storage yet)
|
|
8
|
+
* 3. Attach `request.session` so controllers can use it
|
|
9
|
+
* 4. After response: save dirty session data back to the driver
|
|
10
|
+
* 5. Write Set-Cookie header with (possibly new/rotated) session ID
|
|
11
|
+
* 6. Probabilistically run GC
|
|
12
|
+
*/
|
|
13
|
+
export declare class StartSession {
|
|
14
|
+
private readonly manager;
|
|
15
|
+
constructor(manager: SessionManager);
|
|
16
|
+
handle(request: any, next: (req: any) => Promise<any>, response?: any): Promise<any>;
|
|
17
|
+
private writeSetCookie;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=StartSession.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StartSession.d.ts","sourceRoot":"","sources":["../../src/Middleware/StartSession.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGnD;;;;;;;;;;GAUG;AACH,qBAAa,YAAY;IACT,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,cAAc;IAEvC,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IA8EjG,OAAO,CAAC,cAAc;CAuBzB"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StartSession = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* StartSession middleware.
|
|
6
|
+
*
|
|
7
|
+
* Lifecycle:
|
|
8
|
+
* 1. Read session ID from the request cookie (or generate a new one)
|
|
9
|
+
* 2. Create a Session instance (lazy — does NOT hit storage yet)
|
|
10
|
+
* 3. Attach `request.session` so controllers can use it
|
|
11
|
+
* 4. After response: save dirty session data back to the driver
|
|
12
|
+
* 5. Write Set-Cookie header with (possibly new/rotated) session ID
|
|
13
|
+
* 6. Probabilistically run GC
|
|
14
|
+
*/
|
|
15
|
+
class StartSession {
|
|
16
|
+
constructor(manager) {
|
|
17
|
+
this.manager = manager;
|
|
18
|
+
}
|
|
19
|
+
async handle(request, next, response) {
|
|
20
|
+
const config = this.manager.config;
|
|
21
|
+
const cookieHelper = this.manager.getCookieHelper();
|
|
22
|
+
// 1. Resolve session ID
|
|
23
|
+
const cookieHeader = (typeof request.header === 'function' ? request.header('cookie') : null) ??
|
|
24
|
+
request.req?.headers?.cookie ??
|
|
25
|
+
'';
|
|
26
|
+
let sessionId = cookieHelper.read(cookieHeader);
|
|
27
|
+
let isNewSession = false;
|
|
28
|
+
if (!sessionId) {
|
|
29
|
+
sessionId = cookieHelper.generate();
|
|
30
|
+
isNewSession = true;
|
|
31
|
+
}
|
|
32
|
+
// 2. Create a lazy Session instance
|
|
33
|
+
const session = this.manager.createSession(sessionId);
|
|
34
|
+
// 3. Attach to request
|
|
35
|
+
request.session = session;
|
|
36
|
+
// Acquire lock if enabled
|
|
37
|
+
const locking = config.locking ?? false;
|
|
38
|
+
const lockTimeout = config.lockTimeout ?? 10; // seconds
|
|
39
|
+
let locked = false;
|
|
40
|
+
try {
|
|
41
|
+
if (locking && typeof this.manager.driver().acquireLock === 'function') {
|
|
42
|
+
const startTime = Date.now();
|
|
43
|
+
while (!locked) {
|
|
44
|
+
locked = await this.manager.driver().acquireLock(sessionId, lockTimeout);
|
|
45
|
+
if (locked)
|
|
46
|
+
break;
|
|
47
|
+
if (Date.now() - startTime > lockTimeout * 1000) {
|
|
48
|
+
break; // Timeout reached, proceed anyway to prevent hanging forever
|
|
49
|
+
}
|
|
50
|
+
// Wait 50ms before retrying
|
|
51
|
+
await new Promise(r => setTimeout(r, 50));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// 4. Run pipeline
|
|
55
|
+
const res = await next(request);
|
|
56
|
+
// 5. Persist session
|
|
57
|
+
await session.save();
|
|
58
|
+
// 6. Write cookie (always refresh TTL, or on new session)
|
|
59
|
+
if (isNewSession || session.isDirty() || !session.isDestroyed()) {
|
|
60
|
+
const cookieValue = session.isDestroyed()
|
|
61
|
+
? cookieHelper.clear(config.path ?? '/')
|
|
62
|
+
: cookieHelper.write(session.getId(), {
|
|
63
|
+
lifetime: config.lifetime * 60,
|
|
64
|
+
path: config.path ?? '/',
|
|
65
|
+
secure: config.secure ?? false,
|
|
66
|
+
httpOnly: config.httpOnly ?? true,
|
|
67
|
+
sameSite: config.sameSite ?? 'Lax',
|
|
68
|
+
});
|
|
69
|
+
this.writeSetCookie(res, response, cookieValue);
|
|
70
|
+
}
|
|
71
|
+
// 7. GC with configured probability
|
|
72
|
+
const gcProbability = config.gcProbability ?? 0.01;
|
|
73
|
+
if (Math.random() < gcProbability) {
|
|
74
|
+
const maxLifetime = config.lifetime * 60;
|
|
75
|
+
this.manager.driver().gc(maxLifetime).catch(() => { });
|
|
76
|
+
}
|
|
77
|
+
return res;
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
if (locked && typeof this.manager.driver().releaseLock === 'function') {
|
|
81
|
+
await this.manager.driver().releaseLock(sessionId).catch(() => { });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
writeSetCookie(res, fallbackResponse, cookieValue) {
|
|
86
|
+
const targetRes = res || fallbackResponse;
|
|
87
|
+
// If it's an ArikaJS Response object, push to its internal cookies array
|
|
88
|
+
if (targetRes && targetRes._cookies && Array.isArray(targetRes._cookies)) {
|
|
89
|
+
targetRes._cookies.push(cookieValue);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
// Try to write to the underlying Node.js ServerResponse before it is terminated
|
|
93
|
+
const nodeRes = targetRes?.raw ?? null;
|
|
94
|
+
if (nodeRes && typeof nodeRes.setHeader === 'function' && !nodeRes.headersSent) {
|
|
95
|
+
const existing = nodeRes.getHeader('Set-Cookie');
|
|
96
|
+
if (Array.isArray(existing)) {
|
|
97
|
+
nodeRes.setHeader('Set-Cookie', [...existing, cookieValue]);
|
|
98
|
+
}
|
|
99
|
+
else if (typeof existing === 'string') {
|
|
100
|
+
nodeRes.setHeader('Set-Cookie', [existing, cookieValue]);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
nodeRes.setHeader('Set-Cookie', cookieValue);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
exports.StartSession = StartSession;
|
|
109
|
+
//# sourceMappingURL=StartSession.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StartSession.js","sourceRoot":"","sources":["../../src/Middleware/StartSession.ts"],"names":[],"mappings":"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"}
|