@tstdl/base 0.92.132 → 0.92.134

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.
Files changed (42) hide show
  1. package/api/server/api-request-token.provider.d.ts +3 -0
  2. package/api/server/api-request-token.provider.js +9 -0
  3. package/api/server/module.js +1 -1
  4. package/database/mongo/module.js +6 -6
  5. package/document-management/api/document-management.api.d.ts +20 -4
  6. package/document-management/api/document-management.api.js +9 -3
  7. package/document-management/server/api/document-management.api.d.ts +1 -0
  8. package/document-management/server/api/document-management.api.js +9 -2
  9. package/document-management/server/module.d.ts +1 -0
  10. package/document-management/server/module.js +1 -0
  11. package/document-management/server/services/document-file.service.d.ts +16 -0
  12. package/document-management/server/services/document-file.service.js +54 -24
  13. package/document-management/server/services/document-management-ancillary.service.d.ts +2 -2
  14. package/document-management/server/services/document.service.d.ts +5 -1
  15. package/document-management/server/services/document.service.js +12 -9
  16. package/document-management/service-models/document.service-model.d.ts +1 -0
  17. package/document-management/service-models/document.service-model.js +1 -0
  18. package/examples/document-management/main.d.ts +1 -1
  19. package/examples/document-management/main.js +17 -8
  20. package/http/client/adapters/undici.adapter.js +3 -3
  21. package/http/client/http-client.js +29 -30
  22. package/http/http-body.js +4 -4
  23. package/http/http.error.d.ts +5 -1
  24. package/http/http.error.js +6 -6
  25. package/http/utils.js +4 -4
  26. package/injector/decorators.d.ts +1 -1
  27. package/injector/injector.d.ts +1 -1
  28. package/injector/interfaces.d.ts +1 -1
  29. package/injector/provider.d.ts +4 -4
  30. package/object-storage/object-storage.d.ts +37 -2
  31. package/object-storage/s3/s3.object-storage-provider.js +1 -1
  32. package/object-storage/s3/s3.object-storage.d.ts +6 -3
  33. package/object-storage/s3/s3.object-storage.js +86 -14
  34. package/object-storage/s3/s3.object.js +2 -3
  35. package/package.json +1 -1
  36. package/search-index/elastic/module.js +5 -5
  37. package/utils/cryptography.js +18 -18
  38. package/utils/object/object.d.ts +3 -2
  39. package/utils/object/object.js +5 -2
  40. package/utils/stream/size-limited-stream.js +1 -1
  41. package/utils/type-guards.d.ts +7 -1
  42. package/utils/type-guards.js +13 -1
