@btravstack/storage 0.36.0 → 0.37.0
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/README.md +1 -1
- package/dist/index.cjs +22 -6
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +22 -7
- package/dist/s3.cjs +10 -1
- package/dist/s3.d.cts +1 -1
- package/dist/s3.d.mts +1 -1
- package/dist/s3.mjs +10 -1
- package/dist/{storage-CRkwIhac.mjs → storage-BmbyYPIE.mjs} +3 -1
- package/dist/{storage-QVPXOcO6.cjs → storage-DlAQXJ1t.cjs} +8 -0
- package/dist/{storage-BLJtJ7KF.d.cts → storage-uSBWFyB2.d.cts} +11 -2
- package/dist/{storage-BLJtJ7KF.d.mts → storage-uSBWFyB2.d.mts} +11 -2
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -121,7 +121,7 @@ which is this list's one detailed home.
|
|
|
121
121
|
## What it decides, and what it does not
|
|
122
122
|
|
|
123
123
|
**It decides** that a missing object is an ordinary answer rather than a fault
|
|
124
|
-
(counted `not_found`, logged at `info`), that `delete` is idempotent, that
|
|
124
|
+
(counted `not_found`, logged at `info`), that a held key under `putIfAbsent` is an ordinary answer (`ObjectExists`, counted `exists`), that `delete` is idempotent, that
|
|
125
125
|
presigning asks the store nothing — and that an adapter which cannot presign
|
|
126
126
|
says so instead of minting a URL that would fail only in production.
|
|
127
127
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_storage = require("./storage-
|
|
2
|
+
const require_storage = require("./storage-DlAQXJ1t.cjs");
|
|
3
3
|
let _btravstack_di = require("@btravstack/di");
|
|
4
4
|
let unthrown = require("unthrown");
|
|
5
5
|
let _btravstack_core = require("@btravstack/core");
|
|
@@ -24,6 +24,14 @@ const memoryStorageBackend = () => {
|
|
|
24
24
|
});
|
|
25
25
|
return (0, unthrown.OkAsync)();
|
|
26
26
|
},
|
|
27
|
+
putIfAbsent: (key, bytes, options) => {
|
|
28
|
+
if (objects.has(key)) return (0, unthrown.ErrAsync)(new require_storage.ObjectExists({ key }));
|
|
29
|
+
objects.set(key, {
|
|
30
|
+
bytes,
|
|
31
|
+
contentType: options.contentType
|
|
32
|
+
});
|
|
33
|
+
return (0, unthrown.OkAsync)();
|
|
34
|
+
},
|
|
27
35
|
get: (key) => {
|
|
28
36
|
const object = objects.get(key);
|
|
29
37
|
return object === void 0 ? (0, unthrown.ErrAsync)(new require_storage.ObjectNotFound({ key })) : (0, unthrown.OkAsync)(object);
|
|
@@ -59,17 +67,23 @@ const memoryStorage = () => (0, _btravstack_di.Module)("MemoryStorage")({
|
|
|
59
67
|
*/
|
|
60
68
|
const failed = (failure) => {
|
|
61
69
|
const cause = failure.tag === "Err" ? failure.error : failure.cause;
|
|
62
|
-
const ordinary = failure.tag !== "Err" ? void 0 : failure.error._tag === "
|
|
70
|
+
const ordinary = failure.tag !== "Err" ? void 0 : failure.error._tag === "ObjectExists" ? {
|
|
71
|
+
result: "exists",
|
|
72
|
+
reason: "an object already held the key"
|
|
73
|
+
} : failure.error._tag === "ObjectNotFound" ? {
|
|
74
|
+
result: "not_found",
|
|
75
|
+
reason: "the object was not there"
|
|
76
|
+
} : failure.error._tag === "PresignNotSupported" ? {
|
|
77
|
+
result: "not_found",
|
|
78
|
+
reason: "this store cannot mint a url"
|
|
79
|
+
} : void 0;
|
|
63
80
|
return ordinary === void 0 ? {
|
|
64
81
|
outcome: "error",
|
|
65
82
|
attributes: { result: "error" },
|
|
66
83
|
cause
|
|
67
84
|
} : {
|
|
68
85
|
outcome: "ok",
|
|
69
|
-
attributes:
|
|
70
|
-
result: "not_found",
|
|
71
|
-
reason: ordinary
|
|
72
|
-
}
|
|
86
|
+
attributes: ordinary
|
|
73
87
|
};
|
|
74
88
|
};
|
|
75
89
|
/** The KEY is a detail, not a dimension: on the span and the line, never on an instrument. */
|
|
@@ -90,6 +104,7 @@ const instrument = (backend, observers) => {
|
|
|
90
104
|
const observe = through(observers);
|
|
91
105
|
return {
|
|
92
106
|
put: (key, bytes, options) => observe("put", key, () => backend.put(key, bytes, options)),
|
|
107
|
+
putIfAbsent: (key, bytes, options) => observe("put_if_absent", key, () => backend.putIfAbsent(key, bytes, options)),
|
|
93
108
|
get: (key) => observe("get", key, () => backend.get(key)),
|
|
94
109
|
delete: (key) => observe("delete", key, () => backend.delete(key)),
|
|
95
110
|
presignedUrl: (key, options) => observe("presigned_url", key, () => backend.presignedUrl(key, options)),
|
|
@@ -139,6 +154,7 @@ const storage = ({ adapter }) => {
|
|
|
139
154
|
});
|
|
140
155
|
};
|
|
141
156
|
//#endregion
|
|
157
|
+
exports.ObjectExists = require_storage.ObjectExists;
|
|
142
158
|
exports.ObjectNotFound = require_storage.ObjectNotFound;
|
|
143
159
|
exports.PresignNotSupported = require_storage.PresignNotSupported;
|
|
144
160
|
exports.Storage = require_storage.Storage;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as StorageBackend, c as StoredObject, i as Storage, n as ObjectNotFound, o as StorageService, r as PresignNotSupported, s as StorageUnavailable, t as ObjectExists } from "./storage-uSBWFyB2.cjs";
|
|
2
2
|
import { Module, Provider } from "@btravstack/di";
|
|
3
3
|
import { HealthChecks } from "@btravstack/core";
|
|
4
4
|
//#region src/memory.d.ts
|
|
@@ -47,4 +47,4 @@ type StorageOptions<E, N> = {
|
|
|
47
47
|
*/
|
|
48
48
|
export declare const storage: <E, N>({ adapter }: StorageOptions<E, N>) => Module<Storage | HealthChecks, E, N>;
|
|
49
49
|
//#endregion
|
|
50
|
-
export { ObjectNotFound, PresignNotSupported, Storage, StorageBackend, type StorageOptions, type StorageService, StorageUnavailable, type StoredObject };
|
|
50
|
+
export { ObjectExists, ObjectNotFound, PresignNotSupported, Storage, StorageBackend, type StorageOptions, type StorageService, StorageUnavailable, type StoredObject };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as StorageBackend, c as StoredObject, i as Storage, n as ObjectNotFound, o as StorageService, r as PresignNotSupported, s as StorageUnavailable, t as ObjectExists } from "./storage-uSBWFyB2.mjs";
|
|
2
2
|
import { Module, Provider } from "@btravstack/di";
|
|
3
3
|
import { HealthChecks } from "@btravstack/core";
|
|
4
4
|
//#region src/memory.d.ts
|
|
@@ -47,4 +47,4 @@ type StorageOptions<E, N> = {
|
|
|
47
47
|
*/
|
|
48
48
|
export declare const storage: <E, N>({ adapter }: StorageOptions<E, N>) => Module<Storage | HealthChecks, E, N>;
|
|
49
49
|
//#endregion
|
|
50
|
-
export { ObjectNotFound, PresignNotSupported, Storage, StorageBackend, type StorageOptions, type StorageService, StorageUnavailable, type StoredObject };
|
|
50
|
+
export { ObjectExists, ObjectNotFound, PresignNotSupported, Storage, StorageBackend, type StorageOptions, type StorageService, StorageUnavailable, type StoredObject };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as StorageBackend, i as Storage, n as ObjectNotFound, o as StorageUnavailable, r as PresignNotSupported, t as ObjectExists } from "./storage-BmbyYPIE.mjs";
|
|
2
2
|
import { Module, Provider } from "@btravstack/di";
|
|
3
3
|
import { Err, ErrAsync, Ok, OkAsync, P } from "unthrown";
|
|
4
4
|
import { HealthCheckFailed, HealthChecks, Observers, noObserverMember, observed } from "@btravstack/core";
|
|
@@ -23,6 +23,14 @@ const memoryStorageBackend = () => {
|
|
|
23
23
|
});
|
|
24
24
|
return OkAsync();
|
|
25
25
|
},
|
|
26
|
+
putIfAbsent: (key, bytes, options) => {
|
|
27
|
+
if (objects.has(key)) return ErrAsync(new ObjectExists({ key }));
|
|
28
|
+
objects.set(key, {
|
|
29
|
+
bytes,
|
|
30
|
+
contentType: options.contentType
|
|
31
|
+
});
|
|
32
|
+
return OkAsync();
|
|
33
|
+
},
|
|
26
34
|
get: (key) => {
|
|
27
35
|
const object = objects.get(key);
|
|
28
36
|
return object === void 0 ? ErrAsync(new ObjectNotFound({ key })) : OkAsync(object);
|
|
@@ -58,17 +66,23 @@ const memoryStorage = () => Module("MemoryStorage")({
|
|
|
58
66
|
*/
|
|
59
67
|
const failed = (failure) => {
|
|
60
68
|
const cause = failure.tag === "Err" ? failure.error : failure.cause;
|
|
61
|
-
const ordinary = failure.tag !== "Err" ? void 0 : failure.error._tag === "
|
|
69
|
+
const ordinary = failure.tag !== "Err" ? void 0 : failure.error._tag === "ObjectExists" ? {
|
|
70
|
+
result: "exists",
|
|
71
|
+
reason: "an object already held the key"
|
|
72
|
+
} : failure.error._tag === "ObjectNotFound" ? {
|
|
73
|
+
result: "not_found",
|
|
74
|
+
reason: "the object was not there"
|
|
75
|
+
} : failure.error._tag === "PresignNotSupported" ? {
|
|
76
|
+
result: "not_found",
|
|
77
|
+
reason: "this store cannot mint a url"
|
|
78
|
+
} : void 0;
|
|
62
79
|
return ordinary === void 0 ? {
|
|
63
80
|
outcome: "error",
|
|
64
81
|
attributes: { result: "error" },
|
|
65
82
|
cause
|
|
66
83
|
} : {
|
|
67
84
|
outcome: "ok",
|
|
68
|
-
attributes:
|
|
69
|
-
result: "not_found",
|
|
70
|
-
reason: ordinary
|
|
71
|
-
}
|
|
85
|
+
attributes: ordinary
|
|
72
86
|
};
|
|
73
87
|
};
|
|
74
88
|
/** The KEY is a detail, not a dimension: on the span and the line, never on an instrument. */
|
|
@@ -89,6 +103,7 @@ const instrument = (backend, observers) => {
|
|
|
89
103
|
const observe = through(observers);
|
|
90
104
|
return {
|
|
91
105
|
put: (key, bytes, options) => observe("put", key, () => backend.put(key, bytes, options)),
|
|
106
|
+
putIfAbsent: (key, bytes, options) => observe("put_if_absent", key, () => backend.putIfAbsent(key, bytes, options)),
|
|
92
107
|
get: (key) => observe("get", key, () => backend.get(key)),
|
|
93
108
|
delete: (key) => observe("delete", key, () => backend.delete(key)),
|
|
94
109
|
presignedUrl: (key, options) => observe("presigned_url", key, () => backend.presignedUrl(key, options)),
|
|
@@ -138,4 +153,4 @@ const storage = ({ adapter }) => {
|
|
|
138
153
|
});
|
|
139
154
|
};
|
|
140
155
|
//#endregion
|
|
141
|
-
export { ObjectNotFound, PresignNotSupported, Storage, StorageBackend, StorageUnavailable, memoryStorage, memoryStorageBackend, memoryStorageProvider, storage };
|
|
156
|
+
export { ObjectExists, ObjectNotFound, PresignNotSupported, Storage, StorageBackend, StorageUnavailable, memoryStorage, memoryStorageBackend, memoryStorageProvider, storage };
|
package/dist/s3.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_storage = require("./storage-
|
|
2
|
+
const require_storage = require("./storage-DlAQXJ1t.cjs");
|
|
3
3
|
let _btravstack_di = require("@btravstack/di");
|
|
4
4
|
let unthrown = require("unthrown");
|
|
5
5
|
let _aws_sdk_client_s3 = require("@aws-sdk/client-s3");
|
|
@@ -35,6 +35,8 @@ const unavailable = (operation, key, cause) => new require_storage.StorageUnavai
|
|
|
35
35
|
key,
|
|
36
36
|
reason: cause instanceof Error ? cause.message : String(cause)
|
|
37
37
|
});
|
|
38
|
+
/** S3's answer to `If-None-Match: *` on a key that is held: HTTP 412. */
|
|
39
|
+
const isPreconditionFailed = (cause) => cause?.$metadata?.httpStatusCode === 412;
|
|
38
40
|
/** A missing key is S3's `NoSuchKey`, which is a different fact from "the store is down". */
|
|
39
41
|
const isMissing = (cause) => cause instanceof Error && (cause.name === "NoSuchKey" || cause.name === "NotFound");
|
|
40
42
|
/**
|
|
@@ -49,6 +51,13 @@ const s3StorageBackend = (client, bucket) => ({
|
|
|
49
51
|
Body: bytes,
|
|
50
52
|
ContentType: options.contentType
|
|
51
53
|
})), (cause) => unavailable("put", key, cause)).map(() => void 0),
|
|
54
|
+
putIfAbsent: (key, bytes, options) => (0, unthrown.fromPromise)(client.send(new _aws_sdk_client_s3.PutObjectCommand({
|
|
55
|
+
Bucket: bucket,
|
|
56
|
+
Key: key,
|
|
57
|
+
Body: bytes,
|
|
58
|
+
ContentType: options.contentType,
|
|
59
|
+
IfNoneMatch: "*"
|
|
60
|
+
})), (cause) => isPreconditionFailed(cause) ? new require_storage.ObjectExists({ key }) : unavailable("putIfAbsent", key, cause)).map(() => void 0),
|
|
52
61
|
get: (key) => (0, unthrown.fromPromise)(client.send(new _aws_sdk_client_s3.GetObjectCommand({
|
|
53
62
|
Bucket: bucket,
|
|
54
63
|
Key: key
|
package/dist/s3.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as StorageBackend, o as StorageService } from "./storage-uSBWFyB2.cjs";
|
|
2
2
|
import { Module, Scope } from "@btravstack/di";
|
|
3
3
|
import { S3Client } from "@aws-sdk/client-s3";
|
|
4
4
|
import { ConfigInvalid, EnvReading } from "@btravstack/config";
|
package/dist/s3.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as StorageBackend, o as StorageService } from "./storage-uSBWFyB2.mjs";
|
|
2
2
|
import { Module, Scope } from "@btravstack/di";
|
|
3
3
|
import { S3Client } from "@aws-sdk/client-s3";
|
|
4
4
|
import { ConfigInvalid, EnvReading } from "@btravstack/config";
|
package/dist/s3.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as StorageBackend, n as ObjectNotFound, o as StorageUnavailable, t as ObjectExists } from "./storage-BmbyYPIE.mjs";
|
|
2
2
|
import { Module, Port, Provider } from "@btravstack/di";
|
|
3
3
|
import { Ok, fromPromise } from "unthrown";
|
|
4
4
|
import { DeleteObjectCommand, GetObjectCommand, PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
|
|
@@ -34,6 +34,8 @@ const unavailable = (operation, key, cause) => new StorageUnavailable({
|
|
|
34
34
|
key,
|
|
35
35
|
reason: cause instanceof Error ? cause.message : String(cause)
|
|
36
36
|
});
|
|
37
|
+
/** S3's answer to `If-None-Match: *` on a key that is held: HTTP 412. */
|
|
38
|
+
const isPreconditionFailed = (cause) => cause?.$metadata?.httpStatusCode === 412;
|
|
37
39
|
/** A missing key is S3's `NoSuchKey`, which is a different fact from "the store is down". */
|
|
38
40
|
const isMissing = (cause) => cause instanceof Error && (cause.name === "NoSuchKey" || cause.name === "NotFound");
|
|
39
41
|
/**
|
|
@@ -48,6 +50,13 @@ const s3StorageBackend = (client, bucket) => ({
|
|
|
48
50
|
Body: bytes,
|
|
49
51
|
ContentType: options.contentType
|
|
50
52
|
})), (cause) => unavailable("put", key, cause)).map(() => void 0),
|
|
53
|
+
putIfAbsent: (key, bytes, options) => fromPromise(client.send(new PutObjectCommand({
|
|
54
|
+
Bucket: bucket,
|
|
55
|
+
Key: key,
|
|
56
|
+
Body: bytes,
|
|
57
|
+
ContentType: options.contentType,
|
|
58
|
+
IfNoneMatch: "*"
|
|
59
|
+
})), (cause) => isPreconditionFailed(cause) ? new ObjectExists({ key }) : unavailable("putIfAbsent", key, cause)).map(() => void 0),
|
|
51
60
|
get: (key) => fromPromise(client.send(new GetObjectCommand({
|
|
52
61
|
Bucket: bucket,
|
|
53
62
|
Key: key
|
|
@@ -3,6 +3,8 @@ import { TaggedError } from "unthrown";
|
|
|
3
3
|
//#region src/storage.ts
|
|
4
4
|
/** The key is not there. Only `get` answers it — see `delete` and `presignedUrl` below. */
|
|
5
5
|
var ObjectNotFound = class extends TaggedError("ObjectNotFound") {};
|
|
6
|
+
/** An object already holds the key. Only `putIfAbsent` answers it. */
|
|
7
|
+
var ObjectExists = class extends TaggedError("ObjectExists") {};
|
|
6
8
|
/** The store could not answer — the endpoint is down, the credentials were refused, the bucket is gone. */
|
|
7
9
|
var StorageUnavailable = class extends TaggedError("StorageUnavailable") {};
|
|
8
10
|
/** The adapter cannot mint a time-limited URL, and says so rather than pretending. */
|
|
@@ -22,4 +24,4 @@ var Storage = class extends Port("Storage") {};
|
|
|
22
24
|
/** The port every adapter provides, and the one an application never depends on. */
|
|
23
25
|
var StorageBackend = class extends Port("StorageBackend") {};
|
|
24
26
|
//#endregion
|
|
25
|
-
export {
|
|
27
|
+
export { StorageBackend as a, Storage as i, ObjectNotFound as n, StorageUnavailable as o, PresignNotSupported as r, ObjectExists as t };
|
|
@@ -3,6 +3,8 @@ let unthrown = require("unthrown");
|
|
|
3
3
|
//#region src/storage.ts
|
|
4
4
|
/** The key is not there. Only `get` answers it — see `delete` and `presignedUrl` below. */
|
|
5
5
|
var ObjectNotFound = class extends (0, unthrown.TaggedError)("ObjectNotFound") {};
|
|
6
|
+
/** An object already holds the key. Only `putIfAbsent` answers it. */
|
|
7
|
+
var ObjectExists = class extends (0, unthrown.TaggedError)("ObjectExists") {};
|
|
6
8
|
/** The store could not answer — the endpoint is down, the credentials were refused, the bucket is gone. */
|
|
7
9
|
var StorageUnavailable = class extends (0, unthrown.TaggedError)("StorageUnavailable") {};
|
|
8
10
|
/** The adapter cannot mint a time-limited URL, and says so rather than pretending. */
|
|
@@ -22,6 +24,12 @@ var Storage = class extends (0, _btravstack_di.Port)("Storage") {};
|
|
|
22
24
|
/** The port every adapter provides, and the one an application never depends on. */
|
|
23
25
|
var StorageBackend = class extends (0, _btravstack_di.Port)("StorageBackend") {};
|
|
24
26
|
//#endregion
|
|
27
|
+
Object.defineProperty(exports, "ObjectExists", {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
get: function() {
|
|
30
|
+
return ObjectExists;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
25
33
|
Object.defineProperty(exports, "ObjectNotFound", {
|
|
26
34
|
enumerable: true,
|
|
27
35
|
get: function() {
|
|
@@ -10,10 +10,15 @@ declare const ObjectNotFound_base: import("unthrown").TaggedErrorConstructor<"Ob
|
|
|
10
10
|
declare class ObjectNotFound extends ObjectNotFound_base<{
|
|
11
11
|
readonly key: string;
|
|
12
12
|
}> {}
|
|
13
|
+
declare const ObjectExists_base: import("unthrown").TaggedErrorConstructor<"ObjectExists">;
|
|
14
|
+
/** An object already holds the key. Only `putIfAbsent` answers it. */
|
|
15
|
+
declare class ObjectExists extends ObjectExists_base<{
|
|
16
|
+
readonly key: string;
|
|
17
|
+
}> {}
|
|
13
18
|
declare const StorageUnavailable_base: import("unthrown").TaggedErrorConstructor<"StorageUnavailable">;
|
|
14
19
|
/** The store could not answer — the endpoint is down, the credentials were refused, the bucket is gone. */
|
|
15
20
|
declare class StorageUnavailable extends StorageUnavailable_base<{
|
|
16
|
-
readonly operation: "put" | "get" | "delete" | "presignedUrl" | "presignedUpload";
|
|
21
|
+
readonly operation: "put" | "putIfAbsent" | "get" | "delete" | "presignedUrl" | "presignedUpload";
|
|
17
22
|
readonly key: string;
|
|
18
23
|
readonly reason: string;
|
|
19
24
|
}> {}
|
|
@@ -26,6 +31,10 @@ type StorageService = {
|
|
|
26
31
|
readonly put: (key: string, bytes: Uint8Array, options: {
|
|
27
32
|
readonly contentType: string;
|
|
28
33
|
}) => AsyncResult<void, StorageUnavailable>;
|
|
34
|
+
/** Writes the object only if no object holds the key: the first writer wins, atomically, in the store. */
|
|
35
|
+
readonly putIfAbsent: (key: string, bytes: Uint8Array, options: {
|
|
36
|
+
readonly contentType: string;
|
|
37
|
+
}) => AsyncResult<void, ObjectExists | StorageUnavailable>;
|
|
29
38
|
readonly get: (key: string) => AsyncResult<StoredObject, ObjectNotFound | StorageUnavailable>;
|
|
30
39
|
/** Deleting a key nobody stored is `Ok`: delete is idempotent, which is S3's own behaviour rather than a fiction over it. */
|
|
31
40
|
readonly delete: (key: string) => AsyncResult<void, StorageUnavailable>;
|
|
@@ -80,4 +89,4 @@ declare const StorageBackend_base: import("@btravstack/di").PortClass<"StorageBa
|
|
|
80
89
|
/** The port every adapter provides, and the one an application never depends on. */
|
|
81
90
|
declare class StorageBackend extends StorageBackend_base<StorageService> {}
|
|
82
91
|
//#endregion
|
|
83
|
-
export {
|
|
92
|
+
export { StorageBackend as a, StoredObject as c, Storage as i, ObjectNotFound as n, StorageService as o, PresignNotSupported as r, StorageUnavailable as s, ObjectExists as t };
|
|
@@ -10,10 +10,15 @@ declare const ObjectNotFound_base: import("unthrown").TaggedErrorConstructor<"Ob
|
|
|
10
10
|
declare class ObjectNotFound extends ObjectNotFound_base<{
|
|
11
11
|
readonly key: string;
|
|
12
12
|
}> {}
|
|
13
|
+
declare const ObjectExists_base: import("unthrown").TaggedErrorConstructor<"ObjectExists">;
|
|
14
|
+
/** An object already holds the key. Only `putIfAbsent` answers it. */
|
|
15
|
+
declare class ObjectExists extends ObjectExists_base<{
|
|
16
|
+
readonly key: string;
|
|
17
|
+
}> {}
|
|
13
18
|
declare const StorageUnavailable_base: import("unthrown").TaggedErrorConstructor<"StorageUnavailable">;
|
|
14
19
|
/** The store could not answer — the endpoint is down, the credentials were refused, the bucket is gone. */
|
|
15
20
|
declare class StorageUnavailable extends StorageUnavailable_base<{
|
|
16
|
-
readonly operation: "put" | "get" | "delete" | "presignedUrl" | "presignedUpload";
|
|
21
|
+
readonly operation: "put" | "putIfAbsent" | "get" | "delete" | "presignedUrl" | "presignedUpload";
|
|
17
22
|
readonly key: string;
|
|
18
23
|
readonly reason: string;
|
|
19
24
|
}> {}
|
|
@@ -26,6 +31,10 @@ type StorageService = {
|
|
|
26
31
|
readonly put: (key: string, bytes: Uint8Array, options: {
|
|
27
32
|
readonly contentType: string;
|
|
28
33
|
}) => AsyncResult<void, StorageUnavailable>;
|
|
34
|
+
/** Writes the object only if no object holds the key: the first writer wins, atomically, in the store. */
|
|
35
|
+
readonly putIfAbsent: (key: string, bytes: Uint8Array, options: {
|
|
36
|
+
readonly contentType: string;
|
|
37
|
+
}) => AsyncResult<void, ObjectExists | StorageUnavailable>;
|
|
29
38
|
readonly get: (key: string) => AsyncResult<StoredObject, ObjectNotFound | StorageUnavailable>;
|
|
30
39
|
/** Deleting a key nobody stored is `Ok`: delete is idempotent, which is S3's own behaviour rather than a fiction over it. */
|
|
31
40
|
readonly delete: (key: string) => AsyncResult<void, StorageUnavailable>;
|
|
@@ -80,4 +89,4 @@ declare const StorageBackend_base: import("@btravstack/di").PortClass<"StorageBa
|
|
|
80
89
|
/** The port every adapter provides, and the one an application never depends on. */
|
|
81
90
|
declare class StorageBackend extends StorageBackend_base<StorageService> {}
|
|
82
91
|
//#endregion
|
|
83
|
-
export {
|
|
92
|
+
export { StorageBackend as a, StoredObject as c, Storage as i, ObjectNotFound as n, StorageService as o, PresignNotSupported as r, StorageUnavailable as s, ObjectExists as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@btravstack/storage",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.37.0",
|
|
4
4
|
"description": "A Storage port for @btravstack/core: an in-memory adapter, an S3-compatible adapter with presigned reads, and a composition that spans, counts and logs every operation",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dependency-injection",
|
|
@@ -55,11 +55,11 @@
|
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@aws-sdk/client-s3": "3.1149.0",
|
|
57
57
|
"@aws-sdk/s3-request-presigner": "3.1149.0",
|
|
58
|
-
"@btravstack/config": "0.
|
|
59
|
-
"@btravstack/core": "0.
|
|
60
|
-
"@btravstack/di": "0.
|
|
58
|
+
"@btravstack/config": "0.37.0",
|
|
59
|
+
"@btravstack/core": "0.37.0",
|
|
60
|
+
"@btravstack/di": "0.37.0",
|
|
61
61
|
"@btravstack/internal-test-infra": "0.0.0",
|
|
62
|
-
"@btravstack/observability": "0.
|
|
62
|
+
"@btravstack/observability": "0.37.0",
|
|
63
63
|
"@btravstack/tsconfig": "0.4.0",
|
|
64
64
|
"@opentelemetry/api": "1.9.1",
|
|
65
65
|
"@opentelemetry/sdk-metrics": "2.12.0",
|
|
@@ -76,9 +76,9 @@
|
|
|
76
76
|
"peerDependencies": {
|
|
77
77
|
"@aws-sdk/client-s3": "^3.1000.0",
|
|
78
78
|
"@aws-sdk/s3-request-presigner": "^3.1000.0",
|
|
79
|
-
"@btravstack/config": "^0.
|
|
80
|
-
"@btravstack/core": "^0.
|
|
81
|
-
"@btravstack/di": "^0.
|
|
79
|
+
"@btravstack/config": "^0.37.0",
|
|
80
|
+
"@btravstack/core": "^0.37.0",
|
|
81
|
+
"@btravstack/di": "^0.37.0",
|
|
82
82
|
"unthrown": "^5.0.0"
|
|
83
83
|
},
|
|
84
84
|
"peerDependenciesMeta": {
|