@shware/security 7.1.0 → 8.0.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 +108 -30
- package/dist/auth/attributes.cjs +5 -5
- package/dist/auth/attributes.cjs.map +1 -1
- package/dist/auth/attributes.d.cts +3 -5
- package/dist/auth/attributes.d.cts.map +1 -1
- package/dist/auth/attributes.d.mts +3 -5
- package/dist/auth/attributes.d.mts.map +1 -1
- package/dist/auth/attributes.mjs +5 -5
- package/dist/auth/attributes.mjs.map +1 -1
- package/dist/auth/desktop-codes.cjs +57 -0
- package/dist/auth/desktop-codes.cjs.map +1 -0
- package/dist/auth/desktop-codes.d.cts +24 -0
- package/dist/auth/desktop-codes.d.cts.map +1 -0
- package/dist/auth/desktop-codes.d.mts +24 -0
- package/dist/auth/desktop-codes.d.mts.map +1 -0
- package/dist/auth/desktop-codes.mjs +55 -0
- package/dist/auth/desktop-codes.mjs.map +1 -0
- package/dist/auth/email-codes.cjs +77 -0
- package/dist/auth/email-codes.cjs.map +1 -0
- package/dist/auth/email-codes.d.cts +39 -0
- package/dist/auth/email-codes.d.cts.map +1 -0
- package/dist/auth/email-codes.d.mts +39 -0
- package/dist/auth/email-codes.d.mts.map +1 -0
- package/dist/auth/email-codes.mjs +75 -0
- package/dist/auth/email-codes.mjs.map +1 -0
- package/dist/auth/error.cjs +47 -0
- package/dist/auth/error.cjs.map +1 -0
- package/dist/auth/error.d.cts +88 -0
- package/dist/auth/error.d.cts.map +1 -0
- package/dist/auth/error.d.mts +88 -0
- package/dist/auth/error.d.mts.map +1 -0
- package/dist/auth/error.mjs +45 -0
- package/dist/auth/error.mjs.map +1 -0
- package/dist/auth/index.cjs +245 -385
- package/dist/auth/index.cjs.map +1 -1
- package/dist/auth/index.d.cts +66 -57
- package/dist/auth/index.d.cts.map +1 -1
- package/dist/auth/index.d.mts +66 -57
- package/dist/auth/index.d.mts.map +1 -1
- package/dist/auth/index.mjs +248 -388
- package/dist/auth/index.mjs.map +1 -1
- package/dist/auth/respond.cjs +99 -0
- package/dist/auth/respond.cjs.map +1 -0
- package/dist/auth/respond.d.cts +39 -0
- package/dist/auth/respond.d.cts.map +1 -0
- package/dist/auth/respond.d.mts +39 -0
- package/dist/auth/respond.d.mts.map +1 -0
- package/dist/auth/respond.mjs +92 -0
- package/dist/auth/respond.mjs.map +1 -0
- package/dist/auth/types.d.cts +27 -13
- package/dist/auth/types.d.cts.map +1 -1
- package/dist/auth/types.d.mts +27 -13
- package/dist/auth/types.d.mts.map +1 -1
- package/dist/core/index.cjs +1 -2
- package/dist/core/index.d.cts +0 -2
- package/dist/core/index.d.cts.map +1 -1
- package/dist/core/index.d.mts +0 -2
- package/dist/core/index.d.mts.map +1 -1
- package/dist/core/index.mjs +1 -2
- package/dist/email/schema.cjs +1 -2
- package/dist/email/schema.d.cts +0 -2
- package/dist/email/schema.d.cts.map +1 -1
- package/dist/email/schema.d.mts +0 -2
- package/dist/email/schema.d.mts.map +1 -1
- package/dist/email/schema.mjs +1 -2
- package/dist/index.cjs +5 -0
- package/dist/index.d.cts +4 -1
- package/dist/index.d.mts +4 -1
- package/dist/index.mjs +3 -1
- package/dist/oauth2/client.cjs +1 -2
- package/dist/oauth2/client.d.cts +0 -2
- package/dist/oauth2/client.d.cts.map +1 -1
- package/dist/oauth2/client.d.mts +0 -2
- package/dist/oauth2/client.d.mts.map +1 -1
- package/dist/oauth2/client.mjs +1 -2
- package/dist/oauth2/error.cjs +1 -9
- package/dist/oauth2/error.cjs.map +1 -1
- package/dist/oauth2/error.d.cts +0 -5
- package/dist/oauth2/error.d.cts.map +1 -1
- package/dist/oauth2/error.d.mts +0 -5
- package/dist/oauth2/error.d.mts.map +1 -1
- package/dist/oauth2/error.mjs +2 -9
- package/dist/oauth2/error.mjs.map +1 -1
- package/dist/oauth2/name.cjs +1 -2
- package/dist/oauth2/name.d.cts +0 -2
- package/dist/oauth2/name.d.cts.map +1 -1
- package/dist/oauth2/name.d.mts +0 -2
- package/dist/oauth2/name.d.mts.map +1 -1
- package/dist/oauth2/name.mjs +1 -2
- package/dist/oauth2/provider/apple-client-secret.cjs +1 -2
- package/dist/oauth2/provider/apple-client-secret.d.cts +0 -2
- package/dist/oauth2/provider/apple-client-secret.d.cts.map +1 -1
- package/dist/oauth2/provider/apple-client-secret.d.mts +0 -2
- package/dist/oauth2/provider/apple-client-secret.d.mts.map +1 -1
- package/dist/oauth2/provider/apple-client-secret.mjs +1 -2
- package/dist/oauth2/provider/apple.cjs +1 -2
- package/dist/oauth2/provider/apple.d.cts +0 -2
- package/dist/oauth2/provider/apple.d.cts.map +1 -1
- package/dist/oauth2/provider/apple.d.mts +0 -2
- package/dist/oauth2/provider/apple.d.mts.map +1 -1
- package/dist/oauth2/provider/apple.mjs +1 -2
- package/dist/oauth2/provider/common.cjs +2 -3
- package/dist/oauth2/provider/common.cjs.map +1 -1
- package/dist/oauth2/provider/common.d.cts +0 -2
- package/dist/oauth2/provider/common.d.cts.map +1 -1
- package/dist/oauth2/provider/common.d.mts +0 -2
- package/dist/oauth2/provider/common.d.mts.map +1 -1
- package/dist/oauth2/provider/common.mjs +2 -3
- package/dist/oauth2/provider/common.mjs.map +1 -1
- package/dist/oauth2/provider/facebook.cjs +3 -6
- package/dist/oauth2/provider/facebook.cjs.map +1 -1
- package/dist/oauth2/provider/facebook.d.cts +0 -3
- package/dist/oauth2/provider/facebook.d.cts.map +1 -1
- package/dist/oauth2/provider/facebook.d.mts +0 -3
- package/dist/oauth2/provider/facebook.d.mts.map +1 -1
- package/dist/oauth2/provider/facebook.mjs +3 -6
- package/dist/oauth2/provider/facebook.mjs.map +1 -1
- package/dist/oauth2/provider/github.cjs +1 -2
- package/dist/oauth2/provider/github.d.cts +0 -2
- package/dist/oauth2/provider/github.d.cts.map +1 -1
- package/dist/oauth2/provider/github.d.mts +0 -2
- package/dist/oauth2/provider/github.d.mts.map +1 -1
- package/dist/oauth2/provider/github.mjs +1 -2
- package/dist/oauth2/provider/google.cjs +1 -2
- package/dist/oauth2/provider/google.d.cts +0 -2
- package/dist/oauth2/provider/google.d.cts.map +1 -1
- package/dist/oauth2/provider/google.d.mts +0 -2
- package/dist/oauth2/provider/google.d.mts.map +1 -1
- package/dist/oauth2/provider/google.mjs +1 -2
- package/dist/oauth2/provider/wechat.cjs +1 -2
- package/dist/oauth2/provider/wechat.d.cts +0 -2
- package/dist/oauth2/provider/wechat.d.cts.map +1 -1
- package/dist/oauth2/provider/wechat.d.mts +0 -2
- package/dist/oauth2/provider/wechat.d.mts.map +1 -1
- package/dist/oauth2/provider/wechat.mjs +1 -2
- package/dist/oauth2/provider/x.cjs +7 -6
- package/dist/oauth2/provider/x.cjs.map +1 -1
- package/dist/oauth2/provider/x.d.cts +3 -4
- package/dist/oauth2/provider/x.d.cts.map +1 -1
- package/dist/oauth2/provider/x.d.mts +3 -4
- package/dist/oauth2/provider/x.d.mts.map +1 -1
- package/dist/oauth2/provider/x.mjs +7 -6
- package/dist/oauth2/provider/x.mjs.map +1 -1
- package/dist/oauth2/types.cjs +1 -2
- package/dist/oauth2/types.cjs.map +1 -1
- package/dist/oauth2/types.d.cts +5 -2
- package/dist/oauth2/types.d.cts.map +1 -1
- package/dist/oauth2/types.d.mts +5 -2
- package/dist/oauth2/types.d.mts.map +1 -1
- package/dist/oauth2/types.mjs +1 -2
- package/dist/oauth2/types.mjs.map +1 -1
- package/dist/session/common.cjs +11 -15
- package/dist/session/common.cjs.map +1 -1
- package/dist/session/common.d.cts +7 -5
- package/dist/session/common.d.cts.map +1 -1
- package/dist/session/common.d.mts +7 -5
- package/dist/session/common.d.mts.map +1 -1
- package/dist/session/common.mjs +11 -14
- package/dist/session/common.mjs.map +1 -1
- package/dist/session/db.cjs +3 -4
- package/dist/session/db.cjs.map +1 -1
- package/dist/session/db.d.cts +0 -2
- package/dist/session/db.d.cts.map +1 -1
- package/dist/session/db.d.mts +0 -2
- package/dist/session/db.d.mts.map +1 -1
- package/dist/session/db.mjs +4 -5
- package/dist/session/db.mjs.map +1 -1
- package/dist/session/map-session.cjs +1 -2
- package/dist/session/map-session.d.cts +0 -2
- package/dist/session/map-session.d.cts.map +1 -1
- package/dist/session/map-session.d.mts +0 -2
- package/dist/session/map-session.d.mts.map +1 -1
- package/dist/session/map-session.mjs +1 -2
- package/dist/session/redis.cjs +7 -10
- package/dist/session/redis.cjs.map +1 -1
- package/dist/session/redis.d.cts +0 -2
- package/dist/session/redis.d.cts.map +1 -1
- package/dist/session/redis.d.mts +0 -2
- package/dist/session/redis.d.mts.map +1 -1
- package/dist/session/redis.mjs +8 -11
- package/dist/session/redis.mjs.map +1 -1
- package/dist/session/types.d.cts +0 -14
- package/dist/session/types.d.cts.map +1 -1
- package/dist/session/types.d.mts +0 -14
- package/dist/session/types.d.mts.map +1 -1
- package/dist/utils/http.cjs +1 -2
- package/dist/utils/http.d.cts +0 -2
- package/dist/utils/http.d.cts.map +1 -1
- package/dist/utils/http.d.mts +0 -2
- package/dist/utils/http.d.mts.map +1 -1
- package/dist/utils/http.mjs +1 -2
- package/dist/utils/oauth2.cjs +1 -2
- package/dist/utils/oauth2.d.cts +0 -2
- package/dist/utils/oauth2.d.cts.map +1 -1
- package/dist/utils/oauth2.d.mts +0 -2
- package/dist/utils/oauth2.d.mts.map +1 -1
- package/dist/utils/oauth2.mjs +1 -2
- package/dist/utils/timing.cjs +1 -2
- package/dist/utils/timing.d.cts +0 -2
- package/dist/utils/timing.d.cts.map +1 -1
- package/dist/utils/timing.d.mts +0 -2
- package/dist/utils/timing.d.mts.map +1 -1
- package/dist/utils/timing.mjs +1 -2
- package/dist/utils/valid.cjs +35 -54
- package/dist/utils/valid.cjs.map +1 -1
- package/dist/utils/valid.d.cts +8 -25
- package/dist/utils/valid.d.cts.map +1 -1
- package/dist/utils/valid.d.mts +8 -25
- package/dist/utils/valid.d.mts.map +1 -1
- package/dist/utils/valid.mjs +33 -52
- package/dist/utils/valid.mjs.map +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redis.cjs","names":["resolveIndexesFor","PRINCIPAL_NAME_INDEX_NAME","MapSession","SPRING_SECURITY_CONTEXT"],"sources":["../../src/session/redis.ts"],"sourcesContent":["import type { Redis } from 'ioredis';\nimport { PRINCIPAL_NAME_INDEX_NAME, SPRING_SECURITY_CONTEXT, resolveIndexesFor } from './common';\nimport { MapSession } from './map-session';\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 === session.getId()) return;\n await this.remove(session.originalSessionId);\n await this.save(session);\n }\n\n async cleanupExpiredSessions(cleanupCount = 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// <spring:session:sessions:uuid, hash<session>> + 300s\n// <spring:session:sessions:expirations, sorted_set<uuid>>\n// <spring:session:sessions:expires:uuid, string<empty>>: for expire check & event\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 (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.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\nconst INCREMENT_SCRIPT = `\nlocal count = redis.call('INCR', KEYS[1])\nif count == 1 then redis.call('EXPIRE', KEYS[1], ARGV[1]) end\nreturn count\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 this.redis.get(key);\n }\n\n async removeItem(key: string) {\n await this.redis.del(key);\n }\n\n async increment(key: string, expiresIn: number): Promise<number> {\n // INCR and the creating EXPIRE run as one script, so the key never exists without a TTL and\n // an existing key keeps its expiry.\n const count = await this.redis.eval(INCREMENT_SCRIPT, 1, key, expiresIn);\n return Number(count);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"redis.cjs","names":["principalNameOf","PRINCIPAL_NAME_INDEX_NAME","MapSession"],"sources":["../../src/session/redis.ts"],"sourcesContent":["import type { Redis } from 'ioredis';\nimport { PRINCIPAL_NAME_INDEX_NAME, principalNameOf } from './common';\nimport { MapSession } from './map-session';\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 = principalNameOf(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 === session.getId()) return;\n await this.remove(session.originalSessionId);\n await this.save(session);\n }\n\n async cleanupExpiredSessions(cleanupCount = 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// <namespace>:sessions:<id> hash: the session's fields and `sessionAttr:*` attributes\n// <namespace>:sessions:expirations sorted set of ids by expiry, for cleanup\n// <namespace>:sessions:expires:<id> empty string with the session's TTL, for the expiry check\n// <namespace>:index:principalName:<name> set of the principal's session ids\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 = 'app: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 (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 if (session.delta.has(this.getSessionAttrNameKey(PRINCIPAL_NAME_INDEX_NAME))) {\n if (session.originalPrincipalName !== null) {\n const originalPrincipalRedisKey = this.getPrincipalKey(session.originalPrincipalName);\n await this.redis.srem(originalPrincipalRedisKey, sessionId);\n }\n const principal = principalNameOf(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 = principalNameOf(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.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\nconst INCREMENT_SCRIPT = `\nlocal count = redis.call('INCR', KEYS[1])\nif count == 1 then redis.call('EXPIRE', KEYS[1], ARGV[1]) end\nreturn count\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 this.redis.get(key);\n }\n\n async removeItem(key: string) {\n await this.redis.del(key);\n }\n\n async increment(key: string, expiresIn: number): Promise<number> {\n // INCR and the creating EXPIRE run as one script, so the key never exists without a TTL and\n // an existing key keeps its expiry.\n const count = await this.redis.eval(INCREMENT_SCRIPT, 1, key, expiresIn);\n return Number(count);\n }\n}\n"],"mappings":"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"}
|
package/dist/session/redis.d.cts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { KVRepository, Namespace, Session, SessionRepository } from "./types.cjs";
|
|
2
2
|
import { MapSession } from "./map-session.cjs";
|
|
3
3
|
import { Redis } from "ioredis";
|
|
4
|
-
//#region src/session/redis.d.ts
|
|
5
4
|
declare class RedisSession implements Session {
|
|
6
5
|
private readonly cached;
|
|
7
6
|
isNew: boolean;
|
|
@@ -54,6 +53,5 @@ export declare class RedisKVRepository implements KVRepository {
|
|
|
54
53
|
removeItem(key: string): Promise<void>;
|
|
55
54
|
increment(key: string, expiresIn: number): Promise<number>;
|
|
56
55
|
}
|
|
57
|
-
//#endregion
|
|
58
56
|
export {};
|
|
59
57
|
//# sourceMappingURL=redis.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redis.d.cts","names":[],"sources":["../../src/session/redis.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"redis.d.cts","names":[],"sources":["../../src/session/redis.ts"],"mappings":";;;cAWM,wBAAwB;mBACX;EAEV;EACA,OAAK;EACL;EACA;EACA;EAEP,YAAY,QAAQ,YAAY;EAiBhC,sBAAsB;EAKtB,oBAAoB;EAKpB;EAIA;EAIA;EAIA;EAIA;EAIA,uBAAuB;EAKvB;EAIA,aAAa;EAIb;EAIA,aAAa,cAAc;EAK3B,gBAAgB;;qBA8DL,yCAAyC,kBAAkB;mBACrD;mBACA;mBACA;UAET;EAER,YAAY,OAAO,OAAO,YAAW;EAMrC,8BAA8B;UAItB;UAIA;UAIA;UAIA;UAIM;UAyBA;UA8DA;EAuBd,iBAAa;EAMP,KAAK,SAAS,eAAY;EAK1B,SAAS,oBAAoB,QAAQ;EAIrC,WAAW,oBAAiB;EAkB5B,6BAA6B,mBAAmB,qBAAkB,QAAA,YAAA;EAoBlE,oBAAoB,wBAAqB,QAAA,YAAA;EAIzC,uBAAuB,wBAAqB;;qBAWvC,6BAA6B;mBACvB;EAEjB,YAAY,OAAO;EAIb,QAAQ,aAAa,eAAe,qBAAkB;EAQtD,QAAQ,cAAc;EAItB,WAAW,cAAW;EAItB,UAAU,aAAa,oBAAoB"}
|
package/dist/session/redis.d.mts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { KVRepository, Namespace, Session, SessionRepository } from "./types.mjs";
|
|
2
2
|
import { MapSession } from "./map-session.mjs";
|
|
3
3
|
import { Redis } from "ioredis";
|
|
4
|
-
//#region src/session/redis.d.ts
|
|
5
4
|
declare class RedisSession implements Session {
|
|
6
5
|
private readonly cached;
|
|
7
6
|
isNew: boolean;
|
|
@@ -54,6 +53,5 @@ export declare class RedisKVRepository implements KVRepository {
|
|
|
54
53
|
removeItem(key: string): Promise<void>;
|
|
55
54
|
increment(key: string, expiresIn: number): Promise<number>;
|
|
56
55
|
}
|
|
57
|
-
//#endregion
|
|
58
56
|
export {};
|
|
59
57
|
//# sourceMappingURL=redis.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redis.d.mts","names":[],"sources":["../../src/session/redis.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"redis.d.mts","names":[],"sources":["../../src/session/redis.ts"],"mappings":";;;cAWM,wBAAwB;mBACX;EAEV;EACA,OAAK;EACL;EACA;EACA;EAEP,YAAY,QAAQ,YAAY;EAiBhC,sBAAsB;EAKtB,oBAAoB;EAKpB;EAIA;EAIA;EAIA;EAIA;EAIA,uBAAuB;EAKvB;EAIA,aAAa;EAIb;EAIA,aAAa,cAAc;EAK3B,gBAAgB;;qBA8DL,yCAAyC,kBAAkB;mBACrD;mBACA;mBACA;UAET;EAER,YAAY,OAAO,OAAO,YAAW;EAMrC,8BAA8B;UAItB;UAIA;UAIA;UAIA;UAIM;UAyBA;UA8DA;EAuBd,iBAAa;EAMP,KAAK,SAAS,eAAY;EAK1B,SAAS,oBAAoB,QAAQ;EAIrC,WAAW,oBAAiB;EAkB5B,6BAA6B,mBAAmB,qBAAkB,QAAA,YAAA;EAoBlE,oBAAoB,wBAAqB,QAAA,YAAA;EAIzC,uBAAuB,wBAAqB;;qBAWvC,6BAA6B;mBACvB;EAEjB,YAAY,OAAO;EAIb,QAAQ,aAAa,eAAe,qBAAkB;EAQtD,QAAQ,cAAc;EAItB,WAAW,cAAW;EAItB,UAAU,aAAa,oBAAoB"}
|
package/dist/session/redis.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { PRINCIPAL_NAME_INDEX_NAME,
|
|
1
|
+
import { PRINCIPAL_NAME_INDEX_NAME, principalNameOf } from "./common.mjs";
|
|
2
2
|
import { MapSession } from "./map-session.mjs";
|
|
3
|
-
|
|
3
|
+
// src/session/redis.ts
|
|
4
4
|
const CREATION_TIME_KEY = "creationTime";
|
|
5
5
|
const LAST_ACCESSED_TIME_KEY = "lastAccessedTime";
|
|
6
6
|
const MAX_INACTIVE_INTERVAL_KEY = "maxInactiveInterval";
|
|
@@ -17,7 +17,7 @@ var RedisSession = class {
|
|
|
17
17
|
this.cached = cached;
|
|
18
18
|
this.isNew = isNew;
|
|
19
19
|
this.originalSessionId = cached.getId();
|
|
20
|
-
this.originalPrincipalName =
|
|
20
|
+
this.originalPrincipalName = principalNameOf(this);
|
|
21
21
|
if (isNew) {
|
|
22
22
|
this.delta.set(CREATION_TIME_KEY, cached.getCreationTime());
|
|
23
23
|
this.delta.set(LAST_ACCESSED_TIME_KEY, cached.getLastAccessedTime());
|
|
@@ -112,7 +112,7 @@ var RedisIndexedSessionRepository = class {
|
|
|
112
112
|
namespace;
|
|
113
113
|
expirationStore;
|
|
114
114
|
defaultMaxInactiveInterval = 1800;
|
|
115
|
-
constructor(redis, namespace = "
|
|
115
|
+
constructor(redis, namespace = "app:session") {
|
|
116
116
|
this.redis = redis;
|
|
117
117
|
this.namespace = namespace;
|
|
118
118
|
this.expirationStore = new SortedSetRedisSessionExpirationStore(redis, namespace);
|
|
@@ -160,14 +160,12 @@ var RedisIndexedSessionRepository = class {
|
|
|
160
160
|
});
|
|
161
161
|
if (delta.size !== 0) await this.redis.hset(this.getSessionKey(sessionId), delta);
|
|
162
162
|
if (removes.length !== 0) await this.redis.hdel(this.getSessionKey(sessionId), ...removes);
|
|
163
|
-
|
|
164
|
-
const securityPrincipalSessionKey = this.getSessionAttrNameKey(SPRING_SECURITY_CONTEXT);
|
|
165
|
-
if (session.delta.has(principalSessionKey) || session.delta.has(securityPrincipalSessionKey)) {
|
|
163
|
+
if (session.delta.has(this.getSessionAttrNameKey("principalName"))) {
|
|
166
164
|
if (session.originalPrincipalName !== null) {
|
|
167
165
|
const originalPrincipalRedisKey = this.getPrincipalKey(session.originalPrincipalName);
|
|
168
166
|
await this.redis.srem(originalPrincipalRedisKey, sessionId);
|
|
169
167
|
}
|
|
170
|
-
const principal =
|
|
168
|
+
const principal = principalNameOf(session);
|
|
171
169
|
session.originalPrincipalName = principal;
|
|
172
170
|
if (principal !== null) {
|
|
173
171
|
const principalRedisKey = this.getPrincipalKey(principal);
|
|
@@ -228,7 +226,7 @@ var RedisIndexedSessionRepository = class {
|
|
|
228
226
|
async deleteById(sessionId) {
|
|
229
227
|
const session = await this.getSession(sessionId, true);
|
|
230
228
|
if (!session) return;
|
|
231
|
-
const principal =
|
|
229
|
+
const principal = principalNameOf(session);
|
|
232
230
|
if (principal !== null) await this.redis.srem(this.getPrincipalKey(principal), sessionId);
|
|
233
231
|
await this.expirationStore.remove(sessionId);
|
|
234
232
|
const expiredKey = this.getExpiredKey(sessionId);
|
|
@@ -237,7 +235,7 @@ var RedisIndexedSessionRepository = class {
|
|
|
237
235
|
await this.save(session);
|
|
238
236
|
}
|
|
239
237
|
async findByIndexNameAndIndexValue(indexName, indexValue) {
|
|
240
|
-
if (indexName !== "
|
|
238
|
+
if (indexName !== "principalName") return /* @__PURE__ */ new Map();
|
|
241
239
|
const principalKey = this.getPrincipalKey(indexValue);
|
|
242
240
|
const sessionIds = await this.redis.smembers(principalKey);
|
|
243
241
|
if (sessionIds.length === 0) return /* @__PURE__ */ new Map();
|
|
@@ -280,7 +278,6 @@ var RedisKVRepository = class {
|
|
|
280
278
|
return Number(count);
|
|
281
279
|
}
|
|
282
280
|
};
|
|
283
|
-
//#endregion
|
|
284
281
|
export { RedisIndexedSessionRepository, RedisKVRepository };
|
|
285
282
|
|
|
286
283
|
//# sourceMappingURL=redis.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redis.mjs","names":[],"sources":["../../src/session/redis.ts"],"sourcesContent":["import type { Redis } from 'ioredis';\nimport { PRINCIPAL_NAME_INDEX_NAME, SPRING_SECURITY_CONTEXT, resolveIndexesFor } from './common';\nimport { MapSession } from './map-session';\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 === session.getId()) return;\n await this.remove(session.originalSessionId);\n await this.save(session);\n }\n\n async cleanupExpiredSessions(cleanupCount = 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// <spring:session:sessions:uuid, hash<session>> + 300s\n// <spring:session:sessions:expirations, sorted_set<uuid>>\n// <spring:session:sessions:expires:uuid, string<empty>>: for expire check & event\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 (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.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\nconst INCREMENT_SCRIPT = `\nlocal count = redis.call('INCR', KEYS[1])\nif count == 1 then redis.call('EXPIRE', KEYS[1], ARGV[1]) end\nreturn count\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 this.redis.get(key);\n }\n\n async removeItem(key: string) {\n await this.redis.del(key);\n }\n\n async increment(key: string, expiresIn: number): Promise<number> {\n // INCR and the creating EXPIRE run as one script, so the key never exists without a TTL and\n // an existing key keeps its expiry.\n const count = await this.redis.eval(INCREMENT_SCRIPT, 1, key, expiresIn);\n return Number(count);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"redis.mjs","names":[],"sources":["../../src/session/redis.ts"],"sourcesContent":["import type { Redis } from 'ioredis';\nimport { PRINCIPAL_NAME_INDEX_NAME, principalNameOf } from './common';\nimport { MapSession } from './map-session';\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 = principalNameOf(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 === session.getId()) return;\n await this.remove(session.originalSessionId);\n await this.save(session);\n }\n\n async cleanupExpiredSessions(cleanupCount = 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// <namespace>:sessions:<id> hash: the session's fields and `sessionAttr:*` attributes\n// <namespace>:sessions:expirations sorted set of ids by expiry, for cleanup\n// <namespace>:sessions:expires:<id> empty string with the session's TTL, for the expiry check\n// <namespace>:index:principalName:<name> set of the principal's session ids\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 = 'app: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 (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 if (session.delta.has(this.getSessionAttrNameKey(PRINCIPAL_NAME_INDEX_NAME))) {\n if (session.originalPrincipalName !== null) {\n const originalPrincipalRedisKey = this.getPrincipalKey(session.originalPrincipalName);\n await this.redis.srem(originalPrincipalRedisKey, sessionId);\n }\n const principal = principalNameOf(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 = principalNameOf(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.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\nconst INCREMENT_SCRIPT = `\nlocal count = redis.call('INCR', KEYS[1])\nif count == 1 then redis.call('EXPIRE', KEYS[1], ARGV[1]) end\nreturn count\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 this.redis.get(key);\n }\n\n async removeItem(key: string) {\n await this.redis.del(key);\n }\n\n async increment(key: string, expiresIn: number): Promise<number> {\n // INCR and the creating EXPIRE run as one script, so the key never exists without a TTL and\n // an existing key keeps its expiry.\n const count = await this.redis.eval(INCREMENT_SCRIPT, 1, key, expiresIn);\n return Number(count);\n }\n}\n"],"mappings":";;;AAKA,MAAM,oBAAoB;AAC1B,MAAM,yBAAyB;AAC/B,MAAM,4BAA4B;AAClC,MAAM,mBAAmB;AACzB,MAAM,yBAAyB;AAE/B,IAAM,eAAN,MAAsC;CACpC;CAEA;CACA,wBAAe,IAAI,IAAoC;CACvD;CACA;CACA,yBAA+C;CAE/C,YAAY,QAAoB,OAAgB;EAC9C,KAAK,SAAS;EACd,KAAK,QAAQ;EACb,KAAK,oBAAoB,OAAO,MAAM;EACtC,KAAK,wBAAwB,gBAAgB,IAAI;EAEjD,IAAI,OAAO;GACT,KAAK,MAAM,IAAI,mBAAmB,OAAO,gBAAgB,CAAC;GAC1D,KAAK,MAAM,IAAI,wBAAwB,OAAO,oBAAoB,CAAC;GACnE,KAAK,MAAM,IAAI,2BAA2B,OAAO,uBAAuB,CAAC;GACzE,KAAK,OAAO,kBAAkB,CAAC,CAAC,SAAS,SAAS;IAChD,MAAM,QAAQ,KAAK,OAAO,aAAa,IAAI;IAC3C,IAAI,OAAO,KAAK,MAAM,IAAI,KAAK,sBAAsB,IAAI,GAAG,KAAK;GACnE,CAAC;EACH;CACF;CAEA,sBAAsB,MAAc;EAClC,OAAO,mBAAmB;CAC5B;CAGA,oBAAoB,kBAA0B;EAC5C,KAAK,OAAO,oBAAoB,gBAAgB;EAChD,KAAK,MAAM,IAAI,wBAAwB,gBAAgB;CACzD;CAEA,YAAY;EACV,OAAO,KAAK,OAAO,UAAU;CAC/B;CAEA,kBAAkB;EAChB,OAAO,KAAK,OAAO,gBAAgB;CACrC;CAEA,QAAQ;EACN,OAAO,KAAK,OAAO,MAAM;CAC3B;CAEA,kBAAkB;EAChB,OAAO,KAAK,OAAO,gBAAgB;CACrC;CAEA,sBAAsB;EACpB,OAAO,KAAK,OAAO,oBAAoB;CACzC;CAEA,uBAAuB,UAAkB;EACvC,KAAK,OAAO,uBAAuB,QAAQ;EAC3C,KAAK,MAAM,IAAI,2BAA2B,QAAQ;CACpD;CAEA,yBAAyB;EACvB,OAAO,KAAK,OAAO,uBAAuB;CAC5C;CAEA,aAAa,MAAc;EACzB,OAAO,KAAK,OAAO,aAAa,IAAI;CACtC;CAEA,oBAAoB;EAClB,OAAO,KAAK,OAAO,kBAAkB;CACvC;CAEA,aAAa,MAAc,OAAe;EACxC,KAAK,OAAO,aAAa,MAAM,KAAK;EACpC,KAAK,MAAM,IAAI,KAAK,sBAAsB,IAAI,GAAG,KAAK;CACxD;CAEA,gBAAgB,MAAc;EAC5B,KAAK,OAAO,gBAAgB,IAAI;EAChC,KAAK,MAAM,IAAI,KAAK,sBAAsB,IAAI,GAAG,IAAI;CACvD;AACF;AASA,IAAM,uCAAN,MAAkF;CAChF;CACA;CACA;CAEA,YAAY,OAAc,WAAsB;EAC9C,KAAK,QAAQ;EACb,KAAK,YAAY;EACjB,KAAK,iBAAiB,GAAG,KAAK,UAAU;CAC1C;CAEA,cAAc,WAAmB;EAC/B,OAAO,GAAG,KAAK,UAAU,YAAY;CACvC;CAEA,MAAM,KAAK,SAAuB;EAChC,MAAM,qBACJ,QAAQ,oBAAoB,IAAI,QAAQ,uBAAuB,IAAI;EACrE,MAAM,KAAK,MAAM,KAAK,KAAK,gBAAgB,oBAAoB,QAAQ,MAAM,CAAC;CAChF;CAEA,MAAM,OAAO,WAAmB;EAC9B,MAAM,KAAK,MAAM,KAAK,KAAK,gBAAgB,SAAS;CACtD;CAEA,MAAM,OAAO,SAAuB;EAClC,IAAI,QAAQ,sBAAsB,QAAQ,MAAM,GAAG;EACnD,MAAM,KAAK,OAAO,QAAQ,iBAAiB;EAC3C,MAAM,KAAK,KAAK,OAAO;CACzB;CAEA,MAAM,uBAAuB,eAAe,KAAK;EAC/C,MAAM,MAAM,KAAK;EACjB,MAAM,QAAQ,KAAK,IAAI;EACvB,MAAM,aAAa,MAAM,KAAK,MAAM,iBAAiB,KAAK,OAAO,GAAG,SAAS,GAAG,YAAY;EAC5F,IAAI,WAAW,WAAW,GAAG;EAC7B,KAAK,MAAM,aAAa,YAAY;GAClC,MAAM,aAAa,KAAK,cAAc,SAAS;GAG/C,MAAM,KAAK,MAAM,OAAO,UAAU;EACpC;CACF;AACF;AAMA,IAAa,gCAAb,MAAsF;CACpF;CACA;CACA;CAEA,6BAAqC;CAErC,YAAY,OAAc,YAAuB,eAAe;EAC9D,KAAK,QAAQ;EACb,KAAK,YAAY;EACjB,KAAK,kBAAkB,IAAI,qCAAqC,OAAO,SAAS;CAClF;CAEA,8BAA8B,UAAkB;EAC9C,KAAK,6BAA6B;CACpC;CAEA,cAAsB,WAAmB;EACvC,OAAO,GAAG,KAAK,UAAU,YAAY;CACvC;CAEA,cAAsB,WAAmB;EACvC,OAAO,GAAG,KAAK,UAAU,oBAAoB;CAC/C;CAEA,sBAA8B,MAAc;EAC1C,OAAO,mBAAmB;CAC5B;CAEA,gBAAwB,eAAuB;EAC7C,OAAO,GAAG,KAAK,UAAU,SAAS,0BAA0B,GAAG;CACjE;CAEA,MAAc,WAAW,IAAY,cAAqD;EACxF,MAAM,MAAM,KAAK,cAAc,EAAE;EACjC,MAAM,UAAU,MAAM,KAAK,MAAM,QAAQ,GAAG;EAC5C,IAAI,OAAO,KAAK,OAAO,CAAC,CAAC,WAAW,GAAG,OAAO;EAC9C,MAAM,SAAS,IAAI,WAAW,EAAE;EAChC,IAAI,CAAC,QAAQ,cAAc,MAAM,IAAI,MAAM,kCAAkC;EAC7E,IAAI,CAAC,QAAQ,kBAAkB,MAAM,IAAI,MAAM,sCAAsC;EACrF,IAAI,CAAC,QAAQ,qBAAqB,MAAM,IAAI,MAAM,yCAAyC;EAE3F,OAAO,gBAAgB,OAAO,QAAQ,YAAY,CAAC;EACnD,OAAO,oBAAoB,OAAO,QAAQ,gBAAgB,CAAC;EAC3D,OAAO,uBAAuB,OAAO,QAAQ,mBAAmB,CAAC;EAEjE,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,GAC/C,IAAI,IAAI,WAAW,gBAAgB,GACjC,OAAO,aAAa,IAAI,MAAM,EAAuB,GAAG,KAAK;EAIjE,IAAI,CAAC,gBAAgB,OAAO,UAAU,GAAG,OAAO;EAChD,MAAM,SAAS,IAAI,aAAa,QAAQ,KAAK;EAC7C,OAAO,yBAAyB,OAAO,oBAAoB;EAC3D,OAAO;CACT;CAEA,MAAc,UAAU,SAAuB;EAC7C,IAAI,QAAQ,MAAM,SAAS,GAAG;EAC9B,MAAM,YAAY,QAAQ,MAAM;EAChC,MAAM,wBAAQ,IAAI,IAA6B;EAC/C,MAAM,UAAoB,CAAC;EAC3B,QAAQ,MAAM,SAAS,OAAO,QAAQ;GACpC,IAAI,UAAU,MAAM,MAAM,IAAI,KAAK,KAAK;QACnC,QAAQ,KAAK,GAAG;EACvB,CAAC;EAED,IAAI,MAAM,SAAS,GACjB,MAAM,KAAK,MAAM,KAAK,KAAK,cAAc,SAAS,GAAG,KAAK;EAE5D,IAAI,QAAQ,WAAW,GACrB,MAAM,KAAK,MAAM,KAAK,KAAK,cAAc,SAAS,GAAG,GAAG,OAAO;EAGjE,IAAI,QAAQ,MAAM,IAAI,KAAK,sBAAA,eAA+C,CAAC,GAAG;GAC5E,IAAI,QAAQ,0BAA0B,MAAM;IAC1C,MAAM,4BAA4B,KAAK,gBAAgB,QAAQ,qBAAqB;IACpF,MAAM,KAAK,MAAM,KAAK,2BAA2B,SAAS;GAC5D;GACA,MAAM,YAAY,gBAAgB,OAAO;GACzC,QAAQ,wBAAwB;GAChC,IAAI,cAAc,MAAM;IACtB,MAAM,oBAAoB,KAAK,gBAAgB,SAAS;IACxD,MAAM,KAAK,MAAM,KAAK,mBAAmB,SAAS;GACpD;EACF;EAEA,IAAI,QAAQ,OAEV,QAAQ,QAAQ;EAGlB,MAAM,yBAAyB,QAAQ,uBAAuB;EAG9D,MAAM,cAAc,yBAAyB,QAAQ,MAAM;EAC3D,MAAM,aAAa,KAAK,cAAc,WAAW;EAEjD,IAAI,yBAAyB,GAAG;GAC9B,MAAM,KAAK,MAAM,OAAO,YAAY,EAAE;GACtC,MAAM,KAAK,MAAM,QAAQ,UAAU;GACnC,MAAM,KAAK,MAAM,QAAQ,KAAK,cAAc,QAAQ,MAAM,CAAC,CAAC;EAC9D,OAAO,IAAI,2BAA2B,GACpC,MAAM,KAAK,MAAM,IAAI,UAAU;OAC1B;GACL,MAAM,KAAK,MAAM,OAAO,YAAY,EAAE;GACtC,MAAM,KAAK,MAAM,OAAO,YAAY,sBAAsB;EAC5D;EAGA,IAAI,yBAAyB,GAAG;GAC9B,MAAM,0BAA0B,yBAAyB;GACzD,MAAM,KAAK,MAAM,OAAO,KAAK,cAAc,QAAQ,MAAM,CAAC,GAAG,uBAAuB;EACtF;EAEA,MAAM,KAAK,gBAAgB,KAAK,OAAO;EACvC,QAAQ,MAAM,MAAM;CACtB;CAEA,MAAc,oBAAoB,SAAuB;EACvD,MAAM,YAAY,QAAQ,MAAM;EAChC,IAAI,cAAc,QAAQ,mBAAmB;EAC7C,IAAI,CAAC,QAAQ,OAAO;GAClB,MAAM,uBAAuB,KAAK,cAAc,QAAQ,iBAAiB;GACzE,MAAM,eAAe,KAAK,cAAc,SAAS;GACjD,MAAM,qBAAqB,KAAK,cAAc,QAAQ,iBAAiB;GACvE,MAAM,aAAa,KAAK,cAAc,SAAS;GAE/C,MAAM,KAAK,MAAM,OAAO,sBAAsB,YAAY;GAC1D,MAAM,KAAK,MAAM,OAAO,oBAAoB,UAAU;GAEtD,IAAI,QAAQ,0BAA0B,MAAM;IAC1C,MAAM,4BAA4B,KAAK,gBAAgB,QAAQ,qBAAqB;IACpF,MAAM,KAAK,MAAM,KAAK,2BAA2B,QAAQ,iBAAiB;IAC1E,MAAM,KAAK,MAAM,KAAK,2BAA2B,SAAS;GAC5D;GACA,MAAM,KAAK,gBAAgB,OAAO,OAAO;EAC3C;EACA,QAAQ,oBAAoB;CAC9B;CAGA,gBAAgB;EACd,MAAM,SAAS,IAAI,WAAW;EAC9B,OAAO,uBAAuB,KAAK,0BAA0B;EAC7D,OAAO,IAAI,aAAa,QAAQ,IAAI;CACtC;CAEA,MAAM,KAAK,SAAuB;EAChC,MAAM,KAAK,oBAAoB,OAAO;EACtC,MAAM,KAAK,UAAU,OAAO;CAC9B;CAEA,MAAM,SAAS,WAAiD;EAC9D,OAAO,KAAK,WAAW,WAAW,KAAK;CACzC;CAEA,MAAM,WAAW,WAAmB;EAClC,MAAM,UAAU,MAAM,KAAK,WAAW,WAAW,IAAI;EACrD,IAAI,CAAC,SAAS;EAEd,MAAM,YAAY,gBAAgB,OAAO;EACzC,IAAI,cAAc,MAChB,MAAM,KAAK,MAAM,KAAK,KAAK,gBAAgB,SAAS,GAAG,SAAS;EAGlE,MAAM,KAAK,gBAAgB,OAAO,SAAS;EAE3C,MAAM,aAAa,KAAK,cAAc,SAAS;EAC/C,MAAM,KAAK,MAAM,IAAI,UAAU;EAE/B,QAAQ,uBAAuB,CAAC;EAChC,MAAM,KAAK,KAAK,OAAO;CACzB;CAEA,MAAM,6BAA6B,WAAmB,YAAoB;EACxE,IAAI,cAAA,iBACF,uBAAO,IAAI,IAA0B;EAGvC,MAAM,eAAe,KAAK,gBAAgB,UAAU;EACpD,MAAM,aAAa,MAAM,KAAK,MAAM,SAAS,YAAY;EACzD,IAAI,WAAW,WAAW,GACxB,uBAAO,IAAI,IAA0B;EAEvC,MAAM,2BAAW,IAAI,IAA0B;EAC/C,KAAK,MAAM,aAAa,YAAY;GAClC,MAAM,UAAU,MAAM,KAAK,SAAS,SAAS;GAC7C,IAAI,YAAY,MACd,SAAS,IAAI,WAAW,OAAO;EAEnC;EACA,OAAO;CACT;CAEA,MAAM,oBAAoB,eAAuB;EAC/C,OAAO,KAAK,6BAA6B,2BAA2B,aAAa;CACnF;CAEA,MAAM,uBAAuB,cAAuB;EAClD,MAAM,KAAK,gBAAgB,uBAAuB,YAAY;CAChE;AACF;AAEA,MAAM,mBAAmB;;;;;AAMzB,IAAa,oBAAb,MAAuD;CACrD;CAEA,YAAY,OAAc;EACxB,KAAK,QAAQ;CACf;CAEA,MAAM,QAAQ,KAAa,OAAe,WAAoB;EAC5D,IAAI,WACF,MAAM,KAAK,MAAM,IAAI,KAAK,OAAO,MAAM,SAAS;OAEhD,MAAM,KAAK,MAAM,IAAI,KAAK,KAAK;CAEnC;CAEA,MAAM,QAAQ,KAAqC;EACjD,OAAO,KAAK,MAAM,IAAI,GAAG;CAC3B;CAEA,MAAM,WAAW,KAAa;EAC5B,MAAM,KAAK,MAAM,IAAI,GAAG;CAC1B;CAEA,MAAM,UAAU,KAAa,WAAoC;EAG/D,MAAM,QAAQ,MAAM,KAAK,MAAM,KAAK,kBAAkB,GAAG,KAAK,SAAS;EACvE,OAAO,OAAO,KAAK;CACrB;AACF"}
|
package/dist/session/types.d.cts
CHANGED
|
@@ -1,16 +1,3 @@
|
|
|
1
|
-
import { Principal } from "../core/index.cjs";
|
|
2
|
-
//#region src/session/types.d.ts
|
|
3
|
-
export interface Authentication extends Principal {
|
|
4
|
-
'@class': string;
|
|
5
|
-
principal?: Principal;
|
|
6
|
-
authorities?: string[];
|
|
7
|
-
credentials?: object;
|
|
8
|
-
details?: object;
|
|
9
|
-
}
|
|
10
|
-
export interface SecurityContext {
|
|
11
|
-
'@class': string;
|
|
12
|
-
authentication?: Authentication;
|
|
13
|
-
}
|
|
14
1
|
export type Namespace = `${string}:session`;
|
|
15
2
|
export interface Session {
|
|
16
3
|
getId(): string;
|
|
@@ -51,5 +38,4 @@ export interface KVRepository {
|
|
|
51
38
|
*/
|
|
52
39
|
increment(key: string, expiresIn: number): Promise<number>;
|
|
53
40
|
}
|
|
54
|
-
//#endregion
|
|
55
41
|
//# sourceMappingURL=types.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.cts","names":[],"sources":["../../src/session/types.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.cts","names":[],"sources":["../../src/session/types.ts"],"mappings":"A,YAEY;iBAEK;EACf;EACA;EAEA,aAAa;EACb;EACA,aAAa,cAAc;EAC3B,gBAAgB;EAEhB;EACA;EACA,oBAAoB;EAEpB;EACA,uBAAuB;EAEvB;;iBAGe,kBAAkB,UAAU,UAAU;EACrD,iBAAiB;EACjB,KAAK,SAAS,IAAI;EAClB,SAAS,oBAAoB,QAAQ;EACrC,WAAW,oBAAoB;EAG/B,6BAA6B,mBAAmB,qBAAqB,QAAQ,YAAY;EACzF,oBAAoB,wBAAwB,QAAQ,YAAY;EAGhE,uBAAuB,wBAAwB;;;;;;iBAOhC;EACf,QAAQ,aAAa,eAAe,qBAAqB;EACzD,QAAQ,cAAc;EACtB,WAAW,cAAc;;;;;;;EAOzB,UAAU,aAAa,oBAAoB"}
|
package/dist/session/types.d.mts
CHANGED
|
@@ -1,16 +1,3 @@
|
|
|
1
|
-
import { Principal } from "../core/index.mjs";
|
|
2
|
-
//#region src/session/types.d.ts
|
|
3
|
-
export interface Authentication extends Principal {
|
|
4
|
-
'@class': string;
|
|
5
|
-
principal?: Principal;
|
|
6
|
-
authorities?: string[];
|
|
7
|
-
credentials?: object;
|
|
8
|
-
details?: object;
|
|
9
|
-
}
|
|
10
|
-
export interface SecurityContext {
|
|
11
|
-
'@class': string;
|
|
12
|
-
authentication?: Authentication;
|
|
13
|
-
}
|
|
14
1
|
export type Namespace = `${string}:session`;
|
|
15
2
|
export interface Session {
|
|
16
3
|
getId(): string;
|
|
@@ -51,5 +38,4 @@ export interface KVRepository {
|
|
|
51
38
|
*/
|
|
52
39
|
increment(key: string, expiresIn: number): Promise<number>;
|
|
53
40
|
}
|
|
54
|
-
//#endregion
|
|
55
41
|
//# sourceMappingURL=types.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.mts","names":[],"sources":["../../src/session/types.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.mts","names":[],"sources":["../../src/session/types.ts"],"mappings":"A,YAEY;iBAEK;EACf;EACA;EAEA,aAAa;EACb;EACA,aAAa,cAAc;EAC3B,gBAAgB;EAEhB;EACA;EACA,oBAAoB;EAEpB;EACA,uBAAuB;EAEvB;;iBAGe,kBAAkB,UAAU,UAAU;EACrD,iBAAiB;EACjB,KAAK,SAAS,IAAI;EAClB,SAAS,oBAAoB,QAAQ;EACrC,WAAW,oBAAoB;EAG/B,6BAA6B,mBAAmB,qBAAqB,QAAQ,YAAY;EACzF,oBAAoB,wBAAwB,QAAQ,YAAY;EAGhE,uBAAuB,wBAAwB;;;;;;iBAOhC;EACf,QAAQ,aAAa,eAAe,qBAAqB;EACzD,QAAQ,cAAc;EACtB,WAAW,cAAc;;;;;;;EAOzB,UAAU,aAAa,oBAAoB"}
|
package/dist/utils/http.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
let cookie = require("cookie");
|
|
3
3
|
let path_to_regexp = require("path-to-regexp");
|
|
4
|
-
|
|
4
|
+
// src/utils/http.ts
|
|
5
5
|
function getCookie(request, name) {
|
|
6
6
|
const cookie$1 = request.headers.get("Cookie");
|
|
7
7
|
if (!cookie$1) return void 0;
|
|
@@ -32,7 +32,6 @@ function query(request) {
|
|
|
32
32
|
const url = new URL(request.url);
|
|
33
33
|
return Object.fromEntries(url.searchParams.entries());
|
|
34
34
|
}
|
|
35
|
-
//#endregion
|
|
36
35
|
exports.deleteCookie = deleteCookie;
|
|
37
36
|
exports.getCookie = getCookie;
|
|
38
37
|
exports.param = param;
|
package/dist/utils/http.d.cts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { SerializeOptions } from "cookie";
|
|
2
|
-
//#region src/utils/http.d.ts
|
|
3
2
|
export type CookieOptions = Omit<SerializeOptions, 'encode'>;
|
|
4
3
|
export declare function getCookie(request: Request, name: string): string | undefined;
|
|
5
4
|
export declare function setCookie(response: Response, name: string, value: string, options?: SerializeOptions): void;
|
|
@@ -9,6 +8,5 @@ export declare function param<P extends string>(request: Request, path: P): Path
|
|
|
9
8
|
export declare function query(request: Request): {
|
|
10
9
|
[k: string]: string;
|
|
11
10
|
};
|
|
12
|
-
//#endregion
|
|
13
11
|
export {};
|
|
14
12
|
//# sourceMappingURL=http.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.cts","names":[],"sources":["../../src/utils/http.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"http.d.cts","names":[],"sources":["../../src/utils/http.ts"],"mappings":";YAGY,gBAAgB,KAAK;wBAEjB,UAAU,SAAS,SAAS;wBAO5B,UACd,UAAU,UACV,cACA,eACA,UAAU;wBAKI,aAAa,UAAU,UAAU,cAAc,UAAU;KAOpE,UAAU,oBAAoB,6BAA6B,eAAe,YACxE,KAAK,oBAAmB,UAAU,QACrC,6BAA6B,aACxB,KAAK;wBAIE,MAAM,kBAAkB,SAAS,SAAS,MAAM,IAAI,UAAU;wBAQ9D,MAAM,SAAS"}
|
package/dist/utils/http.d.mts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { SerializeOptions } from "cookie";
|
|
2
|
-
//#region src/utils/http.d.ts
|
|
3
2
|
export type CookieOptions = Omit<SerializeOptions, 'encode'>;
|
|
4
3
|
export declare function getCookie(request: Request, name: string): string | undefined;
|
|
5
4
|
export declare function setCookie(response: Response, name: string, value: string, options?: SerializeOptions): void;
|
|
@@ -9,6 +8,5 @@ export declare function param<P extends string>(request: Request, path: P): Path
|
|
|
9
8
|
export declare function query(request: Request): {
|
|
10
9
|
[k: string]: string;
|
|
11
10
|
};
|
|
12
|
-
//#endregion
|
|
13
11
|
export {};
|
|
14
12
|
//# sourceMappingURL=http.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.mts","names":[],"sources":["../../src/utils/http.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"http.d.mts","names":[],"sources":["../../src/utils/http.ts"],"mappings":";YAGY,gBAAgB,KAAK;wBAEjB,UAAU,SAAS,SAAS;wBAO5B,UACd,UAAU,UACV,cACA,eACA,UAAU;wBAKI,aAAa,UAAU,UAAU,cAAc,UAAU;KAOpE,UAAU,oBAAoB,6BAA6B,eAAe,YACxE,KAAK,oBAAmB,UAAU,QACrC,6BAA6B,aACxB,KAAK;wBAIE,MAAM,kBAAkB,SAAS,SAAS,MAAM,IAAI,UAAU;wBAQ9D,MAAM,SAAS"}
|
package/dist/utils/http.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { parseCookie, stringifySetCookie } from "cookie";
|
|
2
2
|
import { match } from "path-to-regexp";
|
|
3
|
-
|
|
3
|
+
// src/utils/http.ts
|
|
4
4
|
function getCookie(request, name) {
|
|
5
5
|
const cookie = request.headers.get("Cookie");
|
|
6
6
|
if (!cookie) return void 0;
|
|
@@ -31,7 +31,6 @@ function query(request) {
|
|
|
31
31
|
const url = new URL(request.url);
|
|
32
32
|
return Object.fromEntries(url.searchParams.entries());
|
|
33
33
|
}
|
|
34
|
-
//#endregion
|
|
35
34
|
export { deleteCookie, getCookie, param, query, setCookie };
|
|
36
35
|
|
|
37
36
|
//# sourceMappingURL=http.mjs.map
|
package/dist/utils/oauth2.cjs
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
|
|
2
|
+
// src/utils/oauth2.ts
|
|
3
3
|
function inWechatBrowser() {
|
|
4
4
|
return navigator.userAgent.includes("MicroMessenger");
|
|
5
5
|
}
|
|
6
|
-
//#endregion
|
|
7
6
|
exports.inWechatBrowser = inWechatBrowser;
|
|
8
7
|
|
|
9
8
|
//# sourceMappingURL=oauth2.cjs.map
|
package/dist/utils/oauth2.d.cts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth2.d.cts","names":[],"sources":["../../src/utils/oauth2.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"oauth2.d.cts","names":[],"sources":["../../src/utils/oauth2.ts"],"mappings":"A,wBAAgB"}
|
package/dist/utils/oauth2.d.mts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth2.d.mts","names":[],"sources":["../../src/utils/oauth2.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"oauth2.d.mts","names":[],"sources":["../../src/utils/oauth2.ts"],"mappings":"A,wBAAgB"}
|
package/dist/utils/oauth2.mjs
CHANGED
package/dist/utils/timing.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
|
|
2
|
+
// src/utils/timing.ts
|
|
3
3
|
function timing({ enabled, crossOrigin }) {
|
|
4
4
|
let start = performance.now();
|
|
5
5
|
const headers = [];
|
|
@@ -46,7 +46,6 @@ function timing({ enabled, crossOrigin }) {
|
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
|
-
//#endregion
|
|
50
49
|
exports.timing = timing;
|
|
51
50
|
|
|
52
51
|
//# sourceMappingURL=timing.cjs.map
|
package/dist/utils/timing.d.cts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
//#region src/utils/timing.d.ts
|
|
2
1
|
interface Options {
|
|
3
2
|
enabled: boolean;
|
|
4
3
|
crossOrigin?: string;
|
|
@@ -10,6 +9,5 @@ export declare function timing({ enabled, crossOrigin }: Options): {
|
|
|
10
9
|
setMetric: (name: Lowercase<string>, value: number | string | undefined, description?: string, precision?: number) => void;
|
|
11
10
|
setTiming: (response: Response) => void;
|
|
12
11
|
};
|
|
13
|
-
//#endregion
|
|
14
12
|
export {};
|
|
15
13
|
//# sourceMappingURL=timing.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timing.d.cts","names":[],"sources":["../../src/utils/timing.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"timing.d.cts","names":[],"sources":["../../src/utils/timing.ts"],"mappings":"A,UAKU;EACR;EACA;;wBAGc,SAAS,SAAS,eAAe;EAM7C,YAAS,MAAS,mBAAiB;EAGnC,UAAO,MAAS,mBAAiB;EAcjC,OAAI,MAAS,mBAAiB,sBAAsB;EAQpD,YAAS,MACD,mBAAiB,oCACW,sBACd;EActB,YAAS,UAAa"}
|
package/dist/utils/timing.d.mts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
//#region src/utils/timing.d.ts
|
|
2
1
|
interface Options {
|
|
3
2
|
enabled: boolean;
|
|
4
3
|
crossOrigin?: string;
|
|
@@ -10,6 +9,5 @@ export declare function timing({ enabled, crossOrigin }: Options): {
|
|
|
10
9
|
setMetric: (name: Lowercase<string>, value: number | string | undefined, description?: string, precision?: number) => void;
|
|
11
10
|
setTiming: (response: Response) => void;
|
|
12
11
|
};
|
|
13
|
-
//#endregion
|
|
14
12
|
export {};
|
|
15
13
|
//# sourceMappingURL=timing.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timing.d.mts","names":[],"sources":["../../src/utils/timing.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"timing.d.mts","names":[],"sources":["../../src/utils/timing.ts"],"mappings":"A,UAKU;EACR;EACA;;wBAGc,SAAS,SAAS,eAAe;EAM7C,YAAS,MAAS,mBAAiB;EAGnC,UAAO,MAAS,mBAAiB;EAcjC,OAAI,MAAS,mBAAiB,sBAAsB;EAQpD,YAAS,MACD,mBAAiB,oCACW,sBACd;EActB,YAAS,UAAa"}
|
package/dist/utils/timing.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/utils/timing.ts
|
|
2
2
|
function timing({ enabled, crossOrigin }) {
|
|
3
3
|
let start = performance.now();
|
|
4
4
|
const headers = [];
|
|
@@ -45,7 +45,6 @@ function timing({ enabled, crossOrigin }) {
|
|
|
45
45
|
}
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
|
-
//#endregion
|
|
49
48
|
export { timing };
|
|
50
49
|
|
|
51
50
|
//# sourceMappingURL=timing.mjs.map
|