@lucaapp/service-utils 1.56.7 → 1.57.0

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.
@@ -3,5 +3,5 @@ import { Middleware, EndpointResponseSchema } from './types/middleware';
3
3
  import { EndpointOptions, EndpointHandler } from './types/endpoint';
4
4
  import { ZodObjectSchemaOrUndefined } from './types/utils';
5
5
  type HttpMethod = 'get' | 'post' | 'put' | 'delete' | 'patch';
6
- export declare const mountEndpoint: <TResponseSchemas extends readonly EndpointResponseSchema[], TRequestBodySchema extends ZodObjectSchemaOrUndefined, TRequestParamsSchema extends ZodObjectSchemaOrUndefined, TRequestQuerySchema extends ZodObjectSchemaOrUndefined, TRequestHeadersSchema extends ZodObjectSchemaOrUndefined, TMiddlewares extends readonly Middleware<any, any, any, any, any, any>[] | undefined = undefined>(router: Router, method: HttpMethod, path: string, options: EndpointOptions<TResponseSchemas, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TMiddlewares>, handler: EndpointHandler<TResponseSchemas, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TMiddlewares>, debug: boolean) => void;
6
+ export declare const mountEndpoint: <TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBodySchema extends ZodObjectSchemaOrUndefined, TRequestParamsSchema extends ZodObjectSchemaOrUndefined, TRequestQuerySchema extends ZodObjectSchemaOrUndefined, TRequestHeadersSchema extends ZodObjectSchemaOrUndefined, TMiddlewares extends ReadonlyArray<Middleware<any, any, any, any, any, any>> | undefined = undefined>(router: Router, method: HttpMethod, path: string, options: EndpointOptions<TResponseSchemas, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TMiddlewares>, handler: EndpointHandler<TResponseSchemas, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TMiddlewares>, debug: boolean) => void;
7
7
  export {};
@@ -1,2 +1,2 @@
1
1
  import { Middleware, MiddlewareOptions, MiddlewareHandler, EndpointResponseSchema } from './types/middleware';
2
- export declare const createMiddleware: <TResponseSchemas extends readonly EndpointResponseSchema[], TRequestBody = undefined, TRequestParams = undefined, TRequestQuery = undefined, TRequestHeaders = undefined, TContext = undefined>(options: MiddlewareOptions<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TContext>, handler: MiddlewareHandler<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TContext>) => Middleware<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TContext>;
2
+ export declare const createMiddleware: <TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBody = undefined, TRequestParams = undefined, TRequestQuery = undefined, TRequestHeaders = undefined, TContext = undefined>(options: MiddlewareOptions<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TContext>, handler: MiddlewareHandler<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TContext>) => Middleware<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TContext>;
@@ -1,14 +1,14 @@
1
1
  import { z } from 'zod';
2
2
  declare const noContentSchema: z.ZodVoid;
