@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,6 @@
1
+ import { z } from "zod/v4";
2
+ export declare const DurationMsError: {
3
+ readonly Invalid: "duration.invalid";
4
+ };
5
+ export declare const DurationMs: z.core.$ZodBranded<z.ZodNumber, "DurationMs">;
6
+ export type DurationMsType = z.infer<typeof DurationMs>;
@@ -0,0 +1,3 @@
1
+ import { z } from "zod/v4";
2
+ export const DurationMsError = { Invalid: "duration.invalid" };
3
+ export const DurationMs = z.number(DurationMsError.Invalid).int(DurationMsError.Invalid).brand("DurationMs");
@@ -1,13 +1,7 @@
1
- import { z } from "zod/v4";
2
- import { type TimestampType } from "./timestamp.vo";
3
- export declare const DurationMsError: {
4
- readonly error: "duration.invalid";
5
- };
6
- export declare const DurationMsSchema: z.core.$ZodBranded<z.ZodNumber, "DurationMs">;
7
- export type DurationMsType = z.infer<typeof DurationMsSchema>;
1
+ import { type DurationMsType } from "./duration-ms.vo";
8
2
  export declare class Duration {
9
3
  private static readonly rounding;
10
- private readonly valueMs;
4
+ private readonly internal;
11
5
  private static readonly MS_IN_SECOND;
12
6
  private static readonly MS_IN_MINUTE;
13
7
  private static readonly MS_IN_HOUR;
@@ -29,9 +23,3 @@ export declare class Duration {
29
23
  add(another: Duration): Duration;
30
24
  subtract(another: Duration): Duration;
31
25
  }
32
- export declare const Time: {
33
- Now(now: TimestampType): {
34
- Add(duration: Duration): TimestampType;
35
- Minus(duration: Duration): TimestampType;
36
- };
37
- };
@@ -1,21 +1,14 @@
1
- import { z } from "zod/v4";
1
+ import { DurationMs } from "./duration-ms.vo";
2
2
  import { RoundToDecimal } from "./rounding.adapter";
3
- import { Timestamp } from "./timestamp.vo";
4
- export const DurationMsError = { error: "duration.invalid" };
5
- export const DurationMsSchema = z
6
- .number(DurationMsError)
7
- .int(DurationMsError)
8
- .refine(Number.isFinite, DurationMsError)
9
- .brand("DurationMs");
10
3
  export class Duration {
11
4
  static rounding = new RoundToDecimal(2);
12
- valueMs;
5
+ internal;
13
6
  static MS_IN_SECOND = 1_000;
14
- static MS_IN_MINUTE = 60_000;
15
- static MS_IN_HOUR = 3_600_000;
16
- static MS_IN_DAY = 86_400_000;
7
+ static MS_IN_MINUTE = 60 * Duration.MS_IN_SECOND;
8
+ static MS_IN_HOUR = 60 * Duration.MS_IN_MINUTE;
9
+ static MS_IN_DAY = 24 * Duration.MS_IN_HOUR;
17
10
  constructor(candidateMs) {
18
- this.valueMs = DurationMsSchema.parse(candidateMs);
11
+ this.internal = DurationMs.parse(candidateMs);
19
12
  }
20
13
  static Days(value) {
21
14
  return new Duration(value * Duration.MS_IN_DAY);
@@ -33,45 +26,33 @@ export class Duration {
33
26
  return new Duration(value);
34
27
  }
35
28
  get days() {
36
- return Duration.rounding.round(this.valueMs / Duration.MS_IN_DAY);
29
+ return Duration.rounding.round(this.internal / Duration.MS_IN_DAY);
37
30
  }
38
31
  get hours() {
39
- return Duration.rounding.round(this.valueMs / Duration.MS_IN_HOUR);
32
+ return Duration.rounding.round(this.internal / Duration.MS_IN_HOUR);
40
33
  }
41
34
  get minutes() {
42
- return Duration.rounding.round(this.valueMs / Duration.MS_IN_MINUTE);
35
+ return Duration.rounding.round(this.internal / Duration.MS_IN_MINUTE);
43
36
  }
44
37
  get seconds() {
45
- return Duration.rounding.round(this.valueMs / Duration.MS_IN_SECOND);
38
+ return Duration.rounding.round(this.internal / Duration.MS_IN_SECOND);
46
39
  }
47
40
  get ms() {
48
- return this.valueMs;
41
+ return this.internal;
49
42
  }
50
43
  isLongerThan(another) {
51
- return this.valueMs > another.valueMs;
44
+ return this.internal > another.internal;
52
45
  }
53
46
  isShorterThan(another) {
54
- return this.valueMs < another.valueMs;
47
+ return this.internal < another.internal;
55
48
  }
56
49
  equals(other) {
57
- return this.valueMs === other.valueMs;
50
+ return this.internal === other.internal;
58
51
  }
59
52
  add(another) {
60
- return Duration.Ms(this.valueMs + another.valueMs);
53
+ return Duration.Ms(this.internal + another.internal);
61
54
  }
62
55
  subtract(another) {
63
- return Duration.Ms(this.valueMs - another.valueMs);
56
+ return Duration.Ms(this.internal - another.internal);
64
57
  }
65
58
  }
66
- export const Time = {
67
- Now(now) {
68
- return {
69
- Add(duration) {
70
- return Timestamp.parse(now + duration.ms);
71
- },
72
- Minus(duration) {
73
- return Timestamp.parse(now - duration.ms);
74
- },
75
- };
76
- },
77
- };
@@ -1,8 +1,3 @@
1
- import { z } from "zod/v4";
2
- export declare const Email: z.core.$ZodBranded<z.ZodEmail, "Email">;
3
- export type EmailType = z.infer<typeof Email>;
4
- type EmailMaskedType = string;
5
1
  export declare class EmailMask {
6
- static censor(email: EmailType): EmailMaskedType;
2
+ static censor(email: string): string;
7
3
  }
8
- export {};
@@ -1,14 +1,12 @@
1
- import { z } from "zod/v4";
2
- export const Email = z.email().brand("Email");
3
1
  export class EmailMask {
4
2
  static censor(email) {
5
- const [beforeAt, afterAt] = email.split("@");
6
- const local = beforeAt;
7
- const domain = afterAt;
8
- if (local.length <= 2) {
3
+ const [local, domain] = email.split("@");
4
+ if (local.length <= 2)
9
5
  return `${"*".repeat(local.length)}@${domain}`;
10
- }
11
- const censoredLocal = `${local.at(0)}${"*".repeat(local.length - 2)}${local.at(-1)}`;
6
+ const firstCharacter = local.at(0);
7
+ const censoredPart = "*".repeat(local.length - 2);
8
+ const lastCharacter = local.at(-1);
9
+ const censoredLocal = `${firstCharacter}${censoredPart}${lastCharacter}`;
12
10
  return `${censoredLocal}@${domain}`;
13
11
  }
14
12
  }
@@ -1,6 +1,4 @@
1
- import { z } from "zod/v4";
2
- declare const RevisionValue: z.ZodNumber;
3
- type RevisionValueType = z.infer<typeof RevisionValue>;
1
+ import { type RevisionValueType } from "./revision-value.vo";
4
2
  type ETagValueType = string;
5
3
  export declare class ETag {
6
4
  readonly revision: RevisionValueType;
@@ -11,6 +9,9 @@ export declare class ETag {
11
9
  static fromHeader(value?: ETagValueType): ETag | null;
12
10
  }
13
11
  export type WeakETagValueType = string;
12
+ export declare const WeakETagError: {
13
+ readonly Invalid: "weak.etag.invalid";
14
+ };
14
15
  export declare class WeakETag {
15
16
  readonly revision: RevisionValueType;
16
17
  static HEADER_NAME: string;
package/dist/etags.vo.js CHANGED
@@ -1,5 +1,4 @@
1
- import { z } from "zod/v4";
2
- const RevisionValue = z.number().int().min(0);
1
+ import { RevisionValue } from "./revision-value.vo";
3
2
  export class ETag {
4
3
  revision;
5
4
  static HEADER_NAME = "ETag";
@@ -18,6 +17,7 @@ export class ETag {
18
17
  return new ETag(RevisionValue.parse(candidate));
19
18
  }
20
19
  }
20
+ export const WeakETagError = { Invalid: "weak.etag.invalid" };
21
21
  export class WeakETag {
22
22
  revision;
23
23
  static HEADER_NAME = "ETag";
@@ -29,7 +29,7 @@ export class WeakETag {
29
29
  }
30
30
  static fromHeader(value) {
31
31
  if (!value?.startsWith("W/"))
32
- throw Error("Invalid WeakETag");
32
+ throw new Error(WeakETagError.Invalid);
33
33
  const candidate = Number(value.split("W/")[1]);
34
34
  if (Number.isNaN(candidate))
35
35
  return null;
@@ -1,7 +1,9 @@
1
1
  import { z } from "zod/v4";
2
- export declare const ExtensionTypeError: "extension.not.string";
3
- export declare const ExtensionEmptyError: "extension.empty";
4
- export declare const ExtensionTooLongError: "extension.too.long";
5
- export declare const ExtensionBadCharsError: "extension.bad.chars";
2
+ export declare const ExtensionError: {
3
+ readonly Type: "extension.type";
4
+ readonly Empty: "extension.empty";
5
+ readonly TooLong: "extension.too.long";
6
+ readonly BadChars: "extension.bad.chars";
7
+ };
6
8
  export declare const Extension: z.core.$ZodBranded<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, "Extension">;
7
9
  export type ExtensionType = z.infer<typeof Extension>;
@@ -1,14 +1,19 @@
1
1
  import { z } from "zod/v4";
2
- export const ExtensionTypeError = "extension.not.string";
3
- export const ExtensionEmptyError = "extension.empty";
4
- export const ExtensionTooLongError = "extension.too.long";
5
- export const ExtensionBadCharsError = "extension.bad.chars";
2
+ export const ExtensionError = {
3
+ Type: "extension.type",
4
+ Empty: "extension.empty",
5
+ TooLong: "extension.too.long",
6
+ BadChars: "extension.bad.chars",
7
+ };
8
+ // Lowercase letters and digits allowed
9
+ const EXTENSION_WHITELIST = /^[a-z0-9]+$/;
10
+ const LEADING_DOT_FILE = /^\./;
6
11
  export const Extension = z
7
- .string(ExtensionTypeError)
8
- .trim()
12
+ .string(ExtensionError.Type)
9
13
  .toLowerCase()
10
- .transform((value) => (value.startsWith(".") ? value.slice(1) : value))
11
- .refine((value) => value.length >= 1, ExtensionEmptyError)
12
- .refine((value) => value.length <= 16, ExtensionTooLongError)
13
- .refine((value) => /^[a-z0-9]+$/.test(value), ExtensionBadCharsError)
14
+ .min(2, ExtensionError.Empty)
15
+ .max(16, ExtensionError.TooLong)
16
+ // Transform ".png" -> "png"
17
+ .transform((value) => value.replace(LEADING_DOT_FILE, ""))
18
+ .refine((value) => EXTENSION_WHITELIST.test(value), ExtensionError.BadChars)
14
19
  .brand("Extension");
@@ -0,0 +1,10 @@
1
+ import { z } from "zod/v4";
2
+ export declare const FeatureFlagValueError: {
3
+ readonly Invalid: "feature.flag.value.invalid";
4
+ };
5
+ export declare enum FeatureFlagEnum {
6
+ yes = "yes",
7
+ no = "no"
8
+ }
9
+ export declare const FeatureFlagValue: z.ZodEnum<typeof FeatureFlagEnum>;
10
+ export type FeatureFlagValueType = z.infer<typeof FeatureFlagValue>;
@@ -0,0 +1,8 @@
1
+ import { z } from "zod/v4";
2
+ export const FeatureFlagValueError = { Invalid: "feature.flag.value.invalid" };
3
+ export var FeatureFlagEnum;
4
+ (function (FeatureFlagEnum) {
5
+ FeatureFlagEnum["yes"] = "yes";
6
+ FeatureFlagEnum["no"] = "no";
7
+ })(FeatureFlagEnum || (FeatureFlagEnum = {}));
8
+ export const FeatureFlagValue = z.enum(FeatureFlagEnum, FeatureFlagValueError.Invalid);
@@ -1,10 +1,4 @@
1
- import { z } from "zod/v4";
2
- export declare enum FeatureFlagEnum {
3
- yes = "yes",
4
- no = "no"
5
- }
6
- export declare const FeatureFlagValue: z.ZodEnum<typeof FeatureFlagEnum>;
7
- export type FeatureFlagValueType = z.infer<typeof FeatureFlagValue>;
1
+ import { type FeatureFlagValueType } from "./feature-flag-value.vo";
8
2
  export declare class FeatureFlag {
9
3
  static isEnabled(flag: FeatureFlagValueType): boolean;
10
4
  static isDisabled(flag: FeatureFlagValueType): boolean;
@@ -1,10 +1,4 @@
1
- import { z } from "zod/v4";
2
- export var FeatureFlagEnum;
3
- (function (FeatureFlagEnum) {
4
- FeatureFlagEnum["yes"] = "yes";
5
- FeatureFlagEnum["no"] = "no";
6
- })(FeatureFlagEnum || (FeatureFlagEnum = {}));
7
- export const FeatureFlagValue = z.enum(FeatureFlagEnum);
1
+ import { FeatureFlagEnum } from "./feature-flag-value.vo";
8
2
  export class FeatureFlag {
9
3
  static isEnabled(flag) {
10
4
  return flag === FeatureFlagEnum.yes;
@@ -1,11 +1,14 @@
1
1
  import { z } from "zod/v4";
2
2
  import { Filename } from "./filename.vo";
3
- export declare const AbsFilePathTypeError: "abs.file.path.not.string";
4
- export declare const AbsFilePathMustStartWithSlashError: "abs_file_path_must_start_with_slash";
5
- export declare const AbsFilePathBackslashForbiddenError: "abs_file_path_backslash_forbidden";
6
- export declare const AbsFilePathMissingFilenameError: "abs_file_path_missing_filename";
7
- export declare const FilePathAbsoluteSchema: z.ZodPipe<z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, z.ZodTransform<string, string>>, z.ZodTransform<{
8
- directory: string & z.core.$brand<"directory_path_absolute">;
3
+ export declare const FilePathAbsoluteSchemaError: {
4
+ readonly Type: "file.path.absolute.type";
5
+ readonly LeadingSlash: "file.path.absolute.leading.slash";
6
+ readonly TrailingSlash: "file.path.absolute.trailing.slash";
7
+ readonly BackslashForbidden: "file.path.absolute.backslash.forbidden";
8
+ readonly Empty: "file.path.absolute.empty";
9
+ };
10
+ export declare const FilePathAbsoluteSchema: z.core.$ZodBranded<z.ZodPipe<z.ZodString, z.ZodTransform<{
11
+ directory: string & z.core.$brand<"DirectoryPathAbsoluteSchema">;
9
12
  filename: Filename;
10
- }, string>>;
13
+ }, string>>, "FilePathAbsoluteSchema">;
11
14
  export type FilePathAbsoluteType = z.infer<typeof FilePathAbsoluteSchema>;
@@ -1,25 +1,25 @@
1
1
  import { z } from "zod/v4";
2
2
  import { DirectoryPathAbsoluteSchema } from "./directory-path-absolute.vo";
3
3
  import { Filename } from "./filename.vo";
4
- export const AbsFilePathTypeError = "abs.file.path.not.string";
5
- export const AbsFilePathMustStartWithSlashError = "abs_file_path_must_start_with_slash";
6
- export const AbsFilePathBackslashForbiddenError = "abs_file_path_backslash_forbidden";
7
- export const AbsFilePathMissingFilenameError = "abs_file_path_missing_filename";
4
+ export const FilePathAbsoluteSchemaError = {
5
+ Type: "file.path.absolute.type",
6
+ LeadingSlash: "file.path.absolute.leading.slash",
7
+ TrailingSlash: "file.path.absolute.trailing.slash",
8
+ BackslashForbidden: "file.path.absolute.backslash.forbidden",
9
+ Empty: "file.path.absolute.empty",
10
+ };
8
11
  export const FilePathAbsoluteSchema = z
9
- .string(AbsFilePathTypeError)
10
- .trim()
11
- .refine((value) => value.startsWith("/"), AbsFilePathMustStartWithSlashError)
12
- .refine((value) => !value.includes("\\"), AbsFilePathBackslashForbiddenError)
13
- // collapse duplicate slashes
14
- .transform((value) => value.replace(/\/{2,}/g, "/"))
15
- // keep "/" as-is; otherwise remove a trailing slash
16
- .transform((value) => (value !== "/" && value.endsWith("/") ? value.slice(0, -1) : value))
17
- .refine((value) => value !== "/", AbsFilePathMissingFilenameError)
12
+ .string(FilePathAbsoluteSchemaError.Type)
13
+ .min(1, FilePathAbsoluteSchemaError.Empty)
14
+ .refine((value) => value.startsWith("/"), FilePathAbsoluteSchemaError.LeadingSlash)
15
+ .refine((value) => !value.endsWith("/"), FilePathAbsoluteSchemaError.TrailingSlash)
16
+ .refine((value) => !value.includes("\\"), FilePathAbsoluteSchemaError.BackslashForbidden)
18
17
  .transform((normalized) => {
19
- const lastSlashIndex = normalized.lastIndexOf("/");
20
- const directoryCandidate = lastSlashIndex === 0 ? "/" : normalized.slice(0, lastSlashIndex);
21
- const filenameCandidate = normalized.slice(lastSlashIndex + 1);
18
+ const index = normalized.lastIndexOf("/");
19
+ const directoryCandidate = index === 0 ? "/" : normalized.slice(0, index);
20
+ const filenameCandidate = normalized.slice(index + 1);
22
21
  const directory = DirectoryPathAbsoluteSchema.parse(directoryCandidate);
23
22
  const filename = Filename.fromString(filenameCandidate);
24
23
  return { directory, filename };
25
- });
24
+ })
25
+ .brand("FilePathAbsoluteSchema");
@@ -1,11 +1,14 @@
1
1
  import { z } from "zod/v4";
2
2
  import { Filename } from "./filename.vo";
3
- export declare const RelFilePathTypeError: "rel.file.path.not.string";
4
- export declare const RelFilePathMustNotStartWithSlashError: "rel_file_path_must_not_start_with_slash";
5
- export declare const RelFilePathBackslashForbiddenError: "rel_file_path_backslash_forbidden";
6
- export declare const RelFilePathRequiresDirectoryError: "rel_file_path_requires_directory";
7
- export declare const FilePathRelativeSchema: z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, z.ZodTransform<{
8
- directory: string & z.core.$brand<"directory_path_relative">;
3
+ export declare const FilePathRelativeSchemaError: {
4
+ readonly Type: "file.path.relative.type";
5
+ readonly LeadingSlash: "file.path.relative.leading.slash";
6
+ readonly BackslashForbidden: "file.path.relative.backslash.forbidden";
7
+ readonly RequiresDirectory: "file.path.relative.requires.directory";
8
+ readonly Empty: "file.path.relative.empty";
9
+ };
10
+ export declare const FilePathRelativeSchema: z.core.$ZodBranded<z.ZodPipe<z.ZodString, z.ZodTransform<{
11
+ directory: string & z.core.$brand<"DirectoryPathRelativeSchema">;
9
12
  filename: Filename;
10
- }, string>>;
13
+ }, string>>, "FilePathRelativeSchema">;
11
14
  export type FilePathRelativeType = z.infer<typeof FilePathRelativeSchema>;
@@ -1,18 +1,19 @@
1
1
  import { z } from "zod/v4";
2
2
  import { DirectoryPathRelativeSchema } from "./directory-path-relative.vo";
3
3
  import { Filename } from "./filename.vo";
4
- export const RelFilePathTypeError = "rel.file.path.not.string";
5
- export const RelFilePathMustNotStartWithSlashError = "rel_file_path_must_not_start_with_slash";
6
- export const RelFilePathBackslashForbiddenError = "rel_file_path_backslash_forbidden";
7
- export const RelFilePathRequiresDirectoryError = "rel_file_path_requires_directory";
4
+ export const FilePathRelativeSchemaError = {
5
+ Type: "file.path.relative.type",
6
+ LeadingSlash: "file.path.relative.leading.slash",
7
+ BackslashForbidden: "file.path.relative.backslash.forbidden",
8
+ RequiresDirectory: "file.path.relative.requires.directory",
9
+ Empty: "file.path.relative.empty",
10
+ };
8
11
  export const FilePathRelativeSchema = z
9
- .string(RelFilePathTypeError)
10
- .trim()
11
- .refine((value) => !value.startsWith("/"), RelFilePathMustNotStartWithSlashError)
12
- .refine((value) => !value.includes("\\"), RelFilePathBackslashForbiddenError)
13
- // collapse duplicate slashes, then trim leading/trailing slashes
14
- .transform((value) => value.replace(/\/{2,}/g, "/").replace(/^\/+|\/+$/g, ""))
15
- .refine((value) => value.includes("/"), RelFilePathRequiresDirectoryError)
12
+ .string(FilePathRelativeSchemaError.Type)
13
+ .min(1, FilePathRelativeSchemaError.Empty)
14
+ .refine((value) => !value.startsWith("/"), FilePathRelativeSchemaError.LeadingSlash)
15
+ .refine((value) => !value.includes("\\"), FilePathRelativeSchemaError.BackslashForbidden)
16
+ .refine((value) => value.includes("/"), FilePathRelativeSchemaError.RequiresDirectory)
16
17
  .transform((normalized) => {
17
18
  const lastSlashIndex = normalized.lastIndexOf("/");
18
19
  const directoryCandidate = normalized.slice(0, lastSlashIndex);
@@ -20,4 +21,5 @@ export const FilePathRelativeSchema = z
20
21
  const directory = DirectoryPathRelativeSchema.parse(directoryCandidate);
21
22
  const filename = Filename.fromString(filenameCandidate);
22
23
  return { directory, filename };
23
- });
24
+ })
25
+ .brand("FilePathRelativeSchema");
@@ -7,11 +7,11 @@ export declare class FilePathRelative {
7
7
  private constructor();
8
8
  static fromParts(directoryCandidate: string, filename: Filename): FilePathRelative;
9
9
  static fromPartsSafe(directory: DirectoryPathRelativeType, filename: Filename): FilePathRelative;
10
- static fromString(pathCandidate: string): FilePathRelative;
10
+ static fromString(candidate: string): FilePathRelative;
11
11
  get(): string;
12
12
  getDirectory(): DirectoryPathRelativeType;
13
13
  getFilename(): Filename;
14
- withDirectoryRelative(newDirectory: DirectoryPathRelativeType): FilePathRelative;
14
+ withDirectory(newDirectory: DirectoryPathRelativeType): FilePathRelative;
15
15
  withFilename(newFilename: Filename): FilePathRelative;
16
16
  toAbsolute(newDirectory: DirectoryPathAbsoluteType): FilePathAbsolute;
17
17
  }
@@ -21,11 +21,11 @@ export declare class FilePathAbsolute {
21
21
  private constructor();
22
22
  static fromParts(directoryCandidate: string, filename: Filename): FilePathAbsolute;
23
23
  static fromPartsSafe(directory: DirectoryPathAbsoluteType, filename: Filename): FilePathAbsolute;
24
- static fromString(pathCandidate: string): FilePathAbsolute;
24
+ static fromString(candidate: string): FilePathAbsolute;
25
25
  get(): string;
26
26
  getDirectory(): DirectoryPathAbsoluteType;
27
27
  getFilename(): Filename;
28
- withDirectoryAbsolute(newDirectory: DirectoryPathAbsoluteType): FilePathAbsolute;
28
+ withDirectory(newDirectory: DirectoryPathAbsoluteType): FilePathAbsolute;
29
29
  withFilename(newFilename: Filename): FilePathAbsolute;
30
30
  toRelative(newDirectory: DirectoryPathRelativeType): FilePathRelative;
31
31
  }
@@ -16,9 +16,9 @@ export class FilePathRelative {
16
16
  static fromPartsSafe(directory, filename) {
17
17
  return new FilePathRelative(directory, filename);
18
18
  }
19
- static fromString(pathCandidate) {
20
- const parsed = FilePathRelativeSchema.parse(pathCandidate);
21
- return new FilePathRelative(parsed.directory, parsed.filename);
19
+ static fromString(candidate) {
20
+ const schema = FilePathRelativeSchema.parse(candidate);
21
+ return new FilePathRelative(schema.directory, schema.filename);
22
22
  }
23
23
  get() {
24
24
  return `${this.directory}/${this.filename.get()}`;
@@ -29,7 +29,7 @@ export class FilePathRelative {
29
29
  getFilename() {
30
30
  return this.filename;
31
31
  }
32
- withDirectoryRelative(newDirectory) {
32
+ withDirectory(newDirectory) {
33
33
  return new FilePathRelative(newDirectory, this.filename);
34
34
  }
35
35
  withFilename(newFilename) {
@@ -53,9 +53,9 @@ export class FilePathAbsolute {
53
53
  static fromPartsSafe(directory, filename) {
54
54
  return new FilePathAbsolute(directory, filename);
55
55
  }
56
- static fromString(pathCandidate) {
57
- const parsed = FilePathAbsoluteSchema.parse(pathCandidate);
58
- return new FilePathAbsolute(parsed.directory, parsed.filename);
56
+ static fromString(candidate) {
57
+ const schema = FilePathAbsoluteSchema.parse(candidate);
58
+ return new FilePathAbsolute(schema.directory, schema.filename);
59
59
  }
60
60
  get() {
61
61
  if (this.directory === "/")
@@ -68,7 +68,7 @@ export class FilePathAbsolute {
68
68
  getFilename() {
69
69
  return this.filename;
70
70
  }
71
- withDirectoryAbsolute(newDirectory) {
71
+ withDirectory(newDirectory) {
72
72
  return new FilePathAbsolute(newDirectory, this.filename);
73
73
  }
74
74
  withFilename(newFilename) {
@@ -1,6 +1,8 @@
1
1
  import { z } from "zod/v4";
2
- export declare const FilenameTypeError: "filename.not.string";
3
- export declare const FilenameInvalidError: "filename.invalid";
2
+ export declare const FilenameFromStringError: {
3
+ readonly Type: "filename.from.string.type";
4
+ readonly Invalid: "filename.from.string.Invalid";
5
+ };
4
6
  export declare const FilenameFromString: z.ZodPipe<z.ZodString, z.ZodTransform<{
5
7
  basename: string & z.core.$brand<"Basename">;
6
8
  extension: string & z.core.$brand<"Extension">;
@@ -1,15 +1,17 @@
1
1
  import { z } from "zod/v4";
2
2
  import { Basename } from "./basename.vo";
3
3
  import { Extension } from "./extension.vo";
4
- export const FilenameTypeError = "filename.not.string";
5
- export const FilenameInvalidError = "filename.invalid";
4
+ export const FilenameFromStringError = {
5
+ Type: "filename.from.string.type",
6
+ Invalid: "filename.from.string.Invalid",
7
+ };
8
+ // .+ at least one character, advances to the last dot
9
+ // .
10
+ // .+ at least one character
11
+ const DOT_WITH_SIDES = /^.+\..+$/;
6
12
  export const FilenameFromString = z
7
- .string(FilenameTypeError)
8
- .trim()
9
- .refine((value) => {
10
- const index = value.lastIndexOf(".");
11
- return index > 0 && index < value.length - 1;
12
- }, FilenameInvalidError)
13
+ .string(FilenameFromStringError.Type)
14
+ .regex(DOT_WITH_SIDES, FilenameFromStringError.Invalid)
13
15
  .transform((value) => {
14
16
  const index = value.lastIndexOf(".");
15
17
  const basename = Basename.parse(value.slice(0, index));
@@ -1,5 +1,9 @@
1
1
  import { z } from "zod/v4";
2
- export declare const FilenameSuffixTypeError: "suffix.not.string";
3
- export declare const FilenameSuffixTooLongError: "suffix_too_long";
4
- export declare const FilenameSuffix: z.core.$ZodBranded<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, "basename_suffix">;
2
+ export declare const FilenameSuffixError: {
3
+ readonly Type: "suffix.type";
4
+ readonly Empty: "suffix.empty";
5
+ readonly TooLong: "suffix.too.long";
6
+ readonly BadChars: "suffix.bad.chars";
7
+ };
8
+ export declare const FilenameSuffix: z.core.$ZodBranded<z.ZodString, "FilenameSuffix">;
5
9
  export type FilenameSuffixType = z.infer<typeof FilenameSuffix>;
@@ -1,9 +1,15 @@
1
1
  import { z } from "zod/v4";
2
- export const FilenameSuffixTypeError = "suffix.not.string";
3
- export const FilenameSuffixTooLongError = "suffix_too_long";
2
+ export const FilenameSuffixError = {
3
+ Type: "suffix.type",
4
+ Empty: "suffix.empty",
5
+ TooLong: "suffix.too.long",
6
+ BadChars: "suffix.bad.chars",
7
+ };
8
+ // Letters, digits, underscores, and hyphens allowed
9
+ const FILENAME_SUFFIX_WHITELIST = /^[a-zA-Z0-9_-]+$/;
4
10
  export const FilenameSuffix = z
5
- .string(FilenameSuffixTypeError)
6
- .trim()
7
- .transform((value) => value.replace(/[^A-Za-z0-9_-]/g, ""))
8
- .refine((value) => value.length <= 32, FilenameSuffixTooLongError)
9
- .brand("basename_suffix");
11
+ .string(FilenameSuffixError.Type)
12
+ .min(1, FilenameSuffixError.Empty)
13
+ .max(32, FilenameSuffixError.TooLong)
14
+ .regex(FILENAME_SUFFIX_WHITELIST, FilenameSuffixError.BadChars)
15
+ .brand("FilenameSuffix");
@@ -15,4 +15,6 @@ export declare class Filename {
15
15
  withBasename(basename: BasenameType): Filename;
16
16
  withSuffix(candidate: string): Filename;
17
17
  withSuffixSafe(suffix: FilenameSuffixType): Filename;
18
+ toString(): string;
19
+ toJSON(): string;
18
20
  }
@@ -16,8 +16,8 @@ export class Filename {
16
16
  return new Filename(basename, extension);
17
17
  }
18
18
  static fromString(candidate) {
19
- const { basename, extension } = FilenameFromString.parse(candidate);
20
- return new Filename(basename, extension);
19
+ const filename = FilenameFromString.parse(candidate);
20
+ return new Filename(filename.basename, filename.extension);
21
21
  }
22
22
  get() {
23
23
  return `${this.basename}.${this.extension}`;
@@ -43,4 +43,10 @@ export class Filename {
43
43
  const basename = Basename.parse(`${this.basename}${suffix}`);
44
44
  return new Filename(basename, this.extension);
45
45
  }
46
+ toString() {
47
+ return this.get();
48
+ }
49
+ toJSON() {
50
+ return this.get();
51
+ }
46
52
  }
@@ -0,0 +1,6 @@
1
+ import { z } from "zod/v4";
2
+ export declare const HeightMillimetersError: {
3
+ readonly Type: "height.millimeters.type";
4
+ readonly Invalid: "height.millimeters.invalid";
5
+ };
6
+ export declare const HeightMillimeters: z.core.$ZodBranded<z.ZodNumber, "HeightMillimeters">;
@@ -0,0 +1,10 @@
1
+ import { z } from "zod/v4";
2
+ export const HeightMillimetersError = {
3
+ Type: "height.millimeters.type",
4
+ Invalid: "height.millimeters.invalid",
5
+ };
6
+ export const HeightMillimeters = z
7
+ .number(HeightMillimetersError.Type)
8
+ .int(HeightMillimetersError.Type)
9
+ .min(0, HeightMillimetersError.Invalid)
10
+ .brand("HeightMillimeters");