@stacksjs/bun-router 0.0.13 → 0.0.14
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/CHANGELOG.md +770 -0
- package/README.md +584 -261
- package/package.json +43 -47
- package/bin/cli.ts +0 -9
- package/dist/auth.d.ts +0 -134
- package/dist/cache/lru-cache.d.ts +0 -139
- package/dist/cache/middleware-memoization.d.ts +0 -151
- package/dist/cache/route-cache-warmer.d.ts +0 -161
- package/dist/cache/sqlite-cache.d.ts +0 -209
- package/dist/cache/streaming-cache.d.ts +0 -132
- package/dist/chunk-1mvtv6jw.js +0 -13012
- package/dist/cli/colors.d.ts +0 -15
- package/dist/cli/index.d.ts +0 -10
- package/dist/cli/middleware.d.ts +0 -31
- package/dist/cli/openapi.d.ts +0 -17
- package/dist/cli/router.d.ts +0 -15
- package/dist/cli/routes.d.ts +0 -29
- package/dist/cli/utils.d.ts +0 -74
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -3195
- package/dist/config.d.ts +0 -7
- package/dist/container/container.d.ts +0 -273
- package/dist/container/contextual-binding.d.ts +0 -240
- package/dist/container/decorators.d.ts +0 -141
- package/dist/container/service-provider.d.ts +0 -285
- package/dist/development/hot-reload.d.ts +0 -187
- package/dist/development/index.d.ts +0 -167
- package/dist/development/performance-profiler.d.ts +0 -217
- package/dist/development/route-debugger.d.ts +0 -154
- package/dist/development/route-inspector.d.ts +0 -211
- package/dist/development/typescript-utilities.d.ts +0 -209
- package/dist/docs.d.ts +0 -11
- package/dist/errors/circuit-breaker.d.ts +0 -195
- package/dist/errors/error-handler.d.ts +0 -88
- package/dist/errors/error-reporting.d.ts +0 -144
- package/dist/errors/exceptions.d.ts +0 -184
- package/dist/errors/graceful-degradation.d.ts +0 -154
- package/dist/errors/index.d.ts +0 -9
- package/dist/errors/router-errors.d.ts +0 -110
- package/dist/file-serving/static-files.d.ts +0 -143
- package/dist/index.d.ts +0 -14
- package/dist/index.js +0 -13933
- package/dist/middleware/auth.d.ts +0 -63
- package/dist/middleware/content_security_policy.d.ts +0 -53
- package/dist/middleware/cors.d.ts +0 -5
- package/dist/middleware/csrf.d.ts +0 -7
- package/dist/middleware/ddos_protection.d.ts +0 -39
- package/dist/middleware/file_security.d.ts +0 -26
- package/dist/middleware/file_upload.d.ts +0 -38
- package/dist/middleware/helmet.d.ts +0 -54
- package/dist/middleware/index.d.ts +0 -44
- package/dist/middleware/input_validation.d.ts +0 -45
- package/dist/middleware/json_body.d.ts +0 -4
- package/dist/middleware/performance_alerting.d.ts +0 -87
- package/dist/middleware/performance_dashboard.d.ts +0 -87
- package/dist/middleware/performance_monitor.d.ts +0 -209
- package/dist/middleware/pipeline.d.ts +0 -131
- package/dist/middleware/rate_limit.d.ts +0 -36
- package/dist/middleware/request_id.d.ts +0 -4
- package/dist/middleware/request_signing.d.ts +0 -153
- package/dist/middleware/request_tracer.d.ts +0 -72
- package/dist/middleware/response_cache.d.ts +0 -97
- package/dist/middleware/security.d.ts +0 -69
- package/dist/middleware/security_suite.d.ts +0 -46
- package/dist/middleware/session.d.ts +0 -23
- package/dist/model-binding/index.d.ts +0 -2
- package/dist/model-binding/model-middleware.d.ts +0 -118
- package/dist/model-binding/model-registry.d.ts +0 -164
- package/dist/model-binding.d.ts +0 -185
- package/dist/model-resolver-factory.d.ts +0 -31
- package/dist/observability/correlation.d.ts +0 -187
- package/dist/observability/health-checks.d.ts +0 -186
- package/dist/observability/index.d.ts +0 -60
- package/dist/observability/integration.d.ts +0 -147
- package/dist/observability/metrics.d.ts +0 -184
- package/dist/observability/tracing.d.ts +0 -187
- package/dist/optimization/bun-utilities.d.ts +0 -224
- package/dist/query-builder-integration.d.ts +0 -36
- package/dist/request/context.d.ts +0 -34
- package/dist/request/enhanced-request.d.ts +0 -213
- package/dist/request/macros.d.ts +0 -300
- package/dist/response/macros.d.ts +0 -245
- package/dist/response/response-factory.d.ts +0 -133
- package/dist/router/api-routes.d.ts +0 -5
- package/dist/router/file-based-routing.d.ts +0 -118
- package/dist/router/file-streaming.d.ts +0 -5
- package/dist/router/fluent-router.d.ts +0 -315
- package/dist/router/fluent-routing.d.ts +0 -271
- package/dist/router/group-organization.d.ts +0 -5
- package/dist/router/handler-resolver.d.ts +0 -24
- package/dist/router/http-methods.d.ts +0 -10
- package/dist/router/index.d.ts +0 -114
- package/dist/router/middleware-groups.d.ts +0 -94
- package/dist/router/middleware-integration.d.ts +0 -112
- package/dist/router/middleware.d.ts +0 -5
- package/dist/router/model-binding.d.ts +0 -5
- package/dist/router/optimized-route-matching.d.ts +0 -6
- package/dist/router/route-building.d.ts +0 -5
- package/dist/router/route-compiler.d.ts +0 -153
- package/dist/router/route-matching.d.ts +0 -5
- package/dist/router/route-trie.d.ts +0 -114
- package/dist/router/router.d.ts +0 -294
- package/dist/router/server.d.ts +0 -5
- package/dist/router/validation-integration.d.ts +0 -170
- package/dist/router/view-rendering.d.ts +0 -5
- package/dist/router/websocket.d.ts +0 -5
- package/dist/routing/route-caching.d.ts +0 -129
- package/dist/routing/route-throttling.d.ts +0 -150
- package/dist/routing/subdomain-routing.d.ts +0 -206
- package/dist/session/database-store.d.ts +0 -51
- package/dist/session/file-store.d.ts +0 -22
- package/dist/session/index.d.ts +0 -106
- package/dist/session/memory-store.d.ts +0 -21
- package/dist/session/redis-store.d.ts +0 -31
- package/dist/streaming/index.d.ts +0 -3
- package/dist/streaming/sse-handler.d.ts +0 -138
- package/dist/streaming/stream-handler.d.ts +0 -114
- package/dist/testing/auth-testing.d.ts +0 -156
- package/dist/testing/file-upload-testing.d.ts +0 -190
- package/dist/testing/index.d.ts +0 -10
- package/dist/testing/middleware-testing.d.ts +0 -138
- package/dist/testing/model-binding-testing.d.ts +0 -186
- package/dist/testing/performance-testing.d.ts +0 -235
- package/dist/testing/test-client.d.ts +0 -117
- package/dist/testing/test-request.d.ts +0 -85
- package/dist/testing/test-response.d.ts +0 -90
- package/dist/testing/types.d.ts +0 -207
- package/dist/testing/websocket-testing.d.ts +0 -227
- package/dist/types/controller-types.d.ts +0 -208
- package/dist/types/core.d.ts +0 -543
- package/dist/types/middleware-types.d.ts +0 -227
- package/dist/types/request-response-augmentation.d.ts +0 -261
- package/dist/types/route-inference.d.ts +0 -168
- package/dist/types.d.ts +0 -1782
- package/dist/url.d.ts +0 -56
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/query-preservation.d.ts +0 -48
- package/dist/utils.d.ts +0 -69
- package/dist/validation/validator.d.ts +0 -140
- package/dist/websocket/clustering.d.ts +0 -185
- package/src/auth.ts +0 -469
- package/src/cache/lru-cache.ts +0 -457
- package/src/cache/middleware-memoization.ts +0 -531
- package/src/cache/route-cache-warmer.ts +0 -486
- package/src/cache/sqlite-cache.ts +0 -783
- package/src/cache/streaming-cache.ts +0 -572
- package/src/cli/colors.ts +0 -29
- package/src/cli/index.ts +0 -287
- package/src/cli/middleware.ts +0 -291
- package/src/cli/openapi.ts +0 -407
- package/src/cli/router.ts +0 -188
- package/src/cli/routes.ts +0 -265
- package/src/cli/utils.ts +0 -531
- package/src/cli.ts +0 -5
- package/src/config.ts +0 -322
- package/src/container/container.ts +0 -740
- package/src/container/contextual-binding.ts +0 -603
- package/src/container/decorators.ts +0 -359
- package/src/container/service-provider.ts +0 -596
- package/src/development/hot-reload.ts +0 -673
- package/src/development/index.ts +0 -499
- package/src/development/performance-profiler.ts +0 -717
- package/src/development/route-debugger.ts +0 -527
- package/src/development/route-inspector.ts +0 -749
- package/src/development/typescript-utilities.ts +0 -682
- package/src/docs.ts +0 -397
- package/src/errors/circuit-breaker.ts +0 -732
- package/src/errors/error-handler.ts +0 -569
- package/src/errors/error-reporting.ts +0 -672
- package/src/errors/exceptions.ts +0 -536
- package/src/errors/graceful-degradation.ts +0 -621
- package/src/errors/index.ts +0 -21
- package/src/errors/router-errors.ts +0 -632
- package/src/file-serving/static-files.ts +0 -581
- package/src/index.ts +0 -14
- package/src/middleware/auth.ts +0 -219
- package/src/middleware/content_security_policy.ts +0 -215
- package/src/middleware/cors.ts +0 -74
- package/src/middleware/csrf.ts +0 -108
- package/src/middleware/ddos_protection.ts +0 -255
- package/src/middleware/file_security.ts +0 -191
- package/src/middleware/file_upload.ts +0 -264
- package/src/middleware/helmet.ts +0 -268
- package/src/middleware/index.ts +0 -117
- package/src/middleware/input_validation.ts +0 -449
- package/src/middleware/json_body.ts +0 -37
- package/src/middleware/performance_alerting.ts +0 -538
- package/src/middleware/performance_dashboard.ts +0 -661
- package/src/middleware/performance_monitor.ts +0 -943
- package/src/middleware/pipeline.ts +0 -489
- package/src/middleware/rate_limit.ts +0 -245
- package/src/middleware/request_id.ts +0 -36
- package/src/middleware/request_signing.ts +0 -636
- package/src/middleware/request_tracer.ts +0 -636
- package/src/middleware/response_cache.ts +0 -743
- package/src/middleware/security.ts +0 -482
- package/src/middleware/security_suite.ts +0 -257
- package/src/middleware/session.ts +0 -91
- package/src/model-binding/index.ts +0 -18
- package/src/model-binding/model-middleware.ts +0 -425
- package/src/model-binding/model-registry.ts +0 -550
- package/src/model-binding.ts +0 -370
- package/src/model-resolver-factory.ts +0 -106
- package/src/observability/correlation.ts +0 -691
- package/src/observability/health-checks.ts +0 -729
- package/src/observability/index.ts +0 -184
- package/src/observability/integration.ts +0 -548
- package/src/observability/metrics.ts +0 -753
- package/src/observability/tracing.ts +0 -638
- package/src/optimization/bun-utilities.ts +0 -778
- package/src/query-builder-integration.ts +0 -137
- package/src/request/context.ts +0 -62
- package/src/request/enhanced-request.ts +0 -857
- package/src/request/macros.ts +0 -688
- package/src/response/macros.ts +0 -612
- package/src/response/response-factory.ts +0 -596
- package/src/router/api-routes.ts +0 -243
- package/src/router/file-based-routing.ts +0 -670
- package/src/router/file-streaming.ts +0 -372
- package/src/router/fluent-router.ts +0 -927
- package/src/router/fluent-routing.ts +0 -797
- package/src/router/group-organization.ts +0 -213
- package/src/router/handler-resolver.ts +0 -291
- package/src/router/http-methods.ts +0 -377
- package/src/router/index.ts +0 -187
- package/src/router/middleware-groups.ts +0 -222
- package/src/router/middleware-integration.ts +0 -399
- package/src/router/middleware.ts +0 -231
- package/src/router/model-binding.ts +0 -215
- package/src/router/optimized-route-matching.ts +0 -253
- package/src/router/route-building.ts +0 -212
- package/src/router/route-compiler.ts +0 -702
- package/src/router/route-matching.ts +0 -349
- package/src/router/route-trie.ts +0 -464
- package/src/router/router.ts +0 -1581
- package/src/router/server.ts +0 -462
- package/src/router/validation-integration.ts +0 -443
- package/src/router/view-rendering.ts +0 -233
- package/src/router/websocket.ts +0 -100
- package/src/routing/route-caching.ts +0 -402
- package/src/routing/route-throttling.ts +0 -469
- package/src/routing/subdomain-routing.ts +0 -492
- package/src/session/database-store.ts +0 -109
- package/src/session/file-store.ts +0 -148
- package/src/session/index.ts +0 -244
- package/src/session/memory-store.ts +0 -88
- package/src/session/redis-store.ts +0 -93
- package/src/streaming/index.ts +0 -17
- package/src/streaming/sse-handler.ts +0 -482
- package/src/streaming/stream-handler.ts +0 -552
- package/src/testing/auth-testing.ts +0 -446
- package/src/testing/file-upload-testing.ts +0 -543
- package/src/testing/index.ts +0 -10
- package/src/testing/middleware-testing.ts +0 -322
- package/src/testing/model-binding-testing.ts +0 -645
- package/src/testing/performance-testing.ts +0 -738
- package/src/testing/test-client.ts +0 -310
- package/src/testing/test-request.ts +0 -315
- package/src/testing/test-response.ts +0 -332
- package/src/testing/types.ts +0 -224
- package/src/testing/websocket-testing.ts +0 -590
- package/src/types/controller-types.ts +0 -385
- package/src/types/core.ts +0 -683
- package/src/types/middleware-types.ts +0 -419
- package/src/types/request-response-augmentation.ts +0 -489
- package/src/types/route-inference.ts +0 -357
- package/src/types.ts +0 -2055
- package/src/url.ts +0 -126
- package/src/utils/index.ts +0 -1
- package/src/utils/query-preservation.ts +0 -201
- package/src/utils.ts +0 -327
- package/src/validation/validator.ts +0 -685
- package/src/websocket/clustering.ts +0 -762
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readdirSync, unlinkSync, writeFileSync, readFileSync } from 'node:fs'
|
|
2
|
-
import { join } from 'node:path'
|
|
3
|
-
import { tmpdir } from 'node:os'
|
|
4
|
-
import type { SessionData, SessionStore } from '../types/core'
|
|
5
|
-
|
|
6
|
-
interface FileSession {
|
|
7
|
-
data: SessionData
|
|
8
|
-
expiresAt: number
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* File-based session store.
|
|
13
|
-
* Persists sessions to disk as JSON files.
|
|
14
|
-
* Suitable for single-server deployments.
|
|
15
|
-
*/
|
|
16
|
-
export class FileSessionStore implements SessionStore<SessionData> {
|
|
17
|
-
private dir: string
|
|
18
|
-
private cleanupInterval: ReturnType<typeof setInterval> | null = null
|
|
19
|
-
|
|
20
|
-
constructor(
|
|
21
|
-
private defaultTtl: number = 86400,
|
|
22
|
-
dir?: string,
|
|
23
|
-
) {
|
|
24
|
-
this.dir = dir || join(tmpdir(), 'bun-router-sessions')
|
|
25
|
-
if (!existsSync(this.dir)) {
|
|
26
|
-
mkdirSync(this.dir, { recursive: true })
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Cleanup every 10 minutes
|
|
30
|
-
this.cleanupInterval = setInterval(() => this.cleanup(), 10 * 60 * 1000)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
private filePath(sid: string): string {
|
|
34
|
-
// Sanitize session ID to prevent path traversal
|
|
35
|
-
const safeSid = sid.replace(/[^a-zA-Z0-9_-]/g, '')
|
|
36
|
-
return join(this.dir, `${safeSid}.json`)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async get(sid: string): Promise<SessionData | null> {
|
|
40
|
-
const path = this.filePath(sid)
|
|
41
|
-
if (!existsSync(path)) return null
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
const content = readFileSync(path, 'utf-8')
|
|
45
|
-
const stored: FileSession = JSON.parse(content)
|
|
46
|
-
|
|
47
|
-
if (Date.now() > stored.expiresAt) {
|
|
48
|
-
unlinkSync(path)
|
|
49
|
-
return null
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return stored.data
|
|
53
|
-
}
|
|
54
|
-
catch {
|
|
55
|
-
return null
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async set(sid: string, session: SessionData, ttl?: number): Promise<void> {
|
|
60
|
-
const stored: FileSession = {
|
|
61
|
-
data: session,
|
|
62
|
-
expiresAt: Date.now() + (ttl ?? this.defaultTtl) * 1000,
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
writeFileSync(this.filePath(sid), JSON.stringify(stored), 'utf-8')
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
async destroy(sid: string): Promise<void> {
|
|
69
|
-
const path = this.filePath(sid)
|
|
70
|
-
if (existsSync(path)) {
|
|
71
|
-
unlinkSync(path)
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async touch(sid: string, session: SessionData, ttl?: number): Promise<void> {
|
|
76
|
-
const path = this.filePath(sid)
|
|
77
|
-
if (!existsSync(path)) return
|
|
78
|
-
|
|
79
|
-
const stored: FileSession = {
|
|
80
|
-
data: session,
|
|
81
|
-
expiresAt: Date.now() + (ttl ?? this.defaultTtl) * 1000,
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
writeFileSync(path, JSON.stringify(stored), 'utf-8')
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async all(): Promise<Record<string, SessionData>> {
|
|
88
|
-
const result: Record<string, SessionData> = {}
|
|
89
|
-
const now = Date.now()
|
|
90
|
-
|
|
91
|
-
try {
|
|
92
|
-
const files = readdirSync(this.dir).filter(f => f.endsWith('.json'))
|
|
93
|
-
for (const file of files) {
|
|
94
|
-
const content = readFileSync(join(this.dir, file), 'utf-8')
|
|
95
|
-
const stored: FileSession = JSON.parse(content)
|
|
96
|
-
if (now <= stored.expiresAt) {
|
|
97
|
-
const sid = file.replace('.json', '')
|
|
98
|
-
result[sid] = stored.data
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
catch { /* ignore errors */ }
|
|
103
|
-
|
|
104
|
-
return result
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
async length(): Promise<number> {
|
|
108
|
-
try {
|
|
109
|
-
return readdirSync(this.dir).filter(f => f.endsWith('.json')).length
|
|
110
|
-
}
|
|
111
|
-
catch {
|
|
112
|
-
return 0
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
async clear(): Promise<void> {
|
|
117
|
-
try {
|
|
118
|
-
const files = readdirSync(this.dir).filter(f => f.endsWith('.json'))
|
|
119
|
-
for (const file of files) {
|
|
120
|
-
unlinkSync(join(this.dir, file))
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
catch { /* ignore errors */ }
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
private cleanup(): void {
|
|
127
|
-
const now = Date.now()
|
|
128
|
-
try {
|
|
129
|
-
const files = readdirSync(this.dir).filter(f => f.endsWith('.json'))
|
|
130
|
-
for (const file of files) {
|
|
131
|
-
const path = join(this.dir, file)
|
|
132
|
-
const content = readFileSync(path, 'utf-8')
|
|
133
|
-
const stored: FileSession = JSON.parse(content)
|
|
134
|
-
if (now > stored.expiresAt) {
|
|
135
|
-
unlinkSync(path)
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
catch { /* ignore errors */ }
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
dispose(): void {
|
|
143
|
-
if (this.cleanupInterval) {
|
|
144
|
-
clearInterval(this.cleanupInterval)
|
|
145
|
-
this.cleanupInterval = null
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
package/src/session/index.ts
DELETED
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
import type { SessionData, SessionStore } from '../types/core'
|
|
2
|
-
import { MemorySessionStore } from './memory-store'
|
|
3
|
-
import { FileSessionStore } from './file-store'
|
|
4
|
-
import { RedisSessionStore } from './redis-store'
|
|
5
|
-
import type { RedisClient } from './redis-store'
|
|
6
|
-
import { DatabaseSessionStore } from './database-store'
|
|
7
|
-
import type { SessionDatabaseAdapter } from './database-store'
|
|
8
|
-
|
|
9
|
-
export { MemorySessionStore } from './memory-store'
|
|
10
|
-
export { FileSessionStore } from './file-store'
|
|
11
|
-
export { RedisSessionStore } from './redis-store'
|
|
12
|
-
export type { RedisClient } from './redis-store'
|
|
13
|
-
export { DatabaseSessionStore } from './database-store'
|
|
14
|
-
export type { SessionDatabaseAdapter } from './database-store'
|
|
15
|
-
|
|
16
|
-
export interface SessionConfig {
|
|
17
|
-
driver: 'memory' | 'file' | 'redis' | 'database'
|
|
18
|
-
ttl?: number
|
|
19
|
-
cookie?: {
|
|
20
|
-
name?: string
|
|
21
|
-
maxAge?: number
|
|
22
|
-
path?: string
|
|
23
|
-
httpOnly?: boolean
|
|
24
|
-
secure?: boolean
|
|
25
|
-
sameSite?: 'strict' | 'lax' | 'none'
|
|
26
|
-
}
|
|
27
|
-
// Driver-specific options
|
|
28
|
-
file?: {
|
|
29
|
-
dir?: string
|
|
30
|
-
}
|
|
31
|
-
redis?: {
|
|
32
|
-
client: RedisClient
|
|
33
|
-
prefix?: string
|
|
34
|
-
}
|
|
35
|
-
database?: {
|
|
36
|
-
adapter: SessionDatabaseAdapter
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Create a session store based on configuration
|
|
42
|
-
*/
|
|
43
|
-
export function createSessionStore(config: SessionConfig): SessionStore<SessionData> {
|
|
44
|
-
const ttl = config.ttl ?? 86400
|
|
45
|
-
|
|
46
|
-
switch (config.driver) {
|
|
47
|
-
case 'memory':
|
|
48
|
-
return new MemorySessionStore(ttl)
|
|
49
|
-
|
|
50
|
-
case 'file':
|
|
51
|
-
return new FileSessionStore(ttl, config.file?.dir)
|
|
52
|
-
|
|
53
|
-
case 'redis': {
|
|
54
|
-
if (!config.redis?.client) {
|
|
55
|
-
throw new Error('Redis client is required for redis session driver')
|
|
56
|
-
}
|
|
57
|
-
return new RedisSessionStore(config.redis.client, ttl, config.redis.prefix)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
case 'database': {
|
|
61
|
-
if (!config.database?.adapter) {
|
|
62
|
-
throw new Error('Database adapter is required for database session driver')
|
|
63
|
-
}
|
|
64
|
-
return new DatabaseSessionStore(config.database.adapter, ttl)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
default:
|
|
68
|
-
return new MemorySessionStore(ttl)
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Session manager for request handling.
|
|
74
|
-
* Wraps a SessionStore and provides flash data, regeneration, etc.
|
|
75
|
-
*/
|
|
76
|
-
export class SessionManager {
|
|
77
|
-
private sessionId: string
|
|
78
|
-
private data: SessionData
|
|
79
|
-
private store: SessionStore<SessionData>
|
|
80
|
-
private flashedKeys: string[] = []
|
|
81
|
-
private previousFlash: Record<string, unknown> = {}
|
|
82
|
-
private dirty = false
|
|
83
|
-
|
|
84
|
-
constructor(sessionId: string, data: SessionData, store: SessionStore<SessionData>) {
|
|
85
|
-
this.sessionId = sessionId
|
|
86
|
-
this.data = data
|
|
87
|
-
this.store = store
|
|
88
|
-
|
|
89
|
-
// Capture previous flash data to clear after this request
|
|
90
|
-
this.previousFlash = { ...(data.flash || {}) }
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
get id(): string {
|
|
94
|
-
return this.sessionId
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Get a value from the session
|
|
99
|
-
*/
|
|
100
|
-
get<T = unknown>(key: string): T | undefined {
|
|
101
|
-
// Check flash data first
|
|
102
|
-
if (this.data.flash && key in this.data.flash) {
|
|
103
|
-
return this.data.flash[key] as T
|
|
104
|
-
}
|
|
105
|
-
if (this.data.data && key in this.data.data) {
|
|
106
|
-
return this.data.data[key] as T
|
|
107
|
-
}
|
|
108
|
-
return undefined
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Set a value in the session
|
|
113
|
-
*/
|
|
114
|
-
set(key: string, value: unknown): void {
|
|
115
|
-
if (!this.data.data) this.data.data = {}
|
|
116
|
-
this.data.data[key] = value
|
|
117
|
-
this.dirty = true
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Check if a key exists in the session
|
|
122
|
-
*/
|
|
123
|
-
has(key: string): boolean {
|
|
124
|
-
return (this.data.data && key in this.data.data) || (this.data.flash && key in this.data.flash) || false
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Remove a value from the session
|
|
129
|
-
*/
|
|
130
|
-
forget(key: string): void {
|
|
131
|
-
if (this.data.data) {
|
|
132
|
-
delete this.data.data[key]
|
|
133
|
-
this.dirty = true
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Get all session data
|
|
139
|
-
*/
|
|
140
|
-
all(): Record<string, unknown> {
|
|
141
|
-
return { ...(this.data.data || {}), ...(this.data.flash || {}) }
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Flash a key-value pair for the next request only
|
|
146
|
-
*/
|
|
147
|
-
flash(key: string, value: unknown): void {
|
|
148
|
-
if (!this.data.flash) this.data.flash = {}
|
|
149
|
-
this.data.flash[key] = value
|
|
150
|
-
this.flashedKeys.push(key)
|
|
151
|
-
this.dirty = true
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Get a flash value (available for current request)
|
|
156
|
-
*/
|
|
157
|
-
getFlash<T = unknown>(key: string): T | undefined {
|
|
158
|
-
return this.previousFlash[key] as T | undefined
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Keep specific flash data for another request
|
|
163
|
-
*/
|
|
164
|
-
keep(keys: string[]): void {
|
|
165
|
-
for (const key of keys) {
|
|
166
|
-
if (key in this.previousFlash) {
|
|
167
|
-
this.flash(key, this.previousFlash[key])
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Reflash all flash data for another request
|
|
174
|
-
*/
|
|
175
|
-
reflash(): void {
|
|
176
|
-
for (const [key, value] of Object.entries(this.previousFlash)) {
|
|
177
|
-
this.flash(key, value)
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Regenerate session ID (keeps data)
|
|
183
|
-
*/
|
|
184
|
-
async regenerate(): Promise<string> {
|
|
185
|
-
const oldId = this.sessionId
|
|
186
|
-
this.sessionId = generateSessionId()
|
|
187
|
-
|
|
188
|
-
// Move data to new session
|
|
189
|
-
await this.store.set(this.sessionId, this.data)
|
|
190
|
-
await this.store.destroy(oldId)
|
|
191
|
-
|
|
192
|
-
return this.sessionId
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Invalidate the session (new ID, clear data)
|
|
197
|
-
*/
|
|
198
|
-
async invalidate(): Promise<string> {
|
|
199
|
-
const oldId = this.sessionId
|
|
200
|
-
this.sessionId = generateSessionId()
|
|
201
|
-
this.data = { id: this.sessionId }
|
|
202
|
-
|
|
203
|
-
await this.store.destroy(oldId)
|
|
204
|
-
await this.store.set(this.sessionId, this.data)
|
|
205
|
-
|
|
206
|
-
return this.sessionId
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Save session data to the store.
|
|
211
|
-
* Call this at the end of the request.
|
|
212
|
-
*/
|
|
213
|
-
async save(): Promise<void> {
|
|
214
|
-
// Clear old flash data (data that was available this request but not re-flashed)
|
|
215
|
-
if (this.data.flash) {
|
|
216
|
-
const newFlash: Record<string, unknown> = {}
|
|
217
|
-
for (const key of this.flashedKeys) {
|
|
218
|
-
if (this.data.flash[key] !== undefined) {
|
|
219
|
-
newFlash[key] = this.data.flash[key]
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
this.data.flash = Object.keys(newFlash).length > 0 ? newFlash : undefined
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
await this.store.set(this.sessionId, this.data)
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Destroy the session completely
|
|
230
|
-
*/
|
|
231
|
-
async destroy(): Promise<void> {
|
|
232
|
-
await this.store.destroy(this.sessionId)
|
|
233
|
-
this.data = {}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Generate a cryptographically secure session ID
|
|
239
|
-
*/
|
|
240
|
-
export function generateSessionId(): string {
|
|
241
|
-
const bytes = new Uint8Array(32)
|
|
242
|
-
crypto.getRandomValues(bytes)
|
|
243
|
-
return Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('')
|
|
244
|
-
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import type { SessionData, SessionStore } from '../types/core'
|
|
2
|
-
|
|
3
|
-
interface StoredSession {
|
|
4
|
-
data: SessionData
|
|
5
|
-
expiresAt: number
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* In-memory session store.
|
|
10
|
-
* Fast but data is lost on server restart.
|
|
11
|
-
* Suitable for development or single-process deployments.
|
|
12
|
-
*/
|
|
13
|
-
export class MemorySessionStore implements SessionStore<SessionData> {
|
|
14
|
-
private sessions = new Map<string, StoredSession>()
|
|
15
|
-
private cleanupInterval: ReturnType<typeof setInterval> | null = null
|
|
16
|
-
|
|
17
|
-
constructor(private defaultTtl: number = 86400) {
|
|
18
|
-
// Run cleanup every 5 minutes
|
|
19
|
-
this.cleanupInterval = setInterval(() => this.cleanup(), 5 * 60 * 1000)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async get(sid: string): Promise<SessionData | null> {
|
|
23
|
-
const stored = this.sessions.get(sid)
|
|
24
|
-
if (!stored) return null
|
|
25
|
-
|
|
26
|
-
if (Date.now() > stored.expiresAt) {
|
|
27
|
-
this.sessions.delete(sid)
|
|
28
|
-
return null
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return stored.data
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async set(sid: string, session: SessionData, ttl?: number): Promise<void> {
|
|
35
|
-
const expiresAt = Date.now() + (ttl ?? this.defaultTtl) * 1000
|
|
36
|
-
this.sessions.set(sid, { data: session, expiresAt })
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async destroy(sid: string): Promise<void> {
|
|
40
|
-
this.sessions.delete(sid)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async touch(sid: string, session: SessionData, ttl?: number): Promise<void> {
|
|
44
|
-
const stored = this.sessions.get(sid)
|
|
45
|
-
if (stored) {
|
|
46
|
-
stored.expiresAt = Date.now() + (ttl ?? this.defaultTtl) * 1000
|
|
47
|
-
stored.data = session
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async all(): Promise<Record<string, SessionData>> {
|
|
52
|
-
const result: Record<string, SessionData> = {}
|
|
53
|
-
const now = Date.now()
|
|
54
|
-
|
|
55
|
-
for (const [sid, stored] of this.sessions) {
|
|
56
|
-
if (now <= stored.expiresAt) {
|
|
57
|
-
result[sid] = stored.data
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return result
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async length(): Promise<number> {
|
|
65
|
-
return this.sessions.size
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
async clear(): Promise<void> {
|
|
69
|
-
this.sessions.clear()
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
private cleanup(): void {
|
|
73
|
-
const now = Date.now()
|
|
74
|
-
for (const [sid, stored] of this.sessions) {
|
|
75
|
-
if (now > stored.expiresAt) {
|
|
76
|
-
this.sessions.delete(sid)
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
dispose(): void {
|
|
82
|
-
if (this.cleanupInterval) {
|
|
83
|
-
clearInterval(this.cleanupInterval)
|
|
84
|
-
this.cleanupInterval = null
|
|
85
|
-
}
|
|
86
|
-
this.sessions.clear()
|
|
87
|
-
}
|
|
88
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import type { SessionData, SessionStore } from '../types/core'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Minimal Redis client interface.
|
|
5
|
-
* Compatible with ioredis, node-redis, or any client implementing these methods.
|
|
6
|
-
*/
|
|
7
|
-
export interface RedisClient {
|
|
8
|
-
get(key: string): Promise<string | null>
|
|
9
|
-
set(key: string, value: string, ...args: any[]): Promise<any>
|
|
10
|
-
del(key: string | string[]): Promise<number>
|
|
11
|
-
expire(key: string, seconds: number): Promise<number>
|
|
12
|
-
keys(pattern: string): Promise<string[]>
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Redis-backed session store.
|
|
17
|
-
* Ideal for distributed/multi-server deployments.
|
|
18
|
-
* Requires a Redis client to be passed in.
|
|
19
|
-
*/
|
|
20
|
-
export class RedisSessionStore implements SessionStore<SessionData> {
|
|
21
|
-
private prefix: string
|
|
22
|
-
|
|
23
|
-
constructor(
|
|
24
|
-
private client: RedisClient,
|
|
25
|
-
private defaultTtl: number = 86400,
|
|
26
|
-
prefix: string = 'sess:',
|
|
27
|
-
) {
|
|
28
|
-
this.prefix = prefix
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
private key(sid: string): string {
|
|
32
|
-
return `${this.prefix}${sid}`
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async get(sid: string): Promise<SessionData | null> {
|
|
36
|
-
const data = await this.client.get(this.key(sid))
|
|
37
|
-
if (!data) return null
|
|
38
|
-
|
|
39
|
-
try {
|
|
40
|
-
return JSON.parse(data) as SessionData
|
|
41
|
-
}
|
|
42
|
-
catch {
|
|
43
|
-
return null
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async set(sid: string, session: SessionData, ttl?: number): Promise<void> {
|
|
48
|
-
const key = this.key(sid)
|
|
49
|
-
const seconds = ttl ?? this.defaultTtl
|
|
50
|
-
await this.client.set(key, JSON.stringify(session), 'EX', seconds)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async destroy(sid: string): Promise<void> {
|
|
54
|
-
await this.client.del(this.key(sid))
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async touch(sid: string, session: SessionData, ttl?: number): Promise<void> {
|
|
58
|
-
const key = this.key(sid)
|
|
59
|
-
const seconds = ttl ?? this.defaultTtl
|
|
60
|
-
// Reset TTL and update data
|
|
61
|
-
await this.client.set(key, JSON.stringify(session), 'EX', seconds)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async all(): Promise<Record<string, SessionData>> {
|
|
65
|
-
const keys = await this.client.keys(`${this.prefix}*`)
|
|
66
|
-
const result: Record<string, SessionData> = {}
|
|
67
|
-
|
|
68
|
-
for (const key of keys) {
|
|
69
|
-
const data = await this.client.get(key)
|
|
70
|
-
if (data) {
|
|
71
|
-
try {
|
|
72
|
-
const sid = key.slice(this.prefix.length)
|
|
73
|
-
result[sid] = JSON.parse(data)
|
|
74
|
-
}
|
|
75
|
-
catch { /* skip invalid data */ }
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return result
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
async length(): Promise<number> {
|
|
83
|
-
const keys = await this.client.keys(`${this.prefix}*`)
|
|
84
|
-
return keys.length
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async clear(): Promise<void> {
|
|
88
|
-
const keys = await this.client.keys(`${this.prefix}*`)
|
|
89
|
-
if (keys.length > 0) {
|
|
90
|
-
await this.client.del(keys)
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
package/src/streaming/index.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export type { SSEConfig, SSEEvent } from '../types'
|
|
2
|
-
|
|
3
|
-
export {
|
|
4
|
-
createSSEMiddleware,
|
|
5
|
-
SSEConnectionManager,
|
|
6
|
-
SSEHandler,
|
|
7
|
-
sseManager,
|
|
8
|
-
SSEUtils,
|
|
9
|
-
} from './sse-handler'
|
|
10
|
-
|
|
11
|
-
export {
|
|
12
|
-
type BaseStreamConfig,
|
|
13
|
-
FileStreamHandler,
|
|
14
|
-
StreamHandler,
|
|
15
|
-
StreamResponse,
|
|
16
|
-
StreamUtils,
|
|
17
|
-
} from './stream-handler'
|