-
Notifications
You must be signed in to change notification settings - Fork 5
/
index.js
98 lines (81 loc) · 2.23 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
'use strict'
const {
S3Client,
PutObjectCommand,
DeleteObjectCommand
} = require('@aws-sdk/client-s3')
const pReflect = require('p-reflect')
class KeyvS3 {
constructor ({ namespace, hostname, ttl, gotOpts, s3client, got, ...opts }) {
this.Bucket = namespace
this.ttl = ttl
this.hostname = hostname ?? namespace
this.s3client = s3client ?? new S3Client(opts)
this.got =
got ??
require('got').extend({
...gotOpts,
retry: opts.maxAttempts ?? gotOpts?.retry,
timeout: opts.requestHandler?.socketTimeout ?? gotOpts?.timeout
})
}
filename (key) {
const id = key.toString().replace(`${this.Bucket}:`, '')
return `${id}.json`
}
fileUrl (filename) {
return new URL(filename, `https://${this.hostname}`).toString()
}
async get (key) {
const { value, reason, isRejected } = await pReflect(
this.got(this.fileUrl(this.filename(key)), {
responseType: 'json'
})
)
if (isRejected) {
if (reason.response) {
if ([403, 404, 520, 530].includes(reason.response.statusCode)) {
return undefined
}
}
throw reason
}
const { statusCode, headers, body } = value
if (statusCode !== 200) return undefined
const expires = headers.expires
? new Date(headers.expires).getTime()
: Number.POSITIVE_INFINITY
return Date.now() <= expires ? body : undefined
}
async set (key, value, ttl = this.ttl, opts) {
const { reason, isRejected } = await pReflect(
this.s3client.send(
new PutObjectCommand({
Key: this.filename(key),
Body: JSON.stringify(value, null, 2),
ContentType: 'application/json',
Bucket: this.Bucket,
ACL: 'public-read',
Expires: ttl ? new Date(new Date().getTime() + ttl) : undefined,
...opts
})
)
)
if (isRejected) throw reason
return true
}
async delete (key, opts) {
const { isRejected, reason } = await pReflect(
this.s3client.send(
new DeleteObjectCommand({
Key: this.filename(key),
Bucket: this.Bucket,
...opts
})
)
)
if (isRejected) throw reason
return true
}
}
module.exports = KeyvS3