@bgord/tools 0.15.1 → 0.16.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.
- package/dist/basename.vo.d.ts +11 -2
- package/dist/basename.vo.js +22 -13
- package/dist/date-calculator.service.d.ts +2 -2
- package/dist/date-calculator.service.js +10 -11
- package/dist/date-range.vo.d.ts +1 -0
- package/dist/date-range.vo.js +2 -1
- package/dist/day-iso-id.vo.d.ts +3 -0
- package/dist/day-iso-id.vo.js +4 -4
- package/dist/day.vo.js +12 -10
- package/dist/directory-path-absolute.vo.d.ts +5 -0
- package/dist/directory-path-absolute.vo.js +11 -5
- package/dist/directory-path-relative.vo.d.ts +6 -0
- package/dist/directory-path-relative.vo.js +12 -6
- package/dist/dll.service.js +37 -31
- package/dist/extension.vo.d.ts +6 -2
- package/dist/extension.vo.js +11 -9
- package/dist/file-path-absolute-schema.vo.d.ts +5 -0
- package/dist/file-path-absolute-schema.vo.js +12 -6
- package/dist/file-path-relative-schema.vo.d.ts +6 -1
- package/dist/file-path-relative-schema.vo.js +10 -6
- package/dist/file-path.vo.js +4 -4
- package/dist/filename-from-string.vo.d.ts +6 -4
- package/dist/filename-from-string.vo.js +15 -14
- package/dist/filename-suffix.vo.d.ts +4 -2
- package/dist/filename-suffix.vo.js +5 -3
- package/dist/filename.vo.d.ts +2 -2
- package/dist/filename.vo.js +9 -9
- package/dist/height.vo.d.ts +6 -4
- package/dist/height.vo.js +56 -51
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/language.vo.d.ts +1 -1
- package/dist/language.vo.js +1 -2
- package/dist/mime.vo.d.ts +3 -1
- package/dist/mime.vo.js +8 -6
- package/dist/month-iso-id.vo.d.ts +3 -0
- package/dist/month-iso-id.vo.js +7 -12
- package/dist/month.vo.js +15 -13
- package/dist/object-key.vo.d.ts +5 -0
- package/dist/object-key.vo.js +16 -6
- package/dist/package-version.vo.d.ts +3 -0
- package/dist/package-version.vo.js +12 -34
- package/dist/pagination.service.d.ts +1 -1
- package/dist/pagination.service.js +11 -11
- package/dist/quarter-iso-id.vo.d.ts +3 -0
- package/dist/quarter-iso-id.vo.js +8 -7
- package/dist/rate-limiter.service.d.ts +3 -2
- package/dist/rate-limiter.service.js +4 -2
- package/dist/reordering.service.d.ts +20 -2
- package/dist/reordering.service.js +49 -29
- package/dist/revision.vo.d.ts +8 -3
- package/dist/revision.vo.js +13 -6
- package/dist/rounding.adapter.js +1 -2
- package/dist/size.vo.d.ts +1 -0
- package/dist/size.vo.js +4 -7
- package/dist/streak-calculator.service.d.ts +3 -4
- package/dist/streak-calculator.service.js +11 -17
- package/dist/time-zone-offset-value.vo.d.ts +1 -1
- package/dist/time-zone-offset-value.vo.js +1 -7
- package/dist/time.service.d.ts +11 -6
- package/dist/time.service.js +31 -18
- package/dist/timezone.vo.js +1 -3
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/week-iso-id.vo.d.ts +3 -0
- package/dist/week-iso-id.vo.js +4 -4
- package/dist/week.vo.js +1 -1
- package/dist/weekday.vo.d.ts +7 -6
- package/dist/weekday.vo.js +20 -13
- package/dist/weight.vo.d.ts +12 -0
- package/dist/weight.vo.js +37 -27
- package/dist/year-iso-id.vo.d.ts +3 -0
- package/dist/year-iso-id.vo.js +4 -6
- package/dist/year.vo.d.ts +2 -0
- package/dist/year.vo.js +4 -2
- package/package.json +1 -1
- package/readme.md +0 -1
- package/src/basename.vo.ts +25 -14
- package/src/clock.vo.ts +1 -0
- package/src/date-calculator.service.ts +10 -15
- package/src/date-range.vo.ts +3 -1
- package/src/day-iso-id.vo.ts +9 -10
- package/src/day.vo.ts +17 -10
- package/src/directory-path-absolute.vo.ts +12 -5
- package/src/directory-path-relative.vo.ts +13 -6
- package/src/dll.service.ts +45 -43
- package/src/extension.vo.ts +14 -12
- package/src/file-path-absolute-schema.vo.ts +15 -6
- package/src/file-path-relative-schema.vo.ts +13 -6
- package/src/file-path.vo.ts +15 -11
- package/src/filename-from-string.vo.ts +20 -15
- package/src/filename-suffix.vo.ts +8 -4
- package/src/filename.vo.ts +14 -15
- package/src/height.vo.ts +71 -53
- package/src/index.ts +0 -1
- package/src/language.vo.ts +1 -2
- package/src/mime.vo.ts +10 -7
- package/src/month-iso-id.vo.ts +10 -20
- package/src/month.vo.ts +19 -13
- package/src/object-key.vo.ts +21 -7
- package/src/outlier-detector.service.ts +1 -0
- package/src/package-version.vo.ts +18 -47
- package/src/pagination.service.ts +15 -13
- package/src/quarter-iso-id.vo.ts +11 -13
- package/src/quarter.vo.ts +3 -0
- package/src/rate-limiter.service.ts +7 -7
- package/src/reordering.service.ts +52 -38
- package/src/revision.vo.ts +17 -8
- package/src/rounding.adapter.ts +1 -3
- package/src/size.vo.ts +6 -16
- package/src/streak-calculator.service.ts +12 -17
- package/src/time-zone-offset-value.vo.ts +2 -7
- package/src/time.service.ts +43 -45
- package/src/timezone.vo.ts +1 -3
- package/src/week-iso-id.vo.ts +13 -14
- package/src/week.vo.ts +4 -2
- package/src/weekday.vo.ts +27 -13
- package/src/weight.vo.ts +49 -30
- package/src/year-iso-id.vo.ts +6 -9
- package/src/year.vo.ts +12 -2
- package/dist/stepper.service.d.ts +0 -23
- package/dist/stepper.service.js +0 -33
- package/src/stepper.service.ts +0 -43
package/dist/filename.vo.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type BasenameType } from "./basename.vo";
|
|
2
2
|
import { type ExtensionType } from "./extension.vo";
|
|
3
|
-
import { type
|
|
3
|
+
import { type FilenameSuffixType } from "./filename-suffix.vo";
|
|
4
4
|
export declare class Filename {
|
|
5
5
|
private readonly basename;
|
|
6
6
|
private readonly extension;
|
|
@@ -14,5 +14,5 @@ export declare class Filename {
|
|
|
14
14
|
withExtension(extension: ExtensionType): Filename;
|
|
15
15
|
withBasename(basename: BasenameType): Filename;
|
|
16
16
|
withSuffix(candidate: string): Filename;
|
|
17
|
-
withSuffixSafe(suffix:
|
|
17
|
+
withSuffixSafe(suffix: FilenameSuffixType): Filename;
|
|
18
18
|
}
|
package/dist/filename.vo.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { Basename } from "./basename.vo";
|
|
2
|
+
import { Extension } from "./extension.vo";
|
|
3
|
+
import { FilenameFromString } from "./filename-from-string.vo";
|
|
4
|
+
import { FilenameSuffix } from "./filename-suffix.vo";
|
|
5
5
|
export class Filename {
|
|
6
6
|
basename;
|
|
7
7
|
extension;
|
|
@@ -10,13 +10,13 @@ export class Filename {
|
|
|
10
10
|
this.extension = extension;
|
|
11
11
|
}
|
|
12
12
|
static fromParts(basename, extension) {
|
|
13
|
-
return new Filename(
|
|
13
|
+
return new Filename(Basename.parse(basename), Extension.parse(extension));
|
|
14
14
|
}
|
|
15
15
|
static fromPartsSafe(basename, extension) {
|
|
16
16
|
return new Filename(basename, extension);
|
|
17
17
|
}
|
|
18
18
|
static fromString(candidate) {
|
|
19
|
-
const { basename, extension } =
|
|
19
|
+
const { basename, extension } = FilenameFromString.parse(candidate);
|
|
20
20
|
return new Filename(basename, extension);
|
|
21
21
|
}
|
|
22
22
|
get() {
|
|
@@ -35,12 +35,12 @@ export class Filename {
|
|
|
35
35
|
return new Filename(basename, this.extension);
|
|
36
36
|
}
|
|
37
37
|
withSuffix(candidate) {
|
|
38
|
-
const suffix =
|
|
39
|
-
const basename =
|
|
38
|
+
const suffix = FilenameSuffix.parse(candidate);
|
|
39
|
+
const basename = Basename.parse(`${this.basename}${suffix}`);
|
|
40
40
|
return new Filename(basename, this.extension);
|
|
41
41
|
}
|
|
42
42
|
withSuffixSafe(suffix) {
|
|
43
|
-
const basename =
|
|
43
|
+
const basename = Basename.parse(`${this.basename}${suffix}`);
|
|
44
44
|
return new Filename(basename, this.extension);
|
|
45
45
|
}
|
|
46
46
|
}
|
package/dist/height.vo.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export declare class Height {
|
|
|
13
13
|
static fromFeetInches(feet: number, inches?: number, rounding?: RoundingPort): Height;
|
|
14
14
|
static fromMillimeters(millimeters: number, rounding?: RoundingPort): Height;
|
|
15
15
|
static zero(): Height;
|
|
16
|
+
get(): number;
|
|
16
17
|
toMillimeters(): number;
|
|
17
18
|
toCentimeters(rounding?: RoundingPort): number;
|
|
18
19
|
toFeetInches(rounding?: RoundingPort): {
|
|
@@ -20,10 +21,11 @@ export declare class Height {
|
|
|
20
21
|
inches: number;
|
|
21
22
|
};
|
|
22
23
|
format(unit: HeightUnit, rounding?: RoundingPort): string;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
toString(): string;
|
|
25
|
+
equals(another: Height): boolean;
|
|
26
|
+
compare(another: Height): -1 | 0 | 1;
|
|
27
|
+
greaterThan(another: Height): boolean;
|
|
28
|
+
lessThan(another: Height): boolean;
|
|
27
29
|
isZero(): boolean;
|
|
28
30
|
toJSON(): {
|
|
29
31
|
mm: number;
|
package/dist/height.vo.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
2
|
import { RoundToDecimal, RoundToNearest } from "./rounding.adapter";
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
const NonFiniteNumberError = { error: "number.non_finite" };
|
|
4
|
+
const NumberNegativeError = { error: "number.negative" };
|
|
5
|
+
const MillimetersIntegerNonNegativeError = { error: "millimeters.integer_non_negative" };
|
|
6
|
+
const IntegerNonNegativeError = { error: "integer.non_negative" };
|
|
7
|
+
const HeightFiniteNumber = z.number(NonFiniteNumberError).refine(Number.isFinite, NonFiniteNumberError);
|
|
8
|
+
const HeightNonNegativeQuantity = HeightFiniteNumber.min(0, NumberNegativeError);
|
|
9
|
+
const HeightCanonicalMillimeters = HeightFiniteNumber.int(MillimetersIntegerNonNegativeError).min(0, MillimetersIntegerNonNegativeError);
|
|
10
|
+
const HeightRoundedWholeInches = HeightFiniteNumber.int(IntegerNonNegativeError).min(0, IntegerNonNegativeError);
|
|
11
11
|
export var HeightUnit;
|
|
12
12
|
(function (HeightUnit) {
|
|
13
13
|
HeightUnit["cm"] = "cm";
|
|
@@ -22,71 +22,76 @@ export class Height {
|
|
|
22
22
|
this.millimeters = millimeters;
|
|
23
23
|
}
|
|
24
24
|
static fromCentimeters(centimeters, rounding = new RoundToNearest()) {
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
return new Height(
|
|
25
|
+
const validatedCentimeters = HeightNonNegativeQuantity.parse(centimeters);
|
|
26
|
+
const millimetersFloat = validatedCentimeters * Height.MILLIMETERS_PER_CENTIMETER;
|
|
27
|
+
const millimetersRounded = rounding.round(millimetersFloat);
|
|
28
|
+
const validatedMillimeters = HeightCanonicalMillimeters.parse(millimetersRounded);
|
|
29
|
+
return new Height(validatedMillimeters);
|
|
30
30
|
}
|
|
31
31
|
static fromFeetInches(feet, inches = 0, rounding = new RoundToNearest()) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const totalInches =
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
return new Height(
|
|
32
|
+
const validatedFeet = HeightNonNegativeQuantity.parse(feet);
|
|
33
|
+
const validatedInches = HeightNonNegativeQuantity.parse(inches);
|
|
34
|
+
const totalInches = validatedFeet * Height.INCHES_PER_FOOT + validatedInches;
|
|
35
|
+
const millimetersFloat = totalInches * Height.MILLIMETERS_PER_INCH;
|
|
36
|
+
const millimetersRounded = rounding.round(millimetersFloat);
|
|
37
|
+
const validatedMillimeters = HeightCanonicalMillimeters.parse(millimetersRounded);
|
|
38
|
+
return new Height(validatedMillimeters);
|
|
39
39
|
}
|
|
40
40
|
static fromMillimeters(millimeters, rounding = new RoundToNearest()) {
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
return new Height(
|
|
41
|
+
const validatedMillimetersInput = HeightNonNegativeQuantity.parse(millimeters);
|
|
42
|
+
const millimetersRounded = rounding.round(validatedMillimetersInput);
|
|
43
|
+
const validatedMillimeters = HeightCanonicalMillimeters.parse(millimetersRounded);
|
|
44
|
+
return new Height(validatedMillimeters);
|
|
45
45
|
}
|
|
46
46
|
static zero() {
|
|
47
47
|
return new Height(0);
|
|
48
48
|
}
|
|
49
|
+
get() {
|
|
50
|
+
return this.millimeters;
|
|
51
|
+
}
|
|
49
52
|
toMillimeters() {
|
|
50
53
|
return this.millimeters;
|
|
51
54
|
}
|
|
52
55
|
toCentimeters(rounding) {
|
|
53
|
-
const
|
|
54
|
-
|
|
56
|
+
const centimeters = this.millimeters / Height.MILLIMETERS_PER_CENTIMETER;
|
|
57
|
+
if (rounding)
|
|
58
|
+
return rounding.round(centimeters);
|
|
59
|
+
return centimeters;
|
|
55
60
|
}
|
|
56
61
|
toFeetInches(rounding = new RoundToNearest()) {
|
|
57
62
|
const totalInchesFloat = this.millimeters / Height.MILLIMETERS_PER_INCH;
|
|
58
63
|
const totalInchesRounded = rounding.round(totalInchesFloat);
|
|
59
|
-
const
|
|
60
|
-
const feet = (
|
|
61
|
-
const inches =
|
|
64
|
+
const totalWholeInches = HeightRoundedWholeInches.parse(totalInchesRounded);
|
|
65
|
+
const feet = Math.floor(totalWholeInches / Height.INCHES_PER_FOOT);
|
|
66
|
+
const inches = totalWholeInches % Height.INCHES_PER_FOOT;
|
|
62
67
|
return { feet, inches };
|
|
63
68
|
}
|
|
64
69
|
format(unit, rounding) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
equals(
|
|
78
|
-
return this.millimeters ===
|
|
79
|
-
}
|
|
80
|
-
compare(
|
|
81
|
-
if (this.equals(
|
|
70
|
+
if (unit === HeightUnit.cm) {
|
|
71
|
+
const chosen = rounding ?? new RoundToDecimal(1);
|
|
72
|
+
const value = this.toCentimeters(chosen);
|
|
73
|
+
return `${value} cm`;
|
|
74
|
+
}
|
|
75
|
+
const chosen = rounding ?? new RoundToNearest();
|
|
76
|
+
const parts = this.toFeetInches(chosen);
|
|
77
|
+
return `${parts.feet}′${parts.inches}″`;
|
|
78
|
+
}
|
|
79
|
+
toString() {
|
|
80
|
+
return this.format(HeightUnit.cm, new RoundToDecimal(1));
|
|
81
|
+
}
|
|
82
|
+
equals(another) {
|
|
83
|
+
return this.millimeters === another.millimeters;
|
|
84
|
+
}
|
|
85
|
+
compare(another) {
|
|
86
|
+
if (this.equals(another))
|
|
82
87
|
return 0;
|
|
83
|
-
return this.millimeters <
|
|
88
|
+
return this.millimeters < another.millimeters ? -1 : 1;
|
|
84
89
|
}
|
|
85
|
-
greaterThan(
|
|
86
|
-
return this.millimeters >
|
|
90
|
+
greaterThan(another) {
|
|
91
|
+
return this.millimeters > another.millimeters;
|
|
87
92
|
}
|
|
88
|
-
lessThan(
|
|
89
|
-
return this.millimeters <
|
|
93
|
+
lessThan(another) {
|
|
94
|
+
return this.millimeters < another.millimeters;
|
|
90
95
|
}
|
|
91
96
|
isZero() {
|
|
92
97
|
return this.millimeters === 0;
|
package/dist/index.d.ts
CHANGED
|
@@ -53,7 +53,6 @@ export * from "./rounding.adapter";
|
|
|
53
53
|
export * from "./rounding.port";
|
|
54
54
|
export * from "./simple-linear-regression.service";
|
|
55
55
|
export * from "./size.vo";
|
|
56
|
-
export * from "./stepper.service";
|
|
57
56
|
export * from "./stopwatch.service";
|
|
58
57
|
export * from "./streak-calculator.service";
|
|
59
58
|
export * from "./sum.service";
|
package/dist/index.js
CHANGED
|
@@ -53,7 +53,6 @@ export * from "./rounding.adapter";
|
|
|
53
53
|
export * from "./rounding.port";
|
|
54
54
|
export * from "./simple-linear-regression.service";
|
|
55
55
|
export * from "./size.vo";
|
|
56
|
-
export * from "./stepper.service";
|
|
57
56
|
export * from "./stopwatch.service";
|
|
58
57
|
export * from "./streak-calculator.service";
|
|
59
58
|
export * from "./sum.service";
|
package/dist/language.vo.d.ts
CHANGED
|
@@ -2,5 +2,5 @@ import { z } from "zod/v4";
|
|
|
2
2
|
export declare const LanguageError: {
|
|
3
3
|
readonly error: "invalid.language";
|
|
4
4
|
};
|
|
5
|
-
export declare const Language: z.
|
|
5
|
+
export declare const Language: z.ZodString;
|
|
6
6
|
export type LanguageType = z.infer<typeof Language>;
|
package/dist/language.vo.js
CHANGED
package/dist/mime.vo.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { type ExtensionType } from "./extension.vo";
|
|
|
2
2
|
export type MimeRawType = string;
|
|
3
3
|
type MimeTypeType = string;
|
|
4
4
|
type MimeSubtypeType = string;
|
|
5
|
+
export declare const InvalidMimeErrorMessage: "invalid.mime";
|
|
6
|
+
export declare const NotAcceptedMimeErrorMessage: "mime.not.accepted";
|
|
5
7
|
export declare class Mime {
|
|
6
8
|
readonly raw: MimeRawType;
|
|
7
9
|
readonly type: MimeTypeType;
|
|
@@ -16,7 +18,7 @@ export declare class InvalidMimeError extends Error {
|
|
|
16
18
|
}
|
|
17
19
|
export declare class NotAcceptedMimeError extends Error {
|
|
18
20
|
mime: MimeRawType;
|
|
19
|
-
constructor(
|
|
21
|
+
constructor(mimeValue: MimeRawType);
|
|
20
22
|
}
|
|
21
23
|
export declare const MIMES: {
|
|
22
24
|
csv: Mime;
|
package/dist/mime.vo.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as mime from "mime-types";
|
|
2
|
-
import {
|
|
2
|
+
import { Extension } from "./extension.vo";
|
|
3
|
+
export const InvalidMimeErrorMessage = "invalid.mime";
|
|
4
|
+
export const NotAcceptedMimeErrorMessage = "mime.not.accepted";
|
|
3
5
|
export class Mime {
|
|
4
6
|
raw;
|
|
5
7
|
type;
|
|
@@ -26,21 +28,21 @@ export class Mime {
|
|
|
26
28
|
return this.subtype === another.subtype || this.subtype === "*";
|
|
27
29
|
}
|
|
28
30
|
toExtension() {
|
|
29
|
-
return
|
|
31
|
+
return Extension.parse(mime.extension(this.raw));
|
|
30
32
|
}
|
|
31
33
|
}
|
|
32
34
|
export class InvalidMimeError extends Error {
|
|
33
35
|
constructor() {
|
|
34
|
-
super();
|
|
36
|
+
super(InvalidMimeErrorMessage);
|
|
35
37
|
Object.setPrototypeOf(this, InvalidMimeError.prototype);
|
|
36
38
|
}
|
|
37
39
|
}
|
|
38
40
|
export class NotAcceptedMimeError extends Error {
|
|
39
41
|
mime;
|
|
40
|
-
constructor(
|
|
41
|
-
super();
|
|
42
|
+
constructor(mimeValue) {
|
|
43
|
+
super(NotAcceptedMimeErrorMessage);
|
|
42
44
|
Object.setPrototypeOf(this, NotAcceptedMimeError.prototype);
|
|
43
|
-
this.mime =
|
|
45
|
+
this.mime = mimeValue;
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
48
|
export const MIMES = {
|
package/dist/month-iso-id.vo.js
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
+
export const MonthIsoIdError = { error: "month-iso-id.invalid" };
|
|
2
3
|
export const MonthIsoId = z
|
|
3
|
-
.string()
|
|
4
|
-
.regex(/^\d{4}-\d{2}
|
|
4
|
+
.string(MonthIsoIdError)
|
|
5
|
+
.regex(/^\d{4}-\d{2}$/, MonthIsoIdError)
|
|
5
6
|
.refine((value) => {
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
m.length === 2 &&
|
|
11
|
-
Number.isInteger(year) &&
|
|
12
|
-
Number.isInteger(month) &&
|
|
13
|
-
month >= 1 &&
|
|
14
|
-
month <= 12);
|
|
15
|
-
}, { message: "month-iso-id.invalid" });
|
|
7
|
+
const year = Number(value.slice(0, 4));
|
|
8
|
+
const month = Number(value.slice(5, 7));
|
|
9
|
+
return Number.isInteger(year) && Number.isInteger(month) && month >= 1 && month <= 12;
|
|
10
|
+
}, MonthIsoIdError);
|
package/dist/month.vo.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/month.vo.ts
|
|
2
2
|
import { DateRange } from "./date-range.vo";
|
|
3
3
|
import { MonthIsoId } from "./month-iso-id.vo";
|
|
4
4
|
import { Timestamp } from "./timestamp.vo";
|
|
@@ -7,28 +7,30 @@ export class Month extends DateRange {
|
|
|
7
7
|
return new Date(this.getStart()).toISOString().slice(0, 7);
|
|
8
8
|
}
|
|
9
9
|
previous() {
|
|
10
|
-
|
|
11
|
-
return Month.fromTimestamp(Timestamp.parse(shifted));
|
|
10
|
+
return Month.fromTimestamp(Timestamp.parse(this.getStart() - 1));
|
|
12
11
|
}
|
|
13
12
|
next() {
|
|
14
|
-
|
|
15
|
-
return Month.fromTimestamp(Timestamp.parse(shifted));
|
|
13
|
+
return Month.fromTimestamp(Timestamp.parse(this.getEnd() + 1));
|
|
16
14
|
}
|
|
17
15
|
shift(count) {
|
|
18
|
-
const
|
|
19
|
-
|
|
16
|
+
const date = new Date(this.getStart());
|
|
17
|
+
date.setUTCMonth(date.getUTCMonth() + count);
|
|
18
|
+
return Month.fromTimestamp(Timestamp.parse(date.getTime()));
|
|
20
19
|
}
|
|
21
20
|
static fromTimestamp(timestamp) {
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
return new Month(start, end);
|
|
21
|
+
const isoMonth = new Date(timestamp).toISOString().slice(0, 7);
|
|
22
|
+
return Month.fromIsoId(isoMonth);
|
|
25
23
|
}
|
|
26
24
|
static fromNow(now) {
|
|
27
25
|
return Month.fromTimestamp(now);
|
|
28
26
|
}
|
|
29
27
|
static fromIsoId(iso) {
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
|
|
28
|
+
const validated = MonthIsoId.parse(iso);
|
|
29
|
+
const year = Number(validated.slice(0, 4));
|
|
30
|
+
const monthIndex = Number(validated.slice(5, 7)) - 1;
|
|
31
|
+
const startUtc = Date.UTC(year, monthIndex, 1);
|
|
32
|
+
const nextStartUtc = Date.UTC(year, monthIndex + 1, 1);
|
|
33
|
+
const endUtc = nextStartUtc - 1;
|
|
34
|
+
return new Month(Timestamp.parse(startUtc), Timestamp.parse(endUtc));
|
|
33
35
|
}
|
|
34
36
|
}
|
package/dist/object-key.vo.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
+
export declare const ObjectKeyMustNotStartWithSlashError: "obj_key_must_not_start_with_slash";
|
|
3
|
+
export declare const ObjectKeyBackslashForbiddenError: "obj_key_backslash_forbidden";
|
|
4
|
+
export declare const ObjectKeyControlCharsForbiddenError: "obj_key_control_chars_forbidden";
|
|
5
|
+
export declare const ObjectKeyEmptyError: "obj_key_empty";
|
|
6
|
+
export declare const ObjectKeyBadSegmentsError: "obj_key_bad_segments";
|
|
2
7
|
export declare const ObjectKey: z.core.$ZodBranded<z.ZodString, "object_key">;
|
|
3
8
|
export type ObjectKeyType = z.infer<typeof ObjectKey>;
|
package/dist/object-key.vo.js
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
+
export const ObjectKeyMustNotStartWithSlashError = "obj_key_must_not_start_with_slash";
|
|
3
|
+
export const ObjectKeyBackslashForbiddenError = "obj_key_backslash_forbidden";
|
|
4
|
+
export const ObjectKeyControlCharsForbiddenError = "obj_key_control_chars_forbidden";
|
|
5
|
+
export const ObjectKeyEmptyError = "obj_key_empty";
|
|
6
|
+
export const ObjectKeyBadSegmentsError = "obj_key_bad_segments";
|
|
7
|
+
// biome-ignore lint: lint/suspicious/noControlCharactersInRegex
|
|
8
|
+
const CONTROL_CHARS_REGEX = /[\u0000-\u001F\u007F]/;
|
|
9
|
+
const SEGMENT_ALLOWED_REGEX = /^[a-z0-9._-]+$/;
|
|
2
10
|
export const ObjectKey = z
|
|
3
11
|
.string()
|
|
4
12
|
.trim()
|
|
5
|
-
|
|
6
|
-
.refine((
|
|
7
|
-
|
|
8
|
-
.refine((
|
|
9
|
-
.refine((
|
|
10
|
-
.refine((
|
|
13
|
+
// fastest early exits first:
|
|
14
|
+
.refine((value) => value.length > 0, ObjectKeyEmptyError)
|
|
15
|
+
.refine((value) => !value.startsWith("/"), ObjectKeyMustNotStartWithSlashError)
|
|
16
|
+
.refine((value) => !value.includes("\\"), ObjectKeyBackslashForbiddenError)
|
|
17
|
+
.refine((value) => !CONTROL_CHARS_REGEX.test(value), ObjectKeyControlCharsForbiddenError)
|
|
18
|
+
.refine((value) => value
|
|
19
|
+
.split("/")
|
|
20
|
+
.every((segment) => SEGMENT_ALLOWED_REGEX.test(segment) && segment !== "." && segment !== ".."), ObjectKeyBadSegmentsError)
|
|
11
21
|
.brand("object_key");
|
|
@@ -2,6 +2,9 @@ import { z } from "zod/v4";
|
|
|
2
2
|
type MajorType = number;
|
|
3
3
|
type MinorType = number;
|
|
4
4
|
type PatchType = number;
|
|
5
|
+
export declare const PackageVersionError: {
|
|
6
|
+
readonly error: "package.version.error";
|
|
7
|
+
};
|
|
5
8
|
export declare const PackageVersionValue: z.core.$ZodBranded<z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
6
9
|
major: number;
|
|
7
10
|
minor: number;
|
|
@@ -1,36 +1,14 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
+
export const PackageVersionError = { error: "package.version.error" };
|
|
2
3
|
export const PackageVersionValue = z
|
|
3
|
-
.string()
|
|
4
|
-
.
|
|
5
|
-
.refine((value) => {
|
|
6
|
-
try {
|
|
7
|
-
if (!value.startsWith("v"))
|
|
8
|
-
return false;
|
|
9
|
-
const [, version] = value.split("v");
|
|
10
|
-
if (!version)
|
|
11
|
-
return false;
|
|
12
|
-
const [major, minor, patch] = version.split(".");
|
|
13
|
-
if (!(major && minor && patch))
|
|
14
|
-
return false;
|
|
15
|
-
if (!(Number.isInteger(Number(major)) &&
|
|
16
|
-
Number.isInteger(Number(minor)) &&
|
|
17
|
-
Number.isInteger(Number(patch)))) {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
return true;
|
|
21
|
-
}
|
|
22
|
-
catch (_error) {
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
}, { message: "package.version.error" })
|
|
4
|
+
.string(PackageVersionError)
|
|
5
|
+
.regex(/^v(\d+)\.(\d+)\.(\d+)$/, PackageVersionError)
|
|
26
6
|
.transform((value) => {
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
patch: Number(patch),
|
|
33
|
-
};
|
|
7
|
+
const match = /^v(\d+)\.(\d+)\.(\d+)$/.exec(value);
|
|
8
|
+
const major = Number(match[1]);
|
|
9
|
+
const minor = Number(match[2]);
|
|
10
|
+
const patch = Number(match[3]);
|
|
11
|
+
return { major, minor, patch };
|
|
34
12
|
})
|
|
35
13
|
.brand("PackageVersionValue");
|
|
36
14
|
export class PackageVersion {
|
|
@@ -61,11 +39,11 @@ export class PackageVersion {
|
|
|
61
39
|
return `${this.major}.${this.minor}.${this.patch}`;
|
|
62
40
|
}
|
|
63
41
|
static fromStringWithV(value) {
|
|
64
|
-
const
|
|
65
|
-
return new PackageVersion(
|
|
42
|
+
const parsed = PackageVersionValue.parse(value);
|
|
43
|
+
return new PackageVersion(parsed.major, parsed.minor, parsed.patch);
|
|
66
44
|
}
|
|
67
45
|
static fromString(value) {
|
|
68
|
-
const
|
|
69
|
-
return new PackageVersion(
|
|
46
|
+
const parsed = PackageVersionValue.parse(`v${value}`);
|
|
47
|
+
return new PackageVersion(parsed.major, parsed.minor, parsed.patch);
|
|
70
48
|
}
|
|
71
49
|
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
-
const
|
|
3
|
-
const
|
|
2
|
+
const PaginationTakeError = { error: "pagination.take.invalid" };
|
|
3
|
+
const PaginationSkipError = { error: "pagination.skip.invalid" };
|
|
4
|
+
const PaginationPageError = { error: "pagination.page.invalid" };
|
|
5
|
+
const Take = z.number(PaginationTakeError).int(PaginationTakeError).gte(1, PaginationTakeError);
|
|
6
|
+
const Skip = z.number(PaginationSkipError).int(PaginationSkipError).gte(0, PaginationSkipError);
|
|
4
7
|
const Page = z.coerce
|
|
5
|
-
.number()
|
|
6
|
-
.int()
|
|
8
|
+
.number(PaginationPageError)
|
|
9
|
+
.int(PaginationPageError)
|
|
7
10
|
.transform((value) => (value <= 0 ? 1 : value))
|
|
8
11
|
.default(1);
|
|
9
12
|
export class Pagination {
|
|
@@ -25,13 +28,10 @@ export class Pagination {
|
|
|
25
28
|
};
|
|
26
29
|
}
|
|
27
30
|
static isExhausted(config) {
|
|
28
|
-
|
|
29
|
-
const currentPage = config.pagination.page;
|
|
30
|
-
return lastPage <= currentPage;
|
|
31
|
+
return Pagination.getLastPage(config) <= config.pagination.page;
|
|
31
32
|
}
|
|
32
33
|
static getLastPage(config) {
|
|
33
|
-
|
|
34
|
-
return Page.parse(lastPage);
|
|
34
|
+
return Page.parse(Math.ceil(config.total / config.pagination.values.take));
|
|
35
35
|
}
|
|
36
36
|
static empty = {
|
|
37
37
|
result: [],
|
|
@@ -44,7 +44,7 @@ export class Pagination {
|
|
|
44
44
|
total: 0,
|
|
45
45
|
},
|
|
46
46
|
};
|
|
47
|
-
static getFirstPage(
|
|
48
|
-
return { values: { take, skip: Skip.parse(0) }, page: Page.parse(1) };
|
|
47
|
+
static getFirstPage(input) {
|
|
48
|
+
return { values: { take: Take.parse(input.take), skip: Skip.parse(0) }, page: Page.parse(1) };
|
|
49
49
|
}
|
|
50
50
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
+
export const QuarterIsoIdError = { error: "quarter-iso-id.invalid" };
|
|
2
3
|
export const QuarterIsoId = z
|
|
3
|
-
.string()
|
|
4
|
-
.regex(/^\d{4}-Q[1-4]
|
|
4
|
+
.string(QuarterIsoIdError)
|
|
5
|
+
.regex(/^\d{4}-Q[1-4]$/, QuarterIsoIdError)
|
|
5
6
|
.refine((value) => {
|
|
6
|
-
const [
|
|
7
|
-
const year = Number(
|
|
8
|
-
const quarter = Number(
|
|
9
|
-
return
|
|
10
|
-
},
|
|
7
|
+
const [yearPart, quarterPart] = value.split("-Q");
|
|
8
|
+
const year = Number(yearPart);
|
|
9
|
+
const quarter = Number(quarterPart);
|
|
10
|
+
return Number.isInteger(year) && Number.isInteger(quarter) && quarter >= 1 && quarter <= 4;
|
|
11
|
+
}, QuarterIsoIdError);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { TimeResult } from "./time.service";
|
|
2
1
|
import { type TimestampType } from "./timestamp.vo";
|
|
3
|
-
type RateLimiterOptionsType =
|
|
2
|
+
type RateLimiterOptionsType = {
|
|
3
|
+
ms: TimestampType;
|
|
4
|
+
};
|
|
4
5
|
type RateLimiterResultSuccessType = {
|
|
5
6
|
allowed: true;
|
|
6
7
|
};
|
|
@@ -6,7 +6,7 @@ export class RateLimiter {
|
|
|
6
6
|
this.options = options;
|
|
7
7
|
}
|
|
8
8
|
verify(currentTimestampMs) {
|
|
9
|
-
if (this.lastInvocationTimestampMs
|
|
9
|
+
if (this.lastInvocationTimestampMs == null) {
|
|
10
10
|
this.lastInvocationTimestampMs = currentTimestampMs;
|
|
11
11
|
return { allowed: true };
|
|
12
12
|
}
|
|
@@ -15,6 +15,8 @@ export class RateLimiter {
|
|
|
15
15
|
this.lastInvocationTimestampMs = currentTimestampMs;
|
|
16
16
|
return { allowed: true };
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
const remainingDelta = nextAllowedTimestampMs - currentTimestampMs;
|
|
19
|
+
const remainingMs = Timestamp.parse(remainingDelta);
|
|
20
|
+
return { allowed: false, remainingMs };
|
|
19
21
|
}
|
|
20
22
|
}
|