@usegraft/assets 1.0.0-beta.1 → 1.0.0-beta.3
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.d.ts +16 -2
- package/dist/index.js +22 -8
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -24,8 +24,22 @@ declare function defaultKeyFor(file: string): string;
|
|
|
24
24
|
interface PresignOptions {
|
|
25
25
|
expiresIn?: number;
|
|
26
26
|
}
|
|
27
|
+
interface PutOptions {
|
|
28
|
+
/**
|
|
29
|
+
* Write only if nothing is stored under the key yet. Sent as
|
|
30
|
+
* `If-None-Match: *`, so the store decides, not a separate existence check
|
|
31
|
+
* that a concurrent upload could slip past. A taken key throws
|
|
32
|
+
* AssetKeyTakenError. A store that ignores the header writes as usual.
|
|
33
|
+
*/
|
|
34
|
+
ifAbsent?: boolean;
|
|
35
|
+
}
|
|
36
|
+
/** The key already held an object, and the put asked for `ifAbsent`. */
|
|
37
|
+
declare class AssetKeyTakenError extends Error {
|
|
38
|
+
readonly key: string;
|
|
39
|
+
constructor(key: string);
|
|
40
|
+
}
|
|
27
41
|
interface Storage {
|
|
28
|
-
put(key: string, body: Uint8Array | string, contentType?: string): Promise<void>;
|
|
42
|
+
put(key: string, body: Uint8Array | string, contentType?: string, options?: PutOptions): Promise<void>;
|
|
29
43
|
get(key: string): Promise<Uint8Array>;
|
|
30
44
|
delete(key: string): Promise<void>;
|
|
31
45
|
exists(key: string): Promise<boolean>;
|
|
@@ -41,4 +55,4 @@ interface Storage {
|
|
|
41
55
|
}
|
|
42
56
|
declare function createStorage(config?: StorageConfig): Storage;
|
|
43
57
|
|
|
44
|
-
export { type PresignOptions, type Storage, type StorageConfig, contentTypeFor, createStorage, defaultKeyFor, storageConfigFromEnv };
|
|
58
|
+
export { AssetKeyTakenError, type PresignOptions, type PutOptions, type Storage, type StorageConfig, contentTypeFor, createStorage, defaultKeyFor, storageConfigFromEnv };
|
package/dist/index.js
CHANGED
|
@@ -41,6 +41,19 @@ function defaultKeyFor(file) {
|
|
|
41
41
|
|
|
42
42
|
// src/storage.ts
|
|
43
43
|
import { AwsClient } from "aws4fetch";
|
|
44
|
+
var AssetKeyTakenError = class extends Error {
|
|
45
|
+
key;
|
|
46
|
+
constructor(key) {
|
|
47
|
+
super(`An object is already stored under "${key}".`);
|
|
48
|
+
this.name = "AssetKeyTakenError";
|
|
49
|
+
this.key = key;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
function withoutTrailingSlashes(value) {
|
|
53
|
+
let end = value.length;
|
|
54
|
+
while (end > 0 && value.charCodeAt(end - 1) === 47) end -= 1;
|
|
55
|
+
return value.slice(0, end);
|
|
56
|
+
}
|
|
44
57
|
function createStorage(config = storageConfigFromEnv()) {
|
|
45
58
|
const aws = new AwsClient({
|
|
46
59
|
accessKeyId: config.accessKeyId,
|
|
@@ -48,7 +61,7 @@ function createStorage(config = storageConfigFromEnv()) {
|
|
|
48
61
|
region: config.region,
|
|
49
62
|
service: "s3"
|
|
50
63
|
});
|
|
51
|
-
const base = `${config.endpoint
|
|
64
|
+
const base = `${withoutTrailingSlashes(config.endpoint)}/${config.bucket}`;
|
|
52
65
|
const urlFor = (key) => `${base}/${key.split("/").map(encodeURIComponent).join("/")}`;
|
|
53
66
|
const presign = async (key, method, options) => {
|
|
54
67
|
const url = new URL(urlFor(key));
|
|
@@ -57,12 +70,12 @@ function createStorage(config = storageConfigFromEnv()) {
|
|
|
57
70
|
return signed.url;
|
|
58
71
|
};
|
|
59
72
|
return {
|
|
60
|
-
async put(key, body, contentType) {
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
73
|
+
async put(key, body, contentType, options = {}) {
|
|
74
|
+
const headers = {};
|
|
75
|
+
if (contentType) headers["content-type"] = contentType;
|
|
76
|
+
if (options.ifAbsent) headers["if-none-match"] = "*";
|
|
77
|
+
const res = await aws.fetch(urlFor(key), { method: "PUT", body, headers });
|
|
78
|
+
if (res.status === 412 && options.ifAbsent) throw new AssetKeyTakenError(key);
|
|
66
79
|
if (!res.ok) throw new Error(`storage put failed (${res.status}): ${await res.text()}`);
|
|
67
80
|
},
|
|
68
81
|
async get(key) {
|
|
@@ -86,7 +99,7 @@ function createStorage(config = storageConfigFromEnv()) {
|
|
|
86
99
|
},
|
|
87
100
|
async url(key, options = {}) {
|
|
88
101
|
if (config.publicBaseUrl) {
|
|
89
|
-
const publicBase = config.publicBaseUrl
|
|
102
|
+
const publicBase = withoutTrailingSlashes(config.publicBaseUrl);
|
|
90
103
|
return `${publicBase}/${key.split("/").map(encodeURIComponent).join("/")}`;
|
|
91
104
|
}
|
|
92
105
|
return presign(key, "GET", options);
|
|
@@ -94,6 +107,7 @@ function createStorage(config = storageConfigFromEnv()) {
|
|
|
94
107
|
};
|
|
95
108
|
}
|
|
96
109
|
export {
|
|
110
|
+
AssetKeyTakenError,
|
|
97
111
|
contentTypeFor,
|
|
98
112
|
createStorage,
|
|
99
113
|
defaultKeyFor,
|