@bgord/tools 0.17.2 → 1.0.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.
Files changed (257) hide show
  1. package/dist/age-years.vo.d.ts +11 -0
  2. package/dist/age-years.vo.js +9 -0
  3. package/dist/age.vo.d.ts +11 -16
  4. package/dist/age.vo.js +20 -31
  5. package/dist/api-key.vo.d.ts +3 -1
  6. package/dist/api-key.vo.js +10 -5
  7. package/dist/basename.vo.d.ts +9 -9
  8. package/dist/basename.vo.js +22 -22
  9. package/dist/clock.vo.d.ts +10 -4
  10. package/dist/clock.vo.js +12 -14
  11. package/dist/date-calculator.service.d.ts +2 -1
  12. package/dist/date-formatter.service.d.ts +3 -4
  13. package/dist/date-range.vo.d.ts +7 -1
  14. package/dist/date-range.vo.js +5 -2
  15. package/dist/day-iso-id.vo.d.ts +5 -2
  16. package/dist/day-iso-id.vo.js +11 -7
  17. package/dist/day.vo.d.ts +4 -3
  18. package/dist/day.vo.js +18 -16
  19. package/dist/directory-path-absolute.vo.d.ts +10 -6
  20. package/dist/directory-path-absolute.vo.js +19 -17
  21. package/dist/directory-path-relative.vo.d.ts +10 -7
  22. package/dist/directory-path-relative.vo.js +18 -17
  23. package/dist/division-factor.vo.d.ts +7 -0
  24. package/dist/division-factor.vo.js +9 -0
  25. package/dist/duration-ms.vo.d.ts +6 -0
  26. package/dist/duration-ms.vo.js +3 -0
  27. package/dist/duration.service.d.ts +2 -14
  28. package/dist/duration.service.js +16 -35
  29. package/dist/email-mask.service.d.ts +1 -6
  30. package/dist/email-mask.service.js +6 -8
  31. package/dist/etags.vo.d.ts +4 -3
  32. package/dist/etags.vo.js +3 -3
  33. package/dist/extension.vo.d.ts +6 -4
  34. package/dist/extension.vo.js +15 -10
  35. package/dist/feature-flag-value.vo.d.ts +10 -0
  36. package/dist/feature-flag-value.vo.js +8 -0
  37. package/dist/feature-flag.vo.d.ts +1 -7
  38. package/dist/feature-flag.vo.js +1 -7
  39. package/dist/file-path-absolute-schema.vo.d.ts +10 -7
  40. package/dist/file-path-absolute-schema.vo.js +17 -17
  41. package/dist/file-path-relative-schema.vo.d.ts +10 -7
  42. package/dist/file-path-relative-schema.vo.js +14 -12
  43. package/dist/file-path.vo.d.ts +4 -4
  44. package/dist/file-path.vo.js +8 -8
  45. package/dist/filename-from-string.vo.d.ts +4 -2
  46. package/dist/filename-from-string.vo.js +10 -8
  47. package/dist/filename-suffix.vo.d.ts +7 -3
  48. package/dist/filename-suffix.vo.js +13 -7
  49. package/dist/filename.vo.d.ts +2 -0
  50. package/dist/filename.vo.js +8 -2
  51. package/dist/height-milimiters.vo.d.ts +6 -0
  52. package/dist/height-milimiters.vo.js +10 -0
  53. package/dist/height.vo.d.ts +3 -20
  54. package/dist/height.vo.js +11 -62
  55. package/dist/hour-format.service.js +1 -1
  56. package/dist/hour-schema.vo.d.ts +7 -0
  57. package/dist/hour-schema.vo.js +8 -0
  58. package/dist/hour.vo.d.ts +4 -3
  59. package/dist/hour.vo.js +8 -8
  60. package/dist/iban-mask.service.d.ts +1 -3
  61. package/dist/iban-mask.service.js +2 -2
  62. package/dist/iban-schema.vo.d.ts +7 -0
  63. package/dist/iban-schema.vo.js +10 -0
  64. package/dist/iban.vo.d.ts +4 -10
  65. package/dist/iban.vo.js +6 -13
  66. package/dist/image.vo.d.ts +6 -4
  67. package/dist/image.vo.js +13 -12
  68. package/dist/index.d.ts +24 -2
  69. package/dist/index.js +24 -2
  70. package/dist/language.vo.d.ts +2 -1
  71. package/dist/language.vo.js +6 -4
  72. package/dist/linear-regression.service.d.ts +27 -0
  73. package/dist/{simple-linear-regression.service.js → linear-regression.service.js} +17 -15
  74. package/dist/mean.service.d.ts +3 -1
  75. package/dist/mean.service.js +3 -4
  76. package/dist/mime-types.vo.d.ts +1 -2
  77. package/dist/mime-value.vo.d.ts +9 -0
  78. package/dist/mime-value.vo.js +9 -0
  79. package/dist/mime.vo.d.ts +11 -17
  80. package/dist/mime.vo.js +10 -27
  81. package/dist/min-max-scaler.service.d.ts +7 -5
  82. package/dist/min-max-scaler.service.js +12 -10
  83. package/dist/minute-schema.vo.d.ts +7 -0
  84. package/dist/minute-schema.vo.js +8 -0
  85. package/dist/minute.vo.d.ts +4 -3
  86. package/dist/minute.vo.js +8 -8
  87. package/dist/money-amount.vo.d.ts +7 -0
  88. package/dist/money-amount.vo.js +7 -0
  89. package/dist/money.vo.d.ts +9 -18
  90. package/dist/money.vo.js +14 -27
  91. package/dist/month-iso-id.vo.d.ts +4 -2
  92. package/dist/month-iso-id.vo.js +13 -7
  93. package/dist/month.vo.d.ts +4 -3
  94. package/dist/month.vo.js +21 -21
  95. package/dist/multiplication-factor.vo.d.ts +7 -0
  96. package/dist/multiplication-factor.vo.js +9 -0
  97. package/dist/object-key.vo.d.ts +9 -6
  98. package/dist/object-key.vo.js +20 -19
  99. package/dist/outlier-detector.service.d.ts +3 -1
  100. package/dist/outlier-detector.service.js +2 -2
  101. package/dist/package-version-schema.vo.d.ts +11 -0
  102. package/dist/package-version-schema.vo.js +15 -0
  103. package/dist/package-version.vo.d.ts +11 -20
  104. package/dist/package-version.vo.js +11 -20
  105. package/dist/pagination-page.vo.d.ts +6 -0
  106. package/dist/pagination-page.vo.js +7 -0
  107. package/dist/pagination-skip.vo.d.ts +7 -0
  108. package/dist/pagination-skip.vo.js +9 -0
  109. package/dist/pagination-take.vo.d.ts +7 -0
  110. package/dist/pagination-take.vo.js +9 -0
  111. package/dist/pagination.service.d.ts +3 -8
  112. package/dist/pagination.service.js +5 -12
  113. package/dist/percentage.service.d.ts +3 -1
  114. package/dist/percentage.service.js +2 -2
  115. package/dist/population-standard-deviation.service.d.ts +3 -1
  116. package/dist/population-standard-deviation.service.js +5 -4
  117. package/dist/quarter-iso-id.vo.d.ts +3 -2
  118. package/dist/quarter-iso-id.vo.js +7 -9
  119. package/dist/quarter.vo.d.ts +2 -1
  120. package/dist/quarter.vo.js +10 -7
  121. package/dist/random.service.d.ts +3 -4
  122. package/dist/random.service.js +5 -11
  123. package/dist/rate-limiter.service.d.ts +2 -2
  124. package/dist/rate-limiter.service.js +8 -8
  125. package/dist/reordering-item-position-value.vo.d.ts +6 -0
  126. package/dist/reordering-item-position-value.vo.js +6 -0
  127. package/dist/reordering.service.d.ts +7 -23
  128. package/dist/reordering.service.js +15 -24
  129. package/dist/revision-value.vo.d.ts +7 -0
  130. package/dist/revision-value.vo.js +6 -0
  131. package/dist/revision.vo.d.ts +6 -13
  132. package/dist/revision.vo.js +10 -22
  133. package/dist/rounding.adapter.d.ts +7 -2
  134. package/dist/rounding.adapter.js +13 -5
  135. package/dist/size-bytes.vo.d.ts +6 -0
  136. package/dist/size-bytes.vo.js +7 -0
  137. package/dist/size.vo.d.ts +15 -15
  138. package/dist/size.vo.js +41 -51
  139. package/dist/stopwatch.service.d.ts +3 -1
  140. package/dist/stopwatch.service.js +2 -2
  141. package/dist/sum.service.js +8 -8
  142. package/dist/thousands-separator.service.js +4 -1
  143. package/dist/time.service.d.ts +8 -0
  144. package/dist/time.service.js +13 -0
  145. package/dist/timestamp.vo.d.ts +1 -1
  146. package/dist/timestamp.vo.js +4 -5
  147. package/dist/timezone.vo.d.ts +4 -1
  148. package/dist/timezone.vo.js +12 -6
  149. package/dist/tsconfig.tsbuildinfo +1 -1
  150. package/dist/week-iso-id.vo.d.ts +4 -2
  151. package/dist/week-iso-id.vo.js +15 -9
  152. package/dist/week.vo.d.ts +4 -3
  153. package/dist/week.vo.js +21 -22
  154. package/dist/weekday.vo.d.ts +1 -1
  155. package/dist/weekday.vo.js +6 -8
  156. package/dist/weight-grams.vo.d.ts +7 -0
  157. package/dist/weight-grams.vo.js +7 -0
  158. package/dist/weight.vo.d.ts +12 -35
  159. package/dist/weight.vo.js +23 -72
  160. package/dist/year-iso-id.vo.d.ts +3 -2
  161. package/dist/year-iso-id.vo.js +6 -4
  162. package/dist/year.vo.d.ts +5 -6
  163. package/dist/year.vo.js +21 -26
  164. package/dist/z-score.service.d.ts +3 -1
  165. package/dist/z-score.service.js +2 -2
  166. package/package.json +4 -4
  167. package/readme.md +21 -2
  168. package/src/age-years.vo.ts +14 -0
  169. package/src/age.vo.ts +22 -35
  170. package/src/api-key.vo.ts +11 -5
  171. package/src/basename.vo.ts +24 -22
  172. package/src/clock.vo.ts +16 -17
  173. package/src/date-calculator.service.ts +2 -1
  174. package/src/date-formatter.service.ts +4 -5
  175. package/src/date-range.vo.ts +6 -2
  176. package/src/day-iso-id.vo.ts +12 -8
  177. package/src/day.vo.ts +27 -24
  178. package/src/directory-path-absolute.vo.ts +23 -18
  179. package/src/directory-path-relative.vo.ts +21 -18
  180. package/src/division-factor.vo.ts +13 -0
  181. package/src/duration-ms.vo.ts +7 -0
  182. package/src/duration.service.ts +16 -40
  183. package/src/email-mask.service.ts +7 -15
  184. package/src/etags.vo.ts +4 -5
  185. package/src/extension.vo.ts +17 -10
  186. package/src/feature-flag-value.vo.ts +12 -0
  187. package/src/feature-flag.vo.ts +1 -9
  188. package/src/file-path-absolute-schema.vo.ts +18 -17
  189. package/src/file-path-relative-schema.vo.ts +15 -12
  190. package/src/file-path.vo.ts +8 -8
  191. package/src/filename-from-string.vo.ts +12 -9
  192. package/src/filename-suffix.vo.ts +14 -7
  193. package/src/filename.vo.ts +11 -2
  194. package/src/height-milimiters.vo.ts +12 -0
  195. package/src/height.vo.ts +12 -83
  196. package/src/hour-format.service.ts +2 -1
  197. package/src/hour-schema.vo.ts +12 -0
  198. package/src/hour.vo.ts +12 -12
  199. package/src/iban-mask.service.ts +3 -5
  200. package/src/iban-schema.vo.ts +15 -0
  201. package/src/iban.vo.ts +9 -22
  202. package/src/image.vo.ts +14 -12
  203. package/src/index.ts +24 -2
  204. package/src/language.vo.ts +7 -4
  205. package/src/linear-regression.service.ts +71 -0
  206. package/src/mean.service.ts +3 -5
  207. package/src/mime-types.vo.ts +1 -3
  208. package/src/mime-value.vo.ts +12 -0
  209. package/src/mime.vo.ts +12 -33
  210. package/src/min-max-scaler.service.ts +13 -11
  211. package/src/minute-schema.vo.ts +12 -0
  212. package/src/minute.vo.ts +12 -12
  213. package/src/money-amount.vo.ts +11 -0
  214. package/src/money.vo.ts +20 -38
  215. package/src/month-iso-id.vo.ts +14 -7
  216. package/src/month.vo.ts +25 -24
  217. package/src/multiplication-factor.vo.ts +13 -0
  218. package/src/object-key.vo.ts +25 -21
  219. package/src/outlier-detector.service.ts +2 -2
  220. package/src/package-version-schema.vo.ts +21 -0
  221. package/src/package-version.vo.ts +17 -33
  222. package/src/pagination-page.vo.ts +11 -0
  223. package/src/pagination-skip.vo.ts +13 -0
  224. package/src/pagination-take.vo.ts +13 -0
  225. package/src/pagination.service.ts +5 -22
  226. package/src/percentage.service.ts +2 -2
  227. package/src/population-standard-deviation.service.ts +5 -4
  228. package/src/quarter-iso-id.vo.ts +7 -10
  229. package/src/quarter.vo.ts +14 -9
  230. package/src/random.service.ts +6 -9
  231. package/src/rate-limiter.service.ts +9 -8
  232. package/src/reordering-item-position-value.vo.ts +10 -0
  233. package/src/reordering.service.ts +19 -28
  234. package/src/revision-value.vo.ts +10 -0
  235. package/src/revision.vo.ts +10 -25
  236. package/src/rounding.adapter.ts +16 -3
  237. package/src/size-bytes.vo.ts +11 -0
  238. package/src/size.vo.ts +43 -54
  239. package/src/stopwatch.service.ts +3 -3
  240. package/src/sum.service.ts +8 -8
  241. package/src/thousands-separator.service.ts +4 -1
  242. package/src/time.service.ts +15 -0
  243. package/src/timestamp.vo.ts +4 -5
  244. package/src/timezone.vo.ts +12 -6
  245. package/src/week-iso-id.vo.ts +16 -12
  246. package/src/week.vo.ts +26 -28
  247. package/src/weekday.vo.ts +6 -9
  248. package/src/weight-grams.vo.ts +11 -0
  249. package/src/weight.vo.ts +28 -85
  250. package/src/year-iso-id.vo.ts +7 -4
  251. package/src/year.vo.ts +27 -33
  252. package/src/z-score.service.ts +2 -2
  253. package/dist/simple-linear-regression.service.d.ts +0 -25
  254. package/dist/streak-calculator.service.d.ts +0 -13
  255. package/dist/streak-calculator.service.js +0 -22
  256. package/src/simple-linear-regression.service.ts +0 -69
  257. package/src/streak-calculator.service.ts +0 -32
