@budiauktioner/buildi-primitives 0.1.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 (107) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/LICENSE +21 -0
  3. package/README.md +253 -0
  4. package/THIRD_PARTY_NOTICES.md +52 -0
  5. package/dist/banking/index.cjs +6491 -0
  6. package/dist/banking/index.cjs.map +1 -0
  7. package/dist/banking/index.d.cts +58 -0
  8. package/dist/banking/index.d.ts +58 -0
  9. package/dist/banking/index.js +6464 -0
  10. package/dist/banking/index.js.map +1 -0
  11. package/dist/contact/index.cjs +6678 -0
  12. package/dist/contact/index.cjs.map +1 -0
  13. package/dist/contact/index.d.cts +709 -0
  14. package/dist/contact/index.d.ts +709 -0
  15. package/dist/contact/index.js +6586 -0
  16. package/dist/contact/index.js.map +1 -0
  17. package/dist/country-BhD51LDL.d.cts +433 -0
  18. package/dist/country-p0n0EVQ9.d.ts +433 -0
  19. package/dist/finance/index.cjs +3592 -0
  20. package/dist/finance/index.cjs.map +1 -0
  21. package/dist/finance/index.d.cts +83 -0
  22. package/dist/finance/index.d.ts +83 -0
  23. package/dist/finance/index.js +3584 -0
  24. package/dist/finance/index.js.map +1 -0
  25. package/dist/geography/index.cjs +4227 -0
  26. package/dist/geography/index.cjs.map +1 -0
  27. package/dist/geography/index.d.cts +34 -0
  28. package/dist/geography/index.d.ts +34 -0
  29. package/dist/geography/index.js +4202 -0
  30. package/dist/geography/index.js.map +1 -0
  31. package/dist/index.cjs +14087 -0
  32. package/dist/index.cjs.map +1 -0
  33. package/dist/index.d.cts +75 -0
  34. package/dist/index.d.ts +75 -0
  35. package/dist/index.js +13868 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/isin-EeVPpNWu.d.ts +39 -0
  38. package/dist/isin-ZlQLBVm8.d.cts +39 -0
  39. package/dist/organization/index.cjs +2376 -0
  40. package/dist/organization/index.cjs.map +1 -0
  41. package/dist/organization/index.d.cts +117 -0
  42. package/dist/organization/index.d.ts +117 -0
  43. package/dist/organization/index.js +2346 -0
  44. package/dist/organization/index.js.map +1 -0
  45. package/dist/person/index.cjs +1144 -0
  46. package/dist/person/index.cjs.map +1 -0
  47. package/dist/person/index.d.cts +60 -0
  48. package/dist/person/index.d.ts +60 -0
  49. package/dist/person/index.js +1125 -0
  50. package/dist/person/index.js.map +1 -0
  51. package/dist/person-full-name-Cmc9Ynuc.d.cts +82 -0
  52. package/dist/person-full-name-D6Hbsab6.d.ts +82 -0
  53. package/dist/phone-number-C24--ggy.d.ts +139 -0
  54. package/dist/phone-number-DZ-YxCQQ.d.cts +139 -0
  55. package/dist/property/index.cjs +487 -0
  56. package/dist/property/index.cjs.map +1 -0
  57. package/dist/property/index.d.cts +56 -0
  58. package/dist/property/index.d.ts +56 -0
  59. package/dist/property/index.js +480 -0
  60. package/dist/property/index.js.map +1 -0
  61. package/dist/sample-data/index.cjs +12310 -0
  62. package/dist/sample-data/index.cjs.map +1 -0
  63. package/dist/sample-data/index.d.cts +260 -0
  64. package/dist/sample-data/index.d.ts +260 -0
  65. package/dist/sample-data/index.js +12302 -0
  66. package/dist/sample-data/index.js.map +1 -0
  67. package/dist/swedish-address-DNC3ftRF.d.cts +297 -0
  68. package/dist/swedish-address-GMzjqgxb.d.ts +297 -0
  69. package/dist/swedish-bank-account-holder-name-BFJ8h1aO.d.cts +45 -0
  70. package/dist/swedish-bank-account-holder-name-CAAru07F.d.ts +45 -0
  71. package/dist/swedish-municipality-DlUS7g7h.d.cts +87 -0
  72. package/dist/swedish-municipality-nDRHYRAd.d.ts +87 -0
  73. package/dist/swedish-organization-name-D7NvERxA.d.cts +33 -0
  74. package/dist/swedish-organization-name-rR0Q836C.d.ts +33 -0
  75. package/dist/swedish-organization-number-Bcj7V_lh.d.cts +130 -0
  76. package/dist/swedish-organization-number-DM8dpXwR.d.ts +130 -0
  77. package/dist/swedish-organization-type-CZOdETwG.d.cts +29 -0
  78. package/dist/swedish-organization-type-CZOdETwG.d.ts +29 -0
  79. package/dist/swedish-personal-identity-number-BiIg4io3.d.ts +149 -0
  80. package/dist/swedish-personal-identity-number-Cp9Coz55.d.cts +149 -0
  81. package/dist/swedish-property-designation-BM-gdd9x.d.ts +46 -0
  82. package/dist/swedish-property-designation-BaHXufqV.d.cts +46 -0
  83. package/dist/swedish-sni-code-Ccsswpni.d.ts +53 -0
  84. package/dist/swedish-sni-code-CuJFyM6l.d.cts +53 -0
  85. package/dist/swedish-swish-number-CL6Gx_h3.d.cts +397 -0
  86. package/dist/swedish-swish-number-DDG3mNDg.d.ts +397 -0
  87. package/dist/text-candidate-qg2bD9PY.d.cts +110 -0
  88. package/dist/text-candidate-qg2bD9PY.d.ts +110 -0
  89. package/dist/text-scanning/index.cjs +10414 -0
  90. package/dist/text-scanning/index.cjs.map +1 -0
  91. package/dist/text-scanning/index.d.cts +153 -0
  92. package/dist/text-scanning/index.d.ts +153 -0
  93. package/dist/text-scanning/index.js +10406 -0
  94. package/dist/text-scanning/index.js.map +1 -0
  95. package/dist/validation/index.cjs +83 -0
  96. package/dist/validation/index.cjs.map +1 -0
  97. package/dist/validation/index.d.cts +63 -0
  98. package/dist/validation/index.d.ts +63 -0
  99. package/dist/validation/index.js +79 -0
  100. package/dist/validation/index.js.map +1 -0
  101. package/dist/web/index.cjs +3994 -0
  102. package/dist/web/index.cjs.map +1 -0
  103. package/dist/web/index.d.cts +203 -0
  104. package/dist/web/index.d.ts +203 -0
  105. package/dist/web/index.js +3987 -0
  106. package/dist/web/index.js.map +1 -0
  107. package/package.json +211 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,51 @@
