@geekmidas/storage 10.0.0-alpha.9 → 10.0.0-alpha.91
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 +49 -13
- package/dist/aws.cjs +102 -63
- package/dist/aws.cjs.map +1 -1
- package/dist/aws.d.cts +9 -10
- package/dist/aws.d.cts.map +1 -1
- package/dist/aws.d.mts +9 -10
- package/dist/aws.d.mts.map +1 -1
- package/dist/aws.mjs +87 -49
- package/dist/aws.mjs.map +1 -1
- package/dist/{errors-D5UnAd-X.mjs → errors-BB8jdHif.cjs} +83 -5
- package/dist/errors-BB8jdHif.cjs.map +1 -0
- package/dist/{errors-Bce0CJ11.cjs → errors-COXs1iNg.mjs} +42 -35
- package/dist/errors-COXs1iNg.mjs.map +1 -0
- package/dist/index.cjs +19 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -11
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +32 -11
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +17 -4
- package/dist/index.mjs.map +1 -1
- package/dist/{registry-DBsAUTT3.d.cts → registry-ClEvHGpM.d.cts} +3 -6
- package/dist/registry-ClEvHGpM.d.cts.map +1 -0
- package/dist/{registry-DEqSHjx-.d.mts → registry-ClEvHGpM.d.mts} +3 -6
- package/dist/registry-ClEvHGpM.d.mts.map +1 -0
- package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/dist/s3Url.cjs +108 -4
- package/dist/s3Url.cjs.map +1 -0
- package/dist/s3Url.d.cts +52 -2
- package/dist/s3Url.d.cts.map +1 -0
- package/dist/s3Url.d.mts +52 -2
- package/dist/s3Url.d.mts.map +1 -0
- package/dist/s3Url.mjs +89 -3
- package/dist/s3Url.mjs.map +1 -0
- package/package.json +10 -5
- package/dist/chunk-B9dir_RE.mjs +0 -11
- package/dist/errors-Bce0CJ11.cjs.map +0 -1
- package/dist/errors-D5UnAd-X.mjs.map +0 -1
- package/dist/registry-DBsAUTT3.d.cts.map +0 -1
- package/dist/registry-DEqSHjx-.d.mts.map +0 -1
- package/dist/s3Url-BfztIltX.d.cts +0 -39
- package/dist/s3Url-BfztIltX.d.cts.map +0 -1
- package/dist/s3Url-Bo32UTTA.cjs +0 -103
- package/dist/s3Url-Bo32UTTA.cjs.map +0 -1
- package/dist/s3Url-C8FGPNrG.mjs +0 -52
- package/dist/s3Url-C8FGPNrG.mjs.map +0 -1
- package/dist/s3Url-COpMIgF9.d.mts +0 -42
- package/dist/s3Url-COpMIgF9.d.mts.map +0 -1
package/README.md
CHANGED
|
@@ -85,6 +85,49 @@ const storage = AmazonStorageClient.create({
|
|
|
85
85
|
});
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
+
## Storage URLs and credentials
|
|
89
|
+
|
|
90
|
+
A declared bucket reaches an app as one URL, `<ID>_URL`, and
|
|
91
|
+
`createStorageClient(url)` picks the driver by its scheme. An `s3://` URL
|
|
92
|
+
names the bucket as its host and the rest as query parameters:
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
s3://uploads?region=eu-west-1
|
|
96
|
+
s3://uploads?region=auto&endpoint=https://<account>.r2.cloudflarestorage.com
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Credentials are optional, and come from one of two places:
|
|
100
|
+
|
|
101
|
+
- **The URL's userinfo** — `s3://KEY:SECRET@uploads?region=eu-west-1`. A key
|
|
102
|
+
here signs for this bucket only and wins over anything in the environment.
|
|
103
|
+
Percent-encode both halves: AWS secrets often contain `/` (`%2F`) and `+`
|
|
104
|
+
(`%2B`). `s3Url.build` does this for you, and `s3Url.parse` decodes them.
|
|
105
|
+
- **The SDK's default chain** — for a URL with no userinfo: the shared
|
|
106
|
+
`AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY`, a profile, or an execution role.
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import { s3Url } from '@geekmidas/storage/aws';
|
|
110
|
+
|
|
111
|
+
s3Url.build({
|
|
112
|
+
bucket: 'uploads',
|
|
113
|
+
region: 'eu-west-1',
|
|
114
|
+
accessKeyId: 'AKIA…',
|
|
115
|
+
secretAccessKey: 'wJal/rXUt+nFEMI…',
|
|
116
|
+
});
|
|
117
|
+
// 's3://AKIA…:wJal%2FrXUt%2BnFEMI…@uploads?region=eu-west-1'
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Prefer a key per bucket, scoped to that bucket, over one shared pair: an app
|
|
121
|
+
that reads two buckets then holds two narrow keys rather than one that opens
|
|
122
|
+
both. A URL with only one half of a pair (`s3://KEY@uploads`) is refused with
|
|
123
|
+
`IncompleteStorageCredentials` — it is never completed from the environment.
|
|
124
|
+
|
|
125
|
+
Every storage error that carries a URL (`MalformedStorageUrl`,
|
|
126
|
+
`UnexpectedStorageScheme`, `MissingStorageBucket`,
|
|
127
|
+
`UnregisteredStorageScheme`, `IncompleteStorageCredentials`) holds it with the
|
|
128
|
+
userinfo replaced by `REDACTED`, and its message never includes the URL.
|
|
129
|
+
`redactStorageUrl(url)` does the same for your own log lines.
|
|
130
|
+
|
|
88
131
|
## API Reference
|
|
89
132
|
|
|
90
133
|
### StorageClient Interface
|
|
@@ -400,20 +443,13 @@ npm run test:once
|
|
|
400
443
|
|
|
401
444
|
### Local Development with MinIO
|
|
402
445
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
```
|
|
407
|
-
|
|
408
|
-
2. MinIO will be available at:
|
|
409
|
-
- API: http://localhost:9000
|
|
410
|
-
- Console: http://localhost:9001
|
|
411
|
-
- Credentials: minioadmin/minioadmin
|
|
446
|
+
The suite starts the repo compose stack's MinIO itself (`geekmidas` /
|
|
447
|
+
`geekmidas`, with a `geekmidas` bucket). It publishes on port 9000; when
|
|
448
|
+
another project holds that port, move it:
|
|
412
449
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
```
|
|
450
|
+
```bash
|
|
451
|
+
MINIO_API_HOST_PORT=29000 MINIO_CONSOLE_HOST_PORT=29001 pnpm vitest run --project storage
|
|
452
|
+
```
|
|
417
453
|
|
|
418
454
|
### Project Structure
|
|
419
455
|
|
package/dist/aws.cjs
CHANGED
|
@@ -1,46 +1,77 @@
|
|
|
1
|
-
|
|
2
|
-
require(
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
//#region src/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_s3Url = require("./s3Url.cjs");
|
|
3
|
+
let _aws_sdk_client_s3 = require("@aws-sdk/client-s3");
|
|
4
|
+
let _aws_sdk_s3_presigned_post = require("@aws-sdk/s3-presigned-post");
|
|
5
|
+
let _aws_sdk_s3_request_presigner = require("@aws-sdk/s3-request-presigner");
|
|
6
|
+
let _opentelemetry_api = require("@opentelemetry/api");
|
|
7
|
+
//#region src/telemetry.ts
|
|
8
|
+
/**
|
|
9
|
+
* A span per storage call, through the global OpenTelemetry tracer — a no-op
|
|
10
|
+
* without a registered provider.
|
|
11
|
+
*
|
|
12
|
+
* `storage.presign`, `storage.put`, `storage.delete` and `storage.list`, with
|
|
13
|
+
* the backend and the bucket. Never the object's key: keys often name a user.
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
/** Run `fn` inside a `storage.<operation>` span. */
|
|
18
|
+
async function traceStorage(operation, attributes, fn) {
|
|
19
|
+
const span = _opentelemetry_api.trace.getTracer("@geekmidas/storage").startSpan(`storage.${operation}`, {
|
|
20
|
+
kind: _opentelemetry_api.SpanKind.CLIENT,
|
|
21
|
+
attributes: {
|
|
22
|
+
"storage.operation": operation,
|
|
23
|
+
...attributes
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
try {
|
|
27
|
+
return await fn();
|
|
28
|
+
} catch (error) {
|
|
29
|
+
if (error instanceof Error) span.recordException(error);
|
|
30
|
+
span.setStatus({ code: _opentelemetry_api.SpanStatusCode.ERROR });
|
|
31
|
+
throw error;
|
|
32
|
+
} finally {
|
|
33
|
+
span.end();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
15
36
|
//#endregion
|
|
16
37
|
//#region src/AmazonStorageClient.ts
|
|
17
38
|
var AmazonStorageClient = class AmazonStorageClient {
|
|
18
|
-
|
|
39
|
+
client;
|
|
40
|
+
bucket;
|
|
41
|
+
acl;
|
|
42
|
+
cache;
|
|
43
|
+
provider = "geekimdas.toolbox.storage.aws.s3";
|
|
19
44
|
static create(options) {
|
|
20
45
|
const { bucket, region, accessKeyId, acl, endpoint, secretAccessKey, forcePathStyle = false, cache } = options;
|
|
21
|
-
const
|
|
22
|
-
const credentials = hasCredentials ? {
|
|
23
|
-
accessKeyId,
|
|
24
|
-
secretAccessKey
|
|
25
|
-
} : void 0;
|
|
26
|
-
const client = new __aws_sdk_client_s3.S3Client({
|
|
46
|
+
const client = new _aws_sdk_client_s3.S3Client({
|
|
27
47
|
region,
|
|
28
|
-
credentials
|
|
48
|
+
credentials: accessKeyId && secretAccessKey ? {
|
|
49
|
+
accessKeyId,
|
|
50
|
+
secretAccessKey
|
|
51
|
+
} : void 0,
|
|
29
52
|
endpoint,
|
|
30
53
|
forcePathStyle
|
|
31
54
|
});
|
|
32
55
|
return new AmazonStorageClient(client, bucket, acl, cache);
|
|
33
56
|
}
|
|
34
|
-
constructor(client, bucket, acl =
|
|
57
|
+
constructor(client, bucket, acl = "authenticated-read", cache) {
|
|
35
58
|
this.client = client;
|
|
36
59
|
this.bucket = bucket;
|
|
37
60
|
this.acl = acl;
|
|
38
61
|
this.cache = cache;
|
|
39
62
|
}
|
|
63
|
+
/** A storage span on this bucket. */
|
|
64
|
+
traced(operation, fn, attributes = {}) {
|
|
65
|
+
return traceStorage(operation, {
|
|
66
|
+
"storage.system": "s3",
|
|
67
|
+
"storage.bucket": this.bucket,
|
|
68
|
+
...attributes
|
|
69
|
+
}, fn);
|
|
70
|
+
}
|
|
40
71
|
createGetObjectCommand(file, overrides) {
|
|
41
72
|
const disposition = file.disposition ?? (file.name ? "attachment" : void 0);
|
|
42
73
|
const ResponseContentDisposition = disposition ? file.name ? `${disposition}; filename=${encodeURIComponent(file.name)}` : disposition : void 0;
|
|
43
|
-
return new
|
|
74
|
+
return new _aws_sdk_client_s3.GetObjectCommand({
|
|
44
75
|
Bucket: this.bucket,
|
|
45
76
|
Key: file.path,
|
|
46
77
|
ResponseContentDisposition,
|
|
@@ -50,55 +81,53 @@ var AmazonStorageClient = class AmazonStorageClient {
|
|
|
50
81
|
}
|
|
51
82
|
getVersionDownloadURL(file, versionId) {
|
|
52
83
|
const command = this.createGetObjectCommand(file, { VersionId: versionId });
|
|
53
|
-
return (0,
|
|
84
|
+
return this.traced("presign", () => (0, _aws_sdk_s3_request_presigner.getSignedUrl)(this.client, command, { expiresIn: 86400 }), { "storage.presign.method": "GET" });
|
|
54
85
|
}
|
|
55
86
|
async getVersions(key) {
|
|
56
|
-
const command = new
|
|
87
|
+
const command = new _aws_sdk_client_s3.ListObjectVersionsCommand({
|
|
57
88
|
Bucket: this.bucket,
|
|
58
89
|
Prefix: key
|
|
59
90
|
});
|
|
60
|
-
const { Versions = [] } = await this.client.send(command);
|
|
91
|
+
const { Versions = [] } = await this.traced("list", () => this.client.send(command));
|
|
61
92
|
return Versions.map((version) => ({
|
|
62
93
|
id: version.VersionId || "",
|
|
63
94
|
createdAt: version.LastModified || /* @__PURE__ */ new Date()
|
|
64
95
|
}));
|
|
65
96
|
}
|
|
66
|
-
async getDownloadURL(file, expiresIn =
|
|
97
|
+
async getDownloadURL(file, expiresIn = 3600) {
|
|
67
98
|
const cacheKey = `download-url:${file.path}`;
|
|
68
99
|
const cachedURL = await this.cache?.get(cacheKey);
|
|
69
100
|
if (cachedURL) return cachedURL;
|
|
70
101
|
const command = this.createGetObjectCommand(file);
|
|
71
|
-
const url = await (0,
|
|
102
|
+
const url = await this.traced("presign", () => (0, _aws_sdk_s3_request_presigner.getSignedUrl)(this.client, command, { expiresIn }), { "storage.presign.method": "GET" });
|
|
72
103
|
const cacheExpiration = Math.max(expiresIn - 60, 0);
|
|
73
104
|
if (cacheExpiration) await this.cache?.set(cacheKey, url, cacheExpiration);
|
|
74
105
|
return url;
|
|
75
106
|
}
|
|
76
|
-
async getUploadURL(params, expiresIn =
|
|
77
|
-
const command = new
|
|
107
|
+
async getUploadURL(params, expiresIn = 3600) {
|
|
108
|
+
const command = new _aws_sdk_client_s3.PutObjectCommand({
|
|
78
109
|
Bucket: this.bucket,
|
|
79
110
|
Key: params.path,
|
|
80
111
|
ContentType: params.contentType,
|
|
81
112
|
ContentLength: params.contentLength
|
|
82
113
|
});
|
|
83
|
-
return (0,
|
|
114
|
+
return this.traced("presign", () => (0, _aws_sdk_s3_request_presigner.getSignedUrl)(this.client, command, { expiresIn }), { "storage.presign.method": "PUT" });
|
|
84
115
|
}
|
|
85
116
|
async getUpload(params, expiresIn = 5) {
|
|
86
117
|
const { path } = params;
|
|
87
|
-
const { fields: values, url } = await (0,
|
|
118
|
+
const { fields: values, url } = await this.traced("presign", () => (0, _aws_sdk_s3_presigned_post.createPresignedPost)(this.client, {
|
|
88
119
|
Expires: expiresIn * 60,
|
|
89
120
|
Bucket: this.bucket,
|
|
90
121
|
Fields: { acl: this.acl },
|
|
91
122
|
Conditions: [],
|
|
92
123
|
Key: path
|
|
93
|
-
});
|
|
94
|
-
const keys = Object.keys(values);
|
|
95
|
-
const fields = keys.map((key) => ({
|
|
96
|
-
key,
|
|
97
|
-
value: values[key] || ""
|
|
98
|
-
}));
|
|
124
|
+
}), { "storage.presign.method": "POST" });
|
|
99
125
|
return {
|
|
100
126
|
url,
|
|
101
|
-
fields
|
|
127
|
+
fields: Object.keys(values).map((key) => ({
|
|
128
|
+
key,
|
|
129
|
+
value: values[key] || ""
|
|
130
|
+
}))
|
|
102
131
|
};
|
|
103
132
|
}
|
|
104
133
|
async upload(key, data, contentType) {
|
|
@@ -109,52 +138,62 @@ var AmazonStorageClient = class AmazonStorageClient {
|
|
|
109
138
|
Body,
|
|
110
139
|
ContentType: contentType
|
|
111
140
|
};
|
|
112
|
-
const command = new
|
|
113
|
-
await this.client.send(command)
|
|
141
|
+
const command = new _aws_sdk_client_s3.PutObjectCommand(params);
|
|
142
|
+
await this.traced("put", () => this.client.send(command), {
|
|
143
|
+
"storage.object.size": Body.length,
|
|
144
|
+
"storage.object.content_type": contentType
|
|
145
|
+
});
|
|
114
146
|
}
|
|
115
147
|
async delete(key) {
|
|
116
|
-
const command = new
|
|
148
|
+
const command = new _aws_sdk_client_s3.DeleteObjectCommand({
|
|
117
149
|
Bucket: this.bucket,
|
|
118
150
|
Key: key
|
|
119
151
|
});
|
|
120
|
-
await this.client.send(command);
|
|
152
|
+
await this.traced("delete", () => this.client.send(command));
|
|
121
153
|
}
|
|
122
154
|
};
|
|
123
|
-
let AmazonCannedAccessControlList = /* @__PURE__ */ function(AmazonCannedAccessControlList
|
|
124
|
-
AmazonCannedAccessControlList
|
|
125
|
-
AmazonCannedAccessControlList
|
|
126
|
-
AmazonCannedAccessControlList
|
|
127
|
-
AmazonCannedAccessControlList
|
|
128
|
-
AmazonCannedAccessControlList
|
|
129
|
-
AmazonCannedAccessControlList
|
|
130
|
-
AmazonCannedAccessControlList
|
|
131
|
-
AmazonCannedAccessControlList
|
|
132
|
-
return AmazonCannedAccessControlList
|
|
155
|
+
let AmazonCannedAccessControlList = /* @__PURE__ */ function(AmazonCannedAccessControlList) {
|
|
156
|
+
AmazonCannedAccessControlList["AuthenticatedRead"] = "authenticated-read";
|
|
157
|
+
AmazonCannedAccessControlList["Private"] = "private";
|
|
158
|
+
AmazonCannedAccessControlList["PublicRead"] = "public-read";
|
|
159
|
+
AmazonCannedAccessControlList["PublicReadWrite"] = "public-read-write";
|
|
160
|
+
AmazonCannedAccessControlList["AwsExecRead"] = "aws-exec-read";
|
|
161
|
+
AmazonCannedAccessControlList["BucketOwnerRead"] = "bucket-owner-read";
|
|
162
|
+
AmazonCannedAccessControlList["BucketOwnerFullControl"] = "bucket-owner-full-control";
|
|
163
|
+
AmazonCannedAccessControlList["LogDeliveryWrite"] = "log-delivery-write";
|
|
164
|
+
return AmazonCannedAccessControlList;
|
|
133
165
|
}({});
|
|
134
|
-
|
|
135
166
|
//#endregion
|
|
136
167
|
//#region src/s3Driver.ts
|
|
168
|
+
/**
|
|
169
|
+
* The S3 driver — `s3://` URLs to an {@link AmazonStorageClient}.
|
|
170
|
+
*
|
|
171
|
+
* Registered by whoever assembles the application, so neutral code can build a
|
|
172
|
+
* client from a URL without importing this file or the AWS SDK behind it.
|
|
173
|
+
*/
|
|
137
174
|
const s3Driver = {
|
|
138
175
|
scheme: "s3:",
|
|
139
176
|
create(url) {
|
|
140
|
-
const { bucket, region, endpoint, forcePathStyle } = require_s3Url.parse(url);
|
|
177
|
+
const { bucket, region, endpoint, forcePathStyle, accessKeyId, secretAccessKey } = require_s3Url.parse(url);
|
|
141
178
|
return AmazonStorageClient.create({
|
|
142
179
|
bucket,
|
|
143
180
|
region,
|
|
144
181
|
endpoint,
|
|
145
|
-
forcePathStyle
|
|
182
|
+
forcePathStyle,
|
|
183
|
+
accessKeyId,
|
|
184
|
+
secretAccessKey
|
|
146
185
|
});
|
|
147
186
|
}
|
|
148
187
|
};
|
|
149
|
-
|
|
150
188
|
//#endregion
|
|
151
189
|
exports.AmazonCannedAccessControlList = AmazonCannedAccessControlList;
|
|
152
190
|
exports.AmazonStorageClient = AmazonStorageClient;
|
|
153
191
|
exports.s3Driver = s3Driver;
|
|
154
|
-
Object.defineProperty(exports,
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
192
|
+
Object.defineProperty(exports, "s3Url", {
|
|
193
|
+
enumerable: true,
|
|
194
|
+
get: function() {
|
|
195
|
+
return require_s3Url.s3Url_exports;
|
|
196
|
+
}
|
|
159
197
|
});
|
|
198
|
+
|
|
160
199
|
//# sourceMappingURL=aws.cjs.map
|
package/dist/aws.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aws.cjs","names":["options: AmazonStorageClientCreateOptions","S3Client","client: S3Client","bucket: string","cache?: Cache","file: File","overrides?: { VersionId?: string }","GetObjectCommand","versionId: string","key: string","ListObjectVersionsCommand","params: GetUploadParams","PutObjectCommand","data: string | Buffer","contentType: string","DeleteObjectCommand","s3Driver: StorageDriver"],"sources":["../src/StorageClient.ts","../src/AmazonStorageClient.ts","../src/s3Driver.ts"],"sourcesContent":["import type { Cache } from '@geekmidas/cache';\nexport interface DocumentVersion {\n\tid: string;\n\tcreatedAt: Date;\n}\n\nexport enum StorageProvider {\n\tAWSS3 = 'geekimdas.toolbox.storage.aws.s3',\n\tGCP = 'geekimdas.toolbox.storage.gcp',\n\tAZURE = 'geekimdas.toolbox.storage.azure',\n}\n\nexport interface StorageClient {\n\treadonly provider: StorageProvider;\n\treadonly cache?: Cache;\n\t/**\n\t * Get a URL to upload a file to.\n\t *\n\t * @param params - The parameters to get the upload URL for.\n\t * @param expiresIn - The number of minutes the URL should be valid for.\n\t * Defaults to 60 * 60 (1 hour).\n\t * @returns A promise that resolves to the upload URL.\n\t */\n\tgetUploadURL(params: GetUploadParams, expiresIn?: number): Promise<string>;\n\n\t/**\n\t * Get a URL to download a file from.\n\t *\n\t * @param file - The file to get the download URL for.\n\t * @param expiresIn - The number of seconds the URL should be valid for.\n\t * Defaults to 60 * 60 (1 hour).\n\t * @returns A promise that resolves to the download URL.\n\t */\n\tgetDownloadURL(file: File, expiresIn?: number): Promise<string>;\n\t/**\n\t * Get the versions for a key.\n\t *\n\t * @param key - The key to get the versions for.\n\t */\n\tgetVersions(key: string): Promise<DocumentVersion[]>;\n\n\t/**\n\t * Get a URL to download a version of a file from.\n\t *\n\t * @param file - The file to get the download URL for.\n\t * @param versionId - The version ID to get the download URL for.\n\t */\n\tgetVersionDownloadURL(file: File, versionId: string): Promise<string>;\n\t/**\n\t *\n\t * @param key - The key to upload the file to.\n\t * @param data - The data to upload.\n\t * @param contentType - The content type of the data.\n\t */\n\tupload(\n\t\tkey: string,\n\t\tdata: string | Buffer,\n\t\tcontentType: string,\n\t): Promise<void>;\n\t/**\n\t * Get a URL to upload a file to.\n\t *\n\t * @param params - The parameters to get the upload URL for.\n\t * @param expiresIn - The number of minutes the URL should be valid for.\n\t */\n\tgetUpload(\n\t\tparams: GetUploadParams,\n\t\texpiresIn?: number,\n\t): Promise<GetUploadResponse>;\n\t/**\n\t * Delete a file from storage.\n\t *\n\t * @param key - The key (path) of the file to delete.\n\t */\n\tdelete(key: string): Promise<void>;\n}\n\nexport interface GetUploadParams {\n\tpath: string;\n\tcontentType: string;\n\tcontentLength: number;\n}\n\nexport type UploadField = {\n\tkey: string;\n\tvalue: string;\n};\n\nexport type GetUploadResponse = {\n\turl: string;\n\tfields: UploadField[];\n};\n\nexport interface File {\n\tname?: string;\n\tpath: string;\n\t/**\n\t * Override the Content-Type of the response.\n\t * Useful when the stored object's content type differs from what the browser should receive.\n\t */\n\tresponseContentType?: string;\n\t/**\n\t * Control how the browser handles the file.\n\t * - `'attachment'` — prompts download (default when `name` is set)\n\t * - `'inline'` — displays in the browser\n\t */\n\tdisposition?: 'inline' | 'attachment';\n}\n","import {\n\tDeleteObjectCommand,\n\tGetObjectCommand,\n\tListObjectVersionsCommand,\n\tPutObjectCommand,\n\tS3Client,\n} from '@aws-sdk/client-s3';\nimport { createPresignedPost } from '@aws-sdk/s3-presigned-post';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\n\nimport type { Cache } from '@geekmidas/cache';\nimport {\n\ttype DocumentVersion,\n\ttype File,\n\ttype GetUploadParams,\n\ttype GetUploadResponse,\n\ttype StorageClient,\n\tStorageProvider,\n} from './StorageClient';\n\nexport class AmazonStorageClient implements StorageClient {\n\treadonly provider = StorageProvider.AWSS3;\n\n\tstatic create(\n\t\toptions: AmazonStorageClientCreateOptions,\n\t): AmazonStorageClient {\n\t\tconst {\n\t\t\tbucket,\n\t\t\tregion,\n\t\t\taccessKeyId,\n\t\t\tacl,\n\t\t\tendpoint,\n\t\t\tsecretAccessKey,\n\t\t\tforcePathStyle = false,\n\t\t\tcache,\n\t\t} = options;\n\t\tconst hasCredentials = accessKeyId && secretAccessKey;\n\t\tconst credentials = hasCredentials\n\t\t\t? { accessKeyId, secretAccessKey }\n\t\t\t: undefined;\n\n\t\tconst client = new S3Client({\n\t\t\tregion,\n\t\t\tcredentials,\n\t\t\tendpoint,\n\t\t\tforcePathStyle,\n\t\t});\n\n\t\treturn new AmazonStorageClient(client, bucket, acl, cache);\n\t}\n\tconstructor(\n\t\tprivate readonly client: S3Client,\n\t\tprivate readonly bucket: string,\n\t\tprivate readonly acl = AmazonCannedAccessControlList.AuthenticatedRead,\n\t\treadonly cache?: Cache,\n\t) {}\n\n\tprivate createGetObjectCommand(\n\t\tfile: File,\n\t\toverrides?: { VersionId?: string },\n\t): GetObjectCommand {\n\t\tconst disposition =\n\t\t\tfile.disposition ?? (file.name ? 'attachment' : undefined);\n\t\tconst ResponseContentDisposition = disposition\n\t\t\t? file.name\n\t\t\t\t? `${disposition}; filename=${encodeURIComponent(file.name)}`\n\t\t\t\t: disposition\n\t\t\t: undefined;\n\n\t\treturn new GetObjectCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tKey: file.path,\n\t\t\tResponseContentDisposition,\n\t\t\tResponseContentType: file.responseContentType,\n\t\t\t...overrides,\n\t\t});\n\t}\n\n\tgetVersionDownloadURL(file: File, versionId: string): Promise<string> {\n\t\tconst command = this.createGetObjectCommand(file, { VersionId: versionId });\n\t\treturn getSignedUrl(this.client, command, { expiresIn: 60 * 60 * 24 });\n\t}\n\n\tasync getVersions(key: string): Promise<DocumentVersion[]> {\n\t\tconst command = new ListObjectVersionsCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tPrefix: key,\n\t\t});\n\n\t\tconst { Versions = [] } = await this.client.send(command);\n\n\t\treturn Versions.map((version) => ({\n\t\t\tid: version.VersionId || '',\n\t\t\tcreatedAt: version.LastModified || new Date(),\n\t\t}));\n\t}\n\n\tasync getDownloadURL(file: File, expiresIn = 60 * 60): Promise<string> {\n\t\tconst cacheKey = `download-url:${file.path}`;\n\t\tconst cachedURL = await this.cache?.get<string>(cacheKey);\n\n\t\tif (cachedURL) {\n\t\t\treturn cachedURL;\n\t\t}\n\n\t\tconst command = this.createGetObjectCommand(file);\n\t\tconst url = await getSignedUrl(this.client, command, { expiresIn });\n\t\tconst cacheExpiration = Math.max(expiresIn - 60, 0);\n\n\t\tif (cacheExpiration) {\n\t\t\tawait this.cache?.set(cacheKey, url, cacheExpiration);\n\t\t}\n\n\t\treturn url;\n\t}\n\n\tasync getUploadURL(\n\t\tparams: GetUploadParams,\n\t\texpiresIn = 60 * 60,\n\t): Promise<string> {\n\t\tconst command = new PutObjectCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tKey: params.path,\n\t\t\tContentType: params.contentType,\n\t\t\tContentLength: params.contentLength,\n\t\t});\n\n\t\treturn getSignedUrl(this.client, command, { expiresIn });\n\t}\n\n\tasync getUpload(\n\t\tparams: GetUploadParams,\n\t\texpiresIn = 5,\n\t): Promise<GetUploadResponse> {\n\t\tconst { path } = params;\n\t\tconst { fields: values, url } = await createPresignedPost(this.client, {\n\t\t\tExpires: expiresIn * 60,\n\t\t\tBucket: this.bucket,\n\t\t\tFields: {\n\t\t\t\tacl: this.acl,\n\t\t\t},\n\t\t\tConditions: [\n\t\t\t\t// content length restrictions: 0-1MB]\n\t\t\t\t// ['content-length-range', 0, contentLength],\n\t\t\t\t// specify content-type to be more generic- images only\n\t\t\t\t// ['starts-with', '$Content-Type', 'image/'],\n\t\t\t\t// ['starts-with', '$Content-Type', contentType],\n\t\t\t],\n\t\t\tKey: path,\n\t\t});\n\n\t\tconst keys = Object.keys(values);\n\t\tconst fields = keys.map((key) => ({ key, value: values[key] || '' }));\n\n\t\treturn { url, fields };\n\t}\n\n\tasync upload(\n\t\tkey: string,\n\t\tdata: string | Buffer,\n\t\tcontentType: string,\n\t): Promise<void> {\n\t\tconst Body = typeof data === 'string' ? Buffer.from(data, 'base64') : data;\n\n\t\tconst params = {\n\t\t\tBucket: this.bucket,\n\t\t\tKey: key,\n\t\t\tBody,\n\t\t\tContentType: contentType,\n\t\t};\n\n\t\tconst command = new PutObjectCommand(params);\n\n\t\tawait this.client.send(command);\n\t}\n\n\tasync delete(key: string): Promise<void> {\n\t\tconst command = new DeleteObjectCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tKey: key,\n\t\t});\n\n\t\tawait this.client.send(command);\n\t}\n}\n\nexport enum AmazonCannedAccessControlList {\n\tAuthenticatedRead = 'authenticated-read',\n\tPrivate = 'private',\n\tPublicRead = 'public-read',\n\tPublicReadWrite = 'public-read-write',\n\tAwsExecRead = 'aws-exec-read',\n\tBucketOwnerRead = 'bucket-owner-read',\n\tBucketOwnerFullControl = 'bucket-owner-full-control',\n\tLogDeliveryWrite = 'log-delivery-write',\n}\n\ninterface AmazonStorageClientCreateOptions {\n\tbucket: string;\n\tregion?: string;\n\tacl?: AmazonCannedAccessControlList;\n\taccessKeyId?: string;\n\tsecretAccessKey?: string;\n\tendpoint?: string;\n\tforcePathStyle?: boolean;\n\tcache?: Cache;\n}\n","/**\n * The S3 driver — `s3://` URLs to an {@link AmazonStorageClient}.\n *\n * Registered by whoever assembles the application, so neutral code can build a\n * client from a URL without importing this file or the AWS SDK behind it.\n */\n\nimport { AmazonStorageClient } from './AmazonStorageClient';\nimport type { StorageDriver } from './registry';\nimport { parse } from './s3Url';\n\nexport const s3Driver: StorageDriver = {\n\tscheme: 's3:',\n\tcreate(url) {\n\t\tconst { bucket, region, endpoint, forcePathStyle } = parse(url);\n\t\treturn AmazonStorageClient.create({\n\t\t\tbucket,\n\t\t\tregion,\n\t\t\tendpoint,\n\t\t\tforcePathStyle,\n\t\t});\n\t},\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"aws.cjs","names":["trace","SpanKind","SpanStatusCode","S3Client","GetObjectCommand","getSignedUrl","ListObjectVersionsCommand","PutObjectCommand","createPresignedPost","DeleteObjectCommand","parse"],"sources":["../src/telemetry.ts","../src/AmazonStorageClient.ts","../src/s3Driver.ts"],"sourcesContent":["/**\n * A span per storage call, through the global OpenTelemetry tracer — a no-op\n * without a registered provider.\n *\n * `storage.presign`, `storage.put`, `storage.delete` and `storage.list`, with\n * the backend and the bucket. Never the object's key: keys often name a user.\n *\n * @module\n */\nimport {\n\ttype Attributes,\n\tSpanKind,\n\tSpanStatusCode,\n\ttrace,\n} from '@opentelemetry/api';\n\nexport type StorageOperation = 'presign' | 'put' | 'delete' | 'list';\n\n/** Run `fn` inside a `storage.<operation>` span. */\nexport async function traceStorage<T>(\n\toperation: StorageOperation,\n\tattributes: Attributes,\n\tfn: () => Promise<T>,\n): Promise<T> {\n\tconst span = trace\n\t\t.getTracer('@geekmidas/storage')\n\t\t.startSpan(`storage.${operation}`, {\n\t\t\tkind: SpanKind.CLIENT,\n\t\t\tattributes: { 'storage.operation': operation, ...attributes },\n\t\t});\n\ttry {\n\t\treturn await fn();\n\t} catch (error) {\n\t\tif (error instanceof Error) span.recordException(error);\n\t\tspan.setStatus({ code: SpanStatusCode.ERROR });\n\t\tthrow error;\n\t} finally {\n\t\tspan.end();\n\t}\n}\n","import {\n\tDeleteObjectCommand,\n\tGetObjectCommand,\n\tListObjectVersionsCommand,\n\tPutObjectCommand,\n\tS3Client,\n} from '@aws-sdk/client-s3';\nimport { createPresignedPost } from '@aws-sdk/s3-presigned-post';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\n\nimport type { Cache } from '@geekmidas/cache';\nimport type { Attributes } from '@opentelemetry/api';\nimport {\n\ttype DocumentVersion,\n\ttype File,\n\ttype GetUploadParams,\n\ttype GetUploadResponse,\n\ttype StorageClient,\n\tStorageProvider,\n} from './StorageClient';\nimport { type StorageOperation, traceStorage } from './telemetry';\n\nexport class AmazonStorageClient implements StorageClient {\n\treadonly provider = StorageProvider.AWSS3;\n\n\tstatic create(\n\t\toptions: AmazonStorageClientCreateOptions,\n\t): AmazonStorageClient {\n\t\tconst {\n\t\t\tbucket,\n\t\t\tregion,\n\t\t\taccessKeyId,\n\t\t\tacl,\n\t\t\tendpoint,\n\t\t\tsecretAccessKey,\n\t\t\tforcePathStyle = false,\n\t\t\tcache,\n\t\t} = options;\n\t\tconst hasCredentials = accessKeyId && secretAccessKey;\n\t\tconst credentials = hasCredentials\n\t\t\t? { accessKeyId, secretAccessKey }\n\t\t\t: undefined;\n\n\t\tconst client = new S3Client({\n\t\t\tregion,\n\t\t\tcredentials,\n\t\t\tendpoint,\n\t\t\tforcePathStyle,\n\t\t});\n\n\t\treturn new AmazonStorageClient(client, bucket, acl, cache);\n\t}\n\tconstructor(\n\t\tprivate readonly client: S3Client,\n\t\tprivate readonly bucket: string,\n\t\tprivate readonly acl = AmazonCannedAccessControlList.AuthenticatedRead,\n\t\treadonly cache?: Cache,\n\t) {}\n\n\t/** A storage span on this bucket. */\n\tprivate traced<T>(\n\t\toperation: StorageOperation,\n\t\tfn: () => Promise<T>,\n\t\tattributes: Attributes = {},\n\t): Promise<T> {\n\t\treturn traceStorage(\n\t\t\toperation,\n\t\t\t{ 'storage.system': 's3', 'storage.bucket': this.bucket, ...attributes },\n\t\t\tfn,\n\t\t);\n\t}\n\n\tprivate createGetObjectCommand(\n\t\tfile: File,\n\t\toverrides?: { VersionId?: string },\n\t): GetObjectCommand {\n\t\tconst disposition =\n\t\t\tfile.disposition ?? (file.name ? 'attachment' : undefined);\n\t\tconst ResponseContentDisposition = disposition\n\t\t\t? file.name\n\t\t\t\t? `${disposition}; filename=${encodeURIComponent(file.name)}`\n\t\t\t\t: disposition\n\t\t\t: undefined;\n\n\t\treturn new GetObjectCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tKey: file.path,\n\t\t\tResponseContentDisposition,\n\t\t\tResponseContentType: file.responseContentType,\n\t\t\t...overrides,\n\t\t});\n\t}\n\n\tgetVersionDownloadURL(file: File, versionId: string): Promise<string> {\n\t\tconst command = this.createGetObjectCommand(file, { VersionId: versionId });\n\t\treturn this.traced(\n\t\t\t'presign',\n\t\t\t() => getSignedUrl(this.client, command, { expiresIn: 60 * 60 * 24 }),\n\t\t\t{ 'storage.presign.method': 'GET' },\n\t\t);\n\t}\n\n\tasync getVersions(key: string): Promise<DocumentVersion[]> {\n\t\tconst command = new ListObjectVersionsCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tPrefix: key,\n\t\t});\n\n\t\tconst { Versions = [] } = await this.traced('list', () =>\n\t\t\tthis.client.send(command),\n\t\t);\n\n\t\treturn Versions.map((version) => ({\n\t\t\tid: version.VersionId || '',\n\t\t\tcreatedAt: version.LastModified || new Date(),\n\t\t}));\n\t}\n\n\tasync getDownloadURL(file: File, expiresIn = 60 * 60): Promise<string> {\n\t\tconst cacheKey = `download-url:${file.path}`;\n\t\tconst cachedURL = await this.cache?.get<string>(cacheKey);\n\n\t\tif (cachedURL) {\n\t\t\treturn cachedURL;\n\t\t}\n\n\t\tconst command = this.createGetObjectCommand(file);\n\t\tconst url = await this.traced(\n\t\t\t'presign',\n\t\t\t() => getSignedUrl(this.client, command, { expiresIn }),\n\t\t\t{ 'storage.presign.method': 'GET' },\n\t\t);\n\t\tconst cacheExpiration = Math.max(expiresIn - 60, 0);\n\n\t\tif (cacheExpiration) {\n\t\t\tawait this.cache?.set(cacheKey, url, cacheExpiration);\n\t\t}\n\n\t\treturn url;\n\t}\n\n\tasync getUploadURL(\n\t\tparams: GetUploadParams,\n\t\texpiresIn = 60 * 60,\n\t): Promise<string> {\n\t\tconst command = new PutObjectCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tKey: params.path,\n\t\t\tContentType: params.contentType,\n\t\t\tContentLength: params.contentLength,\n\t\t});\n\n\t\treturn this.traced(\n\t\t\t'presign',\n\t\t\t() => getSignedUrl(this.client, command, { expiresIn }),\n\t\t\t{ 'storage.presign.method': 'PUT' },\n\t\t);\n\t}\n\n\tasync getUpload(\n\t\tparams: GetUploadParams,\n\t\texpiresIn = 5,\n\t): Promise<GetUploadResponse> {\n\t\tconst { path } = params;\n\t\tconst { fields: values, url } = await this.traced(\n\t\t\t'presign',\n\t\t\t() =>\n\t\t\t\tcreatePresignedPost(this.client, {\n\t\t\t\t\tExpires: expiresIn * 60,\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tFields: {\n\t\t\t\t\t\tacl: this.acl,\n\t\t\t\t\t},\n\t\t\t\t\tConditions: [\n\t\t\t\t\t\t// content length restrictions: 0-1MB]\n\t\t\t\t\t\t// ['content-length-range', 0, contentLength],\n\t\t\t\t\t\t// specify content-type to be more generic- images only\n\t\t\t\t\t\t// ['starts-with', '$Content-Type', 'image/'],\n\t\t\t\t\t\t// ['starts-with', '$Content-Type', contentType],\n\t\t\t\t\t],\n\t\t\t\t\tKey: path,\n\t\t\t\t}),\n\t\t\t{ 'storage.presign.method': 'POST' },\n\t\t);\n\n\t\tconst keys = Object.keys(values);\n\t\tconst fields = keys.map((key) => ({ key, value: values[key] || '' }));\n\n\t\treturn { url, fields };\n\t}\n\n\tasync upload(\n\t\tkey: string,\n\t\tdata: string | Buffer,\n\t\tcontentType: string,\n\t): Promise<void> {\n\t\tconst Body = typeof data === 'string' ? Buffer.from(data, 'base64') : data;\n\n\t\tconst params = {\n\t\t\tBucket: this.bucket,\n\t\t\tKey: key,\n\t\t\tBody,\n\t\t\tContentType: contentType,\n\t\t};\n\n\t\tconst command = new PutObjectCommand(params);\n\n\t\tawait this.traced('put', () => this.client.send(command), {\n\t\t\t'storage.object.size': Body.length,\n\t\t\t'storage.object.content_type': contentType,\n\t\t});\n\t}\n\n\tasync delete(key: string): Promise<void> {\n\t\tconst command = new DeleteObjectCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tKey: key,\n\t\t});\n\n\t\tawait this.traced('delete', () => this.client.send(command));\n\t}\n}\n\nexport enum AmazonCannedAccessControlList {\n\tAuthenticatedRead = 'authenticated-read',\n\tPrivate = 'private',\n\tPublicRead = 'public-read',\n\tPublicReadWrite = 'public-read-write',\n\tAwsExecRead = 'aws-exec-read',\n\tBucketOwnerRead = 'bucket-owner-read',\n\tBucketOwnerFullControl = 'bucket-owner-full-control',\n\tLogDeliveryWrite = 'log-delivery-write',\n}\n\ninterface AmazonStorageClientCreateOptions {\n\tbucket: string;\n\tregion?: string;\n\tacl?: AmazonCannedAccessControlList;\n\taccessKeyId?: string;\n\tsecretAccessKey?: string;\n\tendpoint?: string;\n\tforcePathStyle?: boolean;\n\tcache?: Cache;\n}\n","/**\n * The S3 driver — `s3://` URLs to an {@link AmazonStorageClient}.\n *\n * Registered by whoever assembles the application, so neutral code can build a\n * client from a URL without importing this file or the AWS SDK behind it.\n */\n\nimport { AmazonStorageClient } from './AmazonStorageClient';\nimport type { StorageDriver } from './registry';\nimport { parse } from './s3Url';\n\nexport const s3Driver: StorageDriver = {\n\tscheme: 's3:',\n\tcreate(url) {\n\t\t// The URL's own key pair, when it has one, wins over the SDK's default\n\t\t// chain; without one the client resolves credentials as it always has.\n\t\tconst {\n\t\t\tbucket,\n\t\t\tregion,\n\t\t\tendpoint,\n\t\t\tforcePathStyle,\n\t\t\taccessKeyId,\n\t\t\tsecretAccessKey,\n\t\t} = parse(url);\n\t\treturn AmazonStorageClient.create({\n\t\t\tbucket,\n\t\t\tregion,\n\t\t\tendpoint,\n\t\t\tforcePathStyle,\n\t\t\taccessKeyId,\n\t\t\tsecretAccessKey,\n\t\t});\n\t},\n};\n"],"mappings":"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"}
|
package/dist/aws.d.cts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { a as DocumentVersion, c as GetUploadResponse, l as StorageClient, o as File, s as GetUploadParams, t as StorageDriver, u as StorageProvider } from "./registry-ClEvHGpM.cjs";
|
|
2
|
+
import { S3Address, t as s3Url_d_exports } from "./s3Url.cjs";
|
|
3
3
|
import { S3Client } from "@aws-sdk/client-s3";
|
|
4
4
|
import { Cache } from "@geekmidas/cache";
|
|
5
|
-
|
|
6
5
|
//#region src/AmazonStorageClient.d.ts
|
|
7
|
-
declare class AmazonStorageClient implements StorageClient {
|
|
6
|
+
export declare class AmazonStorageClient implements StorageClient {
|
|
8
7
|
private readonly client;
|
|
9
8
|
private readonly bucket;
|
|
10
9
|
private readonly acl;
|
|
@@ -12,6 +11,8 @@ declare class AmazonStorageClient implements StorageClient {
|
|
|
12
11
|
readonly provider = StorageProvider.AWSS3;
|
|
13
12
|
static create(options: AmazonStorageClientCreateOptions): AmazonStorageClient;
|
|
14
13
|
constructor(client: S3Client, bucket: string, acl?: AmazonCannedAccessControlList, cache?: Cache);
|
|
14
|
+
/** A storage span on this bucket. */
|
|
15
|
+
private traced;
|
|
15
16
|
private createGetObjectCommand;
|
|
16
17
|
getVersionDownloadURL(file: File, versionId: string): Promise<string>;
|
|
17
18
|
getVersions(key: string): Promise<DocumentVersion[]>;
|
|
@@ -21,7 +22,7 @@ declare class AmazonStorageClient implements StorageClient {
|
|
|
21
22
|
upload(key: string, data: string | Buffer, contentType: string): Promise<void>;
|
|
22
23
|
delete(key: string): Promise<void>;
|
|
23
24
|
}
|
|
24
|
-
declare enum AmazonCannedAccessControlList {
|
|
25
|
+
export declare enum AmazonCannedAccessControlList {
|
|
25
26
|
AuthenticatedRead = "authenticated-read",
|
|
26
27
|
Private = "private",
|
|
27
28
|
PublicRead = "public-read",
|
|
@@ -29,7 +30,7 @@ declare enum AmazonCannedAccessControlList {
|
|
|
29
30
|
AwsExecRead = "aws-exec-read",
|
|
30
31
|
BucketOwnerRead = "bucket-owner-read",
|
|
31
32
|
BucketOwnerFullControl = "bucket-owner-full-control",
|
|
32
|
-
LogDeliveryWrite = "log-delivery-write"
|
|
33
|
+
LogDeliveryWrite = "log-delivery-write"
|
|
33
34
|
}
|
|
34
35
|
interface AmazonStorageClientCreateOptions {
|
|
35
36
|
bucket: string;
|
|
@@ -43,9 +44,7 @@ interface AmazonStorageClientCreateOptions {
|
|
|
43
44
|
}
|
|
44
45
|
//#endregion
|
|
45
46
|
//#region src/s3Driver.d.ts
|
|
46
|
-
declare const s3Driver: StorageDriver;
|
|
47
|
-
//# sourceMappingURL=s3Driver.d.ts.map
|
|
48
|
-
|
|
47
|
+
export declare const s3Driver: StorageDriver;
|
|
49
48
|
//#endregion
|
|
50
|
-
export {
|
|
49
|
+
export { type DocumentVersion, type File, type GetUploadParams, type GetUploadResponse, type S3Address, type StorageClient, s3Url_d_exports as s3Url };
|
|
51
50
|
//# sourceMappingURL=aws.d.cts.map
|
package/dist/aws.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aws.d.cts","names":[],"sources":["../src/AmazonStorageClient.ts","../src/s3Driver.ts"],"
|
|
1
|
+
{"version":3,"file":"aws.d.cts","names":[],"sources":["../src/AmazonStorageClient.ts","../src/s3Driver.ts"],"mappings":";;;;;qBAsBa,+BAA+B;mBA+BzB;mBACA;mBACA;WACR,QAAQ;WAjCT,WAAQ,gBAAA;SAEV,OACN,SAAS,mCACP;EAyBH,YACkB,QAAQ,UACR,gBACA,MAAG,+BACX,QAAQ;;UAIV;UAYA;EAqBR,sBAAsB,MAAM,MAAM,oBAAoB;EAShD,YAAY,cAAc,QAAQ;EAgBlC,eAAe,MAAM,MAAM,qBAAsB;EAuBjD,aACL,QAAQ,iBACR,qBACE;EAeG,UACL,QAAQ,iBACR,qBACE,QAAQ;EA6BL,OACL,aACA,eAAe,QACf,sBACE;EAkBG,OAAO,cAAc;;oBAUhB;EACX;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGS;EACT;EACA;EACA,MAAM;EACN;EACA;EACA;EACA;EACA,QAAQ;;;;qBCvOI,UAAU"}
|
package/dist/aws.d.mts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { DocumentVersion,
|
|
2
|
-
import { S3Address, s3Url_d_exports } from "./s3Url
|
|
1
|
+
import { a as DocumentVersion, c as GetUploadResponse, l as StorageClient, o as File, s as GetUploadParams, t as StorageDriver, u as StorageProvider } from "./registry-ClEvHGpM.mjs";
|
|
2
|
+
import { S3Address, t as s3Url_d_exports } from "./s3Url.mjs";
|
|
3
3
|
import { S3Client } from "@aws-sdk/client-s3";
|
|
4
4
|
import { Cache } from "@geekmidas/cache";
|
|
5
|
-
|
|
6
5
|
//#region src/AmazonStorageClient.d.ts
|
|
7
|
-
declare class AmazonStorageClient implements StorageClient {
|
|
6
|
+
export declare class AmazonStorageClient implements StorageClient {
|
|
8
7
|
private readonly client;
|
|
9
8
|
private readonly bucket;
|
|
10
9
|
private readonly acl;
|
|
@@ -12,6 +11,8 @@ declare class AmazonStorageClient implements StorageClient {
|
|
|
12
11
|
readonly provider = StorageProvider.AWSS3;
|
|
13
12
|
static create(options: AmazonStorageClientCreateOptions): AmazonStorageClient;
|
|
14
13
|
constructor(client: S3Client, bucket: string, acl?: AmazonCannedAccessControlList, cache?: Cache);
|
|
14
|
+
/** A storage span on this bucket. */
|
|
15
|
+
private traced;
|
|
15
16
|
private createGetObjectCommand;
|
|
16
17
|
getVersionDownloadURL(file: File, versionId: string): Promise<string>;
|
|
17
18
|
getVersions(key: string): Promise<DocumentVersion[]>;
|
|
@@ -21,7 +22,7 @@ declare class AmazonStorageClient implements StorageClient {
|
|
|
21
22
|
upload(key: string, data: string | Buffer, contentType: string): Promise<void>;
|
|
22
23
|
delete(key: string): Promise<void>;
|
|
23
24
|
}
|
|
24
|
-
declare enum AmazonCannedAccessControlList {
|
|
25
|
+
export declare enum AmazonCannedAccessControlList {
|
|
25
26
|
AuthenticatedRead = "authenticated-read",
|
|
26
27
|
Private = "private",
|
|
27
28
|
PublicRead = "public-read",
|
|
@@ -29,7 +30,7 @@ declare enum AmazonCannedAccessControlList {
|
|
|
29
30
|
AwsExecRead = "aws-exec-read",
|
|
30
31
|
BucketOwnerRead = "bucket-owner-read",
|
|
31
32
|
BucketOwnerFullControl = "bucket-owner-full-control",
|
|
32
|
-
LogDeliveryWrite = "log-delivery-write"
|
|
33
|
+
LogDeliveryWrite = "log-delivery-write"
|
|
33
34
|
}
|
|
34
35
|
interface AmazonStorageClientCreateOptions {
|
|
35
36
|
bucket: string;
|
|
@@ -43,9 +44,7 @@ interface AmazonStorageClientCreateOptions {
|
|
|
43
44
|
}
|
|
44
45
|
//#endregion
|
|
45
46
|
//#region src/s3Driver.d.ts
|
|
46
|
-
declare const s3Driver: StorageDriver;
|
|
47
|
-
//# sourceMappingURL=s3Driver.d.ts.map
|
|
48
|
-
|
|
47
|
+
export declare const s3Driver: StorageDriver;
|
|
49
48
|
//#endregion
|
|
50
|
-
export {
|
|
49
|
+
export { type DocumentVersion, type File, type GetUploadParams, type GetUploadResponse, type S3Address, type StorageClient, s3Url_d_exports as s3Url };
|
|
51
50
|
//# sourceMappingURL=aws.d.mts.map
|
package/dist/aws.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aws.d.mts","names":[],"sources":["../src/AmazonStorageClient.ts","../src/s3Driver.ts"],"
|
|
1
|
+
{"version":3,"file":"aws.d.mts","names":[],"sources":["../src/AmazonStorageClient.ts","../src/s3Driver.ts"],"mappings":";;;;;qBAsBa,+BAA+B;mBA+BzB;mBACA;mBACA;WACR,QAAQ;WAjCT,WAAQ,gBAAA;SAEV,OACN,SAAS,mCACP;EAyBH,YACkB,QAAQ,UACR,gBACA,MAAG,+BACX,QAAQ;;UAIV;UAYA;EAqBR,sBAAsB,MAAM,MAAM,oBAAoB;EAShD,YAAY,cAAc,QAAQ;EAgBlC,eAAe,MAAM,MAAM,qBAAsB;EAuBjD,aACL,QAAQ,iBACR,qBACE;EAeG,UACL,QAAQ,iBACR,qBACE,QAAQ;EA6BL,OACL,aACA,eAAe,QACf,sBACE;EAkBG,OAAO,cAAc;;oBAUhB;EACX;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGS;EACT;EACA;EACA,MAAM;EACN;EACA;EACA;EACA;EACA,QAAQ;;;;qBCvOI,UAAU"}
|