@oxog/vld 1.1.0 → 1.2.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 (120) hide show
  1. package/CHANGELOG.md +107 -2
  2. package/README.md +274 -3
  3. package/dist/codecs/index.d.ts +89 -0
  4. package/dist/codecs/index.d.ts.map +1 -0
  5. package/dist/codecs/index.js +256 -0
  6. package/dist/codecs/index.js.map +1 -0
  7. package/dist/coercion/string.js +1 -1
  8. package/dist/coercion/string.js.map +1 -1
  9. package/dist/index.d.ts +14 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +27 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/locales/af.d.ts.map +1 -1
  14. package/dist/locales/af.js +18 -4
  15. package/dist/locales/af.js.map +1 -1
  16. package/dist/locales/ar.d.ts.map +1 -1
  17. package/dist/locales/ar.js +15 -1
  18. package/dist/locales/ar.js.map +1 -1
  19. package/dist/locales/bn.d.ts.map +1 -1
  20. package/dist/locales/bn.js +15 -1
  21. package/dist/locales/bn.js.map +1 -1
  22. package/dist/locales/da.d.ts.map +1 -1
  23. package/dist/locales/da.js +15 -1
  24. package/dist/locales/da.js.map +1 -1
  25. package/dist/locales/de.d.ts.map +1 -1
  26. package/dist/locales/de.js +15 -1
  27. package/dist/locales/de.js.map +1 -1
  28. package/dist/locales/en.d.ts.map +1 -1
  29. package/dist/locales/en.js +15 -1
  30. package/dist/locales/en.js.map +1 -1
  31. package/dist/locales/es-MX.d.ts.map +1 -1
  32. package/dist/locales/es-MX.js +15 -1
  33. package/dist/locales/es-MX.js.map +1 -1
  34. package/dist/locales/es.d.ts.map +1 -1
  35. package/dist/locales/es.js +15 -1
  36. package/dist/locales/es.js.map +1 -1
  37. package/dist/locales/fi.d.ts.map +1 -1
  38. package/dist/locales/fi.js +15 -1
  39. package/dist/locales/fi.js.map +1 -1
  40. package/dist/locales/fr.d.ts.map +1 -1
  41. package/dist/locales/fr.js +15 -1
  42. package/dist/locales/fr.js.map +1 -1
  43. package/dist/locales/hi.d.ts.map +1 -1
  44. package/dist/locales/hi.js +15 -1
  45. package/dist/locales/hi.js.map +1 -1
  46. package/dist/locales/id.d.ts.map +1 -1
  47. package/dist/locales/id.js +15 -1
  48. package/dist/locales/id.js.map +1 -1
  49. package/dist/locales/it.d.ts.map +1 -1
  50. package/dist/locales/it.js +15 -1
  51. package/dist/locales/it.js.map +1 -1
  52. package/dist/locales/ja.d.ts.map +1 -1
  53. package/dist/locales/ja.js +15 -1
  54. package/dist/locales/ja.js.map +1 -1
  55. package/dist/locales/ko.d.ts.map +1 -1
  56. package/dist/locales/ko.js +15 -1
  57. package/dist/locales/ko.js.map +1 -1
  58. package/dist/locales/nl.d.ts.map +1 -1
  59. package/dist/locales/nl.js +15 -1
  60. package/dist/locales/nl.js.map +1 -1
  61. package/dist/locales/no.d.ts.map +1 -1
  62. package/dist/locales/no.js +15 -1
  63. package/dist/locales/no.js.map +1 -1
  64. package/dist/locales/pl.d.ts.map +1 -1
  65. package/dist/locales/pl.js +15 -1
  66. package/dist/locales/pl.js.map +1 -1
  67. package/dist/locales/pt-BR.d.ts.map +1 -1
  68. package/dist/locales/pt-BR.js +15 -1
  69. package/dist/locales/pt-BR.js.map +1 -1
  70. package/dist/locales/pt.d.ts.map +1 -1
  71. package/dist/locales/pt.js +15 -1
  72. package/dist/locales/pt.js.map +1 -1
  73. package/dist/locales/ru.d.ts.map +1 -1
  74. package/dist/locales/ru.js +15 -1
  75. package/dist/locales/ru.js.map +1 -1
  76. package/dist/locales/sv.d.ts.map +1 -1
  77. package/dist/locales/sv.js +15 -1
  78. package/dist/locales/sv.js.map +1 -1
  79. package/dist/locales/sw.d.ts.map +1 -1
  80. package/dist/locales/sw.js +15 -1
  81. package/dist/locales/sw.js.map +1 -1
  82. package/dist/locales/th.d.ts.map +1 -1
  83. package/dist/locales/th.js +15 -1
  84. package/dist/locales/th.js.map +1 -1
  85. package/dist/locales/tr.d.ts.map +1 -1
  86. package/dist/locales/tr.js +15 -1
  87. package/dist/locales/tr.js.map +1 -1
  88. package/dist/locales/types.d.ts +10 -0
  89. package/dist/locales/types.d.ts.map +1 -1
  90. package/dist/locales/types.js.map +1 -1
  91. package/dist/locales/vi.d.ts.map +1 -1
  92. package/dist/locales/vi.js +15 -1
  93. package/dist/locales/vi.js.map +1 -1
  94. package/dist/locales/zh.d.ts.map +1 -1
  95. package/dist/locales/zh.js +15 -1
  96. package/dist/locales/zh.js.map +1 -1
  97. package/dist/utils/codec-utils.d.ts +44 -0
  98. package/dist/utils/codec-utils.d.ts.map +1 -0
  99. package/dist/utils/codec-utils.js +118 -0
  100. package/dist/utils/codec-utils.js.map +1 -0
  101. package/dist/validators/base64.d.ts +18 -0
  102. package/dist/validators/base64.d.ts.map +1 -0
  103. package/dist/validators/base64.js +62 -0
  104. package/dist/validators/base64.js.map +1 -0
  105. package/dist/validators/codec.d.ts +55 -0
  106. package/dist/validators/codec.d.ts.map +1 -0
  107. package/dist/validators/codec.js +182 -0
  108. package/dist/validators/codec.js.map +1 -0
  109. package/dist/validators/hex.d.ts +17 -0
  110. package/dist/validators/hex.d.ts.map +1 -0
  111. package/dist/validators/hex.js +61 -0
  112. package/dist/validators/hex.js.map +1 -0
  113. package/dist/validators/object.d.ts.map +1 -1
  114. package/dist/validators/object.js +8 -4
  115. package/dist/validators/object.js.map +1 -1
  116. package/dist/validators/uint8array.d.ts +25 -0
  117. package/dist/validators/uint8array.d.ts.map +1 -0
  118. package/dist/validators/uint8array.js +87 -0
  119. package/dist/validators/uint8array.js.map +1 -0
  120. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -5,7 +5,112 @@ All notable changes to VLD will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [1.1.0] - 2025-01-11
