@travetto/model-s3 8.0.0-alpha.2 → 8.0.0-alpha.20
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 +23 -4
- package/package.json +7 -7
- package/src/config.ts +13 -5
- package/src/service.ts +30 -18
- package/support/service.s3.ts +1 -1
package/README.md
CHANGED
|
@@ -65,11 +65,10 @@ export class S3ModelConfig {
|
|
|
65
65
|
modifyStorage?: boolean;
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
|
-
* Provide
|
|
68
|
+
* Provide base URL for public access
|
|
69
69
|
*/
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
70
|
+
@Required(false)
|
|
71
|
+
publicBaseUrl: string;
|
|
73
72
|
|
|
74
73
|
/**
|
|
75
74
|
* Produces the s3 config from the provide details, post construction
|
|
@@ -81,6 +80,26 @@ export class S3ModelConfig {
|
|
|
81
80
|
this.bucket ??= 'app';
|
|
82
81
|
}
|
|
83
82
|
|
|
83
|
+
if (!this.publicBaseUrl) {
|
|
84
|
+
if (this.endpoint) {
|
|
85
|
+
if (this.endpoint.includes('localhost')) {
|
|
86
|
+
this.publicBaseUrl = this.endpoint;
|
|
87
|
+
} else {
|
|
88
|
+
try {
|
|
89
|
+
this.publicBaseUrl = new URL(this.endpoint).origin;
|
|
90
|
+
} catch {
|
|
91
|
+
this.publicBaseUrl = this.endpoint;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
this.publicBaseUrl = `https://${this.bucket}.s3.amazonaws.com`;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (this.publicBaseUrl && !this.publicBaseUrl.includes('://')) {
|
|
100
|
+
this.publicBaseUrl = `https://${this.publicBaseUrl}`;
|
|
101
|
+
}
|
|
102
|
+
|
|
84
103
|
if (!this.accessKeyId && !this.secretAccessKey) {
|
|
85
104
|
const creds = await fromIni({ profile: this.profile })();
|
|
86
105
|
this.accessKeyId = creds.accessKeyId;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/model-s3",
|
|
3
|
-
"version": "8.0.0-alpha.
|
|
3
|
+
"version": "8.0.0-alpha.20",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "S3 backing for the travetto model module.",
|
|
6
6
|
"keywords": [
|
|
@@ -26,14 +26,14 @@
|
|
|
26
26
|
"directory": "module/model-s3"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@aws-sdk/client-s3": "^3.
|
|
30
|
-
"@aws-sdk/credential-provider-ini": "^3.972.
|
|
31
|
-
"@aws-sdk/s3-request-presigner": "^3.
|
|
32
|
-
"@travetto/config": "^8.0.0-alpha.
|
|
33
|
-
"@travetto/model": "^8.0.0-alpha.
|
|
29
|
+
"@aws-sdk/client-s3": "^3.1063.0",
|
|
30
|
+
"@aws-sdk/credential-provider-ini": "^3.972.50",
|
|
31
|
+
"@aws-sdk/s3-request-presigner": "^3.1063.0",
|
|
32
|
+
"@travetto/config": "^8.0.0-alpha.19",
|
|
33
|
+
"@travetto/model": "^8.0.0-alpha.20"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
|
-
"@travetto/cli": "^8.0.0-alpha.
|
|
36
|
+
"@travetto/cli": "^8.0.0-alpha.25"
|
|
37
37
|
},
|
|
38
38
|
"peerDependenciesMeta": {
|
|
39
39
|
"@travetto/cli": {
|
package/src/config.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { fromIni } from '@aws-sdk/credential-provider-ini';
|
|
|
2
2
|
import type s3 from '@aws-sdk/client-s3';
|
|
3
3
|
|
|
4
4
|
import { Config, EnvVar } from '@travetto/config';
|
|
5
|
-
import { Required } from '@travetto/schema';
|
|
5
|
+
import { Required, Url } from '@travetto/schema';
|
|
6
6
|
import { Runtime } from '@travetto/runtime';
|
|
7
7
|
import { PostConstruct } from '@travetto/di';
|
|
8
8
|
|
|
@@ -33,11 +33,11 @@ export class S3ModelConfig {
|
|
|
33
33
|
modifyStorage?: boolean;
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
|
-
* Provide
|
|
36
|
+
* Provide base URL for public access
|
|
37
37
|
*/
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
@Url()
|
|
39
|
+
@Required(false)
|
|
40
|
+
publicBaseUrl: string;
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* Produces the s3 config from the provide details, post construction
|
|
@@ -49,6 +49,14 @@ export class S3ModelConfig {
|
|
|
49
49
|
this.bucket ??= 'app';
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
if (!this.publicBaseUrl) {
|
|
53
|
+
if (this.endpoint?.includes('localhost')) {
|
|
54
|
+
this.publicBaseUrl = this.endpoint;
|
|
55
|
+
} else {
|
|
56
|
+
this.publicBaseUrl = `https://${this.bucket}.s3.amazonaws.com`;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
52
60
|
if (!this.accessKeyId && !this.secretAccessKey) {
|
|
53
61
|
const creds = await fromIni({ profile: this.profile })();
|
|
54
62
|
this.accessKeyId = creds.accessKeyId;
|
package/src/service.ts
CHANGED
|
@@ -7,7 +7,8 @@ import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
9
|
type ModelCrudSupport, type ModelStorageSupport, type ModelType, ModelRegistryIndex, ExistsError, NotFoundError, type OptionalId,
|
|
10
|
-
type ModelBlobSupport, type ModelExpirySupport, ModelCrudUtil, ModelExpiryUtil, ModelStorageUtil
|
|
10
|
+
type ModelBlobSupport, type ModelExpirySupport, ModelCrudUtil, ModelExpiryUtil, ModelStorageUtil,
|
|
11
|
+
type ModelListOptions
|
|
11
12
|
} from '@travetto/model';
|
|
12
13
|
import { Injectable, PostConstruct } from '@travetto/di';
|
|
13
14
|
import {
|
|
@@ -93,16 +94,26 @@ export class S3ModelService implements ModelCrudSupport, ModelBlobSupport, Model
|
|
|
93
94
|
return {};
|
|
94
95
|
}
|
|
95
96
|
|
|
96
|
-
async * #iterateBucket(cls?: string | Class): AsyncIterable<{ Key: string, id: string }[]> {
|
|
97
|
+
async * #iterateBucket(cls?: string | Class, options?: ModelListOptions): AsyncIterable<{ Key: string, id: string }[]> {
|
|
97
98
|
let Marker: string | undefined;
|
|
98
|
-
|
|
99
|
+
const batchSize = options?.batchSizeHint ?? 100;
|
|
100
|
+
const maxCount = options?.limit ?? Number.MAX_SAFE_INTEGER;
|
|
101
|
+
let produced = 0;
|
|
102
|
+
for (; !(options?.abort?.aborted) && produced < maxCount;) {
|
|
99
103
|
const items = await this.client.listObjects({
|
|
100
104
|
Bucket: this.config.bucket,
|
|
101
105
|
Prefix: cls ? this.#resolveKey(cls) : this.config.namespace,
|
|
102
|
-
Marker
|
|
106
|
+
Marker,
|
|
107
|
+
MaxKeys: batchSize
|
|
103
108
|
});
|
|
104
|
-
|
|
105
|
-
|
|
109
|
+
|
|
110
|
+
let toSend = items.Contents?.map(item => ({ Key: item.Key!, id: item.Key!.split(':').pop()! }));
|
|
111
|
+
if (toSend) {
|
|
112
|
+
produced += toSend.length;
|
|
113
|
+
if (produced > maxCount) {
|
|
114
|
+
toSend = toSend.slice(0, maxCount - (produced - toSend.length));
|
|
115
|
+
}
|
|
116
|
+
yield toSend;
|
|
106
117
|
}
|
|
107
118
|
if (items.NextMarker) {
|
|
108
119
|
Marker = items.NextMarker;
|
|
@@ -293,17 +304,9 @@ export class S3ModelService implements ModelCrudSupport, ModelBlobSupport, Model
|
|
|
293
304
|
await this.client.deleteObject(this.#query(cls, id));
|
|
294
305
|
}
|
|
295
306
|
|
|
296
|
-
async * list<T extends ModelType>(cls: Class<T
|
|
297
|
-
for await (const batch of this.#iterateBucket(cls)) {
|
|
298
|
-
|
|
299
|
-
try {
|
|
300
|
-
yield await this.get(cls, id);
|
|
301
|
-
} catch (error) {
|
|
302
|
-
if (!(error instanceof NotFoundError)) {
|
|
303
|
-
throw error;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
+
async * list<T extends ModelType>(cls: Class<T>, options?: ModelListOptions): AsyncIterable<T[]> {
|
|
308
|
+
for await (const batch of this.#iterateBucket(cls, options)) {
|
|
309
|
+
yield ModelCrudUtil.filterOutNotFound(batch.map(item => this.get(cls, item.id)));
|
|
307
310
|
}
|
|
308
311
|
}
|
|
309
312
|
|
|
@@ -406,7 +409,16 @@ export class S3ModelService implements ModelCrudSupport, ModelBlobSupport, Model
|
|
|
406
409
|
}
|
|
407
410
|
|
|
408
411
|
// Signed urls
|
|
409
|
-
async getBlobReadUrl(location: string, expiresIn: TimeSpan = '1h'): Promise<string> {
|
|
412
|
+
async getBlobReadUrl(location: string, expiresIn: TimeSpan | false = '1h'): Promise<string> {
|
|
413
|
+
if (expiresIn === false) {
|
|
414
|
+
const key = this.#basicKey(location);
|
|
415
|
+
const baseUrl = this.config.publicBaseUrl;
|
|
416
|
+
if (this.config.config.forcePathStyle) {
|
|
417
|
+
return `${baseUrl}/${this.config.bucket}/${key}`;
|
|
418
|
+
} else {
|
|
419
|
+
return `${baseUrl}/${key}`;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
410
422
|
return await getSignedUrl(
|
|
411
423
|
this.client,
|
|
412
424
|
new GetObjectCommand(this.#queryBlob(location)),
|