@live-change/framework 0.9.105 → 0.9.107
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/lib/App.js +39 -5
- package/lib/definition/ModelDefinition.ts +8 -0
- package/lib/runtime/LiveDao.js +4 -0
- package/lib/utils.js +13 -1
- package/package.json +4 -4
package/lib/App.js
CHANGED
|
@@ -632,20 +632,28 @@ class App {
|
|
|
632
632
|
}
|
|
633
633
|
|
|
634
634
|
async cachedTask(taskDescription, expireAfter, task) {
|
|
635
|
-
|
|
635
|
+
/// Parse expireAfter in format "10s", "1m", "1h", "1d"
|
|
636
|
+
const expireAfterMs = utils.parseDuration(expireAfter)
|
|
637
|
+
const utf8 = new TextEncoder().encode(JSON.stringify(taskDescription))
|
|
638
|
+
const taskDescriptionHashBinary = await crypto.subtle.digest('SHA-256', utf8)
|
|
639
|
+
const taskDescriptionHash = Array.from(new Uint8Array(taskDescriptionHashBinary))
|
|
640
|
+
.map(b => b.toString(16).padStart(2, '0')).join('')
|
|
641
|
+
//console.log("taskDescriptionHash", taskDescriptionHash)
|
|
636
642
|
let cacheEntry = await this.dao.get(['database', 'tableObject', this.databaseName, 'cache', taskDescriptionHash])
|
|
637
|
-
if(!cacheEntry || cacheEntry.createdAt < new Date(Date.now() -
|
|
643
|
+
if(!cacheEntry || cacheEntry.createdAt < new Date(Date.now() - expireAfterMs).toISOString()) {
|
|
644
|
+
//console.log("cache miss", taskDescription)
|
|
638
645
|
const result = await task()
|
|
639
|
-
const expiresAt = new Date(Date.now() +
|
|
646
|
+
const expiresAt = new Date(Date.now() + expireAfterMs).toISOString()
|
|
640
647
|
cacheEntry = {
|
|
641
648
|
id: taskDescriptionHash,
|
|
642
649
|
createdAt: new Date().toISOString(),
|
|
643
|
-
expiresAt
|
|
650
|
+
expiresAt,
|
|
644
651
|
result
|
|
645
652
|
}
|
|
646
653
|
await this.dao.request(['database', 'put'], this.databaseName, 'cache', cacheEntry)
|
|
647
654
|
} else { // extend cache entry expiration
|
|
648
|
-
|
|
655
|
+
//console.log("cache hit", taskDescription)
|
|
656
|
+
const newExpiresAt = new Date(new Date(cacheEntry.createdAt).getTime() + expireAfterMs).toISOString()
|
|
649
657
|
if(cacheEntry.expiresAt < newExpiresAt) {
|
|
650
658
|
cacheEntry.expiresAt = newExpiresAt
|
|
651
659
|
await this.dao.request(['database', 'put'], this.databaseName, 'cache', cacheEntry)
|
|
@@ -654,6 +662,32 @@ class App {
|
|
|
654
662
|
return cacheEntry.result
|
|
655
663
|
}
|
|
656
664
|
|
|
665
|
+
async cacheGet(taskDescription, expireAfter) {
|
|
666
|
+
const expireAfterMs = utils.parseDuration(expireAfter)
|
|
667
|
+
const utf8 = new TextEncoder().encode(JSON.stringify(taskDescription))
|
|
668
|
+
const taskDescriptionHashBinary = await crypto.subtle.digest('SHA-256', utf8)
|
|
669
|
+
const taskDescriptionHash = Array.from(new Uint8Array(taskDescriptionHashBinary))
|
|
670
|
+
.map(b => b.toString(16).padStart(2, '0')).join('')
|
|
671
|
+
const cacheEntry = await this.dao.get(['database', 'tableObject', this.databaseName, 'cache', taskDescriptionHash])
|
|
672
|
+
if(!cacheEntry || cacheEntry.createdAt < new Date(Date.now() - expireAfterMs).toISOString()) {
|
|
673
|
+
return null
|
|
674
|
+
}
|
|
675
|
+
return cacheEntry.result
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
async cachePut(taskDescription, result) {
|
|
679
|
+
const utf8 = new TextEncoder().encode(JSON.stringify(taskDescription))
|
|
680
|
+
const taskDescriptionHashBinary = await crypto.subtle.digest('SHA-256', utf8)
|
|
681
|
+
const taskDescriptionHash = Array.from(new Uint8Array(taskDescriptionHashBinary))
|
|
682
|
+
.map(b => b.toString(16).padStart(2, '0')).join('')
|
|
683
|
+
const cacheEntry = {
|
|
684
|
+
id: taskDescriptionHash,
|
|
685
|
+
createdAt: new Date().toISOString(),
|
|
686
|
+
result
|
|
687
|
+
}
|
|
688
|
+
await this.dao.request(['database', 'put'], this.databaseName, 'cache', cacheEntry)
|
|
689
|
+
}
|
|
690
|
+
|
|
657
691
|
}
|
|
658
692
|
|
|
659
693
|
export default App
|
|
@@ -10,8 +10,16 @@ export interface ModelIndexDefinitionSpecification {
|
|
|
10
10
|
multi?: boolean,
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
export type ValidationConfig = string | {
|
|
14
|
+
name: string,
|
|
15
|
+
[key: string]: any
|
|
16
|
+
}
|
|
17
|
+
|
|
13
18
|
export interface ModelPropertyDefinitionSpecification {
|
|
14
19
|
type?: any,
|
|
20
|
+
default?: ((...args: any[]) => any) | any,
|
|
21
|
+
updated?: (...args: any[]) => any,
|
|
22
|
+
validation?: ValidationConfig[],
|
|
15
23
|
index?: ModelIndexDefinitionSpecification
|
|
16
24
|
}
|
|
17
25
|
|
package/lib/runtime/LiveDao.js
CHANGED
|
@@ -31,12 +31,16 @@ class LiveDao extends LcDao.DaoProxy {
|
|
|
31
31
|
|
|
32
32
|
computeCredentials() {
|
|
33
33
|
let credentials = JSON.parse(JSON.stringify(this.initialCredentials))
|
|
34
|
+
const keys = Object.keys(credentials).filter(key => key.endsWith("Key"))
|
|
34
35
|
for(const credentialsObserver of this.credentialsObservations) {
|
|
35
36
|
credentials = {
|
|
36
37
|
...credentials,
|
|
37
38
|
...credentialsObserver.credentials,
|
|
38
39
|
roles: [...credentials.roles, ...(credentialsObserver.credentials.roles || [])]
|
|
39
40
|
}
|
|
41
|
+
}
|
|
42
|
+
for(const key of keys) {
|
|
43
|
+
delete credentials[key]
|
|
40
44
|
}
|
|
41
45
|
return credentials
|
|
42
46
|
}
|
package/lib/utils.js
CHANGED
|
@@ -229,7 +229,6 @@ function prefixRange({ gt, lt, gte, lte, limit, reverse }, prefix, from = "") {
|
|
|
229
229
|
if(id.length > from.length) {
|
|
230
230
|
if(id.slice(0, from.length) !== from) {
|
|
231
231
|
console.error("ID:", id, "does not start with", from)
|
|
232
|
-
console.trace('id does not match prefix')
|
|
233
232
|
throw new Error("id does not match prefix")
|
|
234
233
|
}
|
|
235
234
|
id = id.slice(from.length)
|
|
@@ -354,3 +353,16 @@ export {
|
|
|
354
353
|
prefixRange, rangeProperties, fieldListToFieldsObject,
|
|
355
354
|
encodeIdentifier, extractRange, isomorphic, computeDefaults, computeUpdates
|
|
356
355
|
}
|
|
356
|
+
|
|
357
|
+
export function parseDuration(duration) {
|
|
358
|
+
if(typeof duration === 'number') return duration
|
|
359
|
+
const match = duration.match(/(\d+)([smhd])/g)
|
|
360
|
+
if(!match || match.length === 0) throw new Error(`Invalid duration: ${duration}`)
|
|
361
|
+
let result = 0
|
|
362
|
+
for(const m of match) {
|
|
363
|
+
const value = parseInt(m.slice(0, -1))
|
|
364
|
+
const unit = m.slice(-1)
|
|
365
|
+
result += value * { s: 1000, m: 60000, h: 3600000, d: 86400000 }[unit]
|
|
366
|
+
}
|
|
367
|
+
return result
|
|
368
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@live-change/framework",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.107",
|
|
4
4
|
"description": "Live Change Framework - ultimate solution for real time mobile/web apps",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
},
|
|
23
23
|
"homepage": "https://github.com/live-change/live-change-stack",
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@live-change/dao": "^0.9.
|
|
26
|
-
"@live-change/uid": "^0.9.
|
|
25
|
+
"@live-change/dao": "^0.9.107",
|
|
26
|
+
"@live-change/uid": "^0.9.107",
|
|
27
27
|
"typedoc": "0.28.3",
|
|
28
28
|
"typedoc-plugin-markdown": "^4.6.3",
|
|
29
29
|
"typedoc-plugin-rename-defaults": "^0.7.3"
|
|
30
30
|
},
|
|
31
|
-
"gitHead": "
|
|
31
|
+
"gitHead": "c546be0c12841aa8eca060d4c53d6d89bac2d088"
|
|
32
32
|
}
|