@@ -35,11 +35,11 @@ let HttpClient = class HttpClient {
35
35
  constructor() {
36
36
  this.internalStartMiddleware = [
37
37
  getBuildRequestUrlMiddleware(this.options.baseUrl),
38
- ...((this.options.enableErrorHandling ?? true) ? [errorMiddleware] : [])
38
+ ...((this.options.enableErrorHandling ?? true) ? [errorMiddleware] : []),
39
39
  ];
40
40
  this.internalEndMiddleware = [
41
41
  getAddRequestHeadersMiddleware(this.headers),
42
- getAdapterCallMiddleware(this.adapter)
42
+ getAdapterCallMiddleware(this.adapter),
43
43
  ];
44
44
  this.updateMiddleware();
45
45
  }
@@ -54,22 +54,22 @@ let HttpClient = class HttpClient {
54
54
  this.headers.remove(name);
55
55
  }
56
56
  async head(url, options) {
57
- return this.request('HEAD', url, { ...options });
57
+ return await this.request('HEAD', url, { ...options });
58
58
  }
59
59
  async get(url, options) {
60
- return this.request('GET', url, options);
60
+ return await this.request('GET', url, options);
61
61
  }
62
62
  async getText(url, options) {
63
63
  const response = await this.request('GET', url, { ...options });
64
- return response.body.readAsText();
64
+ return await response.body.readAsText();
65
65
  }
66
66
  async getJson(url, options) {
67
67
  const response = await this.request('GET', url, { ...options });
68
- return response.body.readAsJson();
68
+ return await response.body.readAsJson();
69
69
  }
70
70
  async getBuffer(url, options) {
71
71
  const response = await this.request('GET', url, { ...options });
72
- return response.body.readAsBuffer();
72
+ return await response.body.readAsBuffer();
73
73
  }
74
74
  getStream(url, options) {
75
75
  return readableStreamFromPromise(async () => {
@@ -90,19 +90,19 @@ let HttpClient = class HttpClient {
90
90
  });
91
91
  }
92
92
  async post(url, options) {
93
- return this.request('POST', url, options);
93
+ return await this.request('POST', url, options);
94
94
  }
95
95
  async postText(url, options) {
96
96
  const response = await this.request('POST', url, { ...options });
97
- return response.body.readAsText();
97
+ return await response.body.readAsText();
98
98
  }
99
99
  async postJson(url, options) {
100
100
  const response = await this.request('POST', url, { ...options });
101
- return response.body.readAsJson();
101
+ return await response.body.readAsJson();
102
102
  }
103
103
  async postBuffer(url, options) {
104
104
  const response = await this.request('POST', url, { ...options });
105
- return response.body.readAsBuffer();
105
+ return await response.body.readAsBuffer();
106
106
  }
107
107
  postStream(url, options) {
108
108
  return readableStreamFromPromise(async () => {
@@ -111,19 +111,19 @@ let HttpClient = class HttpClient {
111
111
  });
112
112
  }
113
113
  async put(url, options) {
114
- return this.request('PUT', url, options);
114
+ return await this.request('PUT', url, options);
115
115
  }
116
116
  async putText(url, options) {
117
117
  const response = await this.request('PUT', url, { ...options });
118
- return response.body.readAsText();
118
+ return await response.body.readAsText();
119
119
  }
120
120
  async putJson(url, options) {
121
121
  const response = await this.request('PUT', url, { ...options });
122
- return response.body.readAsJson();
122
+ return await response.body.readAsJson();
123
123
  }
124
124
  async putBuffer(url, options) {
125
125
  const response = await this.request('PUT', url, { ...options });
126
- return response.body.readAsBuffer();
126
+ return await response.body.readAsBuffer();
127
127
  }
128
128
  putStream(url, options) {
129
129
  return readableStreamFromPromise(async () => {
@@ -132,19 +132,19 @@ let HttpClient = class HttpClient {
132
132
  });
133
133
  }
134
134
  async patch(url, options) {
135
- return this.request('PATCH', url, options);
135
+ return await this.request('PATCH', url, options);
136
136
  }
137
137
  async patchText(url, options) {
138
138
  const response = await this.request('PATCH', url, { ...options });
139
- return response.body.readAsText();
139
+ return await response.body.readAsText();
140
140
  }
141
141
  async patchJson(url, options) {
142
142
  const response = await this.request('PATCH', url, { ...options });
143
- return response.body.readAsJson();
143
+ return await response.body.readAsJson();
144
144
  }
145
145
  async patchBuffer(url, options) {
146
146
  const response = await this.request('PATCH', url, { ...options });
147
- return response.body.readAsBuffer();
147
+ return await response.body.readAsBuffer();
148
148
  }
149
149
  patchStream(url, options) {
150
150
  return readableStreamFromPromise(async () => {
@@ -153,19 +153,19 @@ let HttpClient = class HttpClient {
153
153
  });
154
154
  }
155
155
  async delete(url, options) {
156
- return this.request('DELETE', url, options);
156
+ return await this.request('DELETE', url, options);
157
157
  }
158
158
  async deleteText(url, options) {
159
159
  const response = await this.request('DELETE', url, { ...options });
160
- return response.body.readAsText();
160
+ return await response.body.readAsText();
161
161
  }
162
162
  async deleteJson(url, options) {
163
163
  const response = await this.request('DELETE', url, { ...options });
164
- return response.body.readAsJson();
164
+ return await response.body.readAsJson();
165
165
  }
166
166
  async deleteBuffer(url, options) {
167
167
  const response = await this.request('DELETE', url, { ...options });
168
- return response.body.readAsBuffer();
168
+ return await response.body.readAsBuffer();
169
169
  }
170
170
  deleteStream(url, options) {
171
171
  return readableStreamFromPromise(async () => {
@@ -175,7 +175,7 @@ let HttpClient = class HttpClient {
175
175
  }
176
176
  async request(method, url, options = {}) {
177
177
  const request = new HttpClientRequest(url, method, options);
178
- return this.rawRequest(request);
178
+ return await this.rawRequest(request);
179
179
  }
180
180
  async rawRequest(request) {
181
181
  const context = { request };
@@ -197,7 +197,7 @@ function getBuildRequestUrlMiddleware(baseUrl) {
197
197
  if (request.mapParameters) {
198
198
  mapParameters(request, baseUrl);
199
199
  }
200
- return next();
200
+ await next();
201
201
  }
202
202
  return buildUrlParametersMiddleware;
203
203
  }
@@ -238,7 +238,7 @@ function getAddRequestHeadersMiddleware(defaultHeaders) {
238
238
  request.headers.authorization = `Token ${authorization.token}`;
239
239
  }
240
240
  }
241
- return next();
241
+ await next();
242
242
  }
243
243
  return addRequestHeadersMiddleware;
244
244
  }
@@ -267,7 +267,6 @@ async function errorMiddleware(context, next) {
267
267
  throw error;
268
268
  }
269
269
  }
270
- // eslint-disable-next-line max-statements, max-lines-per-function, complexity
271
270
  function mapParameters(request, baseUrl) {
272
271
  const isGetOrHead = (request.method == 'GET') || (request.method == 'HEAD');
273
272
  let url;
@@ -299,7 +298,7 @@ function mapParameters(request, baseUrl) {
299
298
  }
300
299
  }
301
300
  if (parameterEntries.size > 0) {
302
- throw new HttpError(HttpErrorReason.InvalidRequest, request, undefined, 'Not all parameters could be mapped to url, query and body because request is either GET/HEAD or body is already defined');
301
+ throw new HttpError(HttpErrorReason.InvalidRequest, request, { cause: 'Not all parameters could be mapped to url, query and body because request is either GET/HEAD or body is already defined' });
303
302
  }
304
303
  if (isDefined(request.query)) {
305
304
  for (const [key, valueOrValues] of request.query) {
@@ -315,8 +314,8 @@ function mapParameters(request, baseUrl) {
315
314
  }
316
315
  function getAdapterCallMiddleware(adapter) {
317
316
  async function adapterCallMiddleware(context, next) {
318
- context.response = await adapter.call(context.request); // eslint-disable-line require-atomic-updates
319
- return next();
317
+ context.response = await adapter.call(context.request);
318
+ await next();
320
319
  }
321
320
  return adapterCallMiddleware;
322
321
  }
package/http/http-body.js CHANGED
@@ -17,19 +17,19 @@ export class HttpBody {
17
17
  }
18
18
  async readAsBuffer(options) {
19
19
  this.prepareBodyRead();
20
- return readBodyAsBuffer(this.body, this.headers, options);
20
+ return await readBodyAsBuffer(this.body, this.headers, options);
21
21
  }
22
22
  async readAsText(options) {
23
23
  this.prepareBodyRead();
24
- return readBodyAsText(this.body, this.headers, options);
24
+ return await readBodyAsText(this.body, this.headers, options);
25
25
  }
26
26
  async readAsJson(options) {
27
27
  this.prepareBodyRead();
28
- return readBodyAsJson(this.body, this.headers, options);
28
+ return await readBodyAsJson(this.body, this.headers, options);
29
29
  }
30
30
  async read(options) {
31
31
  this.prepareBodyRead();
32
- return readBody(this.body, this.headers, options);
32
+ return await readBody(this.body, this.headers, options);
33
33
  }
34
34
  readAsBinaryStream(options) {
35
35
  this.prepareBodyRead();
@@ -22,7 +22,11 @@ export declare class HttpError extends CustomError implements ErrorExtraInfo {
22
22
  readonly responseBody: UndefinableJson | Uint8Array;
23
23
  readonly requestInstance: HttpClientRequest;
24
24
  readonly responseInstance: HttpClientResponse | undefined;
25
- constructor(reason: HttpErrorReason, request: HttpClientRequest, response?: HttpClientResponse, responseBody?: UndefinableJson | Uint8Array, cause?: Error | string);
25
+ constructor(reason: HttpErrorReason, request: HttpClientRequest, { response, responseBody, cause }?: {
26
+ response?: HttpClientResponse;
27
+ responseBody?: UndefinableJson | Uint8Array;
28
+ cause?: Error | string;
29
+ });
26
30
  static create(reason: HttpErrorReason, request: HttpClientRequest, response: HttpClientResponse | undefined, cause?: Error | string): Promise<HttpError>;
27
31
  getExtraInfo(): UndefinableJson | undefined;
28
32
  }
@@ -22,8 +22,8 @@ export class HttpError extends CustomError {
22
22
  responseBody;
23
23
  requestInstance;
24
24
  responseInstance;
25
- constructor(reason, request, response, responseBody, cause) {
26
- super({ message: (isString(cause) ? cause : cause?.message) ?? 'An error occurred', cause: (isNotString(cause) ? cause : undefined) });
25
+ constructor(reason, request, { response, responseBody, cause } = {}) {
26
+ super({ message: (isString(cause) ? cause : cause?.message) ?? 'An error occurred', cause: (isNotString(cause) ? cause : new Error(cause)) });
27
27
  this.reason = reason;
28
28
  this.request = request.asObject();
29
29
  this.response = response?.asObject();
@@ -35,21 +35,21 @@ export class HttpError extends CustomError {
35
35
  }
36
36
  Object.defineProperty(this, propertyNameOf((instance) => instance.requestInstance), {
37
37
  value: request,
38
- enumerable: false
38
+ enumerable: false,
39
39
  });
40
40
  Object.defineProperty(this, propertyNameOf((instance) => instance.responseInstance), {
41
41
  value: response,
42
- enumerable: false
42
+ enumerable: false,
43
43
  });
44
44
  }
45
45
  static async create(reason, request, response, cause) {
46
46
  const body = (response?.body.available == true) ? await response.body.read() : undefined;
47
- return new HttpError(reason, request, response, body, cause);
47
+ return new HttpError(reason, request, { response, responseBody: body, cause });
48
48
  }
49
49
  getExtraInfo() {
50
50
  const extraInfo = {
51
51
  url: this.request.url,
52
- method: this.request.method
52
+ method: this.request.method,
53
53
  };
54
54
  if (isDefined(this.response)) {
55
55
  const responseExtraInfo = {};
package/http/utils.js CHANGED
@@ -20,7 +20,7 @@ export function readBodyAsBinaryStream(body, headers, options = {}) {
20
20
  start: (controller) => {
21
21
  controller.enqueue(body);
22
22
  controller.close();
23
- }
23
+ },
24
24
  })
25
25
  : isAnyIterable(body)
26
26
  ? getReadableStreamFromIterable(body)
@@ -83,12 +83,12 @@ export async function readBodyAsJson(body, headers, options) {
83
83
  }
84
84
  export async function readBody(body, headers, options) {
85
85
  if (headers.contentType?.includes('json') == true) {
86
- return readBodyAsJson(body, headers, { ...options, fallbackToText: true });
86
+ return await readBodyAsJson(body, headers, { ...options, fallbackToText: true });
87
87
  }
88
88
  if (headers.contentType?.includes('text') == true) {
89
- return readBodyAsText(body, headers, options);
89
+ return await readBodyAsText(body, headers, options);
90
90
  }
91
- return readBodyAsBuffer(body, headers, options);
91
+ return await readBodyAsBuffer(body, headers, options);
92
92
  }
93
93
  export function readBodyAsStream(body, headers, options) {
94
94
  if ((headers.contentType?.includes('json') == true) || (headers.contentType?.includes('text') == true)) {
@@ -28,7 +28,7 @@ export declare function Injectable<T = any, A = any, C extends Record = Record>(
28
28
  * Registers the class in the global container with singleton lifecycle. Decorated class is not modified in any way
29
29
  * @param options registration options
30
30
  */
31
- export declare function Singleton<T = any, A = any>(options?: InjectableOptionsWithoutLifecycle<T, A>): ClassDecorator;
31
+ export declare function Singleton<T = any, A = undefined>(options?: InjectableOptionsWithoutLifecycle<T, A>): ClassDecorator;
32
32
  /**
33
33
  * Registers the class in the global container with scoped lifecycle. Decorated class is not modified in any way
34
34
  * @param options registration options
@@ -49,7 +49,7 @@ export declare class Injector implements AsyncDisposable {
49
49
  * @param provider provider used to resolve the token
50
50
  * @param options registration options
51
51
  */
52
- static registerSingleton<T, A = ResolveArgument<T, any>, C extends Record = Record>(token: InjectionToken<T, A>, providers: OneOrMany<Provider<T, A, C>>, options?: TypedOmit<RegistrationOptions<T, A, C>, 'lifecycle'>): void;
52
+ static registerSingleton<T, A = undefined, C extends Record = Record>(token: InjectionToken<T, A>, providers: OneOrMany<Provider<T, A, C>>, options?: TypedOmit<RegistrationOptions<T, A, C>, 'lifecycle'>): void;
53
53
  dispose(): Promise<void>;
54
54
  [Symbol.asyncDispose](): Promise<void>;
55
55
  fork(name: string): Injector;
@@ -4,7 +4,7 @@ import type { AfterResolveContext } from './types.js';
4
4
  export declare const resolveArgumentType: unique symbol;
5
5
  export declare const afterResolve: unique symbol;
6
6
  export type ResolveArgumentType = typeof resolveArgumentType;
7
- export type ResolveArgument<T, Fallback = undefined> = undefined | (T extends Resolvable<infer U> ? (U | undefined) : T extends Type<Resolvable<infer U>> ? (U | undefined) : T extends (ArgumentedInjectionToken<any, any> | ReifyingInjectionToken) ? InjectionTokenArgument<T> : Fallback);
7
+ export type ResolveArgument<T, Fallback = undefined> = undefined | (T extends Resolvable<infer U> ? (U | undefined) : T extends Type<Pick<Required<Resolvable<infer U>>, typeof resolveArgumentType>> ? (U | undefined) : T extends (ArgumentedInjectionToken<any, any> | ReifyingInjectionToken) ? InjectionTokenArgument<T> : Fallback);
8
8
  export interface Resolvable<A = unknown, D extends Record = Record> extends Partial<AfterResolve<A, D>> {
9
9
  /**
10
10
  * Type of resolve argument
@@ -2,15 +2,15 @@ import type { Constructor, Record, TypedOmit } from '../types.js';
2
2
  import type { ResolveArgument } from './interfaces.js';
3
3
  import type { InjectionToken } from './token.js';
4
4
  import type { AfterResolveContext, ResolveContext } from './types.js';
5
- export type Factory<T, A = any, D extends Record = Record> = (argument: ResolveArgument<T, A>, context: ResolveContext<D>) => T;
5
+ export type Factory<T, A = undefined, D extends Record = Record> = (argument: ResolveArgument<T, A>, context: ResolveContext<D>) => T;
6
6
  export type ProviderWithArgument<T, A> = {
7
7
  defaultArgument?: ResolveArgument<T, A>;
8
8
  defaultArgumentProvider?: () => ResolveArgument<T, A>;
9
9
  };
10
10
  export type ProviderWithInitializer<T, A, D extends Record> = {
11
- afterResolve?: (value: T, argument: A, context: AfterResolveContext<D>) => void | Promise<void>;
11
+ afterResolve?: (value: T, argument: ResolveArgument<T, A>, context: AfterResolveContext<D>) => void | Promise<void>;
12
12
  };
13
- export type Provider<T = any, A = any, D extends Record = Record> = ClassProvider<T, A, D> | ValueProvider<T> | TokenProvider<T, A, D> | FactoryProvider<T, A, D>;
13
+ export type Provider<T = any, A = undefined, D extends Record = Record> = ClassProvider<T, A, D> | ValueProvider<T> | TokenProvider<T, A, D> | FactoryProvider<T, A, D>;
14
14
  export type ClassProvider<T = any, A = any, D extends Record = Record> = ProviderWithArgument<T, A> & ProviderWithInitializer<T, A, D> & {
15
15
  useClass: Constructor<T>;
16
16
  };
@@ -34,7 +34,7 @@ export type TokenProvider<T = any, A = any, D extends Record = Record> = Provide
34
34
  useTokenProvider: () => InjectionToken<T extends (infer U)[] ? U : T, A>;
35
35
  resolveAll: true;
36
36
  });
37
- export type FactoryProvider<T = any, A = unknown, D extends Record = Record> = ProviderWithArgument<T, A> & ProviderWithInitializer<T, A, D> & {
37
+ export type FactoryProvider<T = any, A = undefined, D extends Record = Record> = ProviderWithArgument<T, A> & ProviderWithInitializer<T, A, D> & {
38
38
  useFactory: Factory<T, A, D>;
39
39
  };
40
40
  export declare function classProvider<T, A, D extends Record>(constructor: Constructor<T>, options?: TypedOmit<ClassProvider<T, A, D>, 'useClass'>): ClassProvider<T, A, D>;
@@ -4,7 +4,27 @@ export type UploadObjectOptions = {
4
4
  contentLength?: number;
5
5
  metadata?: ObjectMetadata;
6
6
  };
7
- export type ObjectStorageArgument = string;
7
+ export type UploadUrlOptions = {
8
+ metadata?: ObjectMetadata;
9
+ };
10
+ export type CopyObjectOptions = {
11
+ metadata?: ObjectMetadata;
12
+ };
13
+ export type MoveObjectOptions = {
14
+ metadata?: ObjectMetadata;
15
+ };
16
+ export type ObjectStorageConfiguration = {
17
+ lifecycle?: {
18
+ expiration?: {
19
+ /** Expire (delete) objects after a certain number of seconds. Implementations may round up to supported intervals. */
20
+ after?: number;
21
+ };
22
+ };
23
+ };
24
+ export type ObjectStorageArgument = string | {
25
+ module: string;
26
+ configuration?: ObjectStorageConfiguration;
27
+ };
8
28
  export declare abstract class ObjectStorage implements Resolvable<ObjectStorageArgument> {
9
29
  /** Object storage module */
10
30
  readonly module: string;
@@ -19,14 +39,29 @@ export declare abstract class ObjectStorage implements Resolvable<ObjectStorageA
19
39
  * Uploads an object
20
40
  * @param key object key
21
41
  * @param content content of object
42
+ * @param options options
22
43
  */
23
44
  abstract uploadObject(key: string, content: Uint8Array | ReadableStream<Uint8Array>, options?: UploadObjectOptions): Promise<void>;
45
+ /**
46
+ * Copies an object
47
+ * @param sourceKey source object key
48
+ * @param destinationKey destination object key or destination storage and key
49
+ * @param options options
50
+ */
51
+ abstract copyObject(sourceKey: string, destinationKey: string | [ObjectStorage, string], options?: CopyObjectOptions): Promise<void>;
52
+ /**
53
+ * Moves an object
54
+ * @param sourceKey source object key
55
+ * @param destinationKey destination object key or destination storage and key
56
+ * @param options options
57
+ */
58
+ abstract moveObject(sourceKey: string, destinationKey: string | [ObjectStorage, string], options?: MoveObjectOptions): Promise<void>;
24
59
  /**
25
60
  * Get an url which can be used to upload the object without further authorization
26
61
  * @param key object key
27
62
  * @param expirationTimestamp timestamp when the url expires and can no longer be used
28
63
  */
29
- abstract getUploadUrl(key: string, expirationTimestamp: number): Promise<string>;
64
+ abstract getUploadUrl(key: string, expirationTimestamp: number, options?: UploadUrlOptions): Promise<string>;
30
65
  /**
31
66
  * Get all objects
32
67
  */
@@ -54,7 +54,7 @@ let S3ObjectStorageProvider = class S3ObjectStorageProvider extends ObjectStorag
54
54
  port: (port.length > 0) ? parseInt(port, 10) : undefined,
55
55
  useSSL: protocol == 'https:',
56
56
  accessKey: config.accessKey,
57
- secretKey: config.secretKey
57
+ secretKey: config.secretKey,
58
58
  });
59
59
  this.bucket = assertDefinedPass((config.bucketPerModule == true) ? true : config.bucket, 'either bucket or bucketPerModule must be specified');
60
60
  }
@@ -1,5 +1,5 @@
1
- import type { BucketItemStat, Client } from 'minio';
2
- import { ObjectStorage, type UploadObjectOptions } from '../../object-storage/index.js';
1
+ import { type BucketItemStat, type Client } from 'minio';
2
+ import { ObjectStorage, type CopyObjectOptions, type MoveObjectOptions, type ObjectStorageConfiguration, type UploadObjectOptions, type UploadUrlOptions } from '../../object-storage/index.js';
3
3
  import { S3Object } from './s3.object.js';
4
4
  export declare class S3ObjectStorage extends ObjectStorage {
5
5
  private readonly client;
@@ -9,9 +9,12 @@ export declare class S3ObjectStorage extends ObjectStorage {
9
9
  ensureBucketExists(region?: string, options?: {
10
10
  objectLocking?: boolean;
11
11
  }): Promise<void>;
12
+ configureBucket(configuration: ObjectStorageConfiguration): Promise<void>;
12
13
  exists(key: string): Promise<boolean>;
13
14
  statObject(key: string): Promise<BucketItemStat>;
14
15
  uploadObject(key: string, content: Uint8Array | ReadableStream<Uint8Array>, options?: UploadObjectOptions): Promise<void>;
16
+ copyObject(sourceKey: string, destinationKey: string | [ObjectStorage, string], options?: CopyObjectOptions): Promise<void>;
17
+ moveObject(sourceKey: string, destinationKey: string | [ObjectStorage, string], options?: MoveObjectOptions): Promise<void>;
15
18
  getContent(key: string): Promise<Uint8Array>;
16
19
  getContentStream(key: string): ReadableStream<Uint8Array>;
17
20
  getObjects(): Promise<S3Object[]>;
@@ -19,7 +22,7 @@ export declare class S3ObjectStorage extends ObjectStorage {
19
22
  getObject(key: string): Promise<S3Object>;
20
23
  getResourceUri(key: string): Promise<string>;
21
24
  getDownloadUrl(key: string, expirationTimestamp: number, responseHeaders?: Record<string, string>): Promise<string>;
22
- getUploadUrl(key: string, expirationTimestamp: number): Promise<string>;
25
+ getUploadUrl(key: string, expirationTimestamp: number, options?: UploadUrlOptions): Promise<string>;
23
26
  deleteObject(key: string): Promise<void>;
24
27
  deleteObjects(keys: string[]): Promise<void>;
25
28
  private getResourceUriSync;
@@ -7,18 +7,24 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __metadata = (this && this.__metadata) || function (k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  };
10
+ var S3ObjectStorage_1;
10
11
  import { Readable } from 'node:stream';
12
+ import { CopyDestinationOptions, CopySourceOptions } from 'minio';
11
13
  import { Singleton } from '../../injector/decorators.js';
14
+ import { registerAfterResolve } from '../../injector/resolution.js';
12
15
  import { ObjectStorage } from '../../object-storage/index.js';
16
+ import { toArray } from '../../utils/array/array.js';
13
17
  import { mapAsync } from '../../utils/async-iterable-helpers/map.js';
14
18
  import { toArrayAsync } from '../../utils/async-iterable-helpers/to-array.js';
15
19
  import { now } from '../../utils/date-time.js';
20
+ import { mapObjectKeys } from '../../utils/object/object.js';
16
21
  import { readableStreamFromPromise } from '../../utils/stream/index.js';
17
22
  import { readBinaryStream } from '../../utils/stream/stream-reader.js';
18
- import { assertStringPass, isObject, isUint8Array } from '../../utils/type-guards.js';
23
+ import { assertDefinedPass, assertInstanceOfPass, isDefined, isObject, isString, isUint8Array, isUndefined } from '../../utils/type-guards.js';
24
+ import { secondsPerDay } from '../../utils/units.js';
19
25
  import { S3ObjectStorageProvider } from './s3.object-storage-provider.js';
20
26
  import { S3Object } from './s3.object.js';
21
- let S3ObjectStorage = class S3ObjectStorage extends ObjectStorage {
27
+ let S3ObjectStorage = S3ObjectStorage_1 = class S3ObjectStorage extends ObjectStorage {
22
28
  client;
23
29
  bucket;
24
30
  prefix;
@@ -27,6 +33,11 @@ let S3ObjectStorage = class S3ObjectStorage extends ObjectStorage {
27
33
  this.client = client;
28
34
  this.bucket = bucket;
29
35
  this.prefix = keyPrefix;
36
+ registerAfterResolve(this, async (argument) => {
37
+ const configuration = (isString(argument) ? undefined : argument.configuration) ?? {};
38
+ await this.ensureBucketExists();
39
+ await this.configureBucket(configuration);
40
+ });
30
41
  }
31
42
  async ensureBucketExists(region, options) {
32
43
  const exists = await this.client.bucketExists(this.bucket);
@@ -35,6 +46,49 @@ let S3ObjectStorage = class S3ObjectStorage extends ObjectStorage {
35
46
  }
36
47
  await this.client.makeBucket(this.bucket, region ?? '', { ObjectLocking: options?.objectLocking ?? false });
37
48
  }
49
+ async configureBucket(configuration) {
50
+ let currentLifecycle = null;
51
+ try {
52
+ currentLifecycle = await this.client.getBucketLifecycle(this.bucket);
53
+ }
54
+ catch (error) {
55
+ // ignore error if lifecycle configuration is not set
56
+ if (!isObject(error) || (error.code != 'NoSuchLifecycleConfiguration')) {
57
+ throw error;
58
+ }
59
+ }
60
+ const currentLifecycleRules = isDefined(currentLifecycle?.Rule) ? toArray(currentLifecycle.Rule) : undefined; // https://github.com/minio/minio-js/issues/1407
61
+ const tstdlRule = currentLifecycleRules?.find((rule) => rule.ID == 'TstdlExpireObjects');
62
+ const tstdlRuleExpiration = tstdlRule?.Expiration?.Days;
63
+ const targetExpirationDays = configuration.lifecycle?.expiration?.after;
64
+ const targetExpiration = isDefined(targetExpirationDays) ? Math.ceil(targetExpirationDays / secondsPerDay) : undefined;
65
+ if (tstdlRuleExpiration == targetExpiration) {
66
+ return;
67
+ }
68
+ const nonTstdlRules = currentLifecycleRules?.filter((rule) => rule.ID != 'TstdlExpireObjects') ?? [];
69
+ if (isUndefined(targetExpiration)) {
70
+ if (nonTstdlRules.length == 0) {
71
+ await this.client.removeBucketLifecycle(this.bucket);
72
+ }
73
+ else {
74
+ await this.client.setBucketLifecycle(this.bucket, { Rule: nonTstdlRules });
75
+ }
76
+ }
77
+ else {
78
+ await this.client.setBucketLifecycle(this.bucket, {
79
+ Rule: [
80
+ ...nonTstdlRules,
81
+ {
82
+ ID: 'TstdlExpireObjects',
83
+ Status: 'Enabled',
84
+ Expiration: {
85
+ Days: targetExpiration,
86
+ },
87
+ },
88
+ ],
89
+ });
90
+ }
91
+ }
38
92
  async exists(key) {
39
93
  const bucketKey = this.getBucketKey(key);
40
94
  try {
@@ -50,7 +104,7 @@ let S3ObjectStorage = class S3ObjectStorage extends ObjectStorage {
50
104
  }
51
105
  async statObject(key) {
52
106
  const bucketKey = this.getBucketKey(key);
53
- return this.client.statObject(this.bucket, bucketKey);
107
+ return await this.client.statObject(this.bucket, bucketKey);
54
108
  }
55
109
  async uploadObject(key, content, options) {
56
110
  const bucketKey = this.getBucketKey(key);
@@ -66,10 +120,27 @@ let S3ObjectStorage = class S3ObjectStorage extends ObjectStorage {
66
120
  ]);
67
121
  }
68
122
  }
123
+ async copyObject(sourceKey, destinationKey, options) {
124
+ const sourceBucketKey = this.getBucketKey(sourceKey);
125
+ const destinationBucket = isString(destinationKey) ? this.bucket : assertInstanceOfPass(destinationKey[0], S3ObjectStorage_1, 'Destination storage is not an S3ObjectStorage').bucket;
126
+ const destinationBucketKey = isString(destinationKey) ? destinationKey : destinationKey[0].getBucketKey(destinationKey[1]);
127
+ const sourceObject = await this.getObject(sourceKey);
128
+ const sourceMetadata = await sourceObject.getMetadata();
129
+ await this.client.copyObject(new CopySourceOptions({ Bucket: this.bucket, Object: sourceBucketKey }), new CopyDestinationOptions({
130
+ Bucket: destinationBucket,
131
+ Object: destinationBucketKey,
132
+ MetadataDirective: 'REPLACE',
133
+ UserMetadata: { ...sourceMetadata, ...options?.metadata },
134
+ }));
135
+ }
136
+ async moveObject(sourceKey, destinationKey, options) {
137
+ await this.copyObject(sourceKey, destinationKey, options);
138
+ await this.deleteObject(sourceKey);
139
+ }
69
140
  async getContent(key) {
70
141
  const bucketKey = this.getBucketKey(key);
71
142
  const result = await this.client.getObject(this.bucket, bucketKey);
72
- return readBinaryStream(result);
143
+ return await readBinaryStream(result);
73
144
  }
74
145
  getContentStream(key) {
75
146
  const bucketKey = this.getBucketKey(key);
@@ -79,7 +150,7 @@ let S3ObjectStorage = class S3ObjectStorage extends ObjectStorage {
79
150
  });
80
151
  }
81
152
  async getObjects() {
82
- return toArrayAsync(this.getObjectsCursor());
153
+ return await toArrayAsync(this.getObjectsCursor());
83
154
  }
84
155
  getObjectsCursor() {
85
156
  const stream = this.client.listObjectsV2(this.bucket, this.prefix, true);
@@ -96,12 +167,13 @@ let S3ObjectStorage = class S3ObjectStorage extends ObjectStorage {
96
167
  async getDownloadUrl(key, expirationTimestamp, responseHeaders) {
97
168
  const bucketKey = this.getBucketKey(key);
98
169
  const { date, expiration } = getDateAndExpiration(expirationTimestamp);
99
- return this.client.presignedGetObject(this.bucket, bucketKey, expiration, responseHeaders ?? {}, date);
170
+ return await this.client.presignedGetObject(this.bucket, bucketKey, expiration, responseHeaders ?? {}, date);
100
171
  }
101
- async getUploadUrl(key, expirationTimestamp) {
172
+ async getUploadUrl(key, expirationTimestamp, options) {
102
173
  const bucketKey = this.getBucketKey(key);
103
174
  const { date, expiration } = getDateAndExpiration(expirationTimestamp);
104
- return this.client.presignedUrl('PUT', this.bucket, bucketKey, expiration, {}, date);
175
+ const query = mapObjectKeys(options?.metadata ?? {}, (key) => `X-Amz-Meta-${key}`);
176
+ return await this.client.presignedUrl('PUT', this.bucket, bucketKey, expiration, query, date);
105
177
  }
106
178
  async deleteObject(key) {
107
179
  const bucketKey = this.getBucketKey(key);
@@ -122,14 +194,14 @@ let S3ObjectStorage = class S3ObjectStorage extends ObjectStorage {
122
194
  return bucketKey.slice(this.prefix.length);
123
195
  }
124
196
  };
125
- S3ObjectStorage = __decorate([
197
+ S3ObjectStorage = S3ObjectStorage_1 = __decorate([
126
198
  Singleton({
127
199
  provider: {
128
- useFactory: (argument, context) => context.resolve(S3ObjectStorageProvider).get(assertStringPass(argument, 'resolve argument must be a string (object storage module)')),
129
- async afterResolve(value) {
130
- await value.ensureBucketExists();
131
- }
132
- }
200
+ useFactory: (argument, context) => {
201
+ const { module } = (isString(argument) ? { module: argument } : assertDefinedPass(argument, 'argument must be a string or an object'));
202
+ return context.resolve(S3ObjectStorageProvider).get(module);
203
+ },
204
+ },
133
205
  }),
134
206
  __metadata("design:paramtypes", [Function, String, String, String])
135
207
  ], S3ObjectStorage);
@@ -15,7 +15,6 @@ export class S3Object extends ObjectStorageObject {
15
15
  async getResourceUri() {
16
16
  return this.resourceUri;
17
17
  }
18
- // eslint-disable-next-line @typescript-eslint/require-await
19
18
  async getContentLength() {
20
19
  if (isUndefined(this.contentLength)) {
21
20
  const stat = await this.stat();
@@ -28,7 +27,7 @@ export class S3Object extends ObjectStorageObject {
28
27
  return stat.metaData;
29
28
  }
30
29
  async getContent() {
31
- return this.storage.getContent(this.key);
30
+ return await this.storage.getContent(this.key);
32
31
  }
33
32
  getContentStream() {
34
33
  return this.storage.getContentStream(this.key);
@@ -37,6 +36,6 @@ export class S3Object extends ObjectStorageObject {
37
36
  if (isUndefined(this.statPromise)) {
38
37
  this.statPromise = this.storage.statObject(this.key);
39
38
  }
40
- return this.statPromise;
39
+ return await this.statPromise;
41
40
  }
42
41
  }