@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.
Files changed (42) hide show
  1. package/README.md +429 -0
  2. package/dist/Contracts/SessionDriver.d.ts +33 -0
  3. package/dist/Contracts/SessionDriver.d.ts.map +1 -0
  4. package/dist/Contracts/SessionDriver.js +3 -0
  5. package/dist/Contracts/SessionDriver.js.map +1 -0
  6. package/dist/CookieSessionId.d.ts +35 -0
  7. package/dist/CookieSessionId.d.ts.map +1 -0
  8. package/dist/CookieSessionId.js +129 -0
  9. package/dist/CookieSessionId.js.map +1 -0
  10. package/dist/Drivers/DatabaseDriver.d.ts +19 -0
  11. package/dist/Drivers/DatabaseDriver.d.ts.map +1 -0
  12. package/dist/Drivers/DatabaseDriver.js +90 -0
  13. package/dist/Drivers/DatabaseDriver.js.map +1 -0
  14. package/dist/Drivers/FileDriver.d.ts +18 -0
  15. package/dist/Drivers/FileDriver.d.ts.map +1 -0
  16. package/dist/Drivers/FileDriver.js +170 -0
  17. package/dist/Drivers/FileDriver.js.map +1 -0
  18. package/dist/Drivers/MemoryDriver.d.ts +16 -0
  19. package/dist/Drivers/MemoryDriver.d.ts.map +1 -0
  20. package/dist/Drivers/MemoryDriver.js +53 -0
  21. package/dist/Drivers/MemoryDriver.js.map +1 -0
  22. package/dist/Drivers/RedisDriver.d.ts +20 -0
  23. package/dist/Drivers/RedisDriver.d.ts.map +1 -0
  24. package/dist/Drivers/RedisDriver.js +54 -0
  25. package/dist/Drivers/RedisDriver.js.map +1 -0
  26. package/dist/Middleware/StartSession.d.ts +19 -0
  27. package/dist/Middleware/StartSession.d.ts.map +1 -0
  28. package/dist/Middleware/StartSession.js +109 -0
  29. package/dist/Middleware/StartSession.js.map +1 -0
  30. package/dist/Session.d.ts +88 -0
  31. package/dist/Session.d.ts.map +1 -0
  32. package/dist/Session.js +232 -0
  33. package/dist/Session.js.map +1 -0
  34. package/dist/SessionManager.d.ts +51 -0
  35. package/dist/SessionManager.d.ts.map +1 -0
  36. package/dist/SessionManager.js +117 -0
  37. package/dist/SessionManager.js.map +1 -0
  38. package/dist/index.d.ts +10 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +20 -0
  41. package/dist/index.js.map +1 -0
  42. package/package.json +47 -0