8
+ ## [1.2.0] - 2025-08-24
9
+
10
+ ### 🎯 **100% Test Success Rate Achieved**
11
+ - **569 tests passing** with 0 failures across all test suites
12
+ - **97.3% statement coverage** (up from 97.18%)
13
+ - **93.5% branch coverage**
14
+ - **96.78% function coverage**
15
+ - **97.6% line coverage**
16
+ - All Zod-compatible codec tests now fully passing
17
+
18
+ ### 🚀 Major Features Added
19
+
20
+ #### **Codec System - Bidirectional Transformations**
21
+ - **NEW**: Complete codec system for bidirectional data transformations
22
+ - `v.codec()` factory method for creating custom codecs
23
+ - Full encode/decode support with type safety
24
+ - Async codec support with `parseAsync()` and `encodeAsync()` methods
25
+ - Comprehensive error handling for both directions
26
+
27
+ #### **19 Built-in Zod-Compatible Codecs**
28
+
29
+ **String Conversion Codecs:**
30
+ - `stringToNumber` - String ↔ Number with validation
31
+ - `stringToInt` - String ↔ Integer with validation
32
+ - `stringToBigInt` - String ↔ BigInt conversion
33
+ - `numberToBigInt` - Number ↔ BigInt conversion
34
+ - `stringToBoolean` - Flexible string ↔ boolean (`'true'`, `'1'`, `'yes'`, `'on'` → `true`)
35
+
36
+ **Date Conversion Codecs:**
37
+ - `isoDatetimeToDate` - ISO 8601 string ↔ Date object
38
+ - `epochSecondsToDate` - Unix seconds ↔ Date object
39
+ - `epochMillisToDate` - Unix milliseconds ↔ Date object
40
+
41
+ **JSON and Complex Data:**
42
+ - `jsonCodec()` - Generic JSON string ↔ any type
43
+ - `base64Json()` - Base64-encoded JSON with schema validation
44
+ - `jwtPayload()` - JWT payload decoder (read-only)
45
+
46
+ **URL and Web:**
47
+ - `stringToURL` - String ↔ URL object
48
+ - `stringToHttpURL` - HTTP/HTTPS URL validation and conversion
49
+ - `uriComponent` - URI component encode/decode
50
+
51
+ **Binary Data:**
52
+ - `base64ToBytes` - Base64 ↔ Uint8Array
53
+ - `base64urlToBytes` - URL-safe Base64 ↔ Uint8Array
54
+ - `hexToBytes` - Hexadecimal ↔ Uint8Array
55
+ - `utf8ToBytes` - UTF-8 string ↔ Uint8Array
56
+ - `bytesToUtf8` - Uint8Array ↔ UTF-8 string
57
+
58
+ #### **New Validator Types**
59
+ - `v.base64()` - Base64 string validation with URL-safe mode
60
+ - `v.hex()` - Hexadecimal string validation with lowercase mode
61
+ - `v.uint8Array()` - Uint8Array validation with length constraints
62
+
63
+ #### **Enhanced Utilities**
64
+ - Comprehensive codec utility functions in `codec-utils.ts`
65
+ - Cross-platform Base64 encoding/decoding (Node.js + Browser)
66
+ - Secure error handling for all codec operations
67
+
68
+ ### 📚 Documentation Updates
69
+ - **README.md**: Comprehensive codec documentation with examples
70
+ - **API.md**: Complete codec API reference with TypeScript examples
71
+ - **New Examples**:
72
+ - `examples/codecs.js` - JavaScript codec examples
73
+ - `examples/codecs.ts` - TypeScript codec examples with full type safety
74
+ - Updated CLAUDE.md with codec development guidance
75
+
76
+ ### 🔧 Technical Improvements
77
+ - **Zero Circular Dependencies**: Refactored codec architecture
78
+ - **Full Type Safety**: Complete TypeScript support with inference
79
+ - **97.3% Test Coverage**: Comprehensive test suite with 569 passing tests
80
+ - **Error Message Localization**: All codec errors support 27+ languages
81
+
82
+ ### 🎯 Zod Compatibility
83
+ - **100% Zod Codec Parity**: All Zod codecs implemented and compatible
84
+ - **Beyond Zod**: Additional codecs not available in Zod
85
+ - **Drop-in Replacement**: Seamless migration path from Zod codecs
86
+
87
+ ### Performance
88
+ - **Optimized Transformations**: Efficient bidirectional conversions
89
+ - **Memory Efficient**: Immutable codec architecture prevents leaks
90
+ - **Async Support**: Non-blocking operations for I/O-bound transformations
91
+
92
+ ## [1.1.1] - 2025-08-18
93
+
94
+ ### Security
95
+ - **CRITICAL**: Fixed prototype pollution vulnerability in VldObject passthrough mode
96
+ - Added protection against `__proto__`, `constructor`, and `prototype` key pollution
97
+ - Comprehensive security test suite added
98
+
99
+ ### Fixed
100
+ - Removed unnecessary escape characters in regex patterns (URL validation)
101
+ - Fixed escape characters in locale files (Afrikaans)
102
+ - Added ESLint configuration for code quality
103
+
104
+ ### Added
105
+ - Security test suite with prototype pollution prevention tests
106
+ - Coverage improvement tests for better code quality
107
+ - ESLint configuration with TypeScript support
108
+
109
+ ### Changed
110
+ - Improved test coverage to 97.1% statements
111
+ - All linting issues resolved
112
+
113
+ ## [1.1.0] - 2025-08-12
9
114
 
