cloudworker-proxy
Version:
An api gateway for cloudflare workers
159 lines (127 loc) • 3.72 kB
JavaScript
const lodashGet = require('lodash.get');
const _ = {
get: lodashGet,
};
module.exports = class KvStorage {
constructor({ accountId, namespace, authEmail, authKey, fetch, FormData }) {
this.accountId = accountId;
this.namespace = namespace;
this.authEmail = authEmail;
this.authKey = authKey;
this.fetch = fetch || global.fetch;
this.FormData = FormData || global.FormData;
}
getNamespaceUrl() {
return `https://api.cloudflare.com/client/v4/accounts/${this.accountId}/storage/kv/namespaces/${this.namespace}`;
}
getUrlForKey(key) {
return new URL(`${this.getNamespaceUrl()}/values/${key}`);
}
async list(options = {}) {
const { prefix, limit, cursor } = options;
const url = new URL(`${this.getNamespaceUrl()}/keys`);
const searchParams = new URLSearchParams();
if (prefix) {
searchParams.append('prefix', prefix);
}
if (limit) {
searchParams.append('limit', limit);
}
if (cursor) {
searchParams.append('cursor', cursor);
}
url.search = searchParams.toString();
// eslint-disable-next-line no-undef
const response = await this.fetch(url, {
headers: {
'X-Auth-Email': this.authEmail,
'X-Auth-Key': this.authKey,
},
});
if (response.ok) {
const body = await response.json();
return {
keys: body.result,
list_complete: body.result_info.count < (limit || 1000),
cursor: body.result_info.cursor,
};
}
return null;
}
async get(key, type = 'text') {
const url = this.getUrlForKey(key);
// eslint-disable-next-line no-undef
const response = await this.fetch(url, {
headers: {
'X-Auth-Email': this.authEmail,
'X-Auth-Key': this.authKey,
},
});
if (response.ok) {
switch (type) {
case 'text':
return response.text();
case 'json':
return response.json();
case 'stream':
return response.body;
case 'arraybuffer':
return response.arrayBuffer();
default:
throw new Error('Type not supported');
}
}
return null;
}
async getWithMetadata(key, type) {
const [value, keys] = await Promise.all([
this.get(key, type),
this.list({ prefix: key, limit: 10 }),
]);
const metadata = _.get(keys, 'keys.0.metadata', {});
return {
value,
metadata,
};
}
async put(key, value, options = {}) {
const { expiration, expirationTtl, metadata } = options;
const url = this.getUrlForKey(key);
const searchParams = new URLSearchParams();
if (expiration) {
searchParams.append('expiration', expiration);
} else if (expirationTtl) {
searchParams.append('expiration_ttl', expirationTtl);
}
const headers = {
'X-Auth-Email': this.authEmail,
'X-Auth-Key': this.authKey,
};
url.search = searchParams.toString();
// eslint-disable-next-line no-undef
const formData = new this.FormData();
formData.append('value', value);
if (metadata) {
formData.append('metadata', JSON.stringify(metadata));
}
// eslint-disable-next-line no-undef
const response = await this.fetch(url.toString(), {
method: 'PUT',
headers: { ...formData.headers, ...headers },
body: formData.stream,
});
return response.ok;
}
async delete(key) {
const url = this.getUrlForKey(key);
// eslint-disable-next-line no-undef
const response = await fetch(url, {
headers: {
'X-Auth-Email': this.authEmail,
'X-Auth-Key': this.authKey,
},
method: 'DELETE',
});
return response.ok;
}
};