package/README.md ADDED
@@ -0,0 +1,429 @@
1
+ ## Arika Session
2
+
3
+ `@arikajs/session` provides a powerful, secure, and driver-based session management system for the ArikaJS framework.
4
+
5
+ It answers one critical question: **"How do we persist user state across requests?"**
6
+
7
+ ```ts
8
+ req.session.set('user_id', 42);
9
+ req.session.get('user_id'); // 42
10
+ ```
11
+
12
+ ---
13
+
14
+ ### Status
15
+
16
+ - **Stage**: Experimental / v0.x
17
+ - **Scope**:
18
+ - Driver-based session storage (file, memory, redis, database)
19
+ - Flash session data (one-request messages)
20
+ - Cookie-based session identifiers
21
+ - Automatic session lifecycle middleware
22
+ - Session regeneration for security
23
+ - Lazy session loading
24
+ - Write optimization
25
+ - Session locking for concurrency protection
26
+
27
+ - **Design**:
28
+ - Framework-agnostic session manager
29
+ - Pluggable storage drivers
30
+ - Middleware-driven lifecycle
31
+ - Config-driven architecture
32
+ - Environment variable support
33
+
34
+ ---
35
+
36
+ ## ✨ Purpose
37
+
38
+ HTTP is stateless by design.
39
+ Sessions provide a mechanism to persist data across requests.
40
+
41
+ Typical use cases include:
42
+ - Authentication state
43
+ - Flash messages
44
+ - Shopping carts
45
+ - CSRF tokens
46
+ - Multi-step forms
47
+ - User preferences
48
+
49
+ `@arikajs/session` provides a centralized and scalable session system for modern Node.js applications.
50
+
51
+ ---
52
+
53
+ ## 🚀 Features
54
+
55
+ - **Driver-based storage** — Switch between file, memory, Redis, or database drivers.
56
+ - **Flash session support** — Store temporary messages for the next request.
57
+ - **Automatic middleware lifecycle** — Sessions start and persist automatically.
58
+ - **Cookie-based session IDs** — Lightweight and secure.
59
+ - **Session locking** — Prevent race conditions in concurrent requests.
60
+ - **Lazy session loading** — Sessions load only when accessed.
61
+ - **Write optimization** — Avoid unnecessary storage writes.
62
+ - **Session regeneration** — Protect against session fixation attacks.
63
+ - **Environment configuration** — Configure using `.env`.
64
+
65
+ ---
66
+
67
+ ## 📦 Installation
68
+
69
+ ```bash
70
+ npm install @arikajs/session
71
+ ```
72
+
73
+ ---
74
+
75
+ ## 🧠 Core Concepts
76
+
77
+ ### 1️⃣ Sessions
78
+
79
+ A session is a key-value store associated with a user request.
80
+
81
+ ```ts
82
+ req.session.set('name', 'Prakash');
83
+ req.session.set('role', 'admin');
84
+
85
+ req.session.get('name'); // "Prakash"
86
+ ```
87
+
88
+ Session data persists between requests using a session ID stored in cookies.
89
+
90
+ ### 2️⃣ Flash Data
91
+
92
+ Flash data exists for one request only.
93
+ Commonly used for UI notifications such as login success messages.
94
+
95
+ ```ts
96
+ req.session.flash('success', 'Login successful');
97
+ ```
98
+
99
+ Next request:
100
+ ```ts
101
+ req.session.get('success'); // "Login successful"
102
+ ```
103
+ After the response completes, the flash data is automatically removed.
104
+
105
+ ### 3️⃣ Session Regeneration
106
+
107
+ Session IDs should be regenerated after authentication.
108
+
109
+ ```ts
110
+ await req.session.regenerate();
111
+ ```
112
+ This prevents session fixation attacks.
113
+
114
+ ---
115
+
116
+ ## ⚙️ Configuration
117
+
118
+ Sessions are configured via `config/session.ts`.
119
+
120
+ ```ts
121
+ export default {
122
+ driver: process.env.SESSION_DRIVER || 'file',
123
+ lifetime: Number(process.env.SESSION_LIFETIME) || 120,
124
+ cookie: process.env.SESSION_COOKIE || 'arika_session',
125
+ path: process.env.SESSION_PATH || './storage/sessions',
126
+ secure: false,
127
+ httpOnly: true,
128
+ locking: true,
129
+ lockTimeout: 10
130
+ };
131
+ ```
132
+
133
+ ### Environment Variables
134
+
135
+ ```env
136
+ SESSION_DRIVER=file
137
+ SESSION_LIFETIME=120
138
+ SESSION_COOKIE=arika_session
139
+ SESSION_PATH=./storage/sessions
140
+ SESSION_LOCKING=true
141
+ ```
142
+
143
+ ---
144
+
145
+ ## 🧩 Middleware Support
146
+
147
+ Sessions are automatically initialized via middleware.
148
+
149
+ ```ts
150
+ import { StartSession } from '@arikajs/session';
151
+
152
+ app.use(StartSession);
153
+ ```
154
+
155
+ The middleware:
156
+ 1. Reads session ID from cookies
157
+ 2. Loads session data from the configured driver
158
+ 3. Attaches session to the request
159
+ 4. Persists changes after response
160
+
161
+ ---
162
+
163
+ ## 🗂 Session API
164
+
165
+ **Set Value**
166
+ ```ts
167
+ req.session.set('cart_items', 3);
168
+ ```
169
+
170
+ **Get Value**
171
+ ```ts
172
+ req.session.get('cart_items');
173
+ ```
174
+
175
+ **Check Existence**
176
+ ```ts
177
+ req.session.has('cart_items');
178
+ ```
179
+
180
+ **Remove Value**
181
+ ```ts
182
+ req.session.forget('cart_items');
183
+ ```
184
+
185
+ **Destroy Session**
186
+ ```ts
187
+ await req.session.destroy();
188
+ ```
189
+
190
+ ---
191
+
192
+ ## 💾 Storage Drivers
193
+
194
+ `@arikajs/session` supports multiple storage drivers.
195
+
196
+ | Driver | Description |
197
+ | :--- | :--- |
198
+ | `memory` | In-memory storage (development only) |
199
+ | `file` | Filesystem-based sessions |
200
+ | `redis` | Redis distributed session storage |
201
+ | `database` | SQL-based session storage |
202
+
203
+ Example configuration:
204
+ ```ts
205
+ export default {
206
+ driver: 'redis'
207
+ }
208
+ ```
209
+
210
+ Drivers implement a common interface:
211
+ ```ts
212
+ interface SessionDriver {
213
+ load(sessionId: string): Promise<any>;
214
+ save(sessionId: string, data: any): Promise<void>;
215
+ destroy(sessionId: string): Promise<void>;
216
+ }
217
+ ```
218
+
219
+ ---
220
+
221
+ ## 🔐 Session Locking (Concurrency Protection)
222
+
223
+ Modern applications may issue multiple concurrent requests from the same user.
224
+
225
+ Example:
226
+ ```text
227
+ Browser
228
+ ├─ Request A → update-profile
229
+ └─ Request B → add-to-cart
230
+ ```
231
+ Without protection, both requests may overwrite session data.
232
+
233
+ Session locking ensures:
234
+ 1. Request A → acquires lock
235
+ 2. Request B → waits
236
+ 3. Request A → releases lock
237
+ 4. Request B → proceeds
238
+
239
+ Configuration:
240
+ ```ts
241
+ export default {
242
+ locking: true,
243
+ lockTimeout: 10
244
+ }
245
+ ```
246
+
247
+ Recommended drivers:
248
+
249
+ | Driver | Locking Support |
250
+ | :--- | :--- |
251
+ | Redis | Excellent |
252
+ | Database | Good |
253
+ | File | Basic |
254
+ | Memory | Not recommended |
255
+
256
+ ---
257
+
258
+ ## ⚡ Lazy Session Loading
259
+
260
+ Sessions load only when accessed.
261
+
262
+ Example:
263
+ ```ts
264
+ GET /health → session NOT loaded
265
+ GET /dashboard → session loaded
266
+ req.session.get('user_id');
267
+ ```
268
+
269
+ Benefits:
270
+ - Reduced I/O
271
+ - Faster responses
272
+ - Lower memory usage
273
+
274
+ ---
275
+
276
+ ## 🧾 Write Optimization
277
+
278
+ Session storage writes occur only when data changes.
279
+
280
+ Example:
281
+ ```text
282
+ Request → session accessed
283
+ → no changes
284
+ → skip write
285
+ ```
286
+
287
+ But when modified:
288
+ ```ts
289
+ req.session.set('cart', items)
290
+ ```
291
+ Then storage write occurs.
292
+
293
+ Benefits:
294
+ - Reduced Redis calls
295
+ - Reduced disk writes
296
+ - Better scalability
297
+
298
+ ---
299
+
300
+ ## 🧠 Automatic Garbage Collection
301
+
302
+ Expired sessions must be periodically cleaned.
303
+
304
+ Example strategies:
305
+
306
+ | Driver | Cleanup |
307
+ | :--- | :--- |
308
+ | File | Directory cleanup |
309
+ | Redis | Native TTL |
310
+ | Database | Scheduled cleanup |
311
+
312
+ Configuration:
313
+ ```ts
314
+ export default {
315
+ gcProbability: 0.01
316
+ }
317
+ ```
318
+ Meaning 1% of requests trigger cleanup.
319
+
320
+ ---
321
+
322
+ ## 🔁 Session ID Rotation
323
+
324
+ Session IDs can be rotated for additional security.
325
+
326
+ ```ts
327
+ await req.session.regenerate();
328
+ ```
329
+
330
+ Use cases:
331
+ - After login
332
+ - After role escalation
333
+ - After sensitive actions
334
+
335
+ ---
336
+
337
+ ## 🧩 Custom Drivers
338
+
339
+ Developers can implement custom session drivers.
340
+
341
+ ```ts
342
+ class MongoSessionDriver {
343
+ async load(id) { }
344
+ async save(id, data) { }
345
+ async destroy(id) { }
346
+ }
347
+ ```
348
+
349
+ Register driver:
350
+ ```ts
351
+ SessionManager.extend('mongo', () => new MongoSessionDriver());
352
+ ```
353
+
354
+ ---
355
+
356
+ ## ⚡ Performance
357
+
358
+ `@arikajs/session` is optimized for high-throughput applications.
359
+
360
+ - Lazy session loading
361
+ - Mutation-based writes
362
+ - Efficient cookie parsing
363
+ - Driver abstraction
364
+ - Request lifecycle integration
365
+
366
+ ---
367
+
368
+ ## 🏗 Architecture
369
+
370
+ ```text
371
+ session/
372
+ ├── src/
373
+ │ ├── Contracts
374
+ │ │ └── SessionDriver.ts
375
+ │ ├── Drivers
376
+ │ │ ├── FileDriver.ts
377
+ │ │ ├── MemoryDriver.ts
378
+ │ │ ├── RedisDriver.ts
379
+ │ │ └── DatabaseDriver.ts
380
+ │ ├── Middleware
381
+ │ │ └── StartSession.ts
382
+ │ ├── Session.ts
383
+ │ ├── SessionManager.ts
384
+ │ ├── CookieSessionId.ts
385
+ │ ├── index.ts
386
+ │ └── utils.ts
387
+ ├── tests/
388
+ ├── package.json
389
+ ├── tsconfig.json
390
+ └── README.md
391
+ ```
392
+
393
+ ---
394
+
395
+ ## 🔌 Integration with ArikaJS
396
+
397
+ | Package | Responsibility |
398
+ | :--- | :--- |
399
+ | `@arikajs/http` | Request & response lifecycle |
400
+ | `@arikajs/router` | Route matching |
401
+ | `@arikajs/session` | Session state management |
402
+ | `@arikajs/auth` | Authentication |
403
+ | `@arikajs/authorization` | Access control |
404
+
405
+ ---
406
+
407
+ ## 📌 Design Philosophy
408
+
409
+ - **Stateless by default** — Sessions only when needed.
410
+ - **Driver abstraction** — Swap storage without changing code.
411
+ - **Security-first** — Built-in protection against fixation attacks.
412
+ - **Performance-focused** — Lazy loading and write optimization.
413
+ - **Framework-aligned** — Works seamlessly with ArikaJS middleware lifecycle.
414
+
415
+ > "Sessions maintain continuity in a stateless world."
416
+
417
+ ---
418
+
419
+ ## 🔄 Versioning & Stability
420
+
421
+ - Current version: **v0.x** (Experimental)
422
+ - APIs may change until **v1.0**
423
+ - Semantic versioning will be adopted after stabilization.
424
+
425
+ ---
426
+
427
+ ## 📜 License
428
+
429
+ `@arikajs/session` is open-sourced software licensed under the **MIT License**.
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Session driver contract.
3
+ * All session storage backends must implement this interface.
4
+ */
5
+ export interface SessionDriver {
6
+ /**
7
+ * Read session data by session ID. Returns null if not found or expired.
8
+ */
9
+ load(sessionId: string): Promise<Record<string, any> | null>;
10
+ /**
11
+ * Persist session data with a TTL in seconds.
12
+ */
13
+ save(sessionId: string, data: Record<string, any>, ttlSeconds: number): Promise<void>;
14
+ /**
15
+ * Delete a session by ID.
16
+ */
17
+ destroy(sessionId: string): Promise<void>;
18
+ /**
19
+ * Run garbage collection to delete expired sessions.
20
+ * @param probability 0.0 – 1.0 likelihood of running GC on this call
21
+ */
22
+ gc(maxLifetimeSeconds: number): Promise<void>;
23
+ /**
24
+ * Optional: Acquire a lock for this session (for concurrency protection).
25
+ * Should return true if lock was acquired, false otherwise.
26
+ */
27
+ acquireLock?(sessionId: string, timeoutSeconds: number): Promise<boolean>;
28
+ /**
29
+ * Optional: Release a previously acquired session lock.
30
+ */
31
+ releaseLock?(sessionId: string): Promise<void>;
32
+ }
33
+ //# sourceMappingURL=SessionDriver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionDriver.d.ts","sourceRoot":"","sources":["../../src/Contracts/SessionDriver.ts"],"names":[],"mappings":"AACA;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC1B;;OAEG;IACH,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;IAE7D;;OAEG;IACH,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtF;;OAEG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1C;;;OAGG;IACH,EAAE,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9C;;;OAGG;IACH,WAAW,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAE1E;;OAEG;IACH,WAAW,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClD"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=SessionDriver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionDriver.js","sourceRoot":"","sources":["../../src/Contracts/SessionDriver.ts"],"names":[],"mappings":""}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Handles reading and writing the session ID cookie.
3
+ */
4
+ export declare class CookieSessionId {
5
+ private readonly cookieName;
6
+ private readonly secret;
7
+ constructor(cookieName: string, secret: string);
8
+ /**
9
+ * Generate a cryptographically random session ID.
10
+ */
11
+ generate(): string;
12
+ /**
13
+ * Read the session ID from incoming cookie headers.
14
+ * Returns null if not found or signature is invalid.
15
+ */
16
+ read(cookieHeader: string): string | null;
17
+ /**
18
+ * Produce a Set-Cookie header value for the session ID.
19
+ */
20
+ write(sessionId: string, options: {
21
+ lifetime: number;
22
+ path: string;
23
+ secure: boolean;
24
+ httpOnly: boolean;
25
+ sameSite: string;
26
+ }): string;
27
+ /**
28
+ * Produce a Set-Cookie header that clears the session cookie.
29
+ */
30
+ clear(path?: string): string;
31
+ private sign;
32
+ private verify;
33
+ private parseCookies;
34
+ }
35
+ //# sourceMappingURL=CookieSessionId.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CookieSessionId.d.ts","sourceRoot":"","sources":["../src/CookieSessionId.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,qBAAa,eAAe;IAEpB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM;IAGnC;;OAEG;IACI,QAAQ,IAAI,MAAM;IAIzB;;;OAGG;IACI,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAOhD;;OAEG;IACI,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE;QACrC,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,OAAO,CAAC;QAChB,QAAQ,EAAE,OAAO,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;KACpB,GAAG,MAAM;IAaV;;OAEG;IACI,KAAK,CAAC,IAAI,GAAE,MAAY,GAAG,MAAM;IAIxC,OAAO,CAAC,IAAI;IAKZ,OAAO,CAAC,MAAM;IAgBd,OAAO,CAAC,YAAY;CAYvB"}
@@ -0,0 +1,129 @@
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.CookieSessionId = void 0;
37
+ const crypto = __importStar(require("node:crypto"));
38
+ const SESSION_ID_LENGTH = 40; // 40 hex chars = 20 bytes of entropy
39
+ /**
40
+ * Handles reading and writing the session ID cookie.
41
+ */
42
+ class CookieSessionId {
43
+ constructor(cookieName, secret) {
44
+ this.cookieName = cookieName;
45
+ this.secret = secret;
46
+ }
47
+ /**
48
+ * Generate a cryptographically random session ID.
49
+ */
50
+ generate() {
51
+ return crypto.randomBytes(20).toString('hex');
52
+ }
53
+ /**
54
+ * Read the session ID from incoming cookie headers.
55
+ * Returns null if not found or signature is invalid.
56
+ */
57
+ read(cookieHeader) {
58
+ const cookies = this.parseCookies(cookieHeader);
59
+ const raw = cookies[this.cookieName];
60
+ if (!raw)
61
+ return null;
62
+ return this.verify(raw);
63
+ }
64
+ /**
65
+ * Produce a Set-Cookie header value for the session ID.
66
+ */
67
+ write(sessionId, options) {
68
+ const signed = this.sign(sessionId);
69
+ const parts = [
70
+ `${this.cookieName}=${encodeURIComponent(signed)}`,
71
+ `Path=${options.path}`,
72
+ `Max-Age=${options.lifetime}`,
73
+ `SameSite=${options.sameSite}`,
74
+ ];
75
+ if (options.httpOnly)
76
+ parts.push('HttpOnly');
77
+ if (options.secure)
78
+ parts.push('Secure');
79
+ return parts.join('; ');
80
+ }
81
+ /**
82
+ * Produce a Set-Cookie header that clears the session cookie.
83
+ */
84
+ clear(path = '/') {
85
+ return `${this.cookieName}=; Path=${path}; Max-Age=0; HttpOnly; SameSite=Lax`;
86
+ }
87
+ sign(value) {
88
+ const mac = crypto.createHmac('sha256', this.secret).update(value).digest('base64url');
89
+ return `${value}.${mac}`;
90
+ }
91
+ verify(signed) {
92
+ const dot = signed.lastIndexOf('.');
93
+ if (dot === -1)
94
+ return null;
95
+ const value = signed.slice(0, dot);
96
+ const mac = signed.slice(dot + 1);
97
+ const expected = crypto.createHmac('sha256', this.secret).update(value).digest('base64url');
98
+ try {
99
+ if (!crypto.timingSafeEqual(Buffer.from(mac, 'utf8'), Buffer.from(expected, 'utf8'))) {
100
+ return null;
101
+ }
102
+ }
103
+ catch {
104
+ return null;
105
+ }
106
+ return value;
107
+ }
108
+ parseCookies(header) {
109
+ const result = {};
110
+ if (!header)
111
+ return result;
112
+ for (const pair of header.split(';')) {
113
+ const idx = pair.indexOf('=');
114
+ if (idx === -1)
115
+ continue;
116
+ const key = pair.slice(0, idx).trim();
117
+ const val = pair.slice(idx + 1).trim();
118
+ try {
119
+ result[key] = decodeURIComponent(val);
120
+ }
121
+ catch {
122
+ result[key] = val;
123
+ }
124
+ }
125
+ return result;
126
+ }
127
+ }
128
+ exports.CookieSessionId = CookieSessionId;
129
+ //# sourceMappingURL=CookieSessionId.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CookieSessionId.js","sourceRoot":"","sources":["../src/CookieSessionId.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,oDAAsC;AAEtC,MAAM,iBAAiB,GAAG,EAAE,CAAC,CAAC,qCAAqC;AAEnE;;GAEG;AACH,MAAa,eAAe;IACxB,YACqB,UAAkB,EAClB,MAAc;QADd,eAAU,GAAV,UAAU,CAAQ;QAClB,WAAM,GAAN,MAAM,CAAQ;IAC/B,CAAC;IAEL;;OAEG;IACI,QAAQ;QACX,OAAO,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC;IAED;;;OAGG;IACI,IAAI,CAAC,YAAoB;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;QAChD,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACrC,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QACtB,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,SAAiB,EAAE,OAM/B;QACG,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACpC,MAAM,KAAK,GAAG;YACV,GAAG,IAAI,CAAC,UAAU,IAAI,kBAAkB,CAAC,MAAM,CAAC,EAAE;YAClD,QAAQ,OAAO,CAAC,IAAI,EAAE;YACtB,WAAW,OAAO,CAAC,QAAQ,EAAE;YAC7B,YAAY,OAAO,CAAC,QAAQ,EAAE;SACjC,CAAC;QACF,IAAI,OAAO,CAAC,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC7C,IAAI,OAAO,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,OAAe,GAAG;QAC3B,OAAO,GAAG,IAAI,CAAC,UAAU,WAAW,IAAI,qCAAqC,CAAC;IAClF,CAAC;IAEO,IAAI,CAAC,KAAa;QACtB,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACvF,OAAO,GAAG,KAAK,IAAI,GAAG,EAAE,CAAC;IAC7B,CAAC;IAEO,MAAM,CAAC,MAAc;QACzB,MAAM,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,GAAG,KAAK,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QAC5B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACnC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;QAClC,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAC5F,IAAI,CAAC;YACD,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;gBACnF,OAAO,IAAI,CAAC;YAChB,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;IAEO,YAAY,CAAC,MAAc;QAC/B,MAAM,MAAM,GAA2B,EAAE,CAAC;QAC1C,IAAI,CAAC,MAAM;YAAE,OAAO,MAAM,CAAC;QAC3B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YACnC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC9B,IAAI,GAAG,KAAK,CAAC,CAAC;gBAAE,SAAS;YACzB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;YACtC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACvC,IAAI,CAAC;gBAAC,MAAM,CAAC,GAAG,CAAC,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC;gBAAC,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;YAAC,CAAC;QAC/E,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;CACJ;AAtFD,0CAsFC"}
@@ -0,0 +1,19 @@
1
+ import { SessionDriver } from '../Contracts/SessionDriver';
2
+ /**
3
+ * DatabaseDriver — stores sessions using a SQL database table.
4
+ * Depends on the application's database instance implementing basic
5
+ * table(), where(), update(), insert(), and delete() methods.
6
+ */
7
+ export declare class DatabaseDriver implements SessionDriver {
8
+ private readonly database;
9
+ private readonly table;
10
+ private readonly connection?;
11
+ constructor(database: any, table?: string, connection?: string | undefined);
12
+ load(sessionId: string): Promise<Record<string, any> | null>;
13
+ save(sessionId: string, data: Record<string, any>, ttlSeconds: number): Promise<void>;
14
+ destroy(sessionId: string): Promise<void>;
15
+ gc(maxLifetimeSeconds: number): Promise<void>;
16
+ acquireLock(sessionId: string, timeoutSeconds: number): Promise<boolean>;
17
+ releaseLock(sessionId: string): Promise<void>;
18
+ }
19
+ //# sourceMappingURL=DatabaseDriver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DatabaseDriver.d.ts","sourceRoot":"","sources":["../../src/Drivers/DatabaseDriver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAE3D;;;;GAIG;AACH,qBAAa,cAAe,YAAW,aAAa;IAE5C,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;gBAFX,QAAQ,EAAE,GAAG,EACb,KAAK,GAAE,MAAmB,EAC1B,UAAU,CAAC,EAAE,MAAM,YAAA;IAG3B,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;IAoCrF,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMzC,EAAE,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ7C,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAOxE,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG7D"}