@@ -0,0 +1,11 @@
1
+ import { z } from "zod/v4";
2
+ export declare const AgeYearsError: {
3
+ readonly Type: "age.years.type";
4
+ readonly Invalid: "age.years.invalid";
5
+ };
6
+ export declare const AgeYearsConstraints: {
7
+ min: number;
8
+ max: number;
9
+ };
10
+ export declare const AgeYears: z.core.$ZodBranded<z.ZodNumber, "AgeYears">;
11
+ export type AgeYearsType = z.infer<typeof AgeYears>;
@@ -0,0 +1,9 @@
1
+ import { z } from "zod/v4";
2
+ export const AgeYearsError = { Type: "age.years.type", Invalid: "age.years.invalid" };
3
+ export const AgeYearsConstraints = { min: 1, max: 130 };
4
+ export const AgeYears = z
5
+ .number(AgeYearsError.Type)
6
+ .int(AgeYearsError.Type)
7
+ .min(1, AgeYearsError.Invalid)
8
+ .max(130, AgeYearsError.Invalid)
9
+ .brand("AgeYears");
package/dist/age.vo.d.ts CHANGED
@@ -1,31 +1,26 @@
1
- import { z } from "zod/v4";
2
1
  import type { TimestampType } from "./timestamp.vo";
3
- export declare const AgeValueError: {
4
- readonly error: "invalid.age";
2
+ export declare const AgeError: {
3
+ readonly FutureBirthdate: "age.future.birthdate";
5
4
  };
6
- export declare const InvalidBirthdateInFutureError: "invalid.birthdate_in_future";
7
- export declare const InvalidBirthdateError: "invalid.birthdate";
8
5
  export declare class Age {
9
6
  private readonly value;
10
- static readonly MIN = 1;
11
- static readonly MAX = 130;
12
- static readonly AgeValue: z.core.$ZodBranded<z.ZodNumber, "AgeValue">;
7
+ static readonly MIN: number;
8
+ static readonly MAX: number;
13
9
  private constructor();
14
- get(): number;
15
- compare(other: Age): -1 | 0 | 1;
16
- equals(other: Age): boolean;
17
- isOlderThan(other: Age): boolean;
18
- isYoungerThan(other: Age): boolean;
19
- isAdult(minimumAge: Age): boolean;
20
10
  static fromValue(candidate: number): Age;
21
11
  static fromBirthdateEpochMs(params: {
22
12
  birthdate: TimestampType;
23
13
  now: TimestampType;
24
14
  }): Age;
25
- static fromBirthdate(params: {
15
+ static fromBirthdate(candidate: {
26
16
  birthdate: string;
27
17
  now: TimestampType;
28
18
  }): Age;
29
- toJSON(): number;
19
+ get(): number;
20
+ equals(other: Age): boolean;
21
+ isOlderThan(other: Age): boolean;
22
+ isYoungerThan(other: Age): boolean;
23
+ isAdult(minimumAge: Age): boolean;
30
24
  toString(): string;
25
+ toJSON(): number;
31
26
  }
package/dist/age.vo.js CHANGED
@@ -1,27 +1,30 @@
1
1
  import { differenceInYears } from "date-fns";
2
- import { z } from "zod/v4";
3
- export const AgeValueError = { error: "invalid.age" };
4
- export const InvalidBirthdateInFutureError = "invalid.birthdate_in_future";
5
- export const InvalidBirthdateError = "invalid.birthdate";
2
+ import { AgeYears, AgeYearsConstraints } from "./age-years.vo";
3
+ export const AgeError = { FutureBirthdate: "age.future.birthdate" };
6
4
  export class Age {
7
5
  value;
8
- static MIN = 1;
9
- static MAX = 130;
10
- static AgeValue = z
11
- .number(AgeValueError)
12
- .int(AgeValueError)
13
- .min(Age.MIN, AgeValueError)
14
- .max(Age.MAX, AgeValueError)
15
- .brand("AgeValue");
6
+ static MIN = AgeYearsConstraints.min;
7
+ static MAX = AgeYearsConstraints.max;
16
8
  constructor(value) {
17
9
  this.value = value;
18
10
  }
11
+ static fromValue(candidate) {
12
+ return new Age(AgeYears.parse(candidate));
13
+ }
14
+ static fromBirthdateEpochMs(params) {
15
+ if (params.birthdate > params.now)
16
+ throw new Error(AgeError.FutureBirthdate);
17
+ return Age.fromValue(differenceInYears(params.now, params.birthdate));
18
+ }
19
+ static fromBirthdate(candidate) {
20
+ const birthdateMs = new Date(candidate.birthdate).getTime();
21
+ if (birthdateMs > candidate.now)
22
+ throw new Error(AgeError.FutureBirthdate);
23
+ return Age.fromValue(differenceInYears(candidate.now, birthdateMs));
24
+ }
19
25
  get() {
20
26
  return this.value;
21
27
  }
22
- compare(other) {
23
- return this.value === other.value ? 0 : this.value < other.value ? -1 : 1;
24
- }
25
28
  equals(other) {
26
29
  return this.value === other.value;
27
30
  }
@@ -34,24 +37,10 @@ export class Age {
34
37
  isAdult(minimumAge) {
35
38
  return this.value >= minimumAge.value;
36
39
  }
37
- static fromValue(candidate) {
38
- return new Age(Age.AgeValue.parse(candidate));
39
- }
40
- static fromBirthdateEpochMs(params) {
41
- if (params.birthdate > params.now)
42
- throw new Error(InvalidBirthdateInFutureError);
43
- return Age.fromValue(differenceInYears(params.now, params.birthdate));
44
- }
45
- static fromBirthdate(params) {
46
- const birthdateMs = new Date(params.birthdate).getTime();
47
- if (birthdateMs > params.now)
48
- throw new Error(InvalidBirthdateInFutureError);
49
- return Age.fromValue(differenceInYears(params.now, birthdateMs));
40
+ toString() {
41
+ return this.value.toString();
50
42
  }
51
43
  toJSON() {
52
44
  return this.get();
53
45
  }
54
- toString() {
55
- return String(this.value);
56
- }
57
46
  }
@@ -1,6 +1,8 @@
1
1
  import { z } from "zod/v4";
2
2
  export declare const ApiKeyError: {
3
- error: string;
3
+ readonly Type: "api.key.type";
4
+ readonly Length: "api.key.length";
5
+ readonly BadChars: "api.key.bad.chars";
4
6
  };
5
7
  export declare const ApiKey: z.core.$ZodBranded<z.ZodString, "ApiKey">;
6
8
  export type ApiKeyType = z.infer<typeof ApiKey>;
@@ -1,8 +1,13 @@
1
1
  import { z } from "zod/v4";
2
- export const ApiKeyError = { error: "invalid.api.key" };
2
+ export const ApiKeyError = {
3
+ Type: "api.key.type",
4
+ Length: "api.key.length",
5
+ BadChars: "api.key.bad.chars",
6
+ };
7
+ // 64 letters and digits allowed
8
+ const API_KEY_CHARS = /^[a-zA-Z0-9]{64}$/;
3
9
  export const ApiKey = z
4
- .string(ApiKeyError)
5
- .trim()
6
- .length(64, ApiKeyError)
7
- .regex(/^[0-9a-zA-Z]{64}$/i, ApiKeyError)
10
+ .string(ApiKeyError.Type)
11
+ .length(64, ApiKeyError.Length)
12
+ .regex(API_KEY_CHARS, ApiKeyError.BadChars)
8
13
  .brand("ApiKey");
@@ -1,12 +1,12 @@
1
1
  import { z } from "zod/v4";
2
- export declare const BasenameTypeError: "basename.not.string";
3
- export declare const BasenameEmptyError: "basename.empty";
4
- export declare const BasenameTooLongError: "basename.too.long";
5
- export declare const BasenameSlashesForbiddenError: "basename.slashes.forbidden";
6
- export declare const BasenameControlCharsForbiddenError: "basename.control.chars.forbidden";
7
- export declare const BasenameDotSegmentsForbiddenError: "basename.dot.segments.forbidden";
8
- export declare const BasenameDotfilesForbiddenError: "basename.dotfiles.forbidden";
9
- export declare const BasenameTrailingDotForbiddenError: "basename.trailing.dot.forbidden";
10
- export declare const BasenameBadCharsError: "basename.bad.chars";
2
+ export declare const BasenameError: {
3
+ readonly Type: "basename.type";
4
+ readonly Empty: "basename.empty";
5
+ readonly TooLong: "basename.too.long";
6
+ readonly DotSegments: "basename.dot.segments";
7
+ readonly Dotfiles: "basename.dotfiles";
8
+ readonly TrailingDot: "basename.trailing.dot";
9
+ readonly BadChars: "basename.bad.chars";
10
+ };
11
11
  export declare const Basename: z.core.$ZodBranded<z.ZodString, "Basename">;
12
12
  export type BasenameType = z.infer<typeof Basename>;
@@ -1,25 +1,25 @@
1
1
  import { z } from "zod/v4";
2
- export const BasenameTypeError = "basename.not.string";
3
- export const BasenameEmptyError = "basename.empty";
4
- export const BasenameTooLongError = "basename.too.long";
5
- export const BasenameSlashesForbiddenError = "basename.slashes.forbidden";
6
- export const BasenameControlCharsForbiddenError = "basename.control.chars.forbidden";
7
- export const BasenameDotSegmentsForbiddenError = "basename.dot.segments.forbidden";
8
- export const BasenameDotfilesForbiddenError = "basename.dotfiles.forbidden";
9
- export const BasenameTrailingDotForbiddenError = "basename.trailing.dot.forbidden";
10
- export const BasenameBadCharsError = "basename.bad.chars";
2
+ export const BasenameError = {
3
+ Type: "basename.type",
4
+ Empty: "basename.empty",
5
+ TooLong: "basename.too.long",
6
+ DotSegments: "basename.dot.segments",
7
+ Dotfiles: "basename.dotfiles",
8
+ TrailingDot: "basename.trailing.dot",
9
+ BadChars: "basename.bad.chars",
10
+ };
11
+ // Letters, digits, dots, underscores, and hyphens allowed
12
+ const BASENAME_CHARS = /^[a-zA-Z0-9._-]+$/;
13
+ const DOT_SEGMENTS = [".", ".."];
11
14
  export const Basename = z
12
- .string(BasenameTypeError)
13
- .trim()
14
- .min(1, BasenameEmptyError)
15
- .max(128, BasenameTooLongError)
16
- .refine((s) => !/[/\\]/.test(s), BasenameSlashesForbiddenError)
17
- // dot-related checks: dot-segments first for specific errors…
18
- // biome-ignore lint: lint/suspicious/noControlCharactersInRegex
19
- .refine((value) => !/[\u0000-\u001F\u007F]/.test(value), BasenameControlCharsForbiddenError)
20
- .refine((value) => value !== "." && value !== "..", BasenameDotSegmentsForbiddenError)
21
- // …then any other dotfile
22
- .refine((value) => !value.startsWith("."), BasenameDotfilesForbiddenError)
23
- .refine((value) => !value.endsWith("."), BasenameTrailingDotForbiddenError)
24
- .regex(/^[A-Za-z0-9._-]+$/, BasenameBadCharsError)
15
+ .string(BasenameError.Type)
16
+ .min(1, BasenameError.Empty)
17
+ .max(128, BasenameError.TooLong)
18
+ // Reject "." and ".." as a filename to avoid directory traversal
19
+ .refine((value) => !DOT_SEGMENTS.includes(value), BasenameError.DotSegments)
20
+ // Reject dotfiles like ".env"
21
+ .refine((value) => !value.startsWith("."), BasenameError.Dotfiles)
22
+ // Reject trailing dot like "picture." to avoid extension collision
23
+ .refine((value) => !value.endsWith("."), BasenameError.TrailingDot)
24
+ .regex(BASENAME_CHARS, BasenameError.BadChars)
25
25
  .brand("Basename");
@@ -1,6 +1,8 @@
1
1
  import { type ClockFormatter } from "./clock-format.service";
2
2
  import { Hour } from "./hour.vo";
3
+ import type { HourSchemaType } from "./hour-schema.vo";
3
4
  import { Minute } from "./minute.vo";
5
+ import type { MinuteSchemaType } from "./minute-schema.vo";
4
6
  import type { TimestampType } from "./timestamp.vo";
5
7
  export declare class Clock {
6
8
  private readonly hour;
@@ -9,12 +11,16 @@ export declare class Clock {
9
11
  constructor(hour: Hour, minute: Minute, formatter?: ClockFormatter);
10
12
  static fromEpochMs(timestamp: TimestampType, formatter?: ClockFormatter): Clock;
11
13
  get(): {
12
- hour: number;
13
- minute: number;
14
+ hour: HourSchemaType;
15
+ minute: MinuteSchemaType;
14
16
  };
15
- format(formatter?: ClockFormatter): string;
16
- toString(): string;
17
+ format(): string;
17
18
  equals(another: Clock): boolean;
18
19
  isAfter(another: Clock): boolean;
19
20
  isBefore(another: Clock): boolean;
21
+ toString(): string;
22
+ toJSON(): {
23
+ hour: HourSchemaType;
24
+ minute: MinuteSchemaType;
25
+ };
20
26
  }
package/dist/clock.vo.js CHANGED
@@ -18,28 +18,26 @@ export class Clock {
18
18
  get() {
19
19
  return { hour: this.hour.get(), minute: this.minute.get() };
20
20
  }
21
- format(formatter) {
22
- const chosen = formatter ?? this.formatter;
23
- return chosen(this.hour, this.minute);
24
- }
25
- toString() {
26
- return this.format();
21
+ format() {
22
+ return this.formatter(this.hour, this.minute);
27
23
  }
28
24
  equals(another) {
29
25
  return this.hour.get() === another.hour.get() && this.minute.get() === another.minute.get();
30
26
  }
31
27
  isAfter(another) {
32
- const thisHour = this.hour.get();
33
- const otherHour = another.hour.get();
34
- if (thisHour !== otherHour)
35
- return thisHour > otherHour;
28
+ if (this.hour.get() !== another.hour.get())
29
+ return this.hour.get() > another.hour.get();
36
30
  return this.minute.get() > another.minute.get();
37
31
  }
38
32
  isBefore(another) {
39
- const thisHour = this.hour.get();
40
- const otherHour = another.hour.get();
41
- if (thisHour !== otherHour)
42
- return thisHour < otherHour;
33
+ if (this.hour.get() !== another.hour.get())
34
+ return this.hour.get() < another.hour.get();
43
35
  return this.minute.get() < another.minute.get();
44
36
  }
37
+ toString() {
38
+ return this.format();
39
+ }
40
+ toJSON() {
41
+ return this.get();
42
+ }
45
43
  }
@@ -1,7 +1,8 @@
1
+ import type { TimeZoneOffsetValueType } from "./time-zone-offset-value.vo";
1
2
  import { type TimestampType } from "./timestamp.vo";
2
3
  type GetStartOfDayTsInTzConfigType = {
3
4
  now: TimestampType;
4
- timeZoneOffsetMs: number;
5
+ timeZoneOffsetMs: TimeZoneOffsetValueType;
5
6
  };
6
7
  export declare class DateCalculator {
7
8
  static getStartOfDayTsInTz(config: GetStartOfDayTsInTzConfigType): TimestampType;
@@ -1,10 +1,9 @@
1
1
  import { format } from "date-fns";
2
- type FormattedDateType = string;
3
2
  type DateFormattersInputType = Parameters<typeof format>[0];
4
3
  export declare class DateFormatters {
5
- static datetime(date: DateFormattersInputType): FormattedDateType;
6
- static date(date: DateFormattersInputType): FormattedDateType;
7
- static monthDay(date: DateFormattersInputType): FormattedDateType;
4
+ static datetime(date: DateFormattersInputType): string;
5
+ static date(date: DateFormattersInputType): string;
6
+ static monthDay(date: DateFormattersInputType): string;
8
7
  static relative(date: DateFormattersInputType): string;
9
8
  }
10
9
  export {};
@@ -1,5 +1,7 @@
1
1
  import type { TimestampType } from "./timestamp.vo";
2
- export declare const DateRangeInvalidError: "invalid.date.range";
2
+ export declare const DateRangeError: {
3
+ readonly Invalid: "date.range.invalid";
4
+ };
3
5
  export declare class DateRange {
4
6
  private readonly start;
5
7
  private readonly end;
@@ -9,4 +11,8 @@ export declare class DateRange {
9
11
  toRange(): [TimestampType, TimestampType];
10
12
  contains(timestamp: TimestampType): boolean;
11
13
  equals(other: DateRange): boolean;
14
+ toJSON(): {
15
+ start: number;
16
+ end: number;
17
+ };
12
18
  }
@@ -1,4 +1,4 @@
1
- export const DateRangeInvalidError = "invalid.date.range";
1
+ export const DateRangeError = { Invalid: "date.range.invalid" };
2
2
  export class DateRange {
3
3
  start;
4
4
  end;
@@ -6,7 +6,7 @@ export class DateRange {
6
6
  this.start = start;
7
7
  this.end = end;
8
8
  if (start > end)
9
- throw new Error(DateRangeInvalidError);
9
+ throw new Error(DateRangeError.Invalid);
10
10
  }
11
11
  getStart() {
12
12
  return this.start;
@@ -23,4 +23,7 @@ export class DateRange {
23
23
  equals(other) {
24
24
  return this.start === other.start && this.end === other.end;
25
25
  }
26
+ toJSON() {
27
+ return { start: this.getStart(), end: this.getEnd() };
28
+ }
26
29
  }
@@ -1,6 +1,9 @@
1
1
  import { z } from "zod/v4";
2
2
  export declare const DayIsoIdError: {
3
- readonly error: "invalid.day.iso.id";
3
+ readonly Type: "day.iso.id.type";
4
+ readonly BadChars: "day.iso.id.bad.chars";
5
+ readonly InvalidDate: "day.iso.id.invalid.date";
4
6
  };
5
- export declare const DayIsoId: z.ZodString;
7
+ export declare const DAY_ISO_ID_CHARS: RegExp;
8
+ export declare const DayIsoId: z.core.$ZodBranded<z.ZodString, "DayIsoId">;
6
9
  export type DayIsoIdType = z.infer<typeof DayIsoId>;
@@ -1,10 +1,14 @@
1
1
  import { isValid, parseISO } from "date-fns";
2
2
  import { z } from "zod/v4";
3
- export const DayIsoIdError = { error: "invalid.day.iso.id" };
3
+ export const DayIsoIdError = {
4
+ Type: "day.iso.id.type",
5
+ BadChars: "day.iso.id.bad.chars",
6
+ InvalidDate: "day.iso.id.invalid.date",
7
+ };
8
+ // Four digits, hyphen, two digits, hyphen, two digits
9
+ export const DAY_ISO_ID_CHARS = /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/;
4
10
  export const DayIsoId = z
5
- .string(DayIsoIdError)
6
- .regex(/^\d{4}-\d{2}-\d{2}$/, DayIsoIdError)
7
- .refine((value) => {
8
- const date = parseISO(value);
9
- return isValid(date) && value === date.toISOString().slice(0, 10);
10
- }, DayIsoIdError);
11
+ .string(DayIsoIdError.Type)
12
+ .regex(DAY_ISO_ID_CHARS, DayIsoIdError.BadChars)
13
+ .refine((value) => isValid(parseISO(value)), DayIsoIdError.InvalidDate)
14
+ .brand("DayIsoId");
package/dist/day.vo.d.ts CHANGED
@@ -3,11 +3,12 @@ import { type DayIsoIdType } from "./day-iso-id.vo";
3
3
  import { type TimestampType } from "./timestamp.vo";
4
4
  export declare class Day extends DateRange {
5
5
  private constructor();
6
+ static fromTimestamp(timestamp: TimestampType): Day;
7
+ static fromNow(now: TimestampType): Day;
8
+ static fromIsoId(isoId: DayIsoIdType): Day;
6
9
  toIsoId(): DayIsoIdType;
7
10
  previous(): Day;
8
11
  next(): Day;
9
12
  shift(count: number): Day;
10
- static fromTimestamp(timestamp: TimestampType): Day;
11
- static fromNow(now: TimestampType): Day;
12
- static fromIsoId(isoId: DayIsoIdType): Day;
13
+ toString(): string;
13
14
  }
package/dist/day.vo.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { formatISO } from "date-fns";
1
2
  import { DateRange } from "./date-range.vo";
2
3
  import { DayIsoId } from "./day-iso-id.vo";
3
4
  import { Duration } from "./duration.service";
@@ -6,22 +7,6 @@ export class Day extends DateRange {
6
7
  constructor(start, end) {
7
8
  super(start, end);
8
9
  }
9
- toIsoId() {
10
- const midday = this.getStart() + Duration.Hours(12).ms;
11
- return new Date(midday).toISOString().slice(0, 10);
12
- }
13
- previous() {
14
- const shifted = this.getStart() - Duration.Days(1).ms;
15
- return Day.fromTimestamp(Timestamp.parse(shifted));
16
- }
17
- next() {
18
- const shifted = this.getStart() + Duration.Days(1).ms;
19
- return Day.fromTimestamp(Timestamp.parse(shifted));
20
- }
21
- shift(count) {
22
- const shifted = this.getStart() + count * Duration.Days(1).ms;
23
- return Day.fromTimestamp(Timestamp.parse(shifted));
24
- }
25
10
  static fromTimestamp(timestamp) {
26
11
  const date = new Date(timestamp);
27
12
  const startUtc = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
@@ -37,4 +22,21 @@ export class Day extends DateRange {
37
22
  const endUtc = startUtc + Duration.Days(1).ms - 1;
38
23
  return new Day(Timestamp.parse(startUtc), Timestamp.parse(endUtc));
39
24
  }
25
+ toIsoId() {
26
+ const midday = this.getStart() + Duration.Hours(12).ms;
27
+ return DayIsoId.parse(formatISO(midday, { representation: "date" }));
28
+ }
29
+ previous() {
30
+ return this.shift(-1);
31
+ }
32
+ next() {
33
+ return this.shift(1);
34
+ }
35
+ shift(count) {
36
+ const timestamp = this.getStart() + count * Duration.Days(1).ms;
37
+ return Day.fromTimestamp(Timestamp.parse(timestamp));
38
+ }
39
+ toString() {
40
+ return this.toIsoId();
41
+ }
40
42
  }
@@ -1,8 +1,12 @@
1
1
  import { z } from "zod/v4";
2
- export declare const AbsDirTypeError: "abs_dir.not.string";
3
- export declare const AbsDirMustStartWithSlashError: "abs_dir_must_start_with_slash";
4
- export declare const AbsDirBackslashForbiddenError: "abs_dir_backslash_forbidden";
5
- export declare const AbsDirControlCharsForbiddenError: "abs_dir_control_chars_forbidden";
6
- export declare const AbsDirBadSegmentsError: "abs_dir_bad_segments";
7
- export declare const DirectoryPathAbsoluteSchema: z.core.$ZodBranded<z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, z.ZodTransform<string, string>>, "directory_path_absolute">;
2
+ export declare const DirectoryPathAbsoluteError: {
3
+ readonly BadSegments: "directory.path.absolue.bad.segments";
4
+ readonly Empty: "directory.path.absolue.empty";
5
+ readonly LeadingSlash: "directory.path.absolue.leading.slash";
6
+ readonly TooLong: "directory.path.absolue.too.long";
7
+ readonly TrailingSlash: "directory.path.absolue.trailing.slash";
8
+ readonly Type: "directory.path.absolue.type";
9
+ };
10
+ export declare const DIRECTORY_PATH_ABSOLUTE_CHARS: RegExp;
11
+ export declare const DirectoryPathAbsoluteSchema: z.core.$ZodBranded<z.ZodString, "DirectoryPathAbsoluteSchema">;
8
12
  export type DirectoryPathAbsoluteType = z.infer<typeof DirectoryPathAbsoluteSchema>;
@@ -1,23 +1,25 @@
1
1
  import { z } from "zod/v4";
2
- export const AbsDirTypeError = "abs_dir.not.string";
3
- export const AbsDirMustStartWithSlashError = "abs_dir_must_start_with_slash";
4
- export const AbsDirBackslashForbiddenError = "abs_dir_backslash_forbidden";
5
- export const AbsDirControlCharsForbiddenError = "abs_dir_control_chars_forbidden";
6
- export const AbsDirBadSegmentsError = "abs_dir_bad_segments";
2
+ export const DirectoryPathAbsoluteError = {
3
+ BadSegments: "directory.path.absolue.bad.segments",
4
+ Empty: "directory.path.absolue.empty",
5
+ LeadingSlash: "directory.path.absolue.leading.slash",
6
+ TooLong: "directory.path.absolue.too.long",
7
+ TrailingSlash: "directory.path.absolue.trailing.slash",
8
+ Type: "directory.path.absolue.type",
9
+ };
10
+ // Letters, digits, dots, underscores, and hyphens
11
+ export const DIRECTORY_PATH_ABSOLUTE_CHARS = /^[a-zA-Z0-9._-]+$/;
12
+ const DOT_SEGMENTS = [".", ".."];
7
13
  export const DirectoryPathAbsoluteSchema = z
8
- .string(AbsDirTypeError)
9
- .trim()
10
- .refine((value) => value.startsWith("/"), AbsDirMustStartWithSlashError)
11
- .refine((value) => !value.includes("\\"), AbsDirBackslashForbiddenError)
12
- // biome-ignore lint: lint/suspicious/noControlCharactersInRegex
13
- .refine((value) => !/[\u0000-\u001F\u007F]/.test(value), AbsDirControlCharsForbiddenError)
14
- // collapse duplicate slashes, then drop trailing slash unless it's the root "/"
15
- .transform((value) => value.replace(/\/{2,}/g, "/"))
16
- .transform((value) => (value !== "/" && value.endsWith("/") ? value.slice(0, -1) : value))
14
+ .string(DirectoryPathAbsoluteError.Type)
15
+ .min(1, DirectoryPathAbsoluteError.Empty)
16
+ .max(512, DirectoryPathAbsoluteError.TooLong)
17
+ .refine((value) => value.startsWith("/"), DirectoryPathAbsoluteError.LeadingSlash)
18
+ .refine((value) => (value === "/" ? true : !value.endsWith("/")), DirectoryPathAbsoluteError.TrailingSlash)
17
19
  .refine((value) => {
18
20
  if (value === "/")
19
21
  return true;
20
22
  const segments = value.slice(1).split("/");
21
- return segments.every((segment) => segment.length > 0 && /^[A-Za-z0-9._-]+$/.test(segment) && segment !== "." && segment !== "..");
22
- }, AbsDirBadSegmentsError)
23
- .brand("directory_path_absolute");
23
+ return segments.every((segment) => DIRECTORY_PATH_ABSOLUTE_CHARS.test(segment) && !DOT_SEGMENTS.includes(segment));
24
+ }, DirectoryPathAbsoluteError.BadSegments)
25
+ .brand("DirectoryPathAbsoluteSchema");
@@ -1,9 +1,12 @@
1
1
  import { z } from "zod/v4";
2
- export declare const RelDirTypeError: "rel_dir.not.string";
3
- export declare const RelDirMustNotStartWithSlashError: "rel_dir_must_not_start_with_slash";
4
- export declare const RelDirBackslashForbiddenError: "rel_dir_backslash_forbidden";
5
- export declare const RelDirControlCharsForbiddenError: "rel_dir_control_chars_forbidden";
6
- export declare const RelDirEmptyError: "rel_dir_empty";
7
- export declare const RelDirBadSegmentsError: "rel_dir_bad_segments";
8
- export declare const DirectoryPathRelativeSchema: z.core.$ZodBranded<z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, z.ZodTransform<string, string>>, "directory_path_relative">;
2
+ export declare const DirectoryPathRelativeError: {
3
+ readonly BadSegments: "directory.path.relative.bad.segments";
4
+ readonly Empty: "directory.path.relative.empty";
5
+ readonly LeadingSlash: "directory.path.relative.leading.slash";
6
+ readonly TooLong: "directory.path.absolue.too.long";
7
+ readonly TrailingSlash: "directory.path.absolue.trailing.slash";
8
+ readonly Type: "directory.path.relative.not.type";
9
+ };
10
+ export declare const DIRECTORY_PATH_RELATIVE_CHARS: RegExp;
11
+ export declare const DirectoryPathRelativeSchema: z.core.$ZodBranded<z.ZodString, "DirectoryPathRelativeSchema">;
9
12
  export type DirectoryPathRelativeType = z.infer<typeof DirectoryPathRelativeSchema>;
@@ -1,21 +1,22 @@
1
1
  import { z } from "zod/v4";
2
- export const RelDirTypeError = "rel_dir.not.string";
3
- export const RelDirMustNotStartWithSlashError = "rel_dir_must_not_start_with_slash";
4
- export const RelDirBackslashForbiddenError = "rel_dir_backslash_forbidden";
5
- export const RelDirControlCharsForbiddenError = "rel_dir_control_chars_forbidden";
6
- export const RelDirEmptyError = "rel_dir_empty";
7
- export const RelDirBadSegmentsError = "rel_dir_bad_segments";
2
+ export const DirectoryPathRelativeError = {
3
+ BadSegments: "directory.path.relative.bad.segments",
4
+ Empty: "directory.path.relative.empty",
5
+ LeadingSlash: "directory.path.relative.leading.slash",
6
+ TooLong: "directory.path.absolue.too.long",
7
+ TrailingSlash: "directory.path.absolue.trailing.slash",
8
+ Type: "directory.path.relative.not.type",
9
+ };
10
+ // Letters, digits, dots, underscores, and hyphens
11
+ export const DIRECTORY_PATH_RELATIVE_CHARS = /^[A-Za-z0-9._-]+$/;
12
+ const DOT_SEGMENTS = [".", ".."];
8
13
  export const DirectoryPathRelativeSchema = z
9
- .string(RelDirTypeError)
10
- .trim()
11
- .refine((value) => !value.startsWith("/"), RelDirMustNotStartWithSlashError)
12
- .refine((value) => !value.includes("\\"), RelDirBackslashForbiddenError)
13
- // biome-ignore lint: lint/suspicious/noControlCharactersInRegex
14
- .refine((value) => !/[\u0000-\u001F\u007F]/.test(value), RelDirControlCharsForbiddenError)
15
- .transform((value) => value.replace(/\/{2,}/g, "/"))
16
- .transform((value) => value.replace(/^\/+|\/+$/g, ""))
17
- .refine((value) => value.length > 0, RelDirEmptyError)
14
+ .string(DirectoryPathRelativeError.Type)
15
+ .min(1, DirectoryPathRelativeError.Empty)
16
+ .max(512, DirectoryPathRelativeError.TooLong)
17
+ .refine((value) => !value.startsWith("/"), DirectoryPathRelativeError.LeadingSlash)
18
+ .refine((value) => !value.endsWith("/"), DirectoryPathRelativeError.TrailingSlash)
18
19
  .refine((value) => value
19
20
  .split("/")
20
- .every((segment) => /^[A-Za-z0-9._-]+$/.test(segment) && segment !== "." && segment !== ".."), RelDirBadSegmentsError)
21
- .brand("directory_path_relative");
21
+ .every((segment) => DIRECTORY_PATH_RELATIVE_CHARS.test(segment) && !DOT_SEGMENTS.includes(segment)), DirectoryPathRelativeError.BadSegments)
22
+ .brand("DirectoryPathRelativeSchema");
@@ -0,0 +1,7 @@
1
+ import { z } from "zod/v4";
2
+ export declare const DivisionFactorError: {
3
+ readonly Type: "division.factor.type";
4
+ readonly Invalid: "division.factor.invalid";
5
+ };
6
+ export declare const DivisionFactor: z.core.$ZodBranded<z.ZodNumber, "DivisionFactor">;
7
+ export type DivisionFactorType = z.infer<typeof DivisionFactor>;
@@ -0,0 +1,9 @@
1
+ import { z } from "zod/v4";
2
+ export const DivisionFactorError = {
3
+ Type: "division.factor.type",
4
+ Invalid: "division.factor.invalid",
5
+ };
6
+ export const DivisionFactor = z
7
+ .number(DivisionFactorError.Type)
8
+ .gt(0, DivisionFactorError.Invalid)
9
+ .brand("DivisionFactor");