@volontariapp/storage-client 0.2.2-snap-ffbbcc7 → 0.3.0-snap-856e7a4

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 (29) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/errors/grpc-error.d.ts +3 -0
  3. package/dist/errors/grpc-error.d.ts.map +1 -0
  4. package/dist/errors/grpc-error.js +9 -0
  5. package/dist/errors/grpc-error.js.map +1 -0
  6. package/dist/errors/index.d.ts +4 -2
  7. package/dist/errors/index.d.ts.map +1 -1
  8. package/dist/errors/index.js +4 -8
  9. package/dist/errors/index.js.map +1 -1
  10. package/dist/errors/is-storage-unavailable.d.ts +2 -0
  11. package/dist/errors/is-storage-unavailable.d.ts.map +1 -0
  12. package/dist/errors/is-storage-unavailable.js +21 -0
  13. package/dist/errors/is-storage-unavailable.js.map +1 -0
  14. package/dist/errors/storage-relayed.error.d.ts +15 -0
  15. package/dist/errors/storage-relayed.error.d.ts.map +1 -0
  16. package/dist/errors/storage-relayed.error.js +38 -0
  17. package/dist/errors/storage-relayed.error.js.map +1 -0
  18. package/dist/errors/storage-unavailable.error.d.ts +7 -0
  19. package/dist/errors/storage-unavailable.error.d.ts.map +1 -0
  20. package/dist/errors/storage-unavailable.error.js +11 -0
  21. package/dist/errors/storage-unavailable.error.js.map +1 -0
  22. package/dist/services/storage-client.service.d.ts.map +1 -1
  23. package/dist/services/storage-client.service.js +12 -3
  24. package/dist/services/storage-client.service.js.map +1 -1
  25. package/dist/test/storage-client-errors.unit.spec.d.ts +2 -0
  26. package/dist/test/storage-client-errors.unit.spec.d.ts.map +1 -0
  27. package/dist/test/storage-client-errors.unit.spec.js +124 -0
  28. package/dist/test/storage-client-errors.unit.spec.js.map +1 -0
  29. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Relay the business errors of ms-storage (file not found, attachment refused...) with their own status and code instead of wrapping them in STORAGE_ATTACHMENT_FAILED (500). Transport failures keep their existing codes, so the asynchronous fallback of ms-post and ms-event is unchanged. The reason of STORAGE_ATTACHMENT_FAILED now starts with the gRPC status name (for example "UNAVAILABLE: ..."). Add the isStorageUnavailable helper and the StorageUnavailableError (503) for consumers without an asynchronous fallback, such as the avatar of ms-user.
8
+
3
9
  ## 0.2.2
4
10
 
5
11
  ### Patch Changes
@@ -0,0 +1,3 @@
1
+ import type { GrpcStatusError } from '../interfaces/index.js';
2
+ export declare function isGrpcError(error: unknown): error is GrpcStatusError;
3
+ //# sourceMappingURL=grpc-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grpc-error.d.ts","sourceRoot":"","sources":["../../src/errors/grpc-error.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,eAAe,CASpE"}
@@ -0,0 +1,9 @@
1
+ export function isGrpcError(error) {
2
+ return (typeof error === 'object' &&
3
+ error !== null &&
4
+ 'code' in error &&
5
+ typeof error.code === 'number' &&
6
+ 'details' in error &&
7
+ typeof error.details === 'string');
8
+ }
9
+ //# sourceMappingURL=grpc-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grpc-error.js","sourceRoot":"","sources":["../../src/errors/grpc-error.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,MAAM,IAAI,KAAK;QACf,OAAQ,KAA2B,CAAC,IAAI,KAAK,QAAQ;QACrD,SAAS,IAAI,KAAK;QAClB,OAAQ,KAA8B,CAAC,OAAO,KAAK,QAAQ,CAC5D,CAAC;AACJ,CAAC"}
@@ -6,6 +6,8 @@ export declare class StorageClientError extends Error {
6
6
  export declare class StorageClientTimeoutError extends StorageClientError {
7
7
  constructor(message?: string);
8
8
  }
9
- import type { GrpcStatusError } from '../interfaces/index.js';
10
- export declare function isGrpcError(error: unknown): error is GrpcStatusError;
9
+ export * from './storage-unavailable.error.js';
10
+ export * from './storage-relayed.error.js';
11
+ export * from './is-storage-unavailable.js';
12
+ export * from './grpc-error.js';
11
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA,qBAAa,kBAAmB,SAAQ,KAAK;aAGzB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM;aACtB,OAAO,CAAC,EAAE,OAAO;gBAFjC,OAAO,EAAE,MAAM,EACC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,YAAA,EACtB,OAAO,CAAC,EAAE,OAAO,YAAA;CAMpC;AAED,qBAAa,yBAA0B,SAAQ,kBAAkB;gBACnD,OAAO,SAAgC;CAKpD;AAED,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,eAAe,CASpE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA,qBAAa,kBAAmB,SAAQ,KAAK;aAGzB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM;aACtB,OAAO,CAAC,EAAE,OAAO;gBAFjC,OAAO,EAAE,MAAM,EACC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,YAAA,EACtB,OAAO,CAAC,EAAE,OAAO,YAAA;CAMpC;AAED,qBAAa,yBAA0B,SAAQ,kBAAkB;gBACnD,OAAO,SAAgC;CAKpD;AAED,cAAc,gCAAgC,CAAC;AAC/C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iBAAiB,CAAC"}
@@ -16,12 +16,8 @@ export class StorageClientTimeoutError extends StorageClientError {
16
16
  Object.setPrototypeOf(this, new.target.prototype);
17
17
  }
18
18
  }
