@shware/security 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -0
- package/dist/auth/index.cjs +17 -9
- package/dist/auth/index.cjs.map +1 -1
- package/dist/auth/index.d.cts +5 -2
- package/dist/auth/index.d.ts +5 -2
- package/dist/auth/index.mjs +14 -6
- package/dist/auth/index.mjs.map +1 -1
- package/dist/auth/types.cjs.map +1 -1
- package/dist/auth/types.d.cts +3 -2
- package/dist/auth/types.d.ts +3 -2
- package/dist/index.cjs +9 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -6
- package/dist/index.d.ts +9 -6
- package/dist/index.mjs +6 -2
- package/dist/index.mjs.map +1 -1
- package/dist/session/__test__/redis.test.cjs +5 -4
- package/dist/session/__test__/redis.test.cjs.map +1 -1
- package/dist/session/__test__/redis.test.mjs +3 -2
- package/dist/session/__test__/redis.test.mjs.map +1 -1
- package/dist/session/common.cjs +46 -0
- package/dist/session/common.cjs.map +1 -0
- package/dist/session/common.d.cts +8 -0
- package/dist/session/common.d.ts +8 -0
- package/dist/session/common.mjs +19 -0
- package/dist/session/common.mjs.map +1 -0
- package/dist/session/db.cjs +127 -0
- package/dist/session/db.cjs.map +1 -0
- package/dist/session/db.d.cts +43 -0
- package/dist/session/db.d.ts +43 -0
- package/dist/session/db.mjs +102 -0
- package/dist/session/db.mjs.map +1 -0
- package/dist/session/map-session.cjs +108 -0
- package/dist/session/map-session.cjs.map +1 -0
- package/dist/session/map-session.d.cts +27 -0
- package/dist/session/map-session.d.ts +27 -0
- package/dist/session/map-session.mjs +83 -0
- package/dist/session/map-session.mjs.map +1 -0
- package/dist/session/redis.cjs +32 -128
- package/dist/session/redis.cjs.map +1 -1
- package/dist/session/redis.d.cts +11 -30
- package/dist/session/redis.d.ts +11 -30
- package/dist/session/redis.mjs +20 -116
- package/dist/session/redis.mjs.map +1 -1
- package/dist/session/types.cjs.map +1 -1
- package/dist/session/types.d.cts +6 -4
- package/dist/session/types.d.ts +6 -4
- package/package.json +1 -1
- package/dist/session/index.cjs +0 -33
- package/dist/session/index.cjs.map +0 -1
- package/dist/session/index.d.cts +0 -4
- package/dist/session/index.d.ts +0 -4
- package/dist/session/index.mjs +0 -10
- package/dist/session/index.mjs.map +0 -1
package/dist/session/redis.d.ts
CHANGED
|
@@ -1,30 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MapSession } from './map-session.js';
|
|
2
2
|
import { Redis } from 'ioredis';
|
|
3
|
+
import { SessionRepository, Session, Namespace, KVRepository } from './types.js';
|
|
3
4
|
import '../core/index.js';
|
|
4
5
|
|
|
5
|
-
declare const PRINCIPAL_NAME_INDEX_NAME = "org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME";
|
|
6
|
-
declare class MapSession implements Session {
|
|
7
|
-
private id;
|
|
8
|
-
private sessionAttrs;
|
|
9
|
-
private creationTime;
|
|
10
|
-
private lastAccessedTime;
|
|
11
|
-
private maxInactiveInterval;
|
|
12
|
-
constructor(id?: string);
|
|
13
|
-
constructor(session: Session);
|
|
14
|
-
setCreationTime(creationTime: number): void;
|
|
15
|
-
getId(): string;
|
|
16
|
-
changeSessionId(): `${string}-${string}-${string}-${string}-${string}`;
|
|
17
|
-
getAttribute(name: string): string | number | null;
|
|
18
|
-
getAttributeNames(): string[];
|
|
19
|
-
setAttribute(name: string, value: string | number): void;
|
|
20
|
-
removeAttribute(name: string): void;
|
|
21
|
-
getCreationTime(): number;
|
|
22
|
-
getLastAccessedTime(): number;
|
|
23
|
-
setLastAccessedTime(lastAccessedTime: number): void;
|
|
24
|
-
getMaxInactiveInterval(): number;
|
|
25
|
-
setMaxInactiveInterval(interval: number): void;
|
|
26
|
-
isExpired(): boolean;
|
|
27
|
-
}
|
|
28
6
|
declare class RedisSession implements Session {
|
|
29
7
|
private readonly cached;
|
|
30
8
|
isNew: boolean;
|
|
@@ -47,7 +25,7 @@ declare class RedisSession implements Session {
|
|
|
47
25
|
setAttribute(name: string, value: string): void;
|
|
48
26
|
removeAttribute(name: string): void;
|
|
49
27
|
}
|
|
50
|
-
declare class
|
|
28
|
+
declare class RedisIndexedSessionRepository implements SessionRepository<RedisSession> {
|
|
51
29
|
private readonly redis;
|
|
52
30
|
private readonly namespace;
|
|
53
31
|
private readonly expirationStore;
|
|
@@ -67,11 +45,14 @@ declare class RedisSessionRepository implements SessionRepository<RedisSession>
|
|
|
67
45
|
deleteById(sessionId: string): Promise<void>;
|
|
68
46
|
findByIndexNameAndIndexValue(indexName: string, indexValue: string): Promise<Map<string, RedisSession>>;
|
|
69
47
|
findByPrincipalName(principalName: string): Promise<Map<string, RedisSession>>;
|
|
70
|
-
cleanupExpiredSessions(): Promise<void>;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
48
|
+
cleanupExpiredSessions(cleanupCount?: number): Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
declare class RedisKVRepository implements KVRepository {
|
|
51
|
+
private readonly redis;
|
|
52
|
+
constructor(redis: Redis);
|
|
53
|
+
setItem(key: string, value: string, expiresIn?: number): Promise<void>;
|
|
54
|
+
getItem(key: string): Promise<string | null>;
|
|
74
55
|
removeItem(key: string): Promise<void>;
|
|
75
56
|
}
|
|
76
57
|
|
|
77
|
-
export {
|
|
58
|
+
export { RedisIndexedSessionRepository, RedisKVRepository };
|
package/dist/session/redis.mjs
CHANGED
|
@@ -1,99 +1,11 @@
|
|
|
1
1
|
// src/session/redis.ts
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { resolveIndexesFor, PRINCIPAL_NAME_INDEX_NAME, SPRING_SECURITY_CONTEXT } from "./common.mjs";
|
|
3
|
+
import { MapSession } from "./map-session.mjs";
|
|
4
4
|
var CREATION_TIME_KEY = "creationTime";
|
|
5
5
|
var LAST_ACCESSED_TIME_KEY = "lastAccessedTime";
|
|
6
6
|
var MAX_INACTIVE_INTERVAL_KEY = "maxInactiveInterval";
|
|
7
7
|
var ATTRIBUTE_PREFIX = "sessionAttr:";
|
|
8
8
|
var SESSION_EXPIRES_PREFIX = "expires:";
|
|
9
|
-
var SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
|
|
10
|
-
var PRINCIPAL_NAME_INDEX_NAME = `org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME`;
|
|
11
|
-
function generateId() {
|
|
12
|
-
return randomUUID();
|
|
13
|
-
}
|
|
14
|
-
var MapSession = class {
|
|
15
|
-
id;
|
|
16
|
-
sessionAttrs = /* @__PURE__ */ new Map();
|
|
17
|
-
creationTime = Date.now();
|
|
18
|
-
lastAccessedTime = this.creationTime;
|
|
19
|
-
maxInactiveInterval = DEFAULT_MAX_INACTIVE_INTERVAL;
|
|
20
|
-
constructor(input) {
|
|
21
|
-
if (typeof input === "undefined") {
|
|
22
|
-
this.id = generateId();
|
|
23
|
-
} else if (typeof input === "string") {
|
|
24
|
-
this.id = input;
|
|
25
|
-
} else {
|
|
26
|
-
const session = input;
|
|
27
|
-
this.id = session.getId();
|
|
28
|
-
for (const attrName of session.getAttributeNames()) {
|
|
29
|
-
const attrValue = session.getAttribute(attrName);
|
|
30
|
-
if (attrValue !== null) {
|
|
31
|
-
this.setAttribute(attrName, attrValue);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
this.lastAccessedTime = session.getLastAccessedTime();
|
|
35
|
-
this.creationTime = session.getCreationTime();
|
|
36
|
-
this.maxInactiveInterval = session.getMaxInactiveInterval();
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
setCreationTime(creationTime) {
|
|
40
|
-
this.creationTime = creationTime;
|
|
41
|
-
}
|
|
42
|
-
// override
|
|
43
|
-
getId() {
|
|
44
|
-
return this.id;
|
|
45
|
-
}
|
|
46
|
-
changeSessionId() {
|
|
47
|
-
const changedId = generateId();
|
|
48
|
-
this.id = changedId;
|
|
49
|
-
return changedId;
|
|
50
|
-
}
|
|
51
|
-
getAttribute(name) {
|
|
52
|
-
return this.sessionAttrs.get(name) ?? null;
|
|
53
|
-
}
|
|
54
|
-
getAttributeNames() {
|
|
55
|
-
return Array.from(this.sessionAttrs.keys());
|
|
56
|
-
}
|
|
57
|
-
setAttribute(name, value) {
|
|
58
|
-
if (value === null) {
|
|
59
|
-
this.removeAttribute(name);
|
|
60
|
-
} else {
|
|
61
|
-
this.sessionAttrs.set(name, value);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
removeAttribute(name) {
|
|
65
|
-
this.sessionAttrs.delete(name);
|
|
66
|
-
}
|
|
67
|
-
getCreationTime() {
|
|
68
|
-
return this.creationTime;
|
|
69
|
-
}
|
|
70
|
-
getLastAccessedTime() {
|
|
71
|
-
return this.lastAccessedTime;
|
|
72
|
-
}
|
|
73
|
-
setLastAccessedTime(lastAccessedTime) {
|
|
74
|
-
this.lastAccessedTime = lastAccessedTime;
|
|
75
|
-
}
|
|
76
|
-
getMaxInactiveInterval() {
|
|
77
|
-
return this.maxInactiveInterval;
|
|
78
|
-
}
|
|
79
|
-
setMaxInactiveInterval(interval) {
|
|
80
|
-
this.maxInactiveInterval = interval;
|
|
81
|
-
}
|
|
82
|
-
isExpired() {
|
|
83
|
-
if (this.maxInactiveInterval < 0) return false;
|
|
84
|
-
return Date.now() - this.maxInactiveInterval * 1e3 - this.lastAccessedTime >= 0;
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
function resolveIndexesFor(session) {
|
|
88
|
-
const principalName = session.getAttribute(PRINCIPAL_NAME_INDEX_NAME);
|
|
89
|
-
if (principalName !== null) return principalName;
|
|
90
|
-
const jsonString = session.getAttribute(SPRING_SECURITY_CONTEXT);
|
|
91
|
-
if (typeof jsonString === "string") {
|
|
92
|
-
const context = JSON.parse(jsonString);
|
|
93
|
-
return context?.authentication?.name ?? context.authentication?.principal?.name ?? null;
|
|
94
|
-
}
|
|
95
|
-
return null;
|
|
96
|
-
}
|
|
97
9
|
var RedisSession = class {
|
|
98
10
|
cached;
|
|
99
11
|
isNew;
|
|
@@ -165,7 +77,6 @@ var SortedSetRedisSessionExpirationStore = class {
|
|
|
165
77
|
redis;
|
|
166
78
|
namespace;
|
|
167
79
|
expirationsKey;
|
|
168
|
-
cleanupCount = 100;
|
|
169
80
|
constructor(redis, namespace) {
|
|
170
81
|
this.redis = redis;
|
|
171
82
|
this.namespace = namespace;
|
|
@@ -186,15 +97,10 @@ var SortedSetRedisSessionExpirationStore = class {
|
|
|
186
97
|
await this.remove(session.originalSessionId);
|
|
187
98
|
await this.save(session);
|
|
188
99
|
}
|
|
189
|
-
async cleanupExpiredSessions() {
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
0,
|
|
194
|
-
"LIMIT",
|
|
195
|
-
0,
|
|
196
|
-
this.cleanupCount
|
|
197
|
-
);
|
|
100
|
+
async cleanupExpiredSessions(cleanupCount = 100) {
|
|
101
|
+
const key = this.expirationsKey;
|
|
102
|
+
const score = Date.now();
|
|
103
|
+
const sessionIds = await this.redis.zrevrangebyscore(key, score, 0, "LIMIT", 0, cleanupCount);
|
|
198
104
|
if (sessionIds.length === 0) return;
|
|
199
105
|
for (const sessionId of sessionIds) {
|
|
200
106
|
const sessionKey = this.getSessionKey(sessionId);
|
|
@@ -202,7 +108,7 @@ var SortedSetRedisSessionExpirationStore = class {
|
|
|
202
108
|
}
|
|
203
109
|
}
|
|
204
110
|
};
|
|
205
|
-
var
|
|
111
|
+
var RedisIndexedSessionRepository = class {
|
|
206
112
|
redis;
|
|
207
113
|
namespace;
|
|
208
114
|
expirationStore;
|
|
@@ -366,33 +272,31 @@ var RedisSessionRepository = class {
|
|
|
366
272
|
async findByPrincipalName(principalName) {
|
|
367
273
|
return this.findByIndexNameAndIndexValue(PRINCIPAL_NAME_INDEX_NAME, principalName);
|
|
368
274
|
}
|
|
369
|
-
async cleanupExpiredSessions() {
|
|
370
|
-
await this.expirationStore.cleanupExpiredSessions();
|
|
275
|
+
async cleanupExpiredSessions(cleanupCount) {
|
|
276
|
+
await this.expirationStore.cleanupExpiredSessions(cleanupCount);
|
|
371
277
|
}
|
|
372
|
-
|
|
373
|
-
|
|
278
|
+
};
|
|
279
|
+
var RedisKVRepository = class {
|
|
280
|
+
redis;
|
|
281
|
+
constructor(redis) {
|
|
282
|
+
this.redis = redis;
|
|
374
283
|
}
|
|
375
284
|
async setItem(key, value, expiresIn) {
|
|
376
|
-
const k = this.getItemKey(key);
|
|
377
|
-
const v = JSON.stringify(value);
|
|
378
285
|
if (expiresIn) {
|
|
379
|
-
await this.redis.set(
|
|
286
|
+
await this.redis.set(key, value, "EX", expiresIn);
|
|
380
287
|
} else {
|
|
381
|
-
await this.redis.set(
|
|
288
|
+
await this.redis.set(key, value);
|
|
382
289
|
}
|
|
383
290
|
}
|
|
384
291
|
async getItem(key) {
|
|
385
|
-
|
|
386
|
-
const json = await this.redis.get(k);
|
|
387
|
-
return json ? JSON.parse(json) : null;
|
|
292
|
+
return await this.redis.get(key);
|
|
388
293
|
}
|
|
389
294
|
async removeItem(key) {
|
|
390
|
-
|
|
391
|
-
await this.redis.del(k);
|
|
295
|
+
await this.redis.del(key);
|
|
392
296
|
}
|
|
393
297
|
};
|
|
394
298
|
export {
|
|
395
|
-
|
|
396
|
-
|
|
299
|
+
RedisIndexedSessionRepository,
|
|
300
|
+
RedisKVRepository
|
|
397
301
|
};
|
|
398
302
|
//# sourceMappingURL=redis.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/session/redis.ts"],"sourcesContent":["import { randomUUID } from 'crypto';\nimport type { Redis } from 'ioredis';\nimport type { Namespace, SecurityContext, Session, SessionRepository } from './types';\n\nconst DEFAULT_MAX_INACTIVE_INTERVAL = 1800;\n\nconst CREATION_TIME_KEY = 'creationTime';\nconst LAST_ACCESSED_TIME_KEY = 'lastAccessedTime';\nconst MAX_INACTIVE_INTERVAL_KEY = 'maxInactiveInterval';\nconst ATTRIBUTE_PREFIX = 'sessionAttr:';\nconst SESSION_EXPIRES_PREFIX = 'expires:';\n\nconst SPRING_SECURITY_CONTEXT = 'SPRING_SECURITY_CONTEXT';\nexport const PRINCIPAL_NAME_INDEX_NAME = `org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME`;\n\nfunction generateId() {\n return randomUUID();\n}\n\nclass MapSession implements Session {\n private id: string;\n private sessionAttrs = new Map<string, string | number>();\n private creationTime = Date.now();\n private lastAccessedTime = this.creationTime;\n private maxInactiveInterval = DEFAULT_MAX_INACTIVE_INTERVAL;\n\n constructor(id?: string);\n constructor(session: Session);\n constructor(input?: string | Session) {\n if (typeof input === 'undefined') {\n this.id = generateId();\n } else if (typeof input === 'string') {\n this.id = input;\n } else {\n const session = input;\n this.id = session.getId();\n\n for (const attrName of session.getAttributeNames()) {\n const attrValue = session.getAttribute(attrName);\n if (attrValue !== null) {\n this.setAttribute(attrName, attrValue);\n }\n }\n\n this.lastAccessedTime = session.getLastAccessedTime();\n this.creationTime = session.getCreationTime();\n this.maxInactiveInterval = session.getMaxInactiveInterval();\n }\n }\n\n setCreationTime(creationTime: number) {\n this.creationTime = creationTime;\n }\n\n // override\n getId() {\n return this.id;\n }\n\n changeSessionId() {\n const changedId = generateId();\n this.id = changedId;\n return changedId;\n }\n\n getAttribute(name: string) {\n return this.sessionAttrs.get(name) ?? null;\n }\n\n getAttributeNames(): string[] {\n return Array.from(this.sessionAttrs.keys());\n }\n\n setAttribute(name: string, value: string | number) {\n if (value === null) {\n this.removeAttribute(name);\n } else {\n this.sessionAttrs.set(name, value);\n }\n }\n\n removeAttribute(name: string) {\n this.sessionAttrs.delete(name);\n }\n\n getCreationTime() {\n return this.creationTime;\n }\n\n getLastAccessedTime() {\n return this.lastAccessedTime;\n }\n\n setLastAccessedTime(lastAccessedTime: number) {\n this.lastAccessedTime = lastAccessedTime;\n }\n\n getMaxInactiveInterval() {\n return this.maxInactiveInterval;\n }\n\n setMaxInactiveInterval(interval: number) {\n this.maxInactiveInterval = interval;\n }\n\n isExpired() {\n if (this.maxInactiveInterval < 0) return false;\n return Date.now() - this.maxInactiveInterval * 1000 - this.lastAccessedTime >= 0;\n }\n}\n\nfunction resolveIndexesFor(session: Session): string | null {\n const principalName = session.getAttribute(PRINCIPAL_NAME_INDEX_NAME) as string | null;\n if (principalName !== null) return principalName;\n\n const jsonString = session.getAttribute(SPRING_SECURITY_CONTEXT);\n if (typeof jsonString === 'string') {\n const context = JSON.parse(jsonString) as SecurityContext;\n return context?.authentication?.name ?? context.authentication?.principal?.name ?? null;\n }\n return null;\n}\n\nclass RedisSession implements Session {\n private readonly cached: MapSession;\n\n public isNew: boolean;\n public delta = new Map<string, string | number | null>();\n public originalSessionId: string;\n public originalPrincipalName: string | null;\n public originalLastAccessTime: number | null = null;\n\n constructor(cached: MapSession, isNew: boolean) {\n this.cached = cached;\n this.isNew = isNew;\n this.originalSessionId = cached.getId();\n this.originalPrincipalName = resolveIndexesFor(this);\n\n if (isNew) {\n this.delta.set(CREATION_TIME_KEY, cached.getCreationTime());\n this.delta.set(LAST_ACCESSED_TIME_KEY, cached.getLastAccessedTime());\n this.delta.set(MAX_INACTIVE_INTERVAL_KEY, cached.getMaxInactiveInterval());\n this.cached.getAttributeNames().forEach((name) => {\n const value = this.cached.getAttribute(name);\n if (value) this.delta.set(this.getSessionAttrNameKey(name), value);\n });\n }\n }\n\n getSessionAttrNameKey(name: string) {\n return ATTRIBUTE_PREFIX + name;\n }\n\n // override\n setLastAccessedTime(lastAccessedTime: number) {\n this.cached.setLastAccessedTime(lastAccessedTime);\n this.delta.set(LAST_ACCESSED_TIME_KEY, lastAccessedTime);\n }\n\n isExpired() {\n return this.cached.isExpired();\n }\n\n getCreationTime() {\n return this.cached.getCreationTime();\n }\n\n getId() {\n return this.cached.getId();\n }\n\n changeSessionId() {\n return this.cached.changeSessionId();\n }\n\n getLastAccessedTime() {\n return this.cached.getLastAccessedTime();\n }\n\n setMaxInactiveInterval(interval: number) {\n this.cached.setMaxInactiveInterval(interval);\n this.delta.set(MAX_INACTIVE_INTERVAL_KEY, interval);\n }\n\n getMaxInactiveInterval() {\n return this.cached.getMaxInactiveInterval();\n }\n\n getAttribute(name: string) {\n return this.cached.getAttribute(name);\n }\n\n getAttributeNames() {\n return this.cached.getAttributeNames();\n }\n\n setAttribute(name: string, value: string) {\n this.cached.setAttribute(name, value);\n this.delta.set(this.getSessionAttrNameKey(name), value);\n }\n\n removeAttribute(name: string) {\n this.cached.removeAttribute(name);\n this.delta.set(this.getSessionAttrNameKey(name), null);\n }\n}\n\ninterface RedisSessionExpirationStore {\n save(session: RedisSession): Promise<void>;\n remove(sessionId: string): Promise<void>;\n rename(session: RedisSession): Promise<void>;\n cleanupExpiredSessions(): Promise<void>;\n}\n\nclass SortedSetRedisSessionExpirationStore implements RedisSessionExpirationStore {\n private readonly redis: Redis;\n private readonly namespace: Namespace;\n private readonly expirationsKey: string;\n\n private cleanupCount = 100;\n\n constructor(redis: Redis, namespace: Namespace) {\n this.redis = redis;\n this.namespace = namespace;\n this.expirationsKey = `${this.namespace}:sessions:expirations`;\n }\n\n getSessionKey(sessionId: string) {\n return `${this.namespace}:sessions:${sessionId}`;\n }\n\n async save(session: RedisSession) {\n const expirationInMillis =\n session.getLastAccessedTime() + session.getMaxInactiveInterval() * 1000;\n await this.redis.zadd(this.expirationsKey, expirationInMillis, session.getId());\n }\n\n async remove(sessionId: string) {\n await this.redis.zrem(this.expirationsKey, sessionId);\n }\n\n async rename(session: RedisSession) {\n if (session.originalSessionId === null || session.originalSessionId === session.getId()) return;\n await this.remove(session.originalSessionId);\n await this.save(session);\n }\n\n async cleanupExpiredSessions() {\n const sessionIds = await this.redis.zrevrangebyscore(\n this.expirationsKey,\n Date.now(),\n 0,\n 'LIMIT',\n 0,\n this.cleanupCount\n );\n if (sessionIds.length === 0) return;\n for (const sessionId of sessionIds) {\n const sessionKey = this.getSessionKey(sessionId);\n // Checks if the session exists. By trying to access the session we only trigger a deletion\n // if the TTL is expired.\n await this.redis.exists(sessionKey);\n }\n }\n}\n\n// 15549130 <spring:session:sessions:uuid, hash<session>> + 300s\n// 15549147 <spring:session:sessions:expirations, sorted_set<uuid>> + 300s\n// 15548839 <spring:session:sessions:expires:uuid, string<empty>>\nexport class RedisSessionRepository implements SessionRepository<RedisSession> {\n private readonly redis: Redis;\n private readonly namespace: Namespace;\n private readonly expirationStore: RedisSessionExpirationStore;\n\n private defaultMaxInactiveInterval = 1800;\n\n constructor(redis: Redis, namespace: Namespace = 'spring:session') {\n this.redis = redis;\n this.namespace = namespace;\n this.expirationStore = new SortedSetRedisSessionExpirationStore(redis, namespace);\n }\n\n setDefaultMaxInactiveInterval(interval: number) {\n this.defaultMaxInactiveInterval = interval;\n }\n\n private getSessionKey(sessionId: string) {\n return `${this.namespace}:sessions:${sessionId}`;\n }\n\n private getExpiredKey(sessionId: string) {\n return `${this.namespace}:sessions:expires:${sessionId}`;\n }\n\n private getSessionAttrNameKey(name: string) {\n return ATTRIBUTE_PREFIX + name;\n }\n\n private getPrincipalKey(principalName: string) {\n return `${this.namespace}:index:${PRINCIPAL_NAME_INDEX_NAME}:${principalName}`;\n }\n\n private async getSession(id: string, allowExpired: boolean): Promise<RedisSession | null> {\n const key = this.getSessionKey(id);\n const entries = await this.redis.hgetall(key);\n if (!entries || Object.keys(entries).length === 0) return null;\n const loaded = new MapSession(id);\n if (!entries.creationTime) throw new Error('creationTime attribute not found');\n if (!entries.lastAccessedTime) throw new Error('lastAccessedTime attribute not found');\n if (!entries.maxInactiveInterval) throw new Error('maxInactiveInterval attribute not found');\n\n loaded.setCreationTime(Number(entries.creationTime));\n loaded.setLastAccessedTime(Number(entries.lastAccessedTime));\n loaded.setMaxInactiveInterval(Number(entries.maxInactiveInterval));\n\n for (const [key, value] of Object.entries(entries)) {\n if (key.startsWith(ATTRIBUTE_PREFIX)) {\n loaded.setAttribute(key.slice(ATTRIBUTE_PREFIX.length), value);\n }\n }\n\n if (!allowExpired && loaded.isExpired()) return null;\n const result = new RedisSession(loaded, false);\n result.originalLastAccessTime = loaded.getLastAccessedTime();\n return result;\n }\n\n private async saveDelta(session: RedisSession) {\n if (session.delta.size === 0) return;\n const sessionId = session.getId();\n const delta = new Map<string, string | number>();\n const removes: string[] = [];\n session.delta.forEach((value, key) => {\n if (value !== null) delta.set(key, value);\n else removes.push(key);\n });\n\n if (delta.size !== 0) {\n await this.redis.hset(this.getSessionKey(sessionId), delta);\n }\n if (removes.length !== 0) {\n await this.redis.hdel(this.getSessionKey(sessionId), ...removes);\n }\n\n const principalSessionKey = this.getSessionAttrNameKey(PRINCIPAL_NAME_INDEX_NAME);\n const securityPrincipalSessionKey = this.getSessionAttrNameKey(SPRING_SECURITY_CONTEXT);\n if (session.delta.has(principalSessionKey) || session.delta.has(securityPrincipalSessionKey)) {\n if (session.originalPrincipalName !== null) {\n const originalPrincipalRedisKey = this.getPrincipalKey(session.originalPrincipalName);\n await this.redis.srem(originalPrincipalRedisKey, sessionId);\n }\n const principal = resolveIndexesFor(session);\n session.originalPrincipalName = principal;\n if (principal !== null) {\n const principalRedisKey = this.getPrincipalKey(principal);\n await this.redis.sadd(principalRedisKey, sessionId);\n }\n }\n\n if (session.isNew) {\n // here your can send session created message to channel\n session.isNew = false;\n }\n\n const sessionExpireInSeconds = session.getMaxInactiveInterval();\n\n // createShadowKey start\n const keyToExpire = SESSION_EXPIRES_PREFIX + session.getId();\n const sessionKey = this.getSessionKey(keyToExpire);\n\n if (sessionExpireInSeconds < 0) {\n await this.redis.append(sessionKey, '');\n await this.redis.persist(sessionKey);\n await this.redis.persist(this.getSessionKey(session.getId()));\n } else if (sessionExpireInSeconds === 0) {\n await this.redis.del(sessionKey);\n } else {\n await this.redis.append(sessionKey, '');\n await this.redis.expire(sessionKey, sessionExpireInSeconds);\n }\n // createShadowKey end\n\n if (sessionExpireInSeconds > 0) {\n const fiveMinutesAfterExpires = sessionExpireInSeconds + 5 * 60;\n await this.redis.expire(this.getSessionKey(session.getId()), fiveMinutesAfterExpires);\n }\n\n await this.expirationStore.save(session);\n session.delta.clear();\n }\n\n private async saveChangeSessionId(session: RedisSession) {\n const sessionId = session.getId();\n if (sessionId === session.originalSessionId) return;\n if (!session.isNew) {\n const originalSessionIdKey = this.getSessionKey(session.originalSessionId);\n const sessionIdKey = this.getSessionKey(sessionId);\n const originalExpiredKey = this.getExpiredKey(session.originalSessionId);\n const expiredKey = this.getExpiredKey(sessionId);\n\n await this.redis.rename(originalSessionIdKey, sessionIdKey);\n await this.redis.rename(originalExpiredKey, expiredKey);\n\n if (session.originalPrincipalName !== null) {\n const originalPrincipalRedisKey = this.getPrincipalKey(session.originalPrincipalName);\n await this.redis.srem(originalPrincipalRedisKey, session.originalSessionId);\n await this.redis.sadd(originalPrincipalRedisKey, sessionId);\n }\n await this.expirationStore.rename(session);\n }\n session.originalSessionId = sessionId;\n }\n\n // override\n createSession() {\n const cached = new MapSession();\n cached.setMaxInactiveInterval(this.defaultMaxInactiveInterval);\n return new RedisSession(cached, true);\n }\n\n async save(session: RedisSession) {\n await this.saveChangeSessionId(session);\n await this.saveDelta(session);\n }\n\n async findById(sessionId: string): Promise<RedisSession | null> {\n return this.getSession(sessionId, false);\n }\n\n async deleteById(sessionId: string) {\n const session = await this.getSession(sessionId, true);\n if (!session) return;\n // 1. cleanup index\n const principal = resolveIndexesFor(session);\n if (principal !== null) {\n await this.redis.srem(this.getPrincipalKey(principal), sessionId);\n }\n // 2. delete in set\n await this.expirationStore.remove(sessionId);\n // 3. delete expired key\n const expiredKey = this.getExpiredKey(sessionId);\n await this.redis.del(expiredKey);\n\n session.setMaxInactiveInterval(0);\n await this.save(session);\n }\n\n async findByIndexNameAndIndexValue(indexName: string, indexValue: string) {\n if (indexName !== PRINCIPAL_NAME_INDEX_NAME) {\n return new Map<string, RedisSession>();\n }\n\n const principalKey = this.getPrincipalKey(indexValue);\n const sessionIds = await this.redis.smembers(principalKey);\n if (!sessionIds || sessionIds.length === 0) {\n return new Map<string, RedisSession>();\n }\n const sessions = new Map<string, RedisSession>();\n for (const sessionId of sessionIds) {\n const session = await this.findById(sessionId);\n if (session !== null) {\n sessions.set(sessionId, session);\n }\n }\n return sessions;\n }\n\n async findByPrincipalName(principalName: string) {\n return this.findByIndexNameAndIndexValue(PRINCIPAL_NAME_INDEX_NAME, principalName);\n }\n\n async cleanupExpiredSessions() {\n await this.expirationStore.cleanupExpiredSessions();\n }\n\n private getItemKey(key: string) {\n return `${this.namespace.replace('session', 'storage')}:${key}`;\n }\n\n async setItem(key: string, value: unknown, expiresIn?: number) {\n const k = this.getItemKey(key);\n const v = JSON.stringify(value);\n if (expiresIn) {\n await this.redis.set(k, v, 'EX', expiresIn);\n } else {\n await this.redis.set(k, v);\n }\n }\n\n async getItem<T = unknown>(key: string): Promise<T | null> {\n const k = this.getItemKey(key);\n const json = await this.redis.get(k);\n return json ? (JSON.parse(json) as T) : null;\n }\n\n async removeItem(key: string) {\n const k = this.getItemKey(key);\n await this.redis.del(k);\n }\n}\n"],"mappings":"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","names":["key"]}
|
|
1
|
+
{"version":3,"sources":["../../src/session/redis.ts"],"sourcesContent":["import { resolveIndexesFor, PRINCIPAL_NAME_INDEX_NAME, SPRING_SECURITY_CONTEXT } from './common';\nimport { MapSession } from './map-session';\nimport type { Redis } from 'ioredis';\nimport type { KVRepository, Namespace, Session, SessionRepository } from './types';\n\nconst CREATION_TIME_KEY = 'creationTime';\nconst LAST_ACCESSED_TIME_KEY = 'lastAccessedTime';\nconst MAX_INACTIVE_INTERVAL_KEY = 'maxInactiveInterval';\nconst ATTRIBUTE_PREFIX = 'sessionAttr:';\nconst SESSION_EXPIRES_PREFIX = 'expires:';\n\nclass RedisSession implements Session {\n private readonly cached: MapSession;\n\n public isNew: boolean;\n public delta = new Map<string, string | number | null>();\n public originalSessionId: string;\n public originalPrincipalName: string | null;\n public originalLastAccessTime: number | null = null;\n\n constructor(cached: MapSession, isNew: boolean) {\n this.cached = cached;\n this.isNew = isNew;\n this.originalSessionId = cached.getId();\n this.originalPrincipalName = resolveIndexesFor(this);\n\n if (isNew) {\n this.delta.set(CREATION_TIME_KEY, cached.getCreationTime());\n this.delta.set(LAST_ACCESSED_TIME_KEY, cached.getLastAccessedTime());\n this.delta.set(MAX_INACTIVE_INTERVAL_KEY, cached.getMaxInactiveInterval());\n this.cached.getAttributeNames().forEach((name) => {\n const value = this.cached.getAttribute(name);\n if (value) this.delta.set(this.getSessionAttrNameKey(name), value);\n });\n }\n }\n\n getSessionAttrNameKey(name: string) {\n return ATTRIBUTE_PREFIX + name;\n }\n\n // override\n setLastAccessedTime(lastAccessedTime: number) {\n this.cached.setLastAccessedTime(lastAccessedTime);\n this.delta.set(LAST_ACCESSED_TIME_KEY, lastAccessedTime);\n }\n\n isExpired() {\n return this.cached.isExpired();\n }\n\n getCreationTime() {\n return this.cached.getCreationTime();\n }\n\n getId() {\n return this.cached.getId();\n }\n\n changeSessionId() {\n return this.cached.changeSessionId();\n }\n\n getLastAccessedTime() {\n return this.cached.getLastAccessedTime();\n }\n\n setMaxInactiveInterval(interval: number) {\n this.cached.setMaxInactiveInterval(interval);\n this.delta.set(MAX_INACTIVE_INTERVAL_KEY, interval);\n }\n\n getMaxInactiveInterval() {\n return this.cached.getMaxInactiveInterval();\n }\n\n getAttribute(name: string) {\n return this.cached.getAttribute(name);\n }\n\n getAttributeNames() {\n return this.cached.getAttributeNames();\n }\n\n setAttribute(name: string, value: string) {\n this.cached.setAttribute(name, value);\n this.delta.set(this.getSessionAttrNameKey(name), value);\n }\n\n removeAttribute(name: string) {\n this.cached.removeAttribute(name);\n this.delta.set(this.getSessionAttrNameKey(name), null);\n }\n}\n\ninterface RedisSessionExpirationStore {\n save(session: RedisSession): Promise<void>;\n remove(sessionId: string): Promise<void>;\n rename(session: RedisSession): Promise<void>;\n cleanupExpiredSessions(cleanupCount?: number): Promise<void>;\n}\n\nclass SortedSetRedisSessionExpirationStore implements RedisSessionExpirationStore {\n private readonly redis: Redis;\n private readonly namespace: Namespace;\n private readonly expirationsKey: string;\n\n constructor(redis: Redis, namespace: Namespace) {\n this.redis = redis;\n this.namespace = namespace;\n this.expirationsKey = `${this.namespace}:sessions:expirations`;\n }\n\n getSessionKey(sessionId: string) {\n return `${this.namespace}:sessions:${sessionId}`;\n }\n\n async save(session: RedisSession) {\n const expirationInMillis =\n session.getLastAccessedTime() + session.getMaxInactiveInterval() * 1000;\n await this.redis.zadd(this.expirationsKey, expirationInMillis, session.getId());\n }\n\n async remove(sessionId: string) {\n await this.redis.zrem(this.expirationsKey, sessionId);\n }\n\n async rename(session: RedisSession) {\n if (session.originalSessionId === null || session.originalSessionId === session.getId()) return;\n await this.remove(session.originalSessionId);\n await this.save(session);\n }\n\n async cleanupExpiredSessions(cleanupCount: number = 100) {\n const key = this.expirationsKey;\n const score = Date.now();\n const sessionIds = await this.redis.zrevrangebyscore(key, score, 0, 'LIMIT', 0, cleanupCount);\n if (sessionIds.length === 0) return;\n for (const sessionId of sessionIds) {\n const sessionKey = this.getSessionKey(sessionId);\n // Checks if the session exists. By trying to access the session we only trigger a deletion\n // if the TTL is expired.\n await this.redis.exists(sessionKey);\n }\n }\n}\n\n// 15549130 <spring:session:sessions:uuid, hash<session>> + 300s\n// 15549147 <spring:session:sessions:expirations, sorted_set<uuid>> + 300s\n// 15548839 <spring:session:sessions:expires:uuid, string<empty>>\nexport class RedisIndexedSessionRepository implements SessionRepository<RedisSession> {\n private readonly redis: Redis;\n private readonly namespace: Namespace;\n private readonly expirationStore: RedisSessionExpirationStore;\n\n private defaultMaxInactiveInterval = 1800;\n\n constructor(redis: Redis, namespace: Namespace = 'spring:session') {\n this.redis = redis;\n this.namespace = namespace;\n this.expirationStore = new SortedSetRedisSessionExpirationStore(redis, namespace);\n }\n\n setDefaultMaxInactiveInterval(interval: number) {\n this.defaultMaxInactiveInterval = interval;\n }\n\n private getSessionKey(sessionId: string) {\n return `${this.namespace}:sessions:${sessionId}`;\n }\n\n private getExpiredKey(sessionId: string) {\n return `${this.namespace}:sessions:expires:${sessionId}`;\n }\n\n private getSessionAttrNameKey(name: string) {\n return ATTRIBUTE_PREFIX + name;\n }\n\n private getPrincipalKey(principalName: string) {\n return `${this.namespace}:index:${PRINCIPAL_NAME_INDEX_NAME}:${principalName}`;\n }\n\n private async getSession(id: string, allowExpired: boolean): Promise<RedisSession | null> {\n const key = this.getSessionKey(id);\n const entries = await this.redis.hgetall(key);\n if (!entries || Object.keys(entries).length === 0) return null;\n const loaded = new MapSession(id);\n if (!entries.creationTime) throw new Error('creationTime attribute not found');\n if (!entries.lastAccessedTime) throw new Error('lastAccessedTime attribute not found');\n if (!entries.maxInactiveInterval) throw new Error('maxInactiveInterval attribute not found');\n\n loaded.setCreationTime(Number(entries.creationTime));\n loaded.setLastAccessedTime(Number(entries.lastAccessedTime));\n loaded.setMaxInactiveInterval(Number(entries.maxInactiveInterval));\n\n for (const [key, value] of Object.entries(entries)) {\n if (key.startsWith(ATTRIBUTE_PREFIX)) {\n loaded.setAttribute(key.slice(ATTRIBUTE_PREFIX.length), value);\n }\n }\n\n if (!allowExpired && loaded.isExpired()) return null;\n const result = new RedisSession(loaded, false);\n result.originalLastAccessTime = loaded.getLastAccessedTime();\n return result;\n }\n\n private async saveDelta(session: RedisSession) {\n if (session.delta.size === 0) return;\n const sessionId = session.getId();\n const delta = new Map<string, string | number>();\n const removes: string[] = [];\n session.delta.forEach((value, key) => {\n if (value !== null) delta.set(key, value);\n else removes.push(key);\n });\n\n if (delta.size !== 0) {\n await this.redis.hset(this.getSessionKey(sessionId), delta);\n }\n if (removes.length !== 0) {\n await this.redis.hdel(this.getSessionKey(sessionId), ...removes);\n }\n\n const principalSessionKey = this.getSessionAttrNameKey(PRINCIPAL_NAME_INDEX_NAME);\n const securityPrincipalSessionKey = this.getSessionAttrNameKey(SPRING_SECURITY_CONTEXT);\n if (session.delta.has(principalSessionKey) || session.delta.has(securityPrincipalSessionKey)) {\n if (session.originalPrincipalName !== null) {\n const originalPrincipalRedisKey = this.getPrincipalKey(session.originalPrincipalName);\n await this.redis.srem(originalPrincipalRedisKey, sessionId);\n }\n const principal = resolveIndexesFor(session);\n session.originalPrincipalName = principal;\n if (principal !== null) {\n const principalRedisKey = this.getPrincipalKey(principal);\n await this.redis.sadd(principalRedisKey, sessionId);\n }\n }\n\n if (session.isNew) {\n // here your can send session created message to channel\n session.isNew = false;\n }\n\n const sessionExpireInSeconds = session.getMaxInactiveInterval();\n\n // createShadowKey start\n const keyToExpire = SESSION_EXPIRES_PREFIX + session.getId();\n const sessionKey = this.getSessionKey(keyToExpire);\n\n if (sessionExpireInSeconds < 0) {\n await this.redis.append(sessionKey, '');\n await this.redis.persist(sessionKey);\n await this.redis.persist(this.getSessionKey(session.getId()));\n } else if (sessionExpireInSeconds === 0) {\n await this.redis.del(sessionKey);\n } else {\n await this.redis.append(sessionKey, '');\n await this.redis.expire(sessionKey, sessionExpireInSeconds);\n }\n // createShadowKey end\n\n if (sessionExpireInSeconds > 0) {\n const fiveMinutesAfterExpires = sessionExpireInSeconds + 5 * 60;\n await this.redis.expire(this.getSessionKey(session.getId()), fiveMinutesAfterExpires);\n }\n\n await this.expirationStore.save(session);\n session.delta.clear();\n }\n\n private async saveChangeSessionId(session: RedisSession) {\n const sessionId = session.getId();\n if (sessionId === session.originalSessionId) return;\n if (!session.isNew) {\n const originalSessionIdKey = this.getSessionKey(session.originalSessionId);\n const sessionIdKey = this.getSessionKey(sessionId);\n const originalExpiredKey = this.getExpiredKey(session.originalSessionId);\n const expiredKey = this.getExpiredKey(sessionId);\n\n await this.redis.rename(originalSessionIdKey, sessionIdKey);\n await this.redis.rename(originalExpiredKey, expiredKey);\n\n if (session.originalPrincipalName !== null) {\n const originalPrincipalRedisKey = this.getPrincipalKey(session.originalPrincipalName);\n await this.redis.srem(originalPrincipalRedisKey, session.originalSessionId);\n await this.redis.sadd(originalPrincipalRedisKey, sessionId);\n }\n await this.expirationStore.rename(session);\n }\n session.originalSessionId = sessionId;\n }\n\n // override\n createSession() {\n const cached = new MapSession();\n cached.setMaxInactiveInterval(this.defaultMaxInactiveInterval);\n return new RedisSession(cached, true);\n }\n\n async save(session: RedisSession) {\n await this.saveChangeSessionId(session);\n await this.saveDelta(session);\n }\n\n async findById(sessionId: string): Promise<RedisSession | null> {\n return this.getSession(sessionId, false);\n }\n\n async deleteById(sessionId: string) {\n const session = await this.getSession(sessionId, true);\n if (!session) return;\n // 1. cleanup index\n const principal = resolveIndexesFor(session);\n if (principal !== null) {\n await this.redis.srem(this.getPrincipalKey(principal), sessionId);\n }\n // 2. delete in set\n await this.expirationStore.remove(sessionId);\n // 3. delete expired key\n const expiredKey = this.getExpiredKey(sessionId);\n await this.redis.del(expiredKey);\n\n session.setMaxInactiveInterval(0);\n await this.save(session);\n }\n\n async findByIndexNameAndIndexValue(indexName: string, indexValue: string) {\n if (indexName !== PRINCIPAL_NAME_INDEX_NAME) {\n return new Map<string, RedisSession>();\n }\n\n const principalKey = this.getPrincipalKey(indexValue);\n const sessionIds = await this.redis.smembers(principalKey);\n if (!sessionIds || sessionIds.length === 0) {\n return new Map<string, RedisSession>();\n }\n const sessions = new Map<string, RedisSession>();\n for (const sessionId of sessionIds) {\n const session = await this.findById(sessionId);\n if (session !== null) {\n sessions.set(sessionId, session);\n }\n }\n return sessions;\n }\n\n async findByPrincipalName(principalName: string) {\n return this.findByIndexNameAndIndexValue(PRINCIPAL_NAME_INDEX_NAME, principalName);\n }\n\n async cleanupExpiredSessions(cleanupCount?: number) {\n await this.expirationStore.cleanupExpiredSessions(cleanupCount);\n }\n}\n\nexport class RedisKVRepository implements KVRepository {\n private readonly redis: Redis;\n\n constructor(redis: Redis) {\n this.redis = redis;\n }\n\n async setItem(key: string, value: string, expiresIn?: number) {\n if (expiresIn) {\n await this.redis.set(key, value, 'EX', expiresIn);\n } else {\n await this.redis.set(key, value);\n }\n }\n\n async getItem(key: string): Promise<string | null> {\n return await this.redis.get(key);\n }\n\n async removeItem(key: string) {\n await this.redis.del(key);\n }\n}\n"],"mappings":"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","names":["key"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/session/types.ts"],"sourcesContent":["import type { Principal } from '../core/index';\n\nexport interface Authentication extends Principal {\n '@class': string;\n principal?: Principal;\n authorities?: string[];\n credentials?: object;\n details?: object;\n}\n\nexport interface SecurityContext {\n '@class': string;\n authentication?: Authentication;\n}\n\nexport type Namespace = `${string}:session`;\n\n// package org.springframework.session;\nexport interface Session {\n getId(): string;\n changeSessionId(): string;\n\n getAttribute(name: string): string | number | null;\n getAttributeNames(): string[];\n setAttribute(name: string, value: string | number): void;\n removeAttribute(name: string): void;\n\n getCreationTime(): number;\n getLastAccessedTime(): number;\n setLastAccessedTime(lastAccessedTime: number): void;\n\n getMaxInactiveInterval(): number;\n setMaxInactiveInterval(interval: number): void;\n\n isExpired(): boolean;\n}\n\nexport interface SessionRepository<S extends Session = Session> {\n createSession(): S;\n save(session: S): Promise<void>;\n findById(sessionId: string): Promise<S | null>;\n deleteById(sessionId: string): Promise<void>;\n\n // FindByIndexNameSessionRepository\n findByIndexNameAndIndexValue(indexName: string, indexValue: string): Promise<Map<string, S>>;\n findByPrincipalName(principalName: string): Promise<Map<string, S>>;\n\n // added\n cleanupExpiredSessions(): Promise<void>;\n\n
|
|
1
|
+
{"version":3,"sources":["../../src/session/types.ts"],"sourcesContent":["import type { Principal } from '../core/index';\n\nexport interface Authentication extends Principal {\n '@class': string;\n principal?: Principal;\n authorities?: string[];\n credentials?: object;\n details?: object;\n}\n\nexport interface SecurityContext {\n '@class': string;\n authentication?: Authentication;\n}\n\nexport type Namespace = `${string}:session`;\n\n// package org.springframework.session;\nexport interface Session {\n getId(): string;\n changeSessionId(): string;\n\n getAttribute(name: string): string | number | null;\n getAttributeNames(): string[];\n setAttribute(name: string, value: string | number): void;\n removeAttribute(name: string): void;\n\n getCreationTime(): number;\n getLastAccessedTime(): number;\n setLastAccessedTime(lastAccessedTime: number): void;\n\n getMaxInactiveInterval(): number;\n setMaxInactiveInterval(interval: number): void;\n\n isExpired(): boolean;\n}\n\nexport interface SessionRepository<S extends Session = Session> {\n createSession(): S;\n save(session: S): Promise<void>;\n findById(sessionId: string): Promise<S | null>;\n deleteById(sessionId: string): Promise<void>;\n\n // FindByIndexNameSessionRepository\n findByIndexNameAndIndexValue(indexName: string, indexValue: string): Promise<Map<string, S>>;\n findByPrincipalName(principalName: string): Promise<Map<string, S>>;\n\n // added\n cleanupExpiredSessions(cleanupCount?: number): Promise<void>;\n}\n\nexport interface KVRepository {\n setItem(key: string, value: string, expiresIn?: number): Promise<void>;\n getItem(key: string): Promise<string | null>;\n removeItem(key: string): Promise<void>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
package/dist/session/types.d.cts
CHANGED
|
@@ -33,10 +33,12 @@ interface SessionRepository<S extends Session = Session> {
|
|
|
33
33
|
deleteById(sessionId: string): Promise<void>;
|
|
34
34
|
findByIndexNameAndIndexValue(indexName: string, indexValue: string): Promise<Map<string, S>>;
|
|
35
35
|
findByPrincipalName(principalName: string): Promise<Map<string, S>>;
|
|
36
|
-
cleanupExpiredSessions(): Promise<void>;
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
cleanupExpiredSessions(cleanupCount?: number): Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
interface KVRepository {
|
|
39
|
+
setItem(key: string, value: string, expiresIn?: number): Promise<void>;
|
|
40
|
+
getItem(key: string): Promise<string | null>;
|
|
39
41
|
removeItem(key: string): Promise<void>;
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
export type { Authentication, Namespace, SecurityContext, Session, SessionRepository };
|
|
44
|
+
export type { Authentication, KVRepository, Namespace, SecurityContext, Session, SessionRepository };
|
package/dist/session/types.d.ts
CHANGED
|
@@ -33,10 +33,12 @@ interface SessionRepository<S extends Session = Session> {
|
|
|
33
33
|
deleteById(sessionId: string): Promise<void>;
|
|
34
34
|
findByIndexNameAndIndexValue(indexName: string, indexValue: string): Promise<Map<string, S>>;
|
|
35
35
|
findByPrincipalName(principalName: string): Promise<Map<string, S>>;
|
|
36
|
-
cleanupExpiredSessions(): Promise<void>;
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
cleanupExpiredSessions(cleanupCount?: number): Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
interface KVRepository {
|
|
39
|
+
setItem(key: string, value: string, expiresIn?: number): Promise<void>;
|
|
40
|
+
getItem(key: string): Promise<string | null>;
|
|
39
41
|
removeItem(key: string): Promise<void>;
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
export type { Authentication, Namespace, SecurityContext, Session, SessionRepository };
|
|
44
|
+
export type { Authentication, KVRepository, Namespace, SecurityContext, Session, SessionRepository };
|
package/package.json
CHANGED
package/dist/session/index.cjs
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/session/index.ts
|
|
21
|
-
var session_exports = {};
|
|
22
|
-
__export(session_exports, {
|
|
23
|
-
PRINCIPAL_NAME_INDEX_NAME: () => import_redis.PRINCIPAL_NAME_INDEX_NAME,
|
|
24
|
-
RedisIndexedSessionRepository: () => import_redis.RedisSessionRepository
|
|
25
|
-
});
|
|
26
|
-
module.exports = __toCommonJS(session_exports);
|
|
27
|
-
var import_redis = require("./redis.cjs");
|
|
28
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
29
|
-
0 && (module.exports = {
|
|
30
|
-
PRINCIPAL_NAME_INDEX_NAME,
|
|
31
|
-
RedisIndexedSessionRepository
|
|
32
|
-
});
|
|
33
|
-
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/session/index.ts"],"sourcesContent":["export type { Namespace, SessionRepository } from './types';\nexport {\n RedisSessionRepository as RedisIndexedSessionRepository,\n PRINCIPAL_NAME_INDEX_NAME,\n} from './redis';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,mBAGO;","names":[]}
|
package/dist/session/index.d.cts
DELETED
package/dist/session/index.d.ts
DELETED
package/dist/session/index.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/session/index.ts"],"sourcesContent":["export type { Namespace, SessionRepository } from './types';\nexport {\n RedisSessionRepository as RedisIndexedSessionRepository,\n PRINCIPAL_NAME_INDEX_NAME,\n} from './redis';\n"],"mappings":";AACA;AAAA,EAC4B;AAAA,EAC1B;AAAA,OACK;","names":[]}
|