@parsrun/auth 0.1.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 +133 -0
- package/dist/adapters/hono.d.ts +9 -0
- package/dist/adapters/hono.js +6 -0
- package/dist/adapters/hono.js.map +1 -0
- package/dist/adapters/index.d.ts +9 -0
- package/dist/adapters/index.js +7 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/authorization-By1Xp8Za.d.ts +213 -0
- package/dist/base-BKyR8rcE.d.ts +646 -0
- package/dist/chunk-42MGHABB.js +263 -0
- package/dist/chunk-42MGHABB.js.map +1 -0
- package/dist/chunk-7GOBAL4G.js +3 -0
- package/dist/chunk-7GOBAL4G.js.map +1 -0
- package/dist/chunk-G5I3T73A.js +152 -0
- package/dist/chunk-G5I3T73A.js.map +1 -0
- package/dist/chunk-IB4WUQDZ.js +410 -0
- package/dist/chunk-IB4WUQDZ.js.map +1 -0
- package/dist/chunk-MOG4Y6I7.js +415 -0
- package/dist/chunk-MOG4Y6I7.js.map +1 -0
- package/dist/chunk-NK4TJV2W.js +295 -0
- package/dist/chunk-NK4TJV2W.js.map +1 -0
- package/dist/chunk-RHNVRCF3.js +838 -0
- package/dist/chunk-RHNVRCF3.js.map +1 -0
- package/dist/chunk-YTCPXJR5.js +570 -0
- package/dist/chunk-YTCPXJR5.js.map +1 -0
- package/dist/cloudflare-kv-L64CZKDK.js +105 -0
- package/dist/cloudflare-kv-L64CZKDK.js.map +1 -0
- package/dist/deno-kv-F55HKKP6.js +111 -0
- package/dist/deno-kv-F55HKKP6.js.map +1 -0
- package/dist/index-C3kz9XqE.d.ts +226 -0
- package/dist/index-DOGcetyD.d.ts +1041 -0
- package/dist/index.d.ts +1579 -0
- package/dist/index.js +4294 -0
- package/dist/index.js.map +1 -0
- package/dist/jwt-manager-CH8H0kmm.d.ts +182 -0
- package/dist/providers/index.d.ts +90 -0
- package/dist/providers/index.js +3 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/otp/index.d.ts +3 -0
- package/dist/providers/otp/index.js +4 -0
- package/dist/providers/otp/index.js.map +1 -0
- package/dist/redis-5TIS6XCA.js +121 -0
- package/dist/redis-5TIS6XCA.js.map +1 -0
- package/dist/security/index.d.ts +301 -0
- package/dist/security/index.js +5 -0
- package/dist/security/index.js.map +1 -0
- package/dist/session/index.d.ts +117 -0
- package/dist/session/index.js +4 -0
- package/dist/session/index.js.map +1 -0
- package/dist/storage/index.d.ts +97 -0
- package/dist/storage/index.js +3 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/types-DSjafxJ4.d.ts +193 -0
- package/package.json +102 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import * as jose from 'jose';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* JWT Manager with Key Rotation Support
|
|
5
|
+
* Uses jose library for multi-runtime compatibility (Node, Deno, CF Workers, Bun)
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* JWT configuration
|
|
10
|
+
*/
|
|
11
|
+
interface JwtConfig {
|
|
12
|
+
/** Secret key for signing tokens */
|
|
13
|
+
secret: string;
|
|
14
|
+
/** Token issuer */
|
|
15
|
+
issuer: string;
|
|
16
|
+
/** Token audience */
|
|
17
|
+
audience: string;
|
|
18
|
+
/** Access token TTL (e.g., '15m', '1h') */
|
|
19
|
+
accessTokenTTL?: string;
|
|
20
|
+
/** Refresh token TTL (e.g., '7d', '12h') */
|
|
21
|
+
refreshTokenTTL?: string;
|
|
22
|
+
/** Previous secrets for key rotation */
|
|
23
|
+
previousSecrets?: string[];
|
|
24
|
+
/** Current key version */
|
|
25
|
+
keyVersion?: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* JWT payload structure
|
|
29
|
+
*/
|
|
30
|
+
interface JwtPayload {
|
|
31
|
+
/** User ID */
|
|
32
|
+
sub: string;
|
|
33
|
+
/** Tenant ID */
|
|
34
|
+
tid?: string;
|
|
35
|
+
/** Session ID */
|
|
36
|
+
sid?: string;
|
|
37
|
+
/** Issued at timestamp */
|
|
38
|
+
iat: number;
|
|
39
|
+
/** Expiration timestamp */
|
|
40
|
+
exp: number;
|
|
41
|
+
/** Issuer */
|
|
42
|
+
iss: string;
|
|
43
|
+
/** Audience */
|
|
44
|
+
aud: string | string[];
|
|
45
|
+
/** User roles */
|
|
46
|
+
roles?: string[];
|
|
47
|
+
/** User permissions */
|
|
48
|
+
permissions?: string[];
|
|
49
|
+
/** Additional claims */
|
|
50
|
+
[key: string]: unknown;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Token pair (access + refresh)
|
|
54
|
+
*/
|
|
55
|
+
interface TokenPair {
|
|
56
|
+
accessToken: string;
|
|
57
|
+
refreshToken: string;
|
|
58
|
+
accessExpiresAt: Date;
|
|
59
|
+
refreshExpiresAt: Date;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Key rotation result
|
|
63
|
+
*/
|
|
64
|
+
interface KeyRotationResult {
|
|
65
|
+
previousSecret: string;
|
|
66
|
+
newSecret: string;
|
|
67
|
+
keyVersion: number;
|
|
68
|
+
rotatedAt: Date;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Parse duration string to seconds
|
|
72
|
+
* Supports: s (seconds), m (minutes), h (hours), d (days), w (weeks)
|
|
73
|
+
*/
|
|
74
|
+
declare function parseDuration(duration: string): number;
|
|
75
|
+
/**
|
|
76
|
+
* JWT Manager
|
|
77
|
+
* Handles token generation, verification, and key rotation
|
|
78
|
+
*/
|
|
79
|
+
declare class JwtManager {
|
|
80
|
+
private secret;
|
|
81
|
+
private previousSecrets;
|
|
82
|
+
private config;
|
|
83
|
+
private keyVersion;
|
|
84
|
+
constructor(config: JwtConfig);
|
|
85
|
+
/**
|
|
86
|
+
* Get current key version
|
|
87
|
+
*/
|
|
88
|
+
getKeyVersion(): number;
|
|
89
|
+
/**
|
|
90
|
+
* Rotate the signing key
|
|
91
|
+
* Moves current secret to previousSecrets and sets new secret
|
|
92
|
+
*/
|
|
93
|
+
rotateKey(newSecret: string, options?: {
|
|
94
|
+
maxPreviousSecrets?: number;
|
|
95
|
+
}): KeyRotationResult;
|
|
96
|
+
/**
|
|
97
|
+
* Get current configuration (for persistence)
|
|
98
|
+
*/
|
|
99
|
+
getConfig(): JwtConfig;
|
|
100
|
+
/**
|
|
101
|
+
* Generate access token
|
|
102
|
+
*/
|
|
103
|
+
generateAccessToken(payload: {
|
|
104
|
+
userId: string;
|
|
105
|
+
tenantId?: string;
|
|
106
|
+
sessionId?: string;
|
|
107
|
+
roles?: string[];
|
|
108
|
+
permissions?: string[];
|
|
109
|
+
claims?: Record<string, unknown>;
|
|
110
|
+
}): Promise<{
|
|
111
|
+
token: string;
|
|
112
|
+
expiresAt: Date;
|
|
113
|
+
}>;
|
|
114
|
+
/**
|
|
115
|
+
* Generate refresh token
|
|
116
|
+
*/
|
|
117
|
+
generateRefreshToken(payload: {
|
|
118
|
+
userId: string;
|
|
119
|
+
tenantId?: string;
|
|
120
|
+
sessionId?: string;
|
|
121
|
+
}): Promise<{
|
|
122
|
+
token: string;
|
|
123
|
+
expiresAt: Date;
|
|
124
|
+
}>;
|
|
125
|
+
/**
|
|
126
|
+
* Generate token pair (access + refresh)
|
|
127
|
+
*/
|
|
128
|
+
generateTokenPair(payload: {
|
|
129
|
+
userId: string;
|
|
130
|
+
tenantId?: string;
|
|
131
|
+
sessionId?: string;
|
|
132
|
+
roles?: string[];
|
|
133
|
+
permissions?: string[];
|
|
134
|
+
claims?: Record<string, unknown>;
|
|
135
|
+
}): Promise<TokenPair>;
|
|
136
|
+
/**
|
|
137
|
+
* Verify access token
|
|
138
|
+
* Tries current secret first, then falls back to previous secrets for graceful rotation
|
|
139
|
+
*/
|
|
140
|
+
verifyAccessToken(token: string): Promise<JwtPayload>;
|
|
141
|
+
/**
|
|
142
|
+
* Verify refresh token
|
|
143
|
+
*/
|
|
144
|
+
verifyRefreshToken(token: string): Promise<{
|
|
145
|
+
userId: string;
|
|
146
|
+
tenantId?: string;
|
|
147
|
+
sessionId?: string;
|
|
148
|
+
}>;
|
|
149
|
+
/**
|
|
150
|
+
* Decode token without verification (for inspection)
|
|
151
|
+
*/
|
|
152
|
+
decodeToken(token: string): jose.JWTPayload | null;
|
|
153
|
+
/**
|
|
154
|
+
* Check if token is expired (without signature verification)
|
|
155
|
+
*/
|
|
156
|
+
isTokenExpired(token: string): boolean;
|
|
157
|
+
/**
|
|
158
|
+
* Get token expiration date (without signature verification)
|
|
159
|
+
*/
|
|
160
|
+
getTokenExpiration(token: string): Date | null;
|
|
161
|
+
/**
|
|
162
|
+
* Get time until token expires in seconds
|
|
163
|
+
*/
|
|
164
|
+
getTokenTTL(token: string): number;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* JWT Error class
|
|
168
|
+
*/
|
|
169
|
+
declare class JwtError extends Error {
|
|
170
|
+
readonly code: 'TOKEN_EXPIRED' | 'INVALID_TOKEN' | 'INVALID_TOKEN_TYPE' | 'VERIFICATION_FAILED';
|
|
171
|
+
constructor(message: string, code: 'TOKEN_EXPIRED' | 'INVALID_TOKEN' | 'INVALID_TOKEN_TYPE' | 'VERIFICATION_FAILED');
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Extract token from Authorization header
|
|
175
|
+
*/
|
|
176
|
+
declare function extractBearerToken(authHeader: string | null | undefined): string | null;
|
|
177
|
+
/**
|
|
178
|
+
* Create a JwtManager instance
|
|
179
|
+
*/
|
|
180
|
+
declare function createJwtManager(config: JwtConfig): JwtManager;
|
|
181
|
+
|
|
182
|
+
export { JwtManager as J, type KeyRotationResult as K, type TokenPair as T, JwtError as a, type JwtConfig as b, createJwtManager as c, type JwtPayload as d, extractBearerToken as e, parseDuration as p };
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { A as AuthProvider, P as ProviderType, a as ProviderInfo, O as OAuthProvider, T as TwoFactorProvider } from '../base-BKyR8rcE.js';
|
|
2
|
+
export { b as AuthInput, c as AuthResult, B as BaseProvider, f as OAuthUserInfo, e as TwoFactorSetupResult, V as VerifyInput, d as VerifyResult } from '../base-BKyR8rcE.js';
|
|
3
|
+
import '../types-DSjafxJ4.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Provider Registry
|
|
7
|
+
* Manages authentication providers
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Provider registry for managing auth providers
|
|
12
|
+
*/
|
|
13
|
+
declare class ProviderRegistry {
|
|
14
|
+
private providers;
|
|
15
|
+
/**
|
|
16
|
+
* Register a provider
|
|
17
|
+
*/
|
|
18
|
+
register(provider: AuthProvider): void;
|
|
19
|
+
/**
|
|
20
|
+
* Unregister a provider
|
|
21
|
+
*/
|
|
22
|
+
unregister(name: string): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Get a provider by name
|
|
25
|
+
*/
|
|
26
|
+
get(name: string): AuthProvider | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Get a provider by name (throws if not found)
|
|
29
|
+
*/
|
|
30
|
+
getOrThrow(name: string): AuthProvider;
|
|
31
|
+
/**
|
|
32
|
+
* Check if a provider is registered
|
|
33
|
+
*/
|
|
34
|
+
has(name: string): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Get all providers of a specific type
|
|
37
|
+
*/
|
|
38
|
+
getByType(type: ProviderType): AuthProvider[];
|
|
39
|
+
/**
|
|
40
|
+
* Get all enabled providers
|
|
41
|
+
*/
|
|
42
|
+
getEnabled(): AuthProvider[];
|
|
43
|
+
/**
|
|
44
|
+
* Get all enabled providers of a specific type
|
|
45
|
+
*/
|
|
46
|
+
getEnabledByType(type: ProviderType): AuthProvider[];
|
|
47
|
+
/**
|
|
48
|
+
* Get all registered providers
|
|
49
|
+
*/
|
|
50
|
+
getAll(): AuthProvider[];
|
|
51
|
+
/**
|
|
52
|
+
* Get provider names
|
|
53
|
+
*/
|
|
54
|
+
getNames(): string[];
|
|
55
|
+
/**
|
|
56
|
+
* Get provider info for all providers
|
|
57
|
+
*/
|
|
58
|
+
getInfo(): ProviderInfo[];
|
|
59
|
+
/**
|
|
60
|
+
* Get OAuth providers
|
|
61
|
+
*/
|
|
62
|
+
getOAuthProviders(): OAuthProvider[];
|
|
63
|
+
/**
|
|
64
|
+
* Get 2FA providers
|
|
65
|
+
*/
|
|
66
|
+
getTwoFactorProviders(): TwoFactorProvider[];
|
|
67
|
+
/**
|
|
68
|
+
* Check if a provider type is enabled
|
|
69
|
+
*/
|
|
70
|
+
isTypeEnabled(type: ProviderType): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Get the primary authentication provider
|
|
73
|
+
* Returns the first enabled provider in order: otp > magic-link > oauth > password
|
|
74
|
+
*/
|
|
75
|
+
getPrimary(): AuthProvider | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* Clear all providers
|
|
78
|
+
*/
|
|
79
|
+
clear(): void;
|
|
80
|
+
/**
|
|
81
|
+
* Get provider count
|
|
82
|
+
*/
|
|
83
|
+
get size(): number;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Create a new provider registry
|
|
87
|
+
*/
|
|
88
|
+
declare function createProviderRegistry(): ProviderRegistry;
|
|
89
|
+
|
|
90
|
+
export { AuthProvider, OAuthProvider, ProviderInfo, ProviderRegistry, ProviderType, TwoFactorProvider, createProviderRegistry };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// src/storage/redis.ts
|
|
2
|
+
var RedisStorage = class {
|
|
3
|
+
client;
|
|
4
|
+
prefix;
|
|
5
|
+
constructor(client, prefix) {
|
|
6
|
+
this.client = client;
|
|
7
|
+
this.prefix = prefix ?? "";
|
|
8
|
+
}
|
|
9
|
+
getKey(key) {
|
|
10
|
+
return this.prefix ? `${this.prefix}:${key}` : key;
|
|
11
|
+
}
|
|
12
|
+
async get(key) {
|
|
13
|
+
const fullKey = this.getKey(key);
|
|
14
|
+
const value = await this.client.get(fullKey);
|
|
15
|
+
if (value === null) return null;
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(value);
|
|
18
|
+
} catch {
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async set(key, value, ttl) {
|
|
23
|
+
const fullKey = this.getKey(key);
|
|
24
|
+
const serialized = JSON.stringify(value);
|
|
25
|
+
if (ttl) {
|
|
26
|
+
await this.client.set(fullKey, serialized, "EX", ttl);
|
|
27
|
+
} else {
|
|
28
|
+
await this.client.set(fullKey, serialized);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async delete(key) {
|
|
32
|
+
const fullKey = this.getKey(key);
|
|
33
|
+
await this.client.del(fullKey);
|
|
34
|
+
}
|
|
35
|
+
async has(key) {
|
|
36
|
+
const fullKey = this.getKey(key);
|
|
37
|
+
const exists = await this.client.exists(fullKey);
|
|
38
|
+
return exists > 0;
|
|
39
|
+
}
|
|
40
|
+
async getMany(keys) {
|
|
41
|
+
if (keys.length === 0) return [];
|
|
42
|
+
const fullKeys = keys.map((k) => this.getKey(k));
|
|
43
|
+
const values = await this.client.mget(...fullKeys);
|
|
44
|
+
return values.map((value) => {
|
|
45
|
+
if (value === null) return null;
|
|
46
|
+
try {
|
|
47
|
+
return JSON.parse(value);
|
|
48
|
+
} catch {
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
async setMany(entries) {
|
|
54
|
+
await Promise.all(
|
|
55
|
+
entries.map(([key, value, ttl]) => this.set(key, value, ttl))
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
async deleteMany(keys) {
|
|
59
|
+
if (keys.length === 0) return;
|
|
60
|
+
const fullKeys = keys.map((k) => this.getKey(k));
|
|
61
|
+
await this.client.del(fullKeys);
|
|
62
|
+
}
|
|
63
|
+
async keys(pattern) {
|
|
64
|
+
const searchPattern = pattern ? this.getKey(pattern) : this.prefix ? `${this.prefix}:*` : "*";
|
|
65
|
+
const keys = await this.client.keys(searchPattern);
|
|
66
|
+
const prefixLength = this.prefix ? this.prefix.length + 1 : 0;
|
|
67
|
+
return keys.map((k) => prefixLength ? k.slice(prefixLength) : k);
|
|
68
|
+
}
|
|
69
|
+
async clear() {
|
|
70
|
+
if (this.prefix) {
|
|
71
|
+
const keys = await this.client.keys(`${this.prefix}:*`);
|
|
72
|
+
if (keys.length > 0) {
|
|
73
|
+
await this.client.del(keys);
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
console.warn(
|
|
77
|
+
"[Pars Auth] Cannot clear Redis storage without prefix. Use Redis FLUSHDB command directly if needed."
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async close() {
|
|
82
|
+
if (this.client.quit) {
|
|
83
|
+
await this.client.quit();
|
|
84
|
+
} else if (this.client.disconnect) {
|
|
85
|
+
await this.client.disconnect();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
async function createRedisClientFromUrl(url) {
|
|
90
|
+
try {
|
|
91
|
+
const { Redis } = await import('ioredis');
|
|
92
|
+
return new Redis(url);
|
|
93
|
+
} catch {
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
const { Redis } = await import('@upstash/redis');
|
|
97
|
+
const client = new Redis({ url, token: "" });
|
|
98
|
+
return client;
|
|
99
|
+
} catch {
|
|
100
|
+
}
|
|
101
|
+
throw new Error(
|
|
102
|
+
'[Pars Auth] No Redis client available. Install either "ioredis" or "@upstash/redis"'
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
async function createRedisStorage(config) {
|
|
106
|
+
let client;
|
|
107
|
+
if (config.client) {
|
|
108
|
+
client = config.client;
|
|
109
|
+
} else if (config.url) {
|
|
110
|
+
client = await createRedisClientFromUrl(config.url);
|
|
111
|
+
} else {
|
|
112
|
+
throw new Error(
|
|
113
|
+
"[Pars Auth] Redis storage requires either url or client configuration"
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
return new RedisStorage(client, config.prefix);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export { RedisStorage, createRedisStorage };
|
|
120
|
+
//# sourceMappingURL=redis-5TIS6XCA.js.map
|
|
121
|
+
//# sourceMappingURL=redis-5TIS6XCA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/storage/redis.ts"],"names":[],"mappings":"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","file":"redis-5TIS6XCA.js","sourcesContent":["/**\n * Redis KV Storage adapter\n * Supports both ioredis and Upstash Redis\n */\n\nimport type { KVStorage, RedisConfig } from './types.js';\n\n/**\n * Generic Redis client interface\n * Compatible with both ioredis and Upstash Redis\n */\ninterface RedisClient {\n get(key: string): Promise<string | null>;\n set(key: string, value: string, ...args: unknown[]): Promise<unknown>;\n del(key: string | string[]): Promise<number>;\n exists(key: string | string[]): Promise<number>;\n keys(pattern: string): Promise<string[]>;\n mget(...keys: string[]): Promise<(string | null)[]>;\n expire(key: string, seconds: number): Promise<number>;\n quit?(): Promise<unknown>;\n disconnect?(): Promise<void>;\n}\n\n/**\n * Redis storage adapter\n */\nexport class RedisStorage implements KVStorage {\n private client: RedisClient;\n private readonly prefix: string;\n\n constructor(client: RedisClient, prefix?: string) {\n this.client = client;\n this.prefix = prefix ?? '';\n }\n\n private getKey(key: string): string {\n return this.prefix ? `${this.prefix}:${key}` : key;\n }\n\n async get<T = unknown>(key: string): Promise<T | null> {\n const fullKey = this.getKey(key);\n const value = await this.client.get(fullKey);\n\n if (value === null) return null;\n\n try {\n return JSON.parse(value) as T;\n } catch {\n // Return as string if not valid JSON\n return value as unknown as T;\n }\n }\n\n async set<T = unknown>(key: string, value: T, ttl?: number): Promise<void> {\n const fullKey = this.getKey(key);\n const serialized = JSON.stringify(value);\n\n if (ttl) {\n // Use EX for seconds TTL\n await this.client.set(fullKey, serialized, 'EX', ttl);\n } else {\n await this.client.set(fullKey, serialized);\n }\n }\n\n async delete(key: string): Promise<void> {\n const fullKey = this.getKey(key);\n await this.client.del(fullKey);\n }\n\n async has(key: string): Promise<boolean> {\n const fullKey = this.getKey(key);\n const exists = await this.client.exists(fullKey);\n return exists > 0;\n }\n\n async getMany<T = unknown>(keys: string[]): Promise<(T | null)[]> {\n if (keys.length === 0) return [];\n\n const fullKeys = keys.map((k) => this.getKey(k));\n const values = await this.client.mget(...fullKeys);\n\n return values.map((value) => {\n if (value === null) return null;\n try {\n return JSON.parse(value) as T;\n } catch {\n return value as unknown as T;\n }\n });\n }\n\n async setMany<T = unknown>(\n entries: Array<[key: string, value: T, ttl?: number]>\n ): Promise<void> {\n // Redis doesn't have native MSET with TTL, so we use individual sets\n await Promise.all(\n entries.map(([key, value, ttl]) => this.set(key, value, ttl))\n );\n }\n\n async deleteMany(keys: string[]): Promise<void> {\n if (keys.length === 0) return;\n\n const fullKeys = keys.map((k) => this.getKey(k));\n await this.client.del(fullKeys);\n }\n\n async keys(pattern?: string): Promise<string[]> {\n const searchPattern = pattern\n ? this.getKey(pattern)\n : this.prefix\n ? `${this.prefix}:*`\n : '*';\n\n const keys = await this.client.keys(searchPattern);\n const prefixLength = this.prefix ? this.prefix.length + 1 : 0;\n\n return keys.map((k) => (prefixLength ? k.slice(prefixLength) : k));\n }\n\n async clear(): Promise<void> {\n if (this.prefix) {\n const keys = await this.client.keys(`${this.prefix}:*`);\n if (keys.length > 0) {\n await this.client.del(keys);\n }\n } else {\n console.warn(\n '[Pars Auth] Cannot clear Redis storage without prefix. Use Redis FLUSHDB command directly if needed.'\n );\n }\n }\n\n async close(): Promise<void> {\n if (this.client.quit) {\n await this.client.quit();\n } else if (this.client.disconnect) {\n await this.client.disconnect();\n }\n }\n}\n\n/**\n * Create Redis storage from URL\n * Dynamically imports ioredis or @upstash/redis\n */\nasync function createRedisClientFromUrl(url: string): Promise<RedisClient> {\n // Try ioredis first (Node.js)\n try {\n const { Redis } = await import('ioredis');\n return new Redis(url) as unknown as RedisClient;\n } catch {\n // ioredis not available\n }\n\n // Try @upstash/redis (Edge/Serverless)\n try {\n const { Redis } = await import('@upstash/redis');\n // Upstash Redis v2+ accepts url and token as separate config\n // Type assertion needed for compatibility with different Upstash versions\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const client = new Redis({ url, token: '' } as any);\n return client as unknown as RedisClient;\n } catch {\n // Upstash not available\n }\n\n throw new Error(\n '[Pars Auth] No Redis client available. Install either \"ioredis\" or \"@upstash/redis\"'\n );\n}\n\n/**\n * Create Redis storage adapter\n *\n * @example\n * ```ts\n * // With URL (auto-detects client)\n * const storage = await createRedisStorage({ url: 'redis://localhost:6379' });\n *\n * // With existing client\n * import Redis from 'ioredis';\n * const client = new Redis();\n * const storage = await createRedisStorage({ client });\n *\n * // With prefix\n * const storage = await createRedisStorage({\n * url: 'redis://localhost:6379',\n * prefix: 'pars:auth'\n * });\n * ```\n */\nexport async function createRedisStorage(\n config: RedisConfig\n): Promise<KVStorage> {\n let client: RedisClient;\n\n if (config.client) {\n client = config.client as RedisClient;\n } else if (config.url) {\n client = await createRedisClientFromUrl(config.url);\n } else {\n throw new Error(\n '[Pars Auth] Redis storage requires either url or client configuration'\n );\n }\n\n return new RedisStorage(client, config.prefix);\n}\n"]}
|