@usegraft/assets 1.0.0-beta.2 → 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 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,14 @@ 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
+ };
44
52
  function withoutTrailingSlashes(value) {
45
53
  let end = value.length;
46
54
  while (end > 0 && value.charCodeAt(end - 1) === 47) end -= 1;
@@ -62,12 +70,12 @@ function createStorage(config = storageConfigFromEnv()) {
62
70
  return signed.url;
63
71
  };
64
72
  return {
65
- async put(key, body, contentType) {
66
- const res = await aws.fetch(urlFor(key), {
67
- method: "PUT",
68
- body,
69
- headers: contentType ? { "content-type": contentType } : void 0
70
- });
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);
71
79
  if (!res.ok) throw new Error(`storage put failed (${res.status}): ${await res.text()}`);
72
80
  },
73
81
  async get(key) {
@@ -99,6 +107,7 @@ function createStorage(config = storageConfigFromEnv()) {
99
107
  };
100
108
  }
101
109
  export {
110
+ AssetKeyTakenError,
102
111
  contentTypeFor,
103
112
  createStorage,
104
113
  defaultKeyFor,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usegraft/assets",
3
- "version": "1.0.0-beta.2",
3
+ "version": "1.0.0-beta.3",
4
4
  "description": "S3-compatible object storage for binary assets: Cloudflare R2, MinIO, Tigris.",
5
5
  "keywords": [
6
6
  "agent",