@travetto/model-s3 7.0.0-rc.0 → 7.0.0-rc.2

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 CHANGED
@@ -31,8 +31,8 @@ export class Init {
31
31
  @InjectableFactory({
32
32
  primary: true
33
33
  })
34
- static getModelSource(conf: S3ModelConfig) {
35
- return new S3ModelService(conf);
34
+ static getModelSource(config: S3ModelConfig) {
35
+ return new S3ModelService(config);
36
36
  }
37
37
  }
38
38
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/model-s3",
3
- "version": "7.0.0-rc.0",
3
+ "version": "7.0.0-rc.2",
4
4
  "description": "S3 backing for the travetto model module.",
5
5
  "keywords": [
6
6
  "s3",
@@ -28,9 +28,9 @@
28
28
  "@aws-sdk/client-s3": "^3.940.0",
29
29
  "@aws-sdk/credential-provider-ini": "^3.940.0",
30
30
  "@aws-sdk/s3-request-presigner": "^3.940.0",
31
- "@travetto/cli": "^7.0.0-rc.0",
32
- "@travetto/config": "^7.0.0-rc.0",
33
- "@travetto/model": "^7.0.0-rc.0"
31
+ "@travetto/cli": "^7.0.0-rc.2",
32
+ "@travetto/config": "^7.0.0-rc.2",
33
+ "@travetto/model": "^7.0.0-rc.2"
34
34
  },
35
35
  "travetto": {
36
36
  "displayName": "S3 Model Support"
package/src/service.ts CHANGED
@@ -16,12 +16,12 @@ import { Class, AppError, castTo, asFull, BlobMeta, ByteRange, BinaryInput, Bina
16
16
 
17
17
  import { S3ModelConfig } from './config.ts';
18
18
 
19
- function isMetadataBearer(o: unknown): o is MetadataBearer {
20
- return !!o && typeof o === 'object' && '$metadata' in o;
19
+ function isMetadataBearer(value: unknown): value is MetadataBearer {
20
+ return !!value && typeof value === 'object' && '$metadata' in value;
21
21
  }
22
22
 
23
- function hasContentType<T>(o: T): o is T & { contenttype?: string } {
24
- return o !== undefined && o !== null && Object.hasOwn(o, 'contenttype');
23
+ function hasContentType<T>(value: T): value is T & { contenttype?: string } {
24
+ return value !== undefined && value !== null && Object.hasOwn(value, 'contenttype');
25
25
  }
26
26
 
27
27
  type MetaBase = Pick<CreateMultipartUploadRequest,
@@ -72,12 +72,12 @@ export class S3ModelService implements ModelCrudSupport, ModelBlobSupport, Model
72
72
  return this.#basicKey(key);
73
73
  }
74
74
 
75
- #q<U extends object>(cls: string | Class, id: string, extra: U = asFull({})): (U & { Key: string, Bucket: string }) {
75
+ #query<U extends object>(cls: string | Class, id: string, extra: U = asFull({})): (U & { Key: string, Bucket: string }) {
76
76
  const key = this.#resolveKey(cls, id);
77
77
  return { Key: key, Bucket: this.config.bucket, ...extra };
78
78
  }
79
79
 
80
- #qBlob<U extends object>(id: string, extra: U = asFull({})): (U & { Key: string, Bucket: string }) {
80
+ #queryBlob<U extends object>(id: string, extra: U = asFull({})): (U & { Key: string, Bucket: string }) {
81
81
  const key = this.#basicKey(id);
82
82
  return { Key: key, Bucket: this.config.bucket, ...extra };
83
83
  }
@@ -96,16 +96,16 @@ export class S3ModelService implements ModelCrudSupport, ModelBlobSupport, Model
96
96
  async * #iterateBucket(cls?: string | Class): AsyncIterable<{ Key: string, id: string }[]> {
97
97
  let Marker: string | undefined;
98
98
  for (; ;) {
99
- const obs = await this.client.listObjects({
99
+ const items = await this.client.listObjects({
100
100
  Bucket: this.config.bucket,
101
101
  Prefix: cls ? this.#resolveKey(cls) : this.config.namespace,
102
102
  Marker
103
103
  });
104
- if (obs.Contents?.length) {
105
- yield obs.Contents.map(o => ({ Key: o.Key!, id: o.Key!.split(':').pop()! }));
104
+ if (items.Contents?.length) {
105
+ yield items.Contents.map(item => ({ Key: item.Key!, id: item.Key!.split(':').pop()! }));
106
106
  }
107
- if (obs.NextMarker) {
108
- Marker = obs.NextMarker;
107
+ if (items.NextMarker) {
108
+ Marker = items.NextMarker;
109
109
  } else {
110
110
  return;
111
111
  }
@@ -116,21 +116,21 @@ export class S3ModelService implements ModelCrudSupport, ModelBlobSupport, Model
116
116
  * Write multipart file upload, in chunks
117
117
  */
118
118
  async #writeMultipart(id: string, input: Readable, meta: BlobMeta): Promise<void> {
119
- const { UploadId } = await this.client.createMultipartUpload(this.#qBlob(id, this.#getMetaBase(meta)));
119
+ const { UploadId } = await this.client.createMultipartUpload(this.#queryBlob(id, this.#getMetaBase(meta)));
120
120
 
121
121
  const parts: CompletedPart[] = [];
122
122
  let buffers: Buffer[] = [];
123
123
  let total = 0;
124
- let n = 1;
124
+ let i = 1;
125
125
  const flush = async (): Promise<void> => {
126
126
  if (!total) { return; }
127
- const part = await this.client.uploadPart(this.#qBlob(id, {
127
+ const part = await this.client.uploadPart(this.#queryBlob(id, {
128
128
  Body: Buffer.concat(buffers),
129
- PartNumber: n,
129
+ PartNumber: i,
130
130
  UploadId
131
131
  }));
132
- parts.push({ PartNumber: n, ETag: part.ETag });
133
- n += 1;
132
+ parts.push({ PartNumber: i, ETag: part.ETag });
133
+ i += 1;
134
134
  buffers = [];
135
135
  total = 0;
136
136
  };
@@ -145,13 +145,13 @@ export class S3ModelService implements ModelCrudSupport, ModelBlobSupport, Model
145
145
  }
146
146
  await flush();
147
147
 
148
- await this.client.completeMultipartUpload(this.#qBlob(id, {
148
+ await this.client.completeMultipartUpload(this.#queryBlob(id, {
149
149
  UploadId,
150
150
  MultipartUpload: { Parts: parts }
151
151
  }));
152
- } catch (err) {
153
- await this.client.abortMultipartUpload(this.#qBlob(id, { UploadId }));
154
- throw err;
152
+ } catch (error) {
153
+ await this.client.abortMultipartUpload(this.#queryBlob(id, { UploadId }));
154
+ throw error;
155
155
  }
156
156
  }
157
157
 
@@ -163,9 +163,9 @@ export class S3ModelService implements ModelCrudSupport, ModelBlobSupport, Model
163
163
  Objects: items
164
164
  }
165
165
  });
166
- } catch (err) {
166
+ } catch (error) {
167
167
  // Handle GCS
168
- if (err instanceof Error && err.name === 'NotImplemented') {
168
+ if (error instanceof Error && error.name === 'NotImplemented') {
169
169
  for (const item of items) {
170
170
  await this.client.deleteObject({
171
171
  Bucket: this.config.bucket,
@@ -173,7 +173,7 @@ export class S3ModelService implements ModelCrudSupport, ModelBlobSupport, Model
173
173
  });
174
174
  }
175
175
  } else {
176
- throw err;
176
+ throw error;
177
177
  }
178
178
  }
179
179
  }
@@ -195,25 +195,25 @@ export class S3ModelService implements ModelCrudSupport, ModelBlobSupport, Model
195
195
 
196
196
  async head<T extends ModelType>(cls: Class<T>, id: string): Promise<boolean> {
197
197
  try {
198
- const result = await this.client.headObject(this.#q(cls, id));
198
+ const result = await this.client.headObject(this.#query(cls, id));
199
199
  const { expiresAt } = ModelRegistryIndex.getConfig(cls);
200
200
  if (expiresAt && result.ExpiresString && Date.parse(result.ExpiresString) < Date.now()) {
201
201
  return false;
202
202
  }
203
203
  return true;
204
- } catch (err) {
205
- if (isMetadataBearer(err)) {
206
- if (err.$metadata.httpStatusCode === 404) {
204
+ } catch (error) {
205
+ if (isMetadataBearer(error)) {
206
+ if (error.$metadata.httpStatusCode === 404) {
207
207
  return false;
208
208
  }
209
209
  }
210
- throw err;
210
+ throw error;
211
211
  }
212
212
  }
213
213
 
214
214
  async get<T extends ModelType>(cls: Class<T>, id: string): Promise<T> {
215
215
  try {
216
- const result = await this.client.getObject(this.#q(cls, id));
216
+ const result = await this.client.getObject(this.#query(cls, id));
217
217
  if (result.Body) {
218
218
  const body = await toText(castTo(result.Body));
219
219
  const output = await ModelCrudUtil.load(cls, body);
@@ -230,13 +230,13 @@ export class S3ModelService implements ModelCrudSupport, ModelBlobSupport, Model
230
230
  }
231
231
  }
232
232
  throw new NotFoundError(cls, id);
233
- } catch (err) {
234
- if (isMetadataBearer(err)) {
235
- if (err.$metadata.httpStatusCode === 404) {
236
- err = new NotFoundError(cls, id);
233
+ } catch (error) {
234
+ if (isMetadataBearer(error)) {
235
+ if (error.$metadata.httpStatusCode === 404) {
236
+ error = new NotFoundError(cls, id);
237
237
  }
238
238
  }
239
- throw err;
239
+ throw error;
240
240
  }
241
241
  }
242
242
 
@@ -246,7 +246,7 @@ export class S3ModelService implements ModelCrudSupport, ModelBlobSupport, Model
246
246
  prepped = await ModelCrudUtil.preStore(cls, item, this);
247
247
  }
248
248
  const content = Buffer.from(JSON.stringify(prepped), 'utf8');
249
- await this.client.putObject(this.#q(cls, prepped.id, {
249
+ await this.client.putObject(this.#query(cls, prepped.id, {
250
250
  Body: content,
251
251
  ContentType: 'application/json',
252
252
  ContentLength: content.length,
@@ -289,7 +289,7 @@ export class S3ModelService implements ModelCrudSupport, ModelBlobSupport, Model
289
289
  if (!(await this.head(cls, id))) {
290
290
  throw new NotFoundError(cls, id);
291
291
  }
292
- await this.client.deleteObject(this.#q(cls, id));
292
+ await this.client.deleteObject(this.#query(cls, id));
293
293
  }
294
294
 
295
295
  async * list<T extends ModelType>(cls: Class<T>): AsyncIterable<T> {
@@ -297,9 +297,9 @@ export class S3ModelService implements ModelCrudSupport, ModelBlobSupport, Model
297
297
  for (const { id } of batch) {
298
298
  try {
299
299
  yield await this.get(cls, id);
300
- } catch (err) {
301
- if (!(err instanceof NotFoundError)) {
302
- throw err;
300
+ } catch (error) {
301
+ if (!(error instanceof NotFoundError)) {
302
+ throw error;
303
303
  }
304
304
  }
305
305
  }
@@ -321,7 +321,7 @@ export class S3ModelService implements ModelCrudSupport, ModelBlobSupport, Model
321
321
 
322
322
  if (blobMeta.size && blobMeta.size < this.config.chunkSize) { // If smaller than chunk size
323
323
  // Upload to s3
324
- await this.client.putObject(this.#qBlob(location, {
324
+ await this.client.putObject(this.#queryBlob(location, {
325
325
  Body: await toBuffer(stream),
326
326
  ContentLength: blobMeta.size,
327
327
  ...this.#getMetaBase(blobMeta),
@@ -333,7 +333,7 @@ export class S3ModelService implements ModelCrudSupport, ModelBlobSupport, Model
333
333
 
334
334
  async #getObject(location: string, range?: Required<ByteRange>): Promise<Readable> {
335
335
  // Read from s3
336
- const result = await this.client.getObject(this.#qBlob(location, range ? {
336
+ const result = await this.client.getObject(this.#queryBlob(location, range ? {
337
337
  Range: `bytes=${range.start}-${range.end}`
338
338
  } : {}));
339
339
 
@@ -359,40 +359,40 @@ export class S3ModelService implements ModelCrudSupport, ModelBlobSupport, Model
359
359
  }
360
360
 
361
361
  async headBlob(location: string): Promise<{ Metadata?: BlobMeta, ContentLength?: number }> {
362
- const query = this.#qBlob(location);
362
+ const query = this.#queryBlob(location);
363
363
  try {
364
364
  return (await this.client.headObject(query));
365
- } catch (err) {
366
- if (isMetadataBearer(err)) {
367
- if (err.$metadata.httpStatusCode === 404) {
368
- err = new NotFoundError('Blob', location);
365
+ } catch (error) {
366
+ if (isMetadataBearer(error)) {
367
+ if (error.$metadata.httpStatusCode === 404) {
368
+ error = new NotFoundError('Blob', location);
369
369
  }
370
370
  }
371
- throw err;
371
+ throw error;
372
372
  }
373
373
  }
374
374
 
375
375
  async getBlobMeta(location: string): Promise<BlobMeta> {
376
- const obj = await this.headBlob(location);
376
+ const blob = await this.headBlob(location);
377
377
 
378
- if (obj) {
379
- const ret: BlobMeta = {
378
+ if (blob) {
379
+ const meta: BlobMeta = {
380
380
  contentType: '',
381
- ...obj.Metadata,
382
- size: obj.ContentLength!,
381
+ ...blob.Metadata,
382
+ size: blob.ContentLength!,
383
383
  };
384
- if (hasContentType(ret)) {
385
- ret['contentType'] = ret['contenttype']!;
386
- delete ret['contenttype'];
384
+ if (hasContentType(meta)) {
385
+ meta['contentType'] = meta['contenttype']!;
386
+ delete meta['contenttype'];
387
387
  }
388
- return ret;
388
+ return meta;
389
389
  } else {
390
390
  throw new NotFoundError('Blob', location);
391
391
  }
392
392
  }
393
393
 
394
394
  async deleteBlob(location: string): Promise<void> {
395
- await this.client.deleteObject(this.#qBlob(location));
395
+ await this.client.deleteObject(this.#queryBlob(location));
396
396
  }
397
397
 
398
398
  async updateBlobMeta(location: string, meta: BlobMeta): Promise<void> {
@@ -409,7 +409,7 @@ export class S3ModelService implements ModelCrudSupport, ModelBlobSupport, Model
409
409
  async getBlobReadUrl(location: string, exp: TimeSpan = '1h'): Promise<string> {
410
410
  return await getSignedUrl(
411
411
  this.client,
412
- new GetObjectCommand(this.#qBlob(location)),
412
+ new GetObjectCommand(this.#queryBlob(location)),
413
413
  { expiresIn: TimeUtil.asSeconds(exp) }
414
414
  );
415
415
  }
@@ -419,7 +419,7 @@ export class S3ModelService implements ModelCrudSupport, ModelBlobSupport, Model
419
419
  return await getSignedUrl(
420
420
  this.client,
421
421
  new PutObjectCommand({
422
- ...this.#qBlob(location),
422
+ ...this.#queryBlob(location),
423
423
  ...base,
424
424
  ...(meta.size ? { ContentLength: meta.size } : {}),
425
425
  ...((meta.hash && meta.hash !== '-1') ? { ChecksumSHA256: meta.hash } : {}),