19
- export function isGrpcError(error) {
20
- return (typeof error === 'object' &&
21
- error !== null &&
22
- 'code' in error &&
23
- typeof error.code === 'number' &&
24
- 'details' in error &&
25
- typeof error.details === 'string');
26
- }
19
+ export * from './storage-unavailable.error.js';
20
+ export * from './storage-relayed.error.js';
21
+ export * from './is-storage-unavailable.js';
22
+ export * from './grpc-error.js';
27
23
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAGzB;IACA;IAHlB,YACE,OAAe,EACC,IAAsB,EACtB,OAAiB;QAEjC,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,SAAI,GAAJ,IAAI,CAAkB;QACtB,YAAO,GAAP,OAAO,CAAU;QAGjC,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF;AAED,MAAM,OAAO,yBAA0B,SAAQ,kBAAkB;IAC/D,YAAY,OAAO,GAAG,6BAA6B;QACjD,KAAK,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;QACxC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF;AAID,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,MAAM,IAAI,KAAK;QACf,OAAQ,KAA2B,CAAC,IAAI,KAAK,QAAQ;QACrD,SAAS,IAAI,KAAK;QAClB,OAAQ,KAA8B,CAAC,OAAO,KAAK,QAAQ,CAC5D,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAGzB;IACA;IAHlB,YACE,OAAe,EACC,IAAsB,EACtB,OAAiB;QAEjC,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,SAAI,GAAJ,IAAI,CAAkB;QACtB,YAAO,GAAP,OAAO,CAAU;QAGjC,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF;AAED,MAAM,OAAO,yBAA0B,SAAQ,kBAAkB;IAC/D,YAAY,OAAO,GAAG,6BAA6B;QACjD,KAAK,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;QACxC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF;AAED,cAAc,gCAAgC,CAAC;AAC/C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const isStorageUnavailable: (error: unknown) => boolean;
2
+ //# sourceMappingURL=is-storage-unavailable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-storage-unavailable.d.ts","sourceRoot":"","sources":["../../src/errors/is-storage-unavailable.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,oBAAoB,UAAW,OAAO,KAAG,OAmBrD,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { isBaseError } from '@volontariapp/errors';
2
+ import { isGrpcError } from './grpc-error.js';
3
+ const GRPC_UNAVAILABLE = 14;
4
+ const GRPC_DEADLINE_EXCEEDED = 4;
5
+ export const isStorageUnavailable = (error) => {
6
+ if (isBaseError(error)) {
7
+ if (error.code === 'STORAGE_TIMEOUT') {
8
+ return true;
9
+ }
10
+ if (error.code === 'STORAGE_ATTACHMENT_FAILED') {
11
+ const rawReason = error.details?.['reason'];
12
+ const reason = typeof rawReason === 'string' ? rawReason.toUpperCase() : '';
13
+ return (reason.includes('UNAVAILABLE') ||
14
+ reason.includes('DEADLINE_EXCEEDED') ||
15
+ reason.includes('CONNECT ECONNREFUSED'));
16
+ }
17
+ return false;
18
+ }
19
+ return (isGrpcError(error) && (error.code === GRPC_UNAVAILABLE || error.code === GRPC_DEADLINE_EXCEEDED));
20
+ };
21
+ //# sourceMappingURL=is-storage-unavailable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-storage-unavailable.js","sourceRoot":"","sources":["../../src/errors/is-storage-unavailable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAC5B,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAMjC,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,KAAc,EAAW,EAAE;IAC9D,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;QACvB,IAAI,KAAK,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;YACrC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,KAAK,2BAA2B,EAAE,CAAC;YAC/C,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC;YAC5C,MAAM,MAAM,GAAG,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5E,OAAO,CACL,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC;gBAC9B,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC;gBACpC,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CACxC,CAAC;QACJ,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,CACL,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,gBAAgB,IAAI,KAAK,CAAC,IAAI,KAAK,sBAAsB,CAAC,CACjG,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { BaseApiError, type GrpcStatus } from '@volontariapp/errors';
2
+ import type { GrpcStatusError } from '../interfaces/index.js';
3
+ export interface StorageErrorBody {
4
+ statusCode: number;
5
+ code: string;
6
+ message: string;
7
+ details?: Record<string, unknown>;
8
+ }
9
+ export declare class StorageRelayedError extends BaseApiError {
10
+ readonly statusCode: number;
11
+ readonly grpcCode: GrpcStatus;
12
+ constructor(body: StorageErrorBody, grpcCode: GrpcStatus);
13
+ }
14
+ export declare const relayStorageError: (error: GrpcStatusError) => StorageRelayedError | undefined;
15
+ //# sourceMappingURL=storage-relayed.error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-relayed.error.d.ts","sourceRoot":"","sources":["../../src/errors/storage-relayed.error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAG9D,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAiCD,qBAAa,mBAAoB,SAAQ,YAAY;IACnD,SAAgB,UAAU,EAAE,MAAM,CAAC;IACnC,SAAgB,QAAQ,EAAE,UAAU,CAAC;gBAEzB,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU;CAKzD;AAGD,eAAO,MAAM,iBAAiB,UAAW,eAAe,KAAG,mBAAmB,GAAG,SAGhF,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { BaseApiError } from '@volontariapp/errors';
2
+ const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
3
+ const parseBody = (raw) => {
4
+ let parsed;
5
+ try {
6
+ parsed = JSON.parse(raw);
7
+ }
8
+ catch {
9
+ return undefined;
10
+ }
11
+ if (!isRecord(parsed) ||
12
+ typeof parsed['statusCode'] !== 'number' ||
13
+ typeof parsed['code'] !== 'string' ||
14
+ typeof parsed['message'] !== 'string') {
15
+ return undefined;
16
+ }
17
+ const details = parsed['details'];
18
+ return {
19
+ statusCode: parsed['statusCode'],
20
+ code: parsed['code'],
21
+ message: parsed['message'],
22
+ ...(isRecord(details) ? { details } : {}),
23
+ };
24
+ };
25
+ export class StorageRelayedError extends BaseApiError {
26
+ statusCode;
27
+ grpcCode;
28
+ constructor(body, grpcCode) {
29
+ super(body.message, body.code, body.details);
30
+ this.statusCode = body.statusCode;
31
+ this.grpcCode = grpcCode;
32
+ }
33
+ }
34
+ export const relayStorageError = (error) => {
35
+ const body = parseBody(error.details);
36
+ return body === undefined ? undefined : new StorageRelayedError(body, error.code);
37
+ };
38
+ //# sourceMappingURL=storage-relayed.error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-relayed.error.js","sourceRoot":"","sources":["../../src/errors/storage-relayed.error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAmB,MAAM,sBAAsB,CAAC;AAWrE,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAoC,EAAE,CACpE,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAEvE,MAAM,SAAS,GAAG,CAAC,GAAW,EAAgC,EAAE;IAC9D,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IACE,CAAC,QAAQ,CAAC,MAAM,CAAC;QACjB,OAAO,MAAM,CAAC,YAAY,CAAC,KAAK,QAAQ;QACxC,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,QAAQ;QAClC,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,QAAQ,EACrC,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IAClC,OAAO;QACL,UAAU,EAAE,MAAM,CAAC,YAAY,CAAC;QAChC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC;QAC1B,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1C,CAAC;AACJ,CAAC,CAAC;AAMF,MAAM,OAAO,mBAAoB,SAAQ,YAAY;IACnC,UAAU,CAAS;IACnB,QAAQ,CAAa;IAErC,YAAY,IAAsB,EAAE,QAAoB;QACtD,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7C,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QAClC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;CACF;AAGD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAsB,EAAmC,EAAE;IAC3F,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACtC,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,mBAAmB,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;AACpF,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { BaseApiError, GrpcStatus } from '@volontariapp/errors';
2
+ export declare class StorageUnavailableError extends BaseApiError {
3
+ readonly statusCode = 503;
4
+ readonly grpcCode = GrpcStatus.UNAVAILABLE;
5
+ constructor(entityId: string);
6
+ }
7
+ //# sourceMappingURL=storage-unavailable.error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-unavailable.error.d.ts","sourceRoot":"","sources":["../../src/errors/storage-unavailable.error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAMhE,qBAAa,uBAAwB,SAAQ,YAAY;IACvD,SAAgB,UAAU,OAAO;IACjC,SAAgB,QAAQ,0BAA0B;gBAEtC,QAAQ,EAAE,MAAM;CAK7B"}
@@ -0,0 +1,11 @@
1
+ import { BaseApiError, GrpcStatus } from '@volontariapp/errors';
2
+ export class StorageUnavailableError extends BaseApiError {
3
+ statusCode = 503;
4
+ grpcCode = GrpcStatus.UNAVAILABLE;
5
+ constructor(entityId) {
6
+ super(`Storage service is unavailable for entity ${entityId}`, 'STORAGE_UNAVAILABLE', {
7
+ entityId,
8
+ });
9
+ }
10
+ }
11
+ //# sourceMappingURL=storage-unavailable.error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-unavailable.error.js","sourceRoot":"","sources":["../../src/errors/storage-unavailable.error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAMhE,MAAM,OAAO,uBAAwB,SAAQ,YAAY;IACvC,UAAU,GAAG,GAAG,CAAC;IACjB,QAAQ,GAAG,UAAU,CAAC,WAAW,CAAC;IAElD,YAAY,QAAgB;QAC1B,KAAK,CAAC,6CAA6C,QAAQ,EAAE,EAAE,qBAAqB,EAAE;YACpF,QAAQ;SACT,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"storage-client.service.d.ts","sourceRoot":"","sources":["../../src/services/storage-client.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,YAAY,EAAY,MAAM,gBAAgB,CAAC;AAC5E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAGxD,OAAO,EAGL,KAAK,4BAA4B,EACjC,KAAK,6BAA6B,EAEnC,MAAM,8BAA8B,CAAC;AAKtC,OAAO,KAAK,EACV,wBAAwB,EACxB,oBAAoB,EAErB,MAAM,wBAAwB,CAAC;AAGhC,qBACa,oBAAqB,YAAW,YAAY;IAMrD,OAAO,CAAC,QAAQ,CAAC,UAAU;IAG3B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IARlC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsD;IAC7E,OAAO,CAAC,cAAc,CAAsC;gBAIzC,UAAU,EAAE,UAAU,EAGtB,cAAc,CAAC,EAAE,oBAAoB,YAAA;IAGxD,YAAY;IAKN,qBAAqB,CACzB,OAAO,EAAE,4BAA4B,EACrC,OAAO,CAAC,EAAE,wBAAwB,GACjC,OAAO,CAAC,6BAA6B,CAAC;IA8BnC,qBAAqB,CACzB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,CAAC,EAAE,wBAAwB,GACjC,OAAO,CAAC,6BAA6B,CAAC;IAWnC,2BAA2B,CAC/B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,wBAAwB,GACjC,OAAO,CAAC,6BAA6B,CAAC;IAWnC,2BAA2B,CAC/B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,wBAAwB,GACjC,OAAO,CAAC,6BAA6B,CAAC;IAWnC,0BAA0B,CAC9B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,wBAAwB,GACjC,OAAO,CAAC,6BAA6B,CAAC;CAU1C"}
1
+ {"version":3,"file":"storage-client.service.d.ts","sourceRoot":"","sources":["../../src/services/storage-client.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,YAAY,EAAY,MAAM,gBAAgB,CAAC;AAC5E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAGxD,OAAO,EAGL,KAAK,4BAA4B,EACjC,KAAK,6BAA6B,EAEnC,MAAM,8BAA8B,CAAC;AAKtC,OAAO,KAAK,EACV,wBAAwB,EACxB,oBAAoB,EAErB,MAAM,wBAAwB,CAAC;AAGhC,qBACa,oBAAqB,YAAW,YAAY;IAMrD,OAAO,CAAC,QAAQ,CAAC,UAAU;IAG3B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IARlC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsD;IAC7E,OAAO,CAAC,cAAc,CAAsC;gBAIzC,UAAU,EAAE,UAAU,EAGtB,cAAc,CAAC,EAAE,oBAAoB,YAAA;IAGxD,YAAY;IAKN,qBAAqB,CACzB,OAAO,EAAE,4BAA4B,EACrC,OAAO,CAAC,EAAE,wBAAwB,GACjC,OAAO,CAAC,6BAA6B,CAAC;IA0CnC,qBAAqB,CACzB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,CAAC,EAAE,wBAAwB,GACjC,OAAO,CAAC,6BAA6B,CAAC;IAWnC,2BAA2B,CAC/B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,wBAAwB,GACjC,OAAO,CAAC,6BAA6B,CAAC;IAWnC,2BAA2B,CAC/B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,wBAAwB,GACjC,OAAO,CAAC,6BAA6B,CAAC;IAWnC,0BAA0B,CAC9B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,wBAAwB,GACjC,OAAO,CAAC,6BAA6B,CAAC;CAU1C"}
@@ -16,10 +16,10 @@ import { Metadata } from '@grpc/grpc-js';
16
16
  import { firstValueFrom, throwError, timeout } from 'rxjs';
17
17
  import { STORAGE_SERVICE_NAME, EntityType, } from '@volontariapp/contracts-nest';
18
18
  import { Logger } from '@volontariapp/logger';
19
- import { isBaseError } from '@volontariapp/errors';
19
+ import { GrpcStatus, isBaseError } from '@volontariapp/errors';
20
20
  import { STORAGE_ATTACHMENT_FAILED, STORAGE_TIMEOUT } from '@volontariapp/errors-nest';
21
21
  import { DEFAULT_STORAGE_TIMEOUT_MS, STORAGE_CLIENT_OPTIONS } from '../constants.js';
22
- import { isGrpcError } from '../errors/index.js';
22
+ import { isGrpcError, relayStorageError } from '../errors/index.js';
23
23
  let StorageClientService = StorageClientService_1 = class StorageClientService {
24
24
  clientGrpc;
25
25
  defaultOptions;
@@ -51,7 +51,16 @@ let StorageClientService = StorageClientService_1 = class StorageClientService {
51
51
  throw error;
52
52
  }
53
53
  const grpcErr = isGrpcError(error) ? error : undefined;
54
- const message = grpcErr?.details ?? (error instanceof Error ? error.message : String(error));
54
+ const relayed = grpcErr === undefined ? undefined : relayStorageError(grpcErr);
55
+ if (relayed !== undefined) {
56
+ this.logger.warn(`ConfirmFileAttachment refused for entity ${command.entityId}: ${relayed.code}`);
57
+ throw relayed;
58
+ }
59
+ const message = grpcErr === undefined
60
+ ? error instanceof Error
61
+ ? error.message
62
+ : String(error)
63
+ : `${GrpcStatus[grpcErr.code] ?? String(grpcErr.code)}: ${grpcErr.details}`;
55
64
  this.logger.error(`ConfirmFileAttachment failed for entity ${command.entityId}: ${message}`);
56
65
  throw STORAGE_ATTACHMENT_FAILED(command.entityId, message);
57
66
  }
@@ -1 +1 @@
1
- {"version":3,"file":"storage-client.service.js","sourceRoot":"","sources":["../../src/services/storage-client.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAgB,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE5E,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC3D,OAAO,EACL,oBAAoB,EAIpB,UAAU,GACX,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACvF,OAAO,EAAE,0BAA0B,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAMrF,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAG1C,IAAM,oBAAoB,4BAA1B,MAAM,oBAAoB;IAMZ;IAGA;IARF,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,OAAO,EAAE,sBAAoB,CAAC,IAAI,EAAE,CAAC,CAAC;IACrE,cAAc,CAAsC;IAE5D,YAEmB,UAAsB,EAGtB,cAAqC;QAHrC,eAAU,GAAV,UAAU,CAAY;QAGtB,mBAAc,GAAd,cAAc,CAAuB;IACrD,CAAC;IAEJ,YAAY;QACV,IAAI,CAAC,cAAc;YACjB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAqC,oBAAoB,CAAC,CAAC;IACzF,CAAC;IAED,KAAK,CAAC,qBAAqB,CACzB,OAAqC,EACrC,OAAkC;QAElC,MAAM,SAAS,GACb,OAAO,EAAE,SAAS,IAAI,IAAI,CAAC,cAAc,EAAE,SAAS,IAAI,0BAA0B,CAAC;QACrF,MAAM,aAAa,GAAG,OAAO,EAAE,aAAa,IAAI,IAAI,CAAC,cAAc,EAAE,aAAa,CAAC;QAEnF,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;QAChC,IAAI,aAAa,EAAE,CAAC;YAClB,QAAQ,CAAC,GAAG,CAAC,kBAAkB,EAAE,aAAa,CAAC,CAAC;QAClD,CAAC;QAED,IAAI,CAAC;YACH,OAAO,MAAM,cAAc,CACzB,IAAI,CAAC,cAAc,CAAC,qBAAqB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,IAAI,CAC/D,OAAO,CAAC;gBACN,KAAK,EAAE,SAAS;gBAChB,IAAI,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;aAC3E,CAAC,CACH,CACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;gBACvB,MAAM,KAAK,CAAC;YACd,CAAC;YACD,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;YACvD,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAC7F,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,2CAA2C,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC,CAAC;YAC7F,MAAM,yBAAyB,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IAED,KAAK,CAAC,qBAAqB,CACzB,MAAc,EACd,OAAiB,EACjB,OAAkC;QAElC,OAAO,IAAI,CAAC,qBAAqB,CAC/B;YACE,QAAQ,EAAE,MAAM;YAChB,UAAU,EAAE,UAAU,CAAC,gBAAgB;YACvC,OAAO;SACR,EACD,OAAO,CACR,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,2BAA2B,CAC/B,OAAe,EACf,MAAc,EACd,OAAkC;QAElC,OAAO,IAAI,CAAC,qBAAqB,CAC/B;YACE,QAAQ,EAAE,OAAO;YACjB,UAAU,EAAE,UAAU,CAAC,uBAAuB;YAC9C,OAAO,EAAE,CAAC,MAAM,CAAC;SAClB,EACD,OAAO,CACR,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,2BAA2B,CAC/B,MAAc,EACd,MAAc,EACd,OAAkC;QAElC,OAAO,IAAI,CAAC,qBAAqB,CAC/B;YACE,QAAQ,EAAE,MAAM;YAChB,UAAU,EAAE,UAAU,CAAC,uBAAuB;YAC9C,OAAO,EAAE,CAAC,MAAM,CAAC;SAClB,EACD,OAAO,CACR,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,0BAA0B,CAC9B,OAAe,EACf,MAAc,EACd,OAAkC;QAElC,OAAO,IAAI,CAAC,qBAAqB,CAC/B;YACE,QAAQ,EAAE,OAAO;YACjB,UAAU,EAAE,UAAU,CAAC,sBAAsB;YAC7C,OAAO,EAAE,CAAC,MAAM,CAAC;SAClB,EACD,OAAO,CACR,CAAC;IACJ,CAAC;CACF,CAAA;AA7GY,oBAAoB;IADhC,UAAU,EAAE;IAMR,WAAA,MAAM,CAAC,oBAAoB,CAAC,CAAA;IAE5B,WAAA,QAAQ,EAAE,CAAA;IACV,WAAA,MAAM,CAAC,sBAAsB,CAAC,CAAA;;GARtB,oBAAoB,CA6GhC"}
1
+ {"version":3,"file":"storage-client.service.js","sourceRoot":"","sources":["../../src/services/storage-client.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAgB,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE5E,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC3D,OAAO,EACL,oBAAoB,EAIpB,UAAU,GACX,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACvF,OAAO,EAAE,0BAA0B,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAMrF,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG7D,IAAM,oBAAoB,4BAA1B,MAAM,oBAAoB;IAMZ;IAGA;IARF,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,OAAO,EAAE,sBAAoB,CAAC,IAAI,EAAE,CAAC,CAAC;IACrE,cAAc,CAAsC;IAE5D,YAEmB,UAAsB,EAGtB,cAAqC;QAHrC,eAAU,GAAV,UAAU,CAAY;QAGtB,mBAAc,GAAd,cAAc,CAAuB;IACrD,CAAC;IAEJ,YAAY;QACV,IAAI,CAAC,cAAc;YACjB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAqC,oBAAoB,CAAC,CAAC;IACzF,CAAC;IAED,KAAK,CAAC,qBAAqB,CACzB,OAAqC,EACrC,OAAkC;QAElC,MAAM,SAAS,GACb,OAAO,EAAE,SAAS,IAAI,IAAI,CAAC,cAAc,EAAE,SAAS,IAAI,0BAA0B,CAAC;QACrF,MAAM,aAAa,GAAG,OAAO,EAAE,aAAa,IAAI,IAAI,CAAC,cAAc,EAAE,aAAa,CAAC;QAEnF,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;QAChC,IAAI,aAAa,EAAE,CAAC;YAClB,QAAQ,CAAC,GAAG,CAAC,kBAAkB,EAAE,aAAa,CAAC,CAAC;QAClD,CAAC;QAED,IAAI,CAAC;YACH,OAAO,MAAM,cAAc,CACzB,IAAI,CAAC,cAAc,CAAC,qBAAqB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,IAAI,CAC/D,OAAO,CAAC;gBACN,KAAK,EAAE,SAAS;gBAChB,IAAI,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;aAC3E,CAAC,CACH,CACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;gBACvB,MAAM,KAAK,CAAC;YACd,CAAC;YACD,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;YACvD,MAAM,OAAO,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;YAC/E,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,4CAA4C,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,IAAI,EAAE,CAChF,CAAC;gBACF,MAAM,OAAO,CAAC;YAChB,CAAC;YACD,MAAM,OAAO,GACX,OAAO,KAAK,SAAS;gBACnB,CAAC,CAAC,KAAK,YAAY,KAAK;oBACtB,CAAC,CAAC,KAAK,CAAC,OAAO;oBACf,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;gBACjB,CAAC,CAAC,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC;YAChF,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,2CAA2C,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC,CAAC;YAC7F,MAAM,yBAAyB,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IAED,KAAK,CAAC,qBAAqB,CACzB,MAAc,EACd,OAAiB,EACjB,OAAkC;QAElC,OAAO,IAAI,CAAC,qBAAqB,CAC/B;YACE,QAAQ,EAAE,MAAM;YAChB,UAAU,EAAE,UAAU,CAAC,gBAAgB;YACvC,OAAO;SACR,EACD,OAAO,CACR,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,2BAA2B,CAC/B,OAAe,EACf,MAAc,EACd,OAAkC;QAElC,OAAO,IAAI,CAAC,qBAAqB,CAC/B;YACE,QAAQ,EAAE,OAAO;YACjB,UAAU,EAAE,UAAU,CAAC,uBAAuB;YAC9C,OAAO,EAAE,CAAC,MAAM,CAAC;SAClB,EACD,OAAO,CACR,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,2BAA2B,CAC/B,MAAc,EACd,MAAc,EACd,OAAkC;QAElC,OAAO,IAAI,CAAC,qBAAqB,CAC/B;YACE,QAAQ,EAAE,MAAM;YAChB,UAAU,EAAE,UAAU,CAAC,uBAAuB;YAC9C,OAAO,EAAE,CAAC,MAAM,CAAC;SAClB,EACD,OAAO,CACR,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,0BAA0B,CAC9B,OAAe,EACf,MAAc,EACd,OAAkC;QAElC,OAAO,IAAI,CAAC,qBAAqB,CAC/B;YACE,QAAQ,EAAE,OAAO;YACjB,UAAU,EAAE,UAAU,CAAC,sBAAsB;YAC7C,OAAO,EAAE,CAAC,MAAM,CAAC;SAClB,EACD,OAAO,CACR,CAAC;IACJ,CAAC;CACF,CAAA;AAzHY,oBAAoB;IADhC,UAAU,EAAE;IAMR,WAAA,MAAM,CAAC,oBAAoB,CAAC,CAAA;IAE5B,WAAA,QAAQ,EAAE,CAAA;IACV,WAAA,MAAM,CAAC,sBAAsB,CAAC,CAAA;;GARtB,oBAAoB,CAyHhC"}
@@ -0,0 +1,2 @@
1
+ import 'reflect-metadata';
2
+ //# sourceMappingURL=storage-client-errors.unit.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-client-errors.unit.spec.d.ts","sourceRoot":"","sources":["../../src/test/storage-client-errors.unit.spec.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC"}
@@ -0,0 +1,124 @@
1
+ import 'reflect-metadata';
2
+ import { jest, describe, it, expect, beforeEach } from '@jest/globals';
3
+ import { throwError } from 'rxjs';
4
+ import { GrpcStatus, isBaseApiError } from '@volontariapp/errors';
5
+ import { EntityType, STORAGE_ATTACHMENT_FAILED, STORAGE_TIMEOUT, StorageClientService, StorageUnavailableError, isStorageUnavailable, } from '../index.js';
6
+ const command = {
7
+ entityId: 'user-1',
8
+ entityType: EntityType.ENTITY_TYPE_USER_AVATAR,
9
+ fileIds: ['avatar-file-1'],
10
+ };
11
+ const wireError = (grpcCode, body) => ({
12
+ code: grpcCode,
13
+ details: JSON.stringify({ timestamp: '2026-10-16T10:00:00.000Z', ...body }),
14
+ message: `${String(grpcCode)} ERROR`,
15
+ });
16
+ describe('StorageClientService error mapping (Unit)', () => {
17
+ let service;
18
+ let confirmFileAttachment;
19
+ const failWith = (error) => {
20
+ confirmFileAttachment.mockReturnValue(throwError(() => error));
21
+ };
22
+ beforeEach(() => {
23
+ confirmFileAttachment = jest.fn();
24
+ const clientGrpc = {
25
+ getService: () => ({ confirmFileAttachment }),
26
+ getClientByServiceName: () => ({}),
27
+ };
28
+ service = new StorageClientService(clientGrpc, { timeoutMs: 1000 });
29
+ service.onModuleInit();
30
+ });
31
+ describe('errors raised by ms-storage (JSON body in details)', () => {
32
+ it('relays a not found file with its status and code', async () => {
33
+ failWith(wireError(GrpcStatus.NOT_FOUND, {
34
+ statusCode: 404,
35
+ code: 'FILE_NOT_FOUND',
36
+ message: "File with ID 'avatar-file-1' was not found.",
37
+ details: { fileId: 'avatar-file-1' },
38
+ }));
39
+ const error = await service.confirmFileAttachment(command).catch((e) => e);
40
+ expect(isBaseApiError(error)).toBe(true);
41
+ expect(error).toMatchObject({
42
+ statusCode: 404,
43
+ grpcCode: GrpcStatus.NOT_FOUND,
44
+ code: 'FILE_NOT_FOUND',
45
+ message: "File with ID 'avatar-file-1' was not found.",
46
+ details: { fileId: 'avatar-file-1' },
47
+ });
48
+ });
49
+ it('relays a refused attachment as 422', async () => {
50
+ failWith(wireError(GrpcStatus.FAILED_PRECONDITION, {
51
+ statusCode: 422,
52
+ code: 'FILE_ATTACHMENT_REFUSED',
53
+ message: 'File already reserved for another entity.',
54
+ }));
55
+ await expect(service.confirmFileAttachment(command)).rejects.toMatchObject({
56
+ statusCode: 422,
57
+ grpcCode: GrpcStatus.FAILED_PRECONDITION,
58
+ code: 'FILE_ATTACHMENT_REFUSED',
59
+ });
60
+ });
61
+ });
62
+ describe('failures without a usable body keep their existing error', () => {
63
+ it.each([
64
+ ['a plain gRPC error', { code: 5, details: 'File not found', message: '5 NOT_FOUND' }],
65
+ ['a body that is not JSON', { code: 13, details: '{oops', message: '13 INTERNAL' }],
66
+ [
67
+ 'a JSON body without a status code',
68
+ { code: 13, details: JSON.stringify({ message: 'boom' }), message: '13 INTERNAL' },
69
+ ],
70
+ [
71
+ 'a transport failure (UNAVAILABLE)',
72
+ { code: 14, details: 'No connection established', message: '14 UNAVAILABLE' },
73
+ ],
74
+ ])('still raises STORAGE_ATTACHMENT_FAILED for %s', async (_label, error) => {
75
+ failWith(error);
76
+ await expect(service.confirmFileAttachment(command)).rejects.toMatchObject({
77
+ statusCode: 500,
78
+ code: 'STORAGE_ATTACHMENT_FAILED',
79
+ });
80
+ });
81
+ });
82
+ it('keeps the transport reason readable for the consumers that fall back', async () => {
83
+ failWith({ code: 14, details: 'No connection established', message: '14 UNAVAILABLE' });
84
+ const error = await service.confirmFileAttachment(command).catch((e) => e);
85
+ expect(isStorageUnavailable(error)).toBe(true);
86
+ });
87
+ });
88
+ describe('isStorageUnavailable', () => {
89
+ it.each([
90
+ ['a timeout', STORAGE_TIMEOUT('user-1', 2000)],
91
+ [
92
+ 'an UNAVAILABLE failure',
93
+ STORAGE_ATTACHMENT_FAILED('user-1', '14 UNAVAILABLE: no connection'),
94
+ ],
95
+ ['a DEADLINE_EXCEEDED failure', STORAGE_ATTACHMENT_FAILED('user-1', 'DEADLINE_EXCEEDED')],
96
+ ['a refused connection', STORAGE_ATTACHMENT_FAILED('user-1', 'connect ECONNREFUSED 10.0.0.1')],
97
+ ['a raw UNAVAILABLE gRPC error', { code: 14, details: 'down', message: 'down' }],
98
+ ['a raw DEADLINE_EXCEEDED gRPC error', { code: 4, details: 'slow', message: 'slow' }],
99
+ ])('is true for %s', (_label, error) => {
100
+ expect(isStorageUnavailable(error)).toBe(true);
101
+ });
102
+ it.each([
103
+ ['another attachment failure', STORAGE_ATTACHMENT_FAILED('user-1', 'boom')],
104
+ ['a plain error', new Error('boom')],
105
+ ['a gRPC NOT_FOUND error', { code: 5, details: 'File not found', message: 'File not found' }],
106
+ ['a string', 'UNAVAILABLE'],
107
+ ['nothing', undefined],
108
+ ])('is false for %s', (_label, error) => {
109
+ expect(isStorageUnavailable(error)).toBe(false);
110
+ });
111
+ });
112
+ describe('StorageUnavailableError', () => {
113
+ it('is a 503 UNAVAILABLE API error naming the entity', () => {
114
+ const error = new StorageUnavailableError('user-1');
115
+ expect(isBaseApiError(error)).toBe(true);
116
+ expect(error).toMatchObject({
117
+ statusCode: 503,
118
+ grpcCode: GrpcStatus.UNAVAILABLE,
119
+ code: 'STORAGE_UNAVAILABLE',
120
+ });
121
+ expect(error.message).toContain('user-1');
122
+ });
123
+ });
124
+ //# sourceMappingURL=storage-client-errors.unit.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-client-errors.unit.spec.js","sourceRoot":"","sources":["../../src/test/storage-client-errors.unit.spec.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volontariapp/storage-client",
3
- "version": "0.2.2-snap-ffbbcc7",
3
+ "version": "0.3.0-snap-856e7a4",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "provenance": true
@@ -55,7 +55,7 @@
55
55
  "rxjs": "^7.8.2"
56
56
  },
57
57
  "dependencies": {
58
- "@volontariapp/contracts": "4.5.0-snap-ffbbcc7",
58
+ "@volontariapp/contracts": "4.5.0",
59
59
  "@volontariapp/contracts-nest": "3.3.8",
60
60
  "@volontariapp/errors": "0.6.5",
61
61
  "@volontariapp/errors-nest": "0.14.0",