@katlux/providers 0.1.0-beta.0 → 0.1.0-beta.11
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/dist/index.cjs +5496 -0
- package/dist/index.d.cts +1861 -0
- package/dist/index.d.mts +1861 -0
- package/dist/index.d.ts +1861 -0
- package/dist/index.mjs +5475 -0
- package/package.json +7 -3
- package/build.config.ts +0 -4
- package/services/CacheProvider/ACacheProvider.ts +0 -13
- package/services/CacheProvider/CApplicationCache.ts +0 -123
- package/services/CacheProvider/CCookieCache.ts +0 -212
- package/services/CacheProvider/CIndexedDBCache.ts +0 -312
- package/services/CacheProvider/CLocalStorageCache.ts +0 -232
- package/services/CacheProvider/CMemoryCache.ts +0 -185
- package/services/CacheProvider/CSessionCache.ts +0 -378
- package/services/CacheProvider/CacheProviderFactory.ts +0 -22
- package/services/DataProvider/AAPIDataProvider.ts +0 -24
- package/services/DataProvider/ADataProvider.ts +0 -126
- package/services/DataProvider/CAPIFlatClientDataProvider.ts +0 -199
- package/services/DataProvider/CAPIFlatServerDataProvider.ts +0 -77
- package/services/DataProvider/CAPITreeClientDataProvider.ts +0 -205
- package/services/DataProvider/CAPITreeServerDataProvider.ts +0 -98
- package/services/DataProvider/CFlatClientDataProvider.ts +0 -52
- package/services/DataProvider/CFlatServerDataProvider.ts +0 -104
- package/services/DataProvider/CTreeClientDataProvider.ts +0 -335
- package/services/DataProvider/CTreeServerDataProvider.ts +0 -207
- package/services/RequestProvider/RequestProvider.ts +0 -165
- package/services/RequestProvider/serverCache.ts +0 -24
- package/services/index.ts +0 -19
- package/services/types.ts +0 -172
- package/src/index.ts +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@katlux/providers",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.11",
|
|
4
4
|
"description": "Core data calculation and caching providers for the Katlux ecosystem",
|
|
5
5
|
"author": "Katlux",
|
|
6
6
|
"license": "MIT",
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"types": "./dist/index.d.ts",
|
|
12
12
|
"scripts": {
|
|
13
13
|
"build": "unbuild",
|
|
14
|
-
"dev": "unbuild --stub"
|
|
14
|
+
"dev": "unbuild --stub",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
15
16
|
},
|
|
16
17
|
"exports": {
|
|
17
18
|
".": {
|
|
@@ -20,5 +21,8 @@
|
|
|
20
21
|
"require": "./dist/index.cjs"
|
|
21
22
|
}
|
|
22
23
|
},
|
|
23
|
-
"dependencies": {}
|
|
24
|
+
"dependencies": {},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist"
|
|
27
|
+
]
|
|
24
28
|
}
|
package/build.config.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export abstract class ACacheProvider {
|
|
2
|
-
constructor() {
|
|
3
|
-
// Cleanup expired entries on initialization
|
|
4
|
-
this.cleanupExpired()
|
|
5
|
-
}
|
|
6
|
-
abstract getKeyList(nuxtApp?: any): Array<string> | Promise<Array<string>>
|
|
7
|
-
abstract get<T>(key: string, nuxtApp?: any): Promise<T | null>
|
|
8
|
-
abstract set<T>(key: string, data: T, lifetime: number, nuxtApp?: any): Promise<void>
|
|
9
|
-
abstract remove(key: string, nuxtApp?: any): Promise<void>
|
|
10
|
-
abstract removeByPrefix(prefix: string, nuxtApp?: any): Promise<void>
|
|
11
|
-
abstract getRemainingTime(key: string, nuxtApp?: any): Promise<number | null>
|
|
12
|
-
abstract cleanupExpired(): Promise<void>
|
|
13
|
-
}
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { ACacheProvider } from './ACacheProvider'
|
|
2
|
-
import type { ICacheEntry } from '../types'
|
|
3
|
-
|
|
4
|
-
export class CApplicationCache extends ACacheProvider {
|
|
5
|
-
private static instance: CApplicationCache | null = null
|
|
6
|
-
private static _storage: Map<string, ICacheEntry<any>> | null = null
|
|
7
|
-
|
|
8
|
-
private static get storage(): Map<string, ICacheEntry<any>> {
|
|
9
|
-
if (!this._storage) {
|
|
10
|
-
this._storage = new Map<string, ICacheEntry<any>>()
|
|
11
|
-
}
|
|
12
|
-
return this._storage
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
public static getInstance(): CApplicationCache {
|
|
16
|
-
if (!this.instance) {
|
|
17
|
-
this.instance = new CApplicationCache()
|
|
18
|
-
}
|
|
19
|
-
return this.instance
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
public static getSnapshot(): Map<string, ICacheEntry<any>> {
|
|
23
|
-
return this.storage
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
private constructor() {
|
|
27
|
-
super()
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async getKeyList(nuxtApp?: any): Promise<Array<string>> {
|
|
31
|
-
const prefix = 'cache:'
|
|
32
|
-
const storage = CApplicationCache.storage
|
|
33
|
-
return Array.from(storage.keys())
|
|
34
|
-
.filter(key => key.startsWith(prefix))
|
|
35
|
-
.map(key => key.substring(prefix.length))
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async get<T>(key: string, nuxtApp?: any): Promise<T | null> {
|
|
39
|
-
if (import.meta.server) {
|
|
40
|
-
const prefixedKey = 'cache:' + key
|
|
41
|
-
const storage = CApplicationCache.storage
|
|
42
|
-
const entry = storage.get(prefixedKey)
|
|
43
|
-
if (!entry) return null
|
|
44
|
-
|
|
45
|
-
if (Date.now() - entry.timestamp > entry.lifetime) {
|
|
46
|
-
storage.delete(prefixedKey)
|
|
47
|
-
return null
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return entry.data as T
|
|
51
|
-
}
|
|
52
|
-
return null
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async set<T>(key: string, data: T, lifetime: number, nuxtApp?: any): Promise<void> {
|
|
56
|
-
if (import.meta.server) {
|
|
57
|
-
const prefixedKey = 'cache:' + key
|
|
58
|
-
const storage = CApplicationCache.storage
|
|
59
|
-
storage.set(prefixedKey, {
|
|
60
|
-
data,
|
|
61
|
-
timestamp: Date.now(),
|
|
62
|
-
lifetime
|
|
63
|
-
})
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
async remove(key: string, nuxtApp?: any): Promise<void> {
|
|
68
|
-
if (import.meta.server) {
|
|
69
|
-
const prefixedKey = 'cache:' + key
|
|
70
|
-
CApplicationCache.storage.delete(prefixedKey)
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
async removeByPrefix(prefix: string, nuxtApp?: any): Promise<void> {
|
|
75
|
-
if (import.meta.server) {
|
|
76
|
-
const fullPrefix = 'cache:' + prefix
|
|
77
|
-
const storage = CApplicationCache.storage
|
|
78
|
-
const keysToDelete: string[] = []
|
|
79
|
-
|
|
80
|
-
for (const key of storage.keys()) {
|
|
81
|
-
if (key.startsWith(fullPrefix)) {
|
|
82
|
-
keysToDelete.push(key)
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
for (const key of keysToDelete) {
|
|
87
|
-
storage.delete(key)
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
async getRemainingTime(key: string, nuxtApp?: any): Promise<number | null> {
|
|
93
|
-
if (import.meta.server) {
|
|
94
|
-
const prefixedKey = 'cache:' + key
|
|
95
|
-
const storage = CApplicationCache.storage
|
|
96
|
-
const entry = storage.get(prefixedKey)
|
|
97
|
-
if (!entry) return null
|
|
98
|
-
return Math.max(0, (entry.timestamp + entry.lifetime) - Date.now())
|
|
99
|
-
}
|
|
100
|
-
return null
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
async cleanupExpired(): Promise<void> {
|
|
104
|
-
if (import.meta.server) {
|
|
105
|
-
const prefix = 'cache:'
|
|
106
|
-
const now = Date.now()
|
|
107
|
-
const storage = CApplicationCache.storage
|
|
108
|
-
const keysToDelete: string[] = []
|
|
109
|
-
|
|
110
|
-
for (const [key, entry] of storage.entries()) {
|
|
111
|
-
if (key.startsWith(prefix)) {
|
|
112
|
-
if (now - entry.timestamp > entry.lifetime) {
|
|
113
|
-
keysToDelete.push(key)
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
for (const key of keysToDelete) {
|
|
119
|
-
storage.delete(key)
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
import { ACacheProvider } from './ACacheProvider'
|
|
2
|
-
import type { ICacheEntry } from '../types'
|
|
3
|
-
|
|
4
|
-
export class CCookieCache extends ACacheProvider {
|
|
5
|
-
private static instance: CCookieCache | null = null
|
|
6
|
-
|
|
7
|
-
public static getInstance(): CCookieCache {
|
|
8
|
-
if (!this.instance) {
|
|
9
|
-
this.instance = new CCookieCache()
|
|
10
|
-
}
|
|
11
|
-
return this.instance
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
public type = 'Cookie'
|
|
15
|
-
|
|
16
|
-
private constructor() {
|
|
17
|
-
super()
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async getKeyList(nuxtApp?: any): Promise<Array<string>> {
|
|
21
|
-
const prefix = 'cache:'
|
|
22
|
-
let cookieStr = ''
|
|
23
|
-
|
|
24
|
-
if (import.meta.client) {
|
|
25
|
-
cookieStr = document.cookie
|
|
26
|
-
} else if (nuxtApp) {
|
|
27
|
-
// Extract from H3Event or SSR Context
|
|
28
|
-
const headers = (nuxtApp as any).node?.req?.headers || (nuxtApp as any).ssrContext?.event?.node?.req?.headers
|
|
29
|
-
cookieStr = headers?.['cookie'] || ''
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (!cookieStr) return []
|
|
33
|
-
|
|
34
|
-
const keys: string[] = []
|
|
35
|
-
const cookies = cookieStr.split(';')
|
|
36
|
-
for (let i = 0; i < cookies.length; i++) {
|
|
37
|
-
const cookie = cookies[i].trim()
|
|
38
|
-
const eqPos = cookie.indexOf('=')
|
|
39
|
-
if (eqPos > 0) {
|
|
40
|
-
const name = decodeURIComponent(cookie.substring(0, eqPos))
|
|
41
|
-
if (name.startsWith(prefix)) {
|
|
42
|
-
keys.push(name.substring(prefix.length))
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
return keys
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async get<T>(key: string, nuxtApp?: any): Promise<T | null> {
|
|
50
|
-
const prefixedKey = 'cache:' + key
|
|
51
|
-
let cookieValue: string | null = null
|
|
52
|
-
|
|
53
|
-
if (import.meta.client) {
|
|
54
|
-
const name = prefixedKey + '='
|
|
55
|
-
const ca = document.cookie.split(';')
|
|
56
|
-
for (let i = 0; i < ca.length; i++) {
|
|
57
|
-
let c = ca[i].trim()
|
|
58
|
-
if (c.indexOf(name) === 0) {
|
|
59
|
-
cookieValue = c.substring(name.length, c.length)
|
|
60
|
-
break
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
} else if (nuxtApp) {
|
|
64
|
-
const headers = (nuxtApp as any).node?.req?.headers || (nuxtApp as any).ssrContext?.event?.node?.req?.headers
|
|
65
|
-
const cookieStr = headers?.['cookie'] || ''
|
|
66
|
-
const name = prefixedKey + '='
|
|
67
|
-
const ca = cookieStr.split(';')
|
|
68
|
-
for (let i = 0; i < ca.length; i++) {
|
|
69
|
-
let c = ca[i].trim()
|
|
70
|
-
if (c.indexOf(name) === 0) {
|
|
71
|
-
cookieValue = c.substring(name.length, c.length)
|
|
72
|
-
break
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (!cookieValue) return null
|
|
78
|
-
|
|
79
|
-
try {
|
|
80
|
-
const val = JSON.parse(decodeURIComponent(cookieValue)) as ICacheEntry<T>
|
|
81
|
-
if (val && val.timestamp && val.lifetime) {
|
|
82
|
-
if (Date.now() - val.timestamp <= val.lifetime) {
|
|
83
|
-
return val.data
|
|
84
|
-
} else {
|
|
85
|
-
// Expired
|
|
86
|
-
await this.set(key, null as any, 0, nuxtApp)
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return null
|
|
90
|
-
} catch (e) {
|
|
91
|
-
return null
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
async set<T>(key: string, data: T, lifetime: number, nuxtApp?: any): Promise<void> {
|
|
96
|
-
const prefixedKey = 'cache:' + key
|
|
97
|
-
const entry: ICacheEntry<T> = {
|
|
98
|
-
data,
|
|
99
|
-
timestamp: Date.now(),
|
|
100
|
-
lifetime
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const cookieValue = encodeURIComponent(JSON.stringify(entry))
|
|
104
|
-
const maxAge = Math.floor(lifetime / 1000)
|
|
105
|
-
const expires = new Date(Date.now() + lifetime).toUTCString()
|
|
106
|
-
const cookieStr = `${prefixedKey}=${cookieValue}; Max-Age=${maxAge}; Path=/; SameSite=Lax${import.meta.server ? '; HttpOnly' : ''}`
|
|
107
|
-
|
|
108
|
-
if (import.meta.client) {
|
|
109
|
-
document.cookie = cookieStr
|
|
110
|
-
} else if (nuxtApp) {
|
|
111
|
-
const res = (nuxtApp as any).node?.res || (nuxtApp as any).ssrContext?.event?.node?.res
|
|
112
|
-
if (res) {
|
|
113
|
-
const existing = res.getHeader('Set-Cookie')
|
|
114
|
-
if (!existing) {
|
|
115
|
-
res.setHeader('Set-Cookie', cookieStr)
|
|
116
|
-
} else if (Array.isArray(existing)) {
|
|
117
|
-
res.setHeader('Set-Cookie', [...existing, cookieStr])
|
|
118
|
-
} else {
|
|
119
|
-
res.setHeader('Set-Cookie', [existing as string, cookieStr])
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
async remove(key: string, nuxtApp?: any): Promise<void> {
|
|
126
|
-
const prefixedKey = 'cache:' + key
|
|
127
|
-
const cookieStr = `${prefixedKey}=; Max-Age=0; Path=/; SameSite=Lax${import.meta.server ? '; HttpOnly' : ''}`
|
|
128
|
-
|
|
129
|
-
if (import.meta.client) {
|
|
130
|
-
document.cookie = cookieStr
|
|
131
|
-
} else if (nuxtApp) {
|
|
132
|
-
const res = (nuxtApp as any).node?.res || (nuxtApp as any).ssrContext?.event?.node?.res
|
|
133
|
-
if (res) {
|
|
134
|
-
const existing = res.getHeader('Set-Cookie')
|
|
135
|
-
if (!existing) {
|
|
136
|
-
res.setHeader('Set-Cookie', cookieStr)
|
|
137
|
-
} else if (Array.isArray(existing)) {
|
|
138
|
-
res.setHeader('Set-Cookie', [...existing, cookieStr])
|
|
139
|
-
} else {
|
|
140
|
-
res.setHeader('Set-Cookie', [existing as string, cookieStr])
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
async getRemainingTime(key: string, nuxtApp?: any): Promise<number | null> {
|
|
147
|
-
const prefixedKey = 'cache:' + key
|
|
148
|
-
let cookieValue: string | null = null
|
|
149
|
-
|
|
150
|
-
if (import.meta.client) {
|
|
151
|
-
const name = prefixedKey + '='
|
|
152
|
-
const ca = document.cookie.split(';')
|
|
153
|
-
for (let i = 0; i < ca.length; i++) {
|
|
154
|
-
let c = ca[i].trim()
|
|
155
|
-
if (c.indexOf(name) === 0) {
|
|
156
|
-
cookieValue = c.substring(name.length, c.length)
|
|
157
|
-
break
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
} else if (nuxtApp) {
|
|
161
|
-
const headers = (nuxtApp as any).node?.req?.headers || (nuxtApp as any).ssrContext?.event?.node?.req?.headers
|
|
162
|
-
const cookieStr = headers?.['cookie'] || ''
|
|
163
|
-
const name = prefixedKey + '='
|
|
164
|
-
const ca = cookieStr.split(';')
|
|
165
|
-
for (let i = 0; i < ca.length; i++) {
|
|
166
|
-
let c = ca[i].trim()
|
|
167
|
-
if (c.indexOf(name) === 0) {
|
|
168
|
-
cookieValue = c.substring(name.length, c.length)
|
|
169
|
-
break
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if (!cookieValue) return null
|
|
175
|
-
|
|
176
|
-
try {
|
|
177
|
-
const val = JSON.parse(decodeURIComponent(cookieValue)) as ICacheEntry<any>
|
|
178
|
-
if (val && val.timestamp && val.lifetime) {
|
|
179
|
-
return Math.max(0, (val.timestamp + val.lifetime) - Date.now())
|
|
180
|
-
}
|
|
181
|
-
return null
|
|
182
|
-
} catch (e) {
|
|
183
|
-
return null
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
async cleanupExpired(): Promise<void> {
|
|
188
|
-
if (import.meta.client) {
|
|
189
|
-
const prefix = 'cache:'
|
|
190
|
-
const now = Date.now()
|
|
191
|
-
const cookies = document.cookie.split(';')
|
|
192
|
-
for (let i = 0; i < cookies.length; i++) {
|
|
193
|
-
const cookie = cookies[i].trim()
|
|
194
|
-
const eqPos = cookie.indexOf('=')
|
|
195
|
-
if (eqPos > 0) {
|
|
196
|
-
const name = decodeURIComponent(cookie.substring(0, eqPos))
|
|
197
|
-
if (name.startsWith(prefix)) {
|
|
198
|
-
const value = decodeURIComponent(cookie.substring(eqPos + 1))
|
|
199
|
-
try {
|
|
200
|
-
const entry: ICacheEntry<any> = JSON.parse(value)
|
|
201
|
-
if (now - entry.timestamp > entry.lifetime) {
|
|
202
|
-
document.cookie = `${encodeURIComponent(name)}=; max-age=0; path=/`
|
|
203
|
-
}
|
|
204
|
-
} catch (e) {
|
|
205
|
-
document.cookie = `${encodeURIComponent(name)}=; max-age=0; path=/`
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
@@ -1,312 +0,0 @@
|
|
|
1
|
-
import { ACacheProvider } from './ACacheProvider'
|
|
2
|
-
import type { ICacheEntry } from '../types'
|
|
3
|
-
|
|
4
|
-
export class CIndexedDBCache extends ACacheProvider {
|
|
5
|
-
private static instance: CIndexedDBCache | null = null
|
|
6
|
-
|
|
7
|
-
public static getInstance(): CIndexedDBCache {
|
|
8
|
-
if (!this.instance) {
|
|
9
|
-
this.instance = new CIndexedDBCache()
|
|
10
|
-
}
|
|
11
|
-
return this.instance
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
private dbName = 'KatluxDB'
|
|
15
|
-
private storeName = 'cache'
|
|
16
|
-
private version = 2
|
|
17
|
-
private dbPromise: Promise<IDBDatabase> | null = null
|
|
18
|
-
|
|
19
|
-
public setStore(storeName: string = "cache") {
|
|
20
|
-
this.storeName = storeName || 'cache'
|
|
21
|
-
if (import.meta.client) {
|
|
22
|
-
this.dbPromise = this.openDB()
|
|
23
|
-
this._hydrateFromPayload()
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
private constructor() {
|
|
28
|
-
super()
|
|
29
|
-
this.setStore()
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
private _hydrateFromPayload() {
|
|
33
|
-
try {
|
|
34
|
-
const nuxtApp = typeof useNuxtApp === 'function' ? useNuxtApp() : null
|
|
35
|
-
const payloadData = nuxtApp?.payload?.data || (globalThis as any).__NUXT__?.payload?.data
|
|
36
|
-
if (!payloadData) return
|
|
37
|
-
|
|
38
|
-
const prefix = 'cache:'
|
|
39
|
-
let count = 0
|
|
40
|
-
for (const key in payloadData) {
|
|
41
|
-
if (key.startsWith(prefix)) {
|
|
42
|
-
const value = payloadData[key]
|
|
43
|
-
if (value && typeof value === 'object' && 'data' in value && 'timestamp' in value && 'lifetime' in value) {
|
|
44
|
-
this.dbPromise?.then(async (db) => {
|
|
45
|
-
try {
|
|
46
|
-
const tx = db.transaction(this.storeName, 'readwrite')
|
|
47
|
-
const store = tx.objectStore(this.storeName)
|
|
48
|
-
store.put(value, key)
|
|
49
|
-
tx.commit?.()
|
|
50
|
-
} catch (e) {
|
|
51
|
-
// Silent fail
|
|
52
|
-
}
|
|
53
|
-
})
|
|
54
|
-
count++
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
if (count > 0) console.log(`[CIndexedDBCache] Hydrated ${count} entries from payload`)
|
|
59
|
-
} catch (e) {
|
|
60
|
-
// Silent fail
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
private openDB(): Promise<IDBDatabase> {
|
|
65
|
-
return new Promise((resolve, reject) => {
|
|
66
|
-
const request = indexedDB.open(this.dbName, this.version)
|
|
67
|
-
request.onerror = () => reject(request.error)
|
|
68
|
-
request.onsuccess = () => resolve(request.result)
|
|
69
|
-
request.onupgradeneeded = (event) => {
|
|
70
|
-
const db = (event.target as IDBOpenDBRequest).result
|
|
71
|
-
if (!db.objectStoreNames.contains(this.storeName)) {
|
|
72
|
-
db.createObjectStore(this.storeName)
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
})
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
private async getStore(mode: IDBTransactionMode): Promise<IDBObjectStore> {
|
|
79
|
-
if (!this.dbPromise) return Promise.reject("IndexedDB not initialized")
|
|
80
|
-
const db = await this.dbPromise
|
|
81
|
-
return db.transaction(this.storeName, mode).objectStore(this.storeName)
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async getKeyList(nuxtApp?: any): Promise<Array<string>> {
|
|
85
|
-
if (!import.meta.client || !this.dbPromise) return []
|
|
86
|
-
const db = await this.dbPromise
|
|
87
|
-
const store = db.transaction(this.storeName, 'readonly').objectStore(this.storeName)
|
|
88
|
-
const keys = await new Promise<string[]>((resolve, reject) => {
|
|
89
|
-
const req = store.getAllKeys()
|
|
90
|
-
req.onsuccess = () => resolve(req.result as string[])
|
|
91
|
-
req.onerror = () => reject(req.error)
|
|
92
|
-
})
|
|
93
|
-
const prefix = 'cache:'
|
|
94
|
-
return keys
|
|
95
|
-
.filter(key => key.startsWith(prefix))
|
|
96
|
-
.map(key => key.substring(prefix.length))
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
async get<T>(key: string, nuxtApp?: any): Promise<T | null> {
|
|
100
|
-
const prefixedKey = 'cache:' + key
|
|
101
|
-
|
|
102
|
-
if (import.meta.client) {
|
|
103
|
-
try {
|
|
104
|
-
const store = await this.getStore('readonly')
|
|
105
|
-
const data = await new Promise<ICacheEntry<T> | undefined>((resolve, reject) => {
|
|
106
|
-
const req = store.get(prefixedKey)
|
|
107
|
-
req.onsuccess = () => resolve(req.result)
|
|
108
|
-
req.onerror = () => reject(req.error)
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
if (data) {
|
|
112
|
-
if (Date.now() - data.timestamp <= data.lifetime) {
|
|
113
|
-
console.log(`[CIndexedDBCache] GET SUCCESS: ${key}`)
|
|
114
|
-
return data.data
|
|
115
|
-
} else {
|
|
116
|
-
console.log(`[CIndexedDBCache] EXPIRED: ${key}`)
|
|
117
|
-
const writeStore = await this.getStore('readwrite')
|
|
118
|
-
writeStore.delete(prefixedKey)
|
|
119
|
-
}
|
|
120
|
-
} else {
|
|
121
|
-
console.log(`[CIndexedDBCache] NOT IN DB: ${key}`)
|
|
122
|
-
}
|
|
123
|
-
} catch (e) {
|
|
124
|
-
// Silent fail
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Check SSR Payload
|
|
129
|
-
try {
|
|
130
|
-
let payloadData: any = null
|
|
131
|
-
if (import.meta.client) {
|
|
132
|
-
payloadData = (globalThis as any).__NUXT__?.payload?.data
|
|
133
|
-
} else if (nuxtApp) {
|
|
134
|
-
payloadData = (nuxtApp as any).payload?.data || (nuxtApp as any).ssrContext?.payload?.data
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if (payloadData && payloadData[prefixedKey]) {
|
|
138
|
-
const entry = payloadData[prefixedKey] as ICacheEntry<T>
|
|
139
|
-
if (Date.now() - entry.timestamp <= entry.lifetime) {
|
|
140
|
-
if (import.meta.client) {
|
|
141
|
-
this.set(key, entry.data, entry.lifetime, nuxtApp)
|
|
142
|
-
}
|
|
143
|
-
return entry.data
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
} catch (e) {
|
|
147
|
-
// Silent fail
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return null
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
async set<T>(key: string, data: T, lifetime: number, nuxtApp?: any): Promise<void> {
|
|
154
|
-
const prefixedKey = 'cache:' + key
|
|
155
|
-
const entry: ICacheEntry<T> = {
|
|
156
|
-
data,
|
|
157
|
-
timestamp: Date.now(),
|
|
158
|
-
lifetime
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (import.meta.server && nuxtApp) {
|
|
162
|
-
try {
|
|
163
|
-
const payload = (nuxtApp as any).payload?.data || (nuxtApp as any).ssrContext?.payload?.data
|
|
164
|
-
if (payload) {
|
|
165
|
-
payload[prefixedKey] = entry
|
|
166
|
-
}
|
|
167
|
-
} catch (e) {
|
|
168
|
-
// Silent fail
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (import.meta.client) {
|
|
173
|
-
try {
|
|
174
|
-
const store = await this.getStore('readwrite')
|
|
175
|
-
await new Promise<void>((resolve, reject) => {
|
|
176
|
-
const req = store.put(entry, prefixedKey)
|
|
177
|
-
req.onsuccess = () => resolve()
|
|
178
|
-
req.onerror = () => reject(req.error)
|
|
179
|
-
})
|
|
180
|
-
} catch (e) {
|
|
181
|
-
// Silent fail
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
async remove(key: string, nuxtApp?: any): Promise<void> {
|
|
187
|
-
const prefixedKey = 'cache:' + key
|
|
188
|
-
if (import.meta.client) {
|
|
189
|
-
try {
|
|
190
|
-
const store = await this.getStore('readwrite')
|
|
191
|
-
await new Promise<void>((resolve, reject) => {
|
|
192
|
-
const req = store.delete(prefixedKey)
|
|
193
|
-
req.onsuccess = () => resolve()
|
|
194
|
-
req.onerror = () => reject(req.error)
|
|
195
|
-
})
|
|
196
|
-
} catch (e) {
|
|
197
|
-
// Silent fail
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
if (import.meta.server && nuxtApp) {
|
|
201
|
-
try {
|
|
202
|
-
const payload = (nuxtApp as any).payload?.data || (nuxtApp as any).ssrContext?.payload?.data
|
|
203
|
-
if (payload && payload[prefixedKey]) {
|
|
204
|
-
delete payload[prefixedKey]
|
|
205
|
-
}
|
|
206
|
-
} catch (e) {
|
|
207
|
-
// Silent fail
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
async removeByPrefix(prefix: string, nuxtApp?: any): Promise<void> {
|
|
213
|
-
const fullPrefix = 'cache:' + prefix
|
|
214
|
-
if (import.meta.client) {
|
|
215
|
-
try {
|
|
216
|
-
const store = await this.getStore('readwrite')
|
|
217
|
-
const allKeys = await new Promise<string[]>((resolve, reject) => {
|
|
218
|
-
const req = store.getAllKeys()
|
|
219
|
-
req.onsuccess = () => resolve(req.result as string[])
|
|
220
|
-
req.onerror = () => reject(req.error)
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
const keysToDelete = allKeys.filter(k => k.startsWith(fullPrefix))
|
|
224
|
-
|
|
225
|
-
for (const key of keysToDelete) {
|
|
226
|
-
await new Promise<void>((resolve, reject) => {
|
|
227
|
-
const req = store.delete(key)
|
|
228
|
-
req.onsuccess = () => resolve()
|
|
229
|
-
req.onerror = () => reject(req.error)
|
|
230
|
-
})
|
|
231
|
-
}
|
|
232
|
-
} catch (e) {
|
|
233
|
-
// Silent fail
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
if (import.meta.server && nuxtApp) {
|
|
237
|
-
try {
|
|
238
|
-
const payload = (nuxtApp as any).payload?.data || (nuxtApp as any).ssrContext?.payload?.data
|
|
239
|
-
if (payload) {
|
|
240
|
-
for (const key in payload) {
|
|
241
|
-
if (key.startsWith(fullPrefix)) {
|
|
242
|
-
delete payload[key]
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
} catch (e) {
|
|
247
|
-
// Silent fail
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
async getRemainingTime(key: string, nuxtApp?: any): Promise<number | null> {
|
|
253
|
-
if (import.meta.client) {
|
|
254
|
-
try {
|
|
255
|
-
const prefixedKey = 'cache:' + key
|
|
256
|
-
const store = await this.getStore('readonly')
|
|
257
|
-
const entry = await new Promise<ICacheEntry<any> | undefined>((resolve, reject) => {
|
|
258
|
-
const req = store.get(prefixedKey)
|
|
259
|
-
req.onsuccess = () => resolve(req.result)
|
|
260
|
-
req.onerror = () => reject(req.error)
|
|
261
|
-
})
|
|
262
|
-
|
|
263
|
-
if (!entry) return null
|
|
264
|
-
return Math.max(0, (entry.timestamp + entry.lifetime) - Date.now())
|
|
265
|
-
} catch (e) {
|
|
266
|
-
return null
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
return null
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
async cleanupExpired(): Promise<void> {
|
|
273
|
-
if (import.meta.client && this.dbPromise) {
|
|
274
|
-
try {
|
|
275
|
-
const prefix = 'cache:'
|
|
276
|
-
const now = Date.now()
|
|
277
|
-
const keysToDelete: string[] = []
|
|
278
|
-
|
|
279
|
-
const store = await this.getStore('readwrite')
|
|
280
|
-
const allKeys = await new Promise<string[]>((resolve, reject) => {
|
|
281
|
-
const req = store.getAllKeys()
|
|
282
|
-
req.onsuccess = () => resolve(req.result as string[])
|
|
283
|
-
req.onerror = () => reject(req.error)
|
|
284
|
-
})
|
|
285
|
-
|
|
286
|
-
for (const key of allKeys) {
|
|
287
|
-
if (key.startsWith(prefix)) {
|
|
288
|
-
const entry = await new Promise<ICacheEntry<any> | undefined>((resolve, reject) => {
|
|
289
|
-
const req = store.get(key)
|
|
290
|
-
req.onsuccess = () => resolve(req.result)
|
|
291
|
-
req.onerror = () => reject(req.error)
|
|
292
|
-
})
|
|
293
|
-
|
|
294
|
-
if (entry && now - entry.timestamp > entry.lifetime) {
|
|
295
|
-
keysToDelete.push(key)
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
for (const key of keysToDelete) {
|
|
301
|
-
await new Promise<void>((resolve, reject) => {
|
|
302
|
-
const req = store.delete(key)
|
|
303
|
-
req.onsuccess = () => resolve()
|
|
304
|
-
req.onerror = () => reject(req.error)
|
|
305
|
-
})
|
|
306
|
-
}
|
|
307
|
-
} catch (e) {
|
|
308
|
-
// Silent fail
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
}
|