3
- export declare const okResponse: <T>(schema?: z.ZodType<T, z.ZodTypeDef, T> | undefined) => {
3
+ export declare const okResponse: <T>(schema?: z.ZodSchema<T>) => {
4
4
  status: 200;
5
5
  description: string;
6
- schema: z.ZodVoid | z.ZodType<T, z.ZodTypeDef, T>;
6
+ schema: z.ZodSchema<T> | typeof noContentSchema;
7
7
  };
8
- export declare const createdResponse: <T>(schema?: z.ZodType<T, z.ZodTypeDef, T> | undefined) => {
8
+ export declare const createdResponse: <T>(schema?: z.ZodSchema<T>) => {
9
9
  status: 201;
10
10
  description: string;
11
- schema: z.ZodVoid | z.ZodType<T, z.ZodTypeDef, T>;
11
+ schema: z.ZodSchema<T> | typeof noContentSchema;
12
12
  };
13
13
  export declare const noContentResponse: () => {
14
14
  status: 204;
@@ -1,17 +1,17 @@
1
- export declare const ok: <T, U>(body?: T | undefined, headers?: U | undefined) => {
1
+ export declare const ok: <T, U>(body?: T, headers?: U) => {
2
2
  status: 200;
3
3
  body: T;
4
4
  headers: U;
5
5
  };
6
- export declare const created: <T, U>(body?: T | undefined, headers?: U | undefined) => {
6
+ export declare const created: <T, U>(body?: T, headers?: U) => {
7
7
  status: 201;
8
8
  body: T;
9
9
  headers: U;
10
10
  };
11
- export declare const noContent: <T>(headers?: T | undefined) => {
11
+ export declare const noContent: <T>(headers?: T) => {
12
12
  status: 204;
13
13
  body: void;
14
- headers?: T | undefined;
14
+ headers?: T;
15
15
  };
16
16
  /**
17
17
  * Specifies that the response is a raw response.
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import { z } from 'zod';
3
2
  import { ArrayToUnion, ExtractZodOutput, ZodSchemaOuput } from './utils';
4
3
  export type EndpointResponseSchema = {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createEmailDataType = void 0;
3
+ exports.createEmailDataType = createEmailDataType;
4
4
  const sequelize_1 = require("sequelize");
5
5
  function createEmailDataType() {
6
6
  class Email extends sequelize_1.DataTypes.CITEXT {
@@ -14,4 +14,3 @@ function createEmailDataType() {
14
14
  Email.prototype.key = Email.key = 'Email';
15
15
  sequelize_1.DataTypes.Email = sequelize_1.Utils.classToInvokable(Email);
16
16
  }
17
- exports.createEmailDataType = createEmailDataType;
@@ -1,6 +1,3 @@
1
- /// <reference types="node/http" />
2
- /// <reference types="lib/logger/types" />
3
- /// <reference types="pino-http" />
4
1
  import type { IncomingMessage, ServerResponse } from 'http';
5
2
  import { Logger } from 'pino';
6
3
  import { HttpLoggerCreationOptions } from './utils';
@@ -1 +1,2 @@
1
1
  export * from './money';
2
+ export * from './supportedCurrencies';
@@ -15,3 +15,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./money"), exports);
18
+ __exportStar(require("./supportedCurrencies"), exports);
@@ -1,49 +1,52 @@
1
1
  import { Model } from 'sequelize';
2
- interface MoneyInterface {
2
+ import { SupportedCurrencies } from './supportedCurrencies';
3
+ interface MoneyInterface<T extends SupportedCurrencies> {
3
4
  getAmount(): number;
4
- add(addend?: Money): Money;
5
- subtract(subtrahend?: Money): Money;
6
- multiply(multiplier: number): Money;
7
- divide(divisor: number): Money;
8
- equalsTo(comparator: Money): boolean;
9
- lessThan(comparator: Money): boolean;
10
- lessThanOrEqual(comparator: Money): boolean;
11
- greaterThan(comparator: Money): boolean;
12
- greaterThanOrEqual(comparator: Money): boolean;
5
+ add(addend?: Money<T>): Money<T>;
6
+ subtract(subtrahend?: Money<T>): Money<T>;
7
+ multiply(multiplier: number): Money<T>;
8
+ divide(divisor: number): Money<T>;
9
+ equalsTo(comparator: Money<T>): boolean;
10
+ lessThan(comparator: Money<T>): boolean;
11
+ lessThanOrEqual(comparator: Money<T>): boolean;
12
+ greaterThan(comparator: Money<T>): boolean;
13
+ greaterThanOrEqual(comparator: Money<T>): boolean;
13
14
  isZero(): boolean;
14
15
  isPositive(): boolean;
15
16
  isNegative(): boolean;
16
17
  }
17
- declare class Money implements MoneyInterface {
18
+ export declare class Money<T extends SupportedCurrencies> implements MoneyInterface<T> {
19
+ readonly currency: T;
18
20
  private readonly value;
19
- static fromAmount(value: number): Money;
20
- static fromFloat(value: number): Money;
21
- static zero(): Money;
21
+ static fromAmount<T extends SupportedCurrencies>(value: number, currency: T): Money<T>;
22
+ static fromFloat<T extends SupportedCurrencies>(value: number, currency: T): Money<T>;
23
+ static zero<T extends SupportedCurrencies>(currency: T): Money<T>;
22
24
  private constructor();
23
- clone(): Money;
25
+ clone(): Money<T>;
24
26
  getAmount(): number;
25
- getEuroAmount(): number;
27
+ getAmountInMajorUnits(): number;
26
28
  /**
27
29
  * @deprecated Use getFormattedString in place of getEuroString
28
30
  */
29
31
  getEuroString(): string;
30
32
  getFormattedString(locale: string, includeSymbol?: boolean): string;
31
- add(addend?: Money | null): Money;
32
- subtract(subtrahend?: Money | null): Money;
33
- multiply(multiplier: number): Money;
34
- divide(divisor: number): Money;
35
- percentage(percentage: number): Money;
36
- equalsTo(comparator: Money): boolean;
37
- lessThan(comparator: Money): boolean;
38
- lessThanOrEqual(comparator: Money): boolean;
39
- greaterThan(comparator: Money): boolean;
40
- greaterThanOrEqual(comparator: Money): boolean;
33
+ private assertSameCurrency;
34
+ add(addend?: Money<T>): Money<T>;
35
+ subtract(subtrahend?: Money<T>): Money<T>;
36
+ multiply(multiplier: number): Money<T>;
37
+ divide(divisor: number): Money<T>;
38
+ percentage(percentage: number): Money<T>;
39
+ equalsTo(comparator: Money<T>): boolean;
40
+ lessThan(comparator: Money<T>): boolean;
41
+ lessThanOrEqual(comparator: Money<T>): boolean;
42
+ greaterThan(comparator: Money<T>): boolean;
43
+ greaterThanOrEqual(comparator: Money<T>): boolean;
41
44
  isZero(): boolean;
42
45
  isPositive(): boolean;
43
46
  isNegative(): boolean;
44
- min(comparator: Money): Money;
45
- max(comparator: Money): Money;
47
+ min(comparator: Money<T>): Money<T>;
48
+ max(comparator: Money<T>): Money<T>;
46
49
  }
47
- declare const moneyfiedGet: (model: Model, key: string) => Money | null;
48
- declare const moneyfiedSet: (model: Model, key: string, value: Money | undefined) => void;
49
- export { moneyfiedGet, moneyfiedSet, Money };
50
+ export declare const moneyfiedGet: <T extends SupportedCurrencies>(model: Model, key: string) => Money<T> | null;
51
+ export declare const moneyfiedSet: <T extends SupportedCurrencies>(model: Model, key: string, value: Money<T> | undefined) => void;
52
+ export {};
@@ -1,90 +1,110 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Money = exports.moneyfiedSet = exports.moneyfiedGet = void 0;
4
- const CENTS_PER_EURO = 100;
3
+ exports.moneyfiedSet = exports.moneyfiedGet = exports.Money = void 0;
4
+ const supportedCurrencies_1 = require("./supportedCurrencies");
5
+ const MINOR_UNITS_PER_MAJOR_UNIT = 100;
5
6
  const EPSILON = 0.00000000001;
6
7
  const roundHalfUp = (value) => {
7
8
  const rounded = Math.sign(value) * Math.round(Math.abs(value) + EPSILON);
8
9
  return rounded === 0 ? 0 : rounded;
9
10
  };
10
- const euroToAmount = (amountInEuros) => roundHalfUp(amountInEuros * CENTS_PER_EURO);
11
- const amountToEuro = (value) => value / CENTS_PER_EURO;
11
+ const convertToMinorUnits = (amountInMajorUnits) => roundHalfUp(amountInMajorUnits * MINOR_UNITS_PER_MAJOR_UNIT);
12
+ const convertToMajorUnits = (amountInMinorUnits) => amountInMinorUnits / MINOR_UNITS_PER_MAJOR_UNIT;
12
13
  class Money {
13
- static fromAmount(value) {
14
+ static fromAmount(value, currency) {
14
15
  if (!Number.isInteger(value)) {
15
- throw new TypeError('Integer required.');
16
+ throw new TypeError('Integer required');
16
17
  }
17
- return new Money(value);
18
+ return new Money(value, currency);
18
19
  }
19
- static fromFloat(value) {
20
- return new Money(euroToAmount(value));
20
+ static fromFloat(value, currency) {
21
+ return new Money(convertToMinorUnits(value), currency);
21
22
  }
22
- static zero() {
23
- return Money.fromAmount(0);
23
+ static zero(currency) {
24
+ return Money.fromAmount(0, currency);
24
25
  }
25
- constructor(amount) {
26
+ constructor(amount, currency) {
26
27
  this.value = amount;
28
+ this.currency = currency;
27
29
  }
28
30
  clone() {
29
- return Money.fromAmount(this.value);
31
+ return Money.fromAmount(this.value, this.currency);
30
32
  }
31
33
  getAmount() {
32
34
  return this.value;
33
35
  }
34
- getEuroAmount() {
35
- return amountToEuro(this.value);
36
+ getAmountInMajorUnits() {
37
+ return convertToMajorUnits(this.value);
36
38
  }
37
39
  /**
38
40
  * @deprecated Use getFormattedString in place of getEuroString
39
41
  */
40
42
  getEuroString() {
41
- return this.getEuroAmount().toFixed(2);
43
+ return this.getAmountInMajorUnits().toFixed(2);
42
44
  }
43
45
  getFormattedString(locale, includeSymbol = true) {
44
46
  const transactionalLanguage = locale === 'de' ? 'de-DE' : 'en-US';
45
47
  const formattedString = new Intl.NumberFormat(transactionalLanguage, {
46
48
  style: 'currency',
47
- currency: 'EUR',
49
+ currency: this.currency,
48
50
  minimumFractionDigits: 2,
49
51
  maximumFractionDigits: 2,
50
- })
51
- .format(this.getEuroAmount())
52
- .replace(/\s/, ' ');
53
- return includeSymbol
54
- ? formattedString
55
- : formattedString.replace(/€|\s/g, '');
52
+ }).format(this.getAmountInMajorUnits());
53
+ if (!includeSymbol) {
54
+ const symbol = supportedCurrencies_1.currencySymbols[this.currency];
55
+ return formattedString.replace(new RegExp(`\\${symbol}`, 'g'), '').trim();
56
+ }
57
+ return formattedString.replace(/\s/, ' ');
58
+ }
59
+ assertSameCurrency(other) {
60
+ if (!other) {
61
+ return;
62
+ }
63
+ if (this.currency !== other.currency) {
64
+ throw new TypeError('Currencies must match');
65
+ }
56
66
  }
57
67
  add(addend) {
58
- return Money.fromAmount(this.value + (addend?.value || 0));
68
+ this.assertSameCurrency(addend);
69
+ return Money.fromAmount(this.value + (addend?.value || 0), this.currency);
59
70
  }
60
71
  subtract(subtrahend) {
61
- return Money.fromAmount(this.value - (subtrahend?.value || 0));
72
+ this.assertSameCurrency(subtrahend);
73
+ return Money.fromAmount(this.value - (subtrahend?.value || 0), this.currency);
62
74
  }
63
75
  multiply(multiplier) {
64
- return Money.fromAmount(roundHalfUp(this.value * multiplier));
76
+ return Money.fromAmount(roundHalfUp(this.value * multiplier), this.currency);
65
77
  }
66
78
  divide(divisor) {
67
- return Money.fromAmount(roundHalfUp(this.value / divisor));
79
+ if (divisor === 0) {
80
+ throw new TypeError('Divisor cannot be zero');
81
+ }
82
+ return Money.fromAmount(roundHalfUp(this.value / divisor), this.currency);
68
83
  }
69
84
  percentage(percentage) {
70
85
  if (Number.isNaN(percentage) || percentage < 0 || percentage > 100) {
71
86
  throw new TypeError('Expected number between 0 and 100');
72
87
  }
73
- return Money.fromAmount(roundHalfUp((this.value / 100) * percentage));
88
+ return Money.fromAmount(roundHalfUp((this.value / 100) * percentage), this.currency);
74
89
  }
75
90
  equalsTo(comparator) {
91
+ this.assertSameCurrency(comparator);
76
92
  return this.value === comparator.value;
77
93
  }
78
94
  lessThan(comparator) {
95
+ this.assertSameCurrency(comparator);
79
96
  return this.value < comparator.value;
80
97
  }
81
98
  lessThanOrEqual(comparator) {
99
+ this.assertSameCurrency(comparator);
82
100
  return this.value <= comparator.value;
83
101
  }
84
102
  greaterThan(comparator) {
103
+ this.assertSameCurrency(comparator);
85
104
  return this.value > comparator.value;
86
105
  }
87
106
  greaterThanOrEqual(comparator) {
107
+ this.assertSameCurrency(comparator);
88
108
  return this.value >= comparator.value;
89
109
  }
90
110
  isZero() {
@@ -97,9 +117,11 @@ class Money {
97
117
  return this.value < 0;
98
118
  }
99
119
  min(comparator) {
120
+ this.assertSameCurrency(comparator);
100
121
  return this.value < comparator.value ? this.clone() : comparator.clone();
101
122
  }
102
123
  max(comparator) {
124
+ this.assertSameCurrency(comparator);
103
125
  return this.value > comparator.value ? this.clone() : comparator.clone();
104
126
  }
105
127
  }
@@ -108,10 +130,13 @@ const moneyfiedGet = (model, key) => {
108
130
  const currentValue = model.getDataValue(key);
109
131
  return currentValue === null || currentValue === undefined
110
132
  ? null
111
- : Money.fromAmount(currentValue);
133
+ : Money.fromAmount(currentValue, model.getDataValue('currency'));
112
134
  };
113
135
  exports.moneyfiedGet = moneyfiedGet;
114
136
  const moneyfiedSet = (model, key, value) => {
137
+ if (value?.currency && value.currency !== model.getDataValue('currency')) {
138
+ throw new TypeError('Currencies must match');
139
+ }
115
140
  model.setDataValue(key, value?.getAmount());
116
141
  };
117
142
  exports.moneyfiedSet = moneyfiedSet;
@@ -0,0 +1,4 @@
1
+ export declare enum SupportedCurrencies {
2
+ EUR = "EUR"
3
+ }
4
+ export declare const currencySymbols: Record<SupportedCurrencies, string>;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.currencySymbols = exports.SupportedCurrencies = void 0;
4
+ var SupportedCurrencies;
5
+ (function (SupportedCurrencies) {
6
+ SupportedCurrencies["EUR"] = "EUR";
7
+ })(SupportedCurrencies || (exports.SupportedCurrencies = SupportedCurrencies = {}));
8
+ exports.currencySymbols = {
9
+ [SupportedCurrencies.EUR]: '€',
10
+ };
@@ -1,6 +1,3 @@
1
- /// <reference types="node/http" />
2
- /// <reference types="lib/logger/types" />
3
- /// <reference types="pino-http" />
4
1
  declare const getRequestTracerId: () => string;
5
2
  declare const getRequestTracerMixin: () => {
6
3
  reqId: {};
@@ -8,5 +5,5 @@ declare const getRequestTracerMixin: () => {
8
5
  reqId?: undefined;
9
6
  };
10
7
  declare const getRequestIdHeader: () => object;
11
- declare const requestTracerMiddleware: () => (req: import("http").IncomingMessage, res: import("http").ServerResponse<import("http").IncomingMessage>, next: (err?: any) => void) => void;
8
+ declare const requestTracerMiddleware: () => (req: import("http").IncomingMessage, res: import("http").ServerResponse, next: (err?: any) => void) => void;
12
9
  export { getRequestTracerId, getRequestTracerMixin, getRequestIdHeader, requestTracerMiddleware, };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lucaapp/service-utils",
3
- "version": "1.56.7",
3
+ "version": "1.57.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [
@@ -55,8 +55,8 @@
55
55
  "@types/pino-http": "5.8.4",
56
56
  "@types/supertest": "2.0.11",
57
57
  "@types/uuid": "^8.3.4",
58
- "@typescript-eslint/eslint-plugin": "^7.1.1",
59
- "@typescript-eslint/parser": "^7.1.1",
58
+ "@typescript-eslint/eslint-plugin": "^7.15.0",
59
+ "@typescript-eslint/parser": "^7.15.0",
60
60
  "@vitest/coverage-v8": "1.4.0",
61
61
  "conventional-changelog-conventionalcommits": "^5.0.0",
62
62
  "eslint": "8.57.0",
@@ -67,7 +67,7 @@
67
67
  "semantic-release": "^19.0.3",
68
68
  "semantic-release-monorepo": "^7.0.5",
69
69
  "supertest": "^6.3.3",
70
- "typescript": "5.3.3",
70
+ "typescript": "5.5.3",
71
71
  "vite-tsconfig-paths": "4.3.2"
72
72
  },
73
73
  "resolutions": {