1
+ # Changelog — `@budiauktioner/buildi-primitives`
2
+
3
+ All notable changes to the TypeScript port of `Buildi.Primitives` will be
4
+ documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
5
+ and this package adheres to [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.1.0] - 2026-08-07
10
+
11
+ First public release.
12
+
13
+ ### Added
14
+
15
+ - Initial TypeScript port scaffolding.
16
+ - Public types for the Organization, Banking, Person, Geography, Finance,
17
+ Contact, Web, Property, Validation, and TextScanning namespaces.
18
+ - Subpath exports per namespace for tree-shaking.
19
+ - Local SwedishPersonalIdentityNumber implementation (no ActiveLogin dependency).
20
+ - `TextScanResult` typed accessors for all 24 scannable types.
21
+ - `Country.usesEuro`, `currencyCode`, `currency`, `currencies`,
22
+ `primaryLanguage`, `officialLanguages`, `latitude`, `longitude`, `value`, and
23
+ `formatted`.
24
+ - `Address.asCountryAddress()`, `Address.toDomesticMultilineString()`,
25
+ `Address.supportedCountryAddressTypes`, and `SwedishAddress.countryZipCode`.
26
+ - `Currency.nativeName` / `toNativeString()` and `Url.toUrl()` / `Url.fromUrl()`.
27
+ - `maskSwedishOrganizationName` and `maskPersonAge`.
28
+ - 28 further `PhoneCallingCode` named constants, for 35 in total.
29
+ - `PhoneNumberTestData` covering all 495 PTS-reserved test phone numbers.
30
+ - `TextDirection`, `WritingScript`, and `SwedishOrganizationTypeHintResult` are
31
+ now exported from their namespace barrels.
32
+ - [PARITY.md](PARITY.md) and a parity guard test covering the .NET public surface.
33
+
34
+ ### Changed
35
+
36
+ - `Country.isEuropeanUnion` and `Country.isNordic` renamed to
37
+ `isInEuropeanUnion` and `isInNordics`. See [BREAKING_CHANGES.md](BREAKING_CHANGES.md).
38
+ - Scannable types now import the `text-scanning` leaf modules instead of its
39
+ barrel, removing an import cycle between the two.
40
+ - `registerDefaultTextScanners` is now exported from the `text-scanning`
41
+ namespace.
42
+ - `sideEffects` lists the four entries that register defaults at import time
43
+ instead of claiming `false` for the whole package. Every other entry stays
44
+ tree-shakeable, so subpath imports are unaffected.
45
+
46
+ ### Fixed
47
+
48
+ - Importing `@budiauktioner/buildi-primitives/text-scanning` on its own left
49
+ `defaultTextScanner` empty, so scans silently returned no candidates. The
50
+ registration ran only from the package root. It now runs when the
51
+ `text-scanning` entry itself is imported.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Budi AB
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,253 @@
1
+ # @budiauktioner/buildi-primitives
2
+
3
+ TypeScript primitives for Swedish, EU, and international value-object
4
+ validation, normalization, masking, and text scanning.
5
+
6
+ This is the TypeScript port of the .NET package
7
+ [`Buildi.Primitives`](https://www.nuget.org/packages/Buildi.Primitives), whose
8
+ [source](https://github.com/BudiAuktioner/Buildi.Primitives) remains the
9
+ behavioural specification for both languages.
10
+
11
+ > **Status**: early release, versioned from 0.1.0. Ten of the thirteen .NET
12
+ > namespaces are ported and track the .NET package closely; three are not
13
+ > ported yet. See [PARITY.md](PARITY.md) for the exact coverage and gaps.
14
+
15
+ ## Install
16
+
17
+ ```sh
18
+ pnpm add @budiauktioner/buildi-primitives
19
+ # or
20
+ npm install @budiauktioner/buildi-primitives
21
+ # or
22
+ yarn add @budiauktioner/buildi-primitives
23
+ # or
24
+ bun add @budiauktioner/buildi-primitives
25
+ ```
26
+
27
+ ## Quick start
28
+
29
+ ```ts
30
+ import { SwedishOrganizationNumber } from "@budiauktioner/buildi-primitives/organization";
31
+
32
+ SwedishOrganizationNumber.isValid("559246-0421"); // true
33
+ SwedishOrganizationNumber.isValid("559246-0420"); // false — bad check digit
34
+
35
+ // Static helpers accept messy input and return null when it is not valid.
36
+ SwedishOrganizationNumber.format("5592460421"); // "559246-0421"
37
+ SwedishOrganizationNumber.normalize("559246-0421"); // "165592460421"
38
+ SwedishOrganizationNumber.format("nonsense"); // null
39
+
40
+ // Or parse once and keep the value object around.
41
+ const org = SwedishOrganizationNumber.parse("5592460421");
42
+ org.toString(); // "559246-0421" — display form
43
+ org.toNormalizedString(); // "165592460421" — storage form
44
+ org.isPerson; // false — this is a legal entity, not a sole trader
45
+ ```
46
+
47
+ `format()` produces the display form and `normalize()` the canonical form for
48
+ storage and comparison. For roughly half the types these are the same string;
49
+ for the rest they deliberately differ, as above. Store the normalized value and
50
+ render the formatted one.
51
+
52
+ ## API conventions
53
+
54
+ Every value-object type follows the same shape:
55
+
56
+ ```ts
57
+ class TypeName {
58
+ static readonly typeInfo: PrimitiveTypeInfo;
59
+
60
+ static tryParse(input: string | null | undefined): TypeName | null;
61
+ static parse(input: string): TypeName; // throws on invalid input
62
+ static isValid(input: string | null | undefined): boolean;
63
+ static format(
64
+ input: string | null | undefined,
65
+ options?: { fallbackToTrimmedInputWhenInvalid?: boolean },
66
+ ): string | null;
67
+ static normalize(
68
+ input: string | null | undefined,
69
+ options?: { fallbackToTrimmedInputWhenInvalid?: boolean },
70
+ ): string | null;
71
+ static isNormalized(input: string | null | undefined): boolean;
72
+
73
+ toNormalizedString(): string;
74
+ toString(): string;
75
+
76
+ equals(other: TypeName | null | undefined): boolean;
77
+ compareTo(other: TypeName | null | undefined): number;
78
+ }
79
+ ```
80
+
81
+ Constructors are private: a value object can only come from `parse` or
82
+ `tryParse`, so an instance is always valid. Every static helper accepts
83
+ `string | null | undefined`, so unvalidated input can be passed straight in.
84
+
85
+ Pass `{ fallbackToTrimmedInputWhenInvalid: true }` to `format` or `normalize`
86
+ to get the trimmed original input back instead of `null` when the input is not
87
+ valid — useful when rendering user-entered values you do not want to drop.
88
+
89
+ ## Validation
90
+
91
+ Types with more than one meaningful failure mode add `validate()`, which
92
+ reports why the input was rejected rather than just that it was:
93
+
94
+ ```ts
95
+ import { Iban } from "@budiauktioner/buildi-primitives/banking";
96
+
97
+ const result = Iban.validate("SE45 5000 0000 0583 9825 7460");
98
+
99
+ result.isValid; // false
100
+ result.issues.map((i) => i.reason); // ["InvalidCheckDigit"]
101
+ result.issues[0].description; // "Ogiltiga IBAN-kontrollsiffror."
102
+ ```
103
+
104
+ `reason` is a stable `ValidationErrorReason` enum value safe to branch on.
105
+ `description` is human-readable and follows the display language described
106
+ under [Defaults and display language](#defaults-and-display-language); each
107
+ issue also exposes `englishDescription` and `localizedDescription` directly.
108
+
109
+ ## Masking
110
+
111
+ Masking is done by module-level `maskX` functions, exported from the same
112
+ subpath as the type they mask:
113
+
114
+ ```ts
115
+ import { Iban, maskIban } from "@budiauktioner/buildi-primitives/banking";
116
+ import { EmailAddress, maskEmailAddress } from "@budiauktioner/buildi-primitives/web";
117
+ import { PhoneNumber, maskPhoneNumber } from "@budiauktioner/buildi-primitives/contact";
118
+
119
+ maskIban(Iban.parse("SE4550000000058398257466")); // "SE45 **** **** **** **** ****"
120
+ maskEmailAddress(EmailAddress.parse("info@example.com")); // "i***@example.com"
121
+ maskPhoneNumber(PhoneNumber.parse("070-174 06 33")); // "+46*****0633"
122
+ ```
123
+
124
+ Some take options, for example `maskEmailAddress(email, { maskDomain: true })`.
125
+
126
+ ## Text scanning
127
+
128
+ Types that can plausibly appear in prose expose `findCandidatesInText`, and
129
+ `defaultTextScanner` runs all of them at once:
130
+
131
+ ```ts
132
+ import { defaultTextScanner } from "@budiauktioner/buildi-primitives/text-scanning";
133
+
134
+ const text = "Hör av dig till info@example.com eller ring 070-174 06 33.";
135
+ const result = defaultTextScanner.scan(text);
136
+
137
+ result.emails.map((c) => c.normalizedForm); // ["info@example.com"]
138
+ result.phoneNumbers.map((c) => c.normalizedForm); // ["0046701740633"]
139
+
140
+ result.maskAll(text); // "Hör av dig till i***@example.com eller ring +46*****0633."
141
+ result.redactAll(text); // "Hör av dig till [REDACTED] eller ring [REDACTED]."
142
+ ```
143
+
144
+ `TextScanResult` has a typed accessor per scannable type (`emails`, `ibans`,
145
+ `organizationNumbers`, and so on). Every candidate carries its span in the
146
+ source text, its normalized, formatted and masked forms, and a
147
+ `TextMatchConfidence`. Types with a checksum report `High`; bare digit
148
+ sequences report `Low`. Narrow a scan with
149
+ `scan(text, { minimumConfidence, includeCategories, excludeCategories })`.
150
+
151
+ Scanning is the one part of the package with import-time behaviour: importing
152
+ `@budiauktioner/buildi-primitives/text-scanning` (or the root entry) registers
153
+ all built-in scanners on `defaultTextScanner`. Importing only a value-object
154
+ subpath deliberately does not. Construct your own `TextScanner` if you want an
155
+ isolated registry.
156
+
157
+ ## Defaults and display language
158
+
159
+ `PrimitivesDefaults` holds the process-wide culture, UI culture, default
160
+ country and default calling code. It affects display names, localized
161
+ validation messages, and how ambiguous input such as a national phone number
162
+ is interpreted.
163
+
164
+ ```ts
165
+ import { PrimitivesDefaults, Country } from "@budiauktioner/buildi-primitives";
166
+
167
+ PrimitivesDefaults.culture; // "sv-SE"
168
+ PrimitivesDefaults.countryAlpha2Code; // "SE"
169
+
170
+ Country.parse("SE").displayName; // "Sverige"
171
+
172
+ PrimitivesDefaults.uiCulture = "en-US";
173
+ Country.parse("SE").displayName; // "Sweden"
174
+
175
+ PrimitivesDefaults.reset(); // back to the defaults
176
+ ```
177
+
178
+ `useLocalizedDisplayNames` is a read-only getter derived from `uiCulture` — it
179
+ is `true` when `uiCulture` is Swedish. Set `uiCulture` to change the display
180
+ language; assigning to `useLocalizedDisplayNames` throws a `TypeError`. Types
181
+ that expose a `displayName` also expose `englishName` and `localizedName`, so a
182
+ mixed-locale app can bypass the global entirely.
183
+
184
+ ## Sample data
185
+
186
+ Valid, publicly known values for tests, fixtures and documentation. Everything
187
+ here is a real parsed value object, so it stays valid as the rules evolve.
188
+
189
+ ```ts
190
+ import { OrganizationSampleData } from "@budiauktioner/buildi-primitives/sample-data";
191
+
192
+ OrganizationSampleData.OrganizationNumber.all[0].toString(); // "559246-0421"
193
+ ```
194
+
195
+ Only publicly known organizations and reserved test values are used, such as
196
+ RFC 2606 domains for email and the standard international test IBANs.
197
+
198
+ ## Subpath exports and bundle size
199
+
200
+ The root entry re-exports everything for convenience. Import from a namespace
201
+ subpath instead when bundle size matters:
202
+
203
+ ```ts
204
+ // ~283 kB minified — the root entry registers every text scanner
205
+ import { SwedishOrganizationNumber } from "@budiauktioner/buildi-primitives";
206
+
207
+ // ~39 kB minified — the same type, nothing else
208
+ import { SwedishOrganizationNumber } from "@budiauktioner/buildi-primitives/organization";
209
+ ```
210
+
211
+ Available subpaths: `contact`, `person`, `organization`, `geography`, `web`,
212
+ `finance`, `property`, `banking`, `validation`, `text-scanning`, and
213
+ `sample-data`.
214
+
215
+ ```ts
216
+ import { SwedishPersonalIdentityNumber } from "@budiauktioner/buildi-primitives/person";
217
+ import { Country, Continent, Language } from "@budiauktioner/buildi-primitives/geography";
218
+ import { AddressCity, PhoneNumber, SwedishAddress } from "@budiauktioner/buildi-primitives/contact";
219
+ import { Currency, MoneyAmount, ExchangeRates } from "@budiauktioner/buildi-primitives/finance";
220
+ import { ValidationErrorReason } from "@budiauktioner/buildi-primitives/validation";
221
+ ```
222
+
223
+ Use the root entry when you want the batteries-included behaviour, in
224
+ particular a `defaultTextScanner` that already knows every scannable type.
225
+
226
+ ## Runtime targets
227
+
228
+ - Node.js 20.10 or newer (see [`.nvmrc`](.nvmrc)).
229
+ - Bun 1.1 or newer.
230
+ - Modern browsers (current Chromium, Firefox, Safari).
231
+ - No Node-only runtime APIs and no runtime dependencies; ES2022 plus standard
232
+ `Intl` only.
233
+ - Ships ESM and CJS builds with type definitions for both.
234
+
235
+ ## Development
236
+
237
+ All commands run from the repository root:
238
+
239
+ ```sh
240
+ pnpm install
241
+ pnpm typecheck
242
+ pnpm lint
243
+ pnpm test
244
+ pnpm build
245
+ ```
246
+
247
+ See [AGENTS.md](AGENTS.md) for conventions and the per-type pattern,
248
+ [PARITY.md](PARITY.md) for the current state of .NET parity, and
249
+ [CHANGELOG.md](CHANGELOG.md) for release notes.
250
+
251
+ ## License
252
+
253
+ MIT. See [LICENSE](LICENSE) and [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
@@ -0,0 +1,52 @@
1
+ # Third-party notices — `@budiauktioner/buildi-primitives` (TypeScript)
2
+
3
+ `@budiauktioner/buildi-primitives` ships with **zero runtime dependencies**. This document
4
+ collects attributions for the development tooling that builds, tests, and
5
+ validates the package, plus any public references whose definitions or test
6
+ data influenced the implementation.
7
+
8
+ ## Reference specifications and test data
9
+
10
+ The TypeScript port reimplements all logic from scratch. The following public
11
+ sources are referenced for behavioural parity. None of them are linked at
12
+ runtime.
13
+
14
+ - [Skatteverket — Personnummer](https://skatteverket.se/privat/folkbokforing/personnummer.4.3810a01c150939e893f18c29.html)
15
+ — official Swedish personal identity number rules.
16
+ - [Skatteverket — Samordningsnummer](https://skatteverket.se/) — coordination
17
+ number rules.
18
+ - [Bolagsverket](https://bolagsverket.se/) — Swedish organization registry.
19
+ - [PostNord](https://www.postnord.se/) — Swedish postal city/zip-code rules.
20
+ - ISO 3166-1, ISO 3166-2, ISO 4217, ISO 639 — country / subdivision /
21
+ currency / language codes.
22
+ - [GLEIF](https://www.gleif.org/) — LEI codes.
23
+ - [VIES VAT](https://ec.europa.eu/taxation_customs/vies/) — EU VAT number
24
+ formats.
25
+ - [D&B](https://www.dnb.com/) — DUNS numbers.
26
+ - [Skatteverket — OCR](https://skatteverket.se/) and Bankgirot — OCR reference
27
+ numbers.
28
+
29
+ ## Algorithm derivations
30
+
31
+ - Luhn (mod 10) checksum — public domain algorithm.
32
+ - IBAN MOD-97 — defined in ISO 13616.
33
+ - LEI MOD-97-10 — defined in ISO 17442.
34
+
35
+ If any logic is later derived by reading the source of an MIT-licensed library
36
+ such as [ActiveLogin.Identity](https://github.com/ActiveLogin/ActiveLogin.Identity),
37
+ list that derivation here together with the upstream license.
38
+
39
+ ## Development tooling
40
+
41
+ This package is built and validated using the following tools (development
42
+ dependencies; not shipped to consumers):
43
+
44
+ - [TypeScript](https://www.typescriptlang.org/) — Apache-2.0
45
+ - [tsup](https://tsup.egoist.dev/) — MIT
46
+ - [tsx](https://tsx.is/) — MIT
47
+ - [vitest](https://vitest.dev/) — MIT
48
+ - [eslint](https://eslint.org/) — MIT
49
+ - [typescript-eslint](https://typescript-eslint.io/) — MIT
50
+ - [prettier](https://prettier.io/) — MIT
51
+ - [publint](https://publint.dev/) — MIT
52
+ - [@arethetypeswrong/cli](https://arethetypeswrong.github.io/) — MIT