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
99
100
import { API_URL } from "https://esm.town/v/std/API_URL";
import { ValTownBlobError } from "https://esm.town/v/std/ValTownBlobError";
import { ValTownBlobNotFoundError } from "https://esm.town/v/std/ValTownBlobNotFoundError";
/**
* Provides functions for interacting with your account's blob storage.
* Blobs can store any data type (text, JSON, images, etc.) and allow
* retrieval across different vals using the same key.
* ([Docs β](https://docs.val.town/std/blob))
*/
export const blob = {
/**
* Gets the data of a blob with the given key.
*
* @param {string} key - The key of the blob to get.
* @returns {Promise<Response>} A promise that resolves with the blob data as a Response object.
* @throws {ValTownBlobNotFoundError} If the blob is not found.
* @throws {ValTownBlobError} If an error occurs while getting the blob data.
*/
get: get,
/**
* Sets the data of a blob with the given key.
*
* @param {string} key - The key of the blob to set.
* @param {BodyInit} value - The data to set for the blob.
* @throws {ValTownBlobError} If an error occurs while setting the blob data.
*/
set: set,
/**
* Copies the data of a blob from one key to another.
*
* @param {string} previous - The key of the blob to copy from.
* @param {string} next - The key of the blob to copy to.
*/
copy: copy,
/**
* Moves the data of a blob from one key to another by copying and then deleting the original.
*
* @param {string} previous - The key of the blob to move from.
* @param {string} next - The key of the blob to move to.
*/
move: move,
/**
* Lists blobs with an optional prefix filter.
*
* @param {string} [prefix] - The prefix to filter the blobs by.
* @returns {Promise<{ key: string; size: number; lastModified: string }[]>} A promise that resolves with an array of blob metadata.
*/
list: list,
/**
* Deletes a blob with the given key.
*
* @param {string} key - The key of the blob to delete.
* @throws {ValTownBlobError} If an error occurs while deleting the blob.
*/
delete: delete_,
/**
* Gets the JSON data of a blob with the given key.
*
* @param {string} key - The key of the blob to get.
* @returns {Promise<any | undefined>} A promise that resolves with the JSON data of the blob, or undefined if the blob is not found.
* @throws {ValTownBlobError} If an error occurs while getting the blob data.
*/
getJSON: getJSON,
/**
* Sets the JSON data of a blob with the given key.
*
* @param {string} key - The key of the blob to set.
* @param {any} value - The JSON data to set for the blob.
* @throws {ValTownBlobError} If an error occurs while setting the blob data.
*/
setJSON: setJSON,
};
async function list(prefix?: string): Promise<{ key: string; size: number; lastModified: string }[]> {
let querystring = prefix ? `?prefix=${encodeURIComponent(prefix)}` : "";
const res = await fetch(`${API_URL}/v1/blob${querystring}`, {
headers: {
Authorization: `Bearer ${Deno.env.get("valtown")}`,
},
});
if (!res.ok) {
const body = await res.text();
throw new ValTownBlobError(body ? body : "Error listing blobs");
}
return res.json();
}
async function delete_(key: string) {
const res = await fetch(`${API_URL}/v1/blob/${encodeURIComponent(key)}`, {
method: "DELETE",
headers: {
Authorization: `Bearer ${Deno.env.get("valtown")}`,
Val Town is a social website to write and deploy JavaScript.
Build APIs and schedule functions from your browser.
August 13, 2024
I think it would be helpful if this doc mentioned the scope of the blob storage. My assumption, because it is not mentioned, is that this is global (account-scoped), not val-scoped, i.e., if I get and set the same key from two different vals, they will be sharing and overwriting the same value in the global store.
Great note! I added this to the readme above: "Blob storage is scoped globally to your account. If you set a blob in one val, you can retrieve it by the same key in another val." What do you think?
Sounds good!
Another note: I converted a val to use blob instead of separate val to store a string value, and I expected to use
get
andset
becauseset
hasvalue: string | BodyInit
for that. Took me a bit to figure out thatget
returns aResponse
(though I can see why it does) and it is not what you want for storing a stringgetJSON
with a plain string because a string is valid JSONI think of these as things that could use noting in the docs rather than a problem with the API. However, I will say unqualified
get/set
presents to me as the default/simplest API unless I'm told otherwise, but it seems likegetJSON/setJSON
are actually the first thing most people will want to reach for. That is hinted at by the fact that most of the examples on this page and here use the JSON variant. I think get/set are good names based on the implementation (get
is most general,getJSON
wrapsget
) but it would be nice to see that more clearly in the docs.Great point! I reorganized the readme to emphasize how they are lower-level primitives. Lmk if you have any other suggestions
It would be nice to have a rename/move function here.
I don't think rename/move is in the s3 API, so it'd be a get and then set operation, in which case building it would be a great pull request to this val (when we launch pull requests later today or tomorrow)
Thanks for the PR @pomdtr!