10
115
  ### Added
11
116
  - Professional benchmark suite with real-world performance testing
@@ -46,7 +151,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
46
151
  - Schema creation: 8.22x faster
47
152
  - Overall performance: 2.07x faster average
48
153
 
49
- ## [1.0.0] - 2024-12-15
154
+ ## [1.0.0] - 2025-08-11
50
155
 
51
156
  ### Initial Release
52
157
 
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)
6
6
  [![Zero Dependencies](https://img.shields.io/badge/Dependencies-0-green.svg)](package.json)
7
- [![Test Coverage](https://img.shields.io/badge/Coverage-99.5%25-brightgreen.svg)](package.json)
7
+ [![Test Coverage](https://img.shields.io/badge/Coverage-97.3%25-brightgreen.svg)](package.json)
8
8
 
9
9
  VLD is a blazing-fast, type-safe validation library for TypeScript and JavaScript with **full Zod feature parity**. Built with performance in mind, it provides a simple and intuitive API while maintaining excellent type inference and 27+ language internationalization support.
10
10
 
@@ -18,7 +18,7 @@ VLD is a blazing-fast, type-safe validation library for TypeScript and JavaScrip
18
18
  - **🔧 Composable**: Chain validations for complex schemas
19
19
  - **⚠️ Advanced Error Formatting**: Tree, pretty, and flatten error utilities
20
20
  - **🌍 Multi-language**: Built-in support for 27+ languages
21
- - **✅ 99.5% Test Coverage**: Rigorously tested with comprehensive test suite
21
+ - **✅ 97.3% Test Coverage**: Rigorously tested with 569 passing tests
22
22
  - **🏆 Industry Leading Performance**: 2.07x faster than Zod on average
23
23
 
24
24
  ### Advanced Zod-Compatible Features
@@ -31,6 +31,14 @@ VLD is a blazing-fast, type-safe validation library for TypeScript and JavaScrip
31
31
  - **🛡️ Fallback Handling**: `catch()` for graceful error recovery
32
32
  - **🎯 Object Utilities**: `pick()`, `omit()`, `extend()` for flexible object schemas
33
33
 
34
+ ### 🚀 **NEW** Codec System - Beyond Zod
35
+ - **↔️ Bidirectional Transformations**: Full encode/decode support for data conversion
36
+ - **📦 19 Built-in Codecs**: String conversions, date parsing, JSON, URL, binary data
37
+ - **🔗 Zod-Compatible**: All `stringToNumber`, `jsonCodec`, `base64ToBytes`, etc.
38
+ - **⚡ Async Support**: Both sync and async codec operations
39
+ - **🛠 Custom Codecs**: Create your own bidirectional transformations
40
+ - **🎯 Type-Safe**: Full TypeScript support with perfect type inference
41
+
34
42
  ## 📊 Performance
35
43
 
36
44
  VLD is designed for speed and efficiency with recent optimizations delivering exceptional performance:
@@ -768,6 +776,269 @@ schema.extend({ email: v.string().email() })
768
776
  .catch({ name: 'Unknown', email: 'no-email@example.com' });
769
777
  ```
770
778
 
779
+ ## 🔄 Codecs - Bidirectional Transformations
780
+
781
+ VLD introduces **codecs** - powerful bidirectional transformations that can convert data between different representations. Unlike simple transformations, codecs can both **decode** (input → output) and **encode** (output → input).
782
+
783
+ ### 🎯 What are Codecs?
784
+
785
+ Codecs enable safe, type-checked conversions between different data formats. They're perfect for:
786
+ - **API boundaries**: Convert strings to structured data
787
+ - **Database serialization**: Transform objects to/from storage formats
788
+ - **Network protocols**: Handle data encoding/decoding
789
+ - **Configuration parsing**: Convert config strings to typed values
790
+
791
+ ### 📦 Built-in Codecs
792
+
793
+ VLD provides all Zod-compatible codecs plus additional utilities:
794
+
795
+ #### **String Conversion Codecs**
796
+
797
+ ```typescript
798
+ import { stringToNumber, stringToInt, stringToBigInt, stringToBoolean } from '@oxog/vld';
799
+
800
+ // String to number conversion
801
+ const age = stringToNumber.parse('25'); // 25
802
+ const price = stringToNumber.encode(99.99); // "99.99"
803
+
804
+ // String to integer (validates integer constraint)
805
+ const count = stringToInt.parse('42'); // 42
806
+ stringToInt.parse('42.5'); // ❌ Validation error: must be integer
807
+
808
+ // String to BigInt for large numbers
809
+ const bigNum = stringToBigInt.parse('123456789012345678901234567890'); // 123456789012345678901234567890n
810
+
811
+ // String to boolean (flexible parsing)
812
+ stringToBoolean.parse('true'); // true
813
+ stringToBoolean.parse('1'); // true
814
+ stringToBoolean.parse('yes'); // true
815
+ stringToBoolean.parse('on'); // true
816
+ stringToBoolean.parse('false'); // false
817
+ stringToBoolean.parse('0'); // false
818
+ ```
819
+
820
+ #### **Date Conversion Codecs**
821
+
822
+ ```typescript
823
+ import { isoDatetimeToDate, epochSecondsToDate, epochMillisToDate } from '@oxog/vld';
824
+
825
+ // ISO datetime string to Date
826
+ const date1 = isoDatetimeToDate.parse('2023-12-25T10:30:00.000Z');
827
+ console.log(date1.toISOString()); // "2023-12-25T10:30:00.000Z"
828
+
829
+ // Unix epoch seconds to Date
830
+ const date2 = epochSecondsToDate.parse(1703505000);
831
+ console.log(date2.getFullYear()); // 2023
832
+
833
+ // Unix epoch milliseconds to Date
834
+ const date3 = epochMillisToDate.parse(1703505000000);
835
+ console.log(date3.getMonth()); // 11 (December)
836
+
837
+ // All support bidirectional conversion
838
+ const backToEpoch = epochSecondsToDate.encode(new Date()); // Unix timestamp
839
+ ```
840
+
841
+ #### **JSON and Complex Data Codecs**
842
+
843
+ ```typescript
844
+ import { jsonCodec, base64Json } from '@oxog/vld';
845
+
846
+ // Generic JSON codec
847
+ const userJson = jsonCodec();
848
+ const user = userJson.parse('{"name":"John","age":30}'); // { name: "John", age: 30 }
849
+ const jsonString = userJson.encode(user); // '{"name":"John","age":30}'
850
+
851
+ // JSON codec with schema validation
852
+ const userSchema = v.object({
853
+ name: v.string(),
854
+ age: v.number()
855
+ });
856
+ const typedJsonCodec = jsonCodec(userSchema);
857
+ const validatedUser = typedJsonCodec.parse('{"name":"John","age":30}'); // Fully typed!
858
+
859
+ // Base64-encoded JSON
860
+ const b64JsonCodec = base64Json(userSchema);
861
+ const encoded = b64JsonCodec.encode({ name: "Alice", age: 25 }); // Base64 string
862
+ const decoded = b64JsonCodec.parse(encoded); // { name: "Alice", age: 25 }
863
+ ```
864
+
865
+ #### **URL and Web Codecs**
866
+
867
+ ```typescript
868
+ import { stringToURL, stringToHttpURL, uriComponent } from '@oxog/vld';
869
+
870
+ // String to URL object
871
+ const url = stringToURL.parse('https://example.com/path?param=value');
872
+ console.log(url.hostname); // "example.com"
873
+ console.log(url.searchParams.get('param')); // "value"
874
+
875
+ // Restrict to HTTP/HTTPS only
876
+ const httpUrl = stringToHttpURL.parse('https://api.example.com');
877
+ stringToHttpURL.parse('ftp://files.example.com'); // ❌ Error: Must be HTTP/HTTPS
878
+
879
+ // URI component encoding/decoding
880
+ const encoded = uriComponent.parse('Hello World! 🚀'); // "Hello%20World!%20%F0%9F%9A%80"
881
+ const decoded = uriComponent.encode(encoded); // "Hello World! 🚀"
882
+ ```
883
+
884
+ #### **Binary Data Codecs**
885
+
886
+ ```typescript
887
+ import { base64ToBytes, hexToBytes, utf8ToBytes, bytesToUtf8 } from '@oxog/vld';
888
+
889
+ // Base64 to byte array
890
+ const bytes1 = base64ToBytes.parse('SGVsbG8gV29ybGQ='); // Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100])
891
+
892
+ // Hex to byte array
893
+ const bytes2 = hexToBytes.parse('48656c6c6f'); // Uint8Array([72, 101, 108, 108, 111])
894
+
895
+ // UTF-8 string to bytes
896
+ const bytes3 = utf8ToBytes.parse('Hello! 👋'); // Uint8Array([...])
897
+
898
+ // Bytes to UTF-8 string
899
+ const text = bytesToUtf8.parse(bytes3); // "Hello! 👋"
900
+
901
+ // All support round-trip conversion
902
+ const original = 'Hello World!';
903
+ const roundTrip = bytesToUtf8.parse(utf8ToBytes.parse(original)); // "Hello World!"
904
+ ```
905
+
906
+ ### 🛠 Custom Codecs
907
+
908
+ Create your own codecs for specific use cases:
909
+
910
+ ```typescript
911
+ import { v } from '@oxog/vld';
912
+
913
+ // Custom CSV to array codec
914
+ const csvToArray = v.codec(
915
+ v.string(), // Input: CSV string
916
+ v.array(v.string()), // Output: Array of strings
917
+ {
918
+ decode: (csv: string) => csv.split(',').map(s => s.trim()),
919
+ encode: (arr: string[]) => arr.join(', ')
920
+ }
921
+ );
922
+
923
+ const tags = csvToArray.parse('react, typescript, vld'); // ["react", "typescript", "vld"]
924
+ const csvString = csvToArray.encode(['node', 'express', 'api']); // "node, express, api"
925
+
926
+ // Complex: Environment config codec
927
+ const envConfigCodec = v.codec(
928
+ v.string(),
929
+ v.object({
930
+ port: v.number(),
931
+ debug: v.boolean(),
932
+ dbUrl: v.string()
933
+ }),
934
+ {
935
+ decode: (envString: string) => {
936
+ const config = {};
937
+ envString.split('\n').forEach(line => {
938
+ const [key, value] = line.split('=');
939
+ if (key === 'PORT') config.port = parseInt(value, 10);
940
+ if (key === 'DEBUG') config.debug = value === 'true';
941
+ if (key === 'DB_URL') config.dbUrl = value;
942
+ });
943
+ return config;
944
+ },
945
+ encode: (config) => [
946
+ `PORT=${config.port}`,
947
+ `DEBUG=${config.debug}`,
948
+ `DB_URL=${config.dbUrl}`
949
+ ].join('\n')
950
+ }
951
+ );
952
+ ```
953
+
954
+ ### 🚀 Advanced Codec Features
955
+
956
+ #### **Async Codecs**
957
+ ```typescript
958
+ const asyncCodec = v.codec(
959
+ v.string(),
960
+ v.object({ data: v.string() }),
961
+ {
962
+ decode: async (str: string) => {
963
+ // Simulate API call
964
+ const response = await fetch(`/api/decode?data=${str}`);
965
+ return response.json();
966
+ },
967
+ encode: async (obj) => {
968
+ const response = await fetch('/api/encode', {
969
+ method: 'POST',
970
+ body: JSON.stringify(obj)
971
+ });
972
+ return response.text();
973
+ }
974
+ }
975
+ );
976
+
977
+ // Use async methods
978
+ const result = await asyncCodec.parseAsync('input-data');
979
+ const encoded = await asyncCodec.encodeAsync({ data: 'output' });
980
+ ```
981
+
982
+ #### **Error Handling**
983
+ ```typescript
984
+ const safeParseResult = stringToNumber.safeParse('not-a-number');
985
+ if (!safeParseResult.success) {
986
+ console.error('Parse failed:', safeParseResult.error.message);
987
+ }
988
+
989
+ const safeEncodeResult = stringToNumber.safeEncode('invalid-input');
990
+ if (!safeEncodeResult.success) {
991
+ console.error('Encode failed:', safeEncodeResult.error.message);
992
+ }
993
+ ```
994
+
995
+ #### **JWT Payload Decoder**
996
+ ```typescript
997
+ import { jwtPayload } from '@oxog/vld';
998
+
999
+ // Decode JWT payload (read-only)
1000
+ const payloadSchema = v.object({
1001
+ sub: v.string(),
1002
+ name: v.string(),
1003
+ iat: v.number()
1004
+ });
1005
+
1006
+ const decoder = jwtPayload(payloadSchema);
1007
+ const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';
1008
+
1009
+ const payload = decoder.parse(token);
1010
+ console.log(payload.name); // "John Doe"
1011
+ console.log(payload.sub); // "1234567890"
1012
+ ```
1013
+
1014
+ ### 🎯 Codec vs Transform
1015
+
1016
+ | Feature | Codec | Transform |
1017
+ |---------|--------|-----------|
1018
+ | **Direction** | Bidirectional (encode/decode) | Unidirectional (transform only) |
1019
+ | **Type Safety** | Input and output validation | Output validation only |
1020
+ | **Use Case** | Data serialization, API boundaries | Data cleaning, formatting |
1021
+ | **Performance** | Optimized for round-trips | Optimized for single direction |
1022
+
1023
+ ```typescript
1024
+ // Transform: One-way conversion
1025
+ const upperCase = v.string().transform(s => s.toUpperCase());
1026
+ const result = upperCase.parse('hello'); // "HELLO"
1027
+ // No way to get back to "hello"
1028
+
1029
+ // Codec: Two-way conversion
1030
+ const upperCaseCodec = v.codec(
1031
+ v.string(),
1032
+ v.string(),
1033
+ {
1034
+ decode: s => s.toUpperCase(),
1035
+ encode: s => s.toLowerCase()
1036
+ }
1037
+ );
1038
+ const encoded = upperCaseCodec.parse('hello'); // "HELLO"
1039
+ const original = upperCaseCodec.encode('HELLO'); // "hello"
1040
+ ```
1041
+
771
1042
  ## 🔄 Migrating from Zod
772
1043
 
773
1044
  VLD provides 100% feature parity with Zod, making migration seamless:
@@ -789,7 +1060,7 @@ const schema = v.string().email();
789
1060
  - **🌍 Internationalization**: Built-in 27+ language support
790
1061
  - **📦 Bundle Size**: Smaller with zero dependencies
791
1062
  - **🔒 Security**: Immutable validators prevent memory leaks
792
- - **✅ Testing**: 99.5% test coverage with 584 tests
1063
+ - **✅ Testing**: 97.3% test coverage with 569 tests
793
1064
 
794
1065
  ## 📈 Benchmarks
795
1066
 
@@ -0,0 +1,89 @@
1
+ import { VldCodec } from '../validators/codec';
2
+ /**
3
+ * Predefined codecs for common transformations (Zod-compatible)
4
+ */
5
+ /**
6
+ * String to number codec
7
+ */
8
+ export declare const stringToNumber: VldCodec<string, number>;
9
+ /**
10
+ * String to integer codec
11
+ */
12
+ export declare const stringToInt: VldCodec<string, number>;
13
+ /**
14
+ * String to BigInt codec
15
+ */
16
+ export declare const stringToBigInt: VldCodec<string, bigint>;
17
+ /**
18
+ * Number to BigInt codec
19
+ */
20
+ export declare const numberToBigInt: VldCodec<number, bigint>;
21
+ /**
22
+ * ISO datetime string to Date codec
23
+ */
24
+ export declare const isoDatetimeToDate: VldCodec<string, Date>;
25
+ /**
26
+ * Epoch seconds to Date codec
27
+ */
28
+ export declare const epochSecondsToDate: VldCodec<number, Date>;
29
+ /**
30
+ * Epoch milliseconds to Date codec
31
+ */
32
+ export declare const epochMillisToDate: VldCodec<number, Date>;
33
+ /**
34
+ * JSON string codec for any type
35
+ */
36
+ export declare const jsonCodec: <T = any>(schema?: any) => VldCodec<string, T>;
37
+ /**
38
+ * String to URL codec
39
+ */
40
+ export declare const stringToURL: VldCodec<string, import("url").URL>;
41
+ /**
42
+ * String to HTTP/HTTPS URL codec
43
+ */
44
+ export declare const stringToHttpURL: VldCodec<string, import("url").URL>;
45
+ /**
46
+ * URI component encode/decode codec
47
+ */
48
+ export declare const uriComponent: VldCodec<string, string>;
49
+ /**
50
+ * String to boolean codec
51
+ */
52
+ export declare const stringToBoolean: VldCodec<string, boolean>;
53
+ /**
54
+ * Base64 to Uint8Array codec
55
+ */
56
+ export declare const base64ToBytes: VldCodec<string, Uint8Array<ArrayBufferLike>>;
57
+ /**
58
+ * URL-safe Base64 to Uint8Array codec
59
+ */
60
+ export declare const base64UrlToBytes: VldCodec<string, Uint8Array<ArrayBufferLike>>;
61
+ /**
62
+ * Hexadecimal to Uint8Array codec
63
+ */
64
+ export declare const hexToBytes: VldCodec<string, Uint8Array<ArrayBufferLike>>;
65
+ /**
66
+ * Lowercase hexadecimal to Uint8Array codec
67
+ */
68
+ export declare const hexLowerToBytes: VldCodec<string, Uint8Array<ArrayBufferLike>>;
69
+ /**
70
+ * UTF-8 string to Uint8Array codec
71
+ */
72
+ export declare const utf8ToBytes: VldCodec<string, Uint8Array<ArrayBufferLike>>;
73
+ /**
74
+ * Uint8Array to UTF-8 string codec (reverse of utf8ToBytes)
75
+ */
76
+ export declare const bytesToUtf8: VldCodec<Uint8Array<ArrayBufferLike>, string>;
77
+ /**
78
+ * Base64URL to Uint8Array codec (updated)
79
+ */
80
+ export declare const base64urlToBytes: VldCodec<string, Uint8Array<ArrayBufferLike>>;
81
+ /**
82
+ * Base64 encoded JSON codec (updated)
83
+ */
84
+ export declare const base64Json: <T = any>(schema?: any) => VldCodec<string, T>;
85
+ /**
86
+ * JWT payload decoder (base64url encoded JSON) - updated
87
+ */
88
+ export declare const jwtPayload: (schema?: any) => VldCodec<string, any>;
89
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/codecs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAoB/C;;GAEG;AAIH;;GAEG;AACH,eAAO,MAAM,cAAc,0BAW1B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,0BAWvB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,0BAa1B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,0BAO1B,CAAC;AAIF;;GAEG;AACH,eAAO,MAAM,iBAAiB,wBAW7B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,wBAO9B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,wBAO7B,CAAC;AAIF;;GAEG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,GAAG,GAAG,EAAE,SAAS,GAAG,wBAiB9C,CAAC;AAIF;;GAEG;AACH,eAAO,MAAM,WAAW,qCAavB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,qCAiB3B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,0BAaxB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,2BAY3B,CAAC;AAIF;;GAEG;AACH,eAAO,MAAM,aAAa,+CAOzB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,+CAO5B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,UAAU,+CAOtB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,+CAO3B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,+CAOvB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,+CAOvB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,+CAO5B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,UAAU,GAAI,CAAC,GAAG,GAAG,EAAE,SAAS,GAAG,wBAiB/C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,UAAU,GAAI,SAAS,GAAG,0BAuBtC,CAAC"}