@oxyhq/core 1.0.0 → 1.0.1

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.
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "عرض {{count}} المزيد",
46
46
  "status": {
47
47
  "accountSwitched": "استخدام {{name}} الآن"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "Veure {{count}} més",
46
46
  "status": {
47
47
  "accountSwitched": "Ara utilitzant {{name}}"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "{{count}} weitere anzeigen",
46
46
  "status": {
47
47
  "accountSwitched": "Verwende jetzt {{name}}"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "Voir {{count}} de plus",
46
46
  "status": {
47
47
  "accountSwitched": "Utilisation de {{name}}"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "Visualizza {{count}} altri",
46
46
  "status": {
47
47
  "accountSwitched": "Ora usando {{name}}"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "さらに{{count}}件を表示",
46
46
  "status": {
47
47
  "accountSwitched": "{{name}}を使用中"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "{{count}}개 더 보기",
46
46
  "status": {
47
47
  "accountSwitched": "{{name}} 사용 중"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "Ver mais {{count}}",
46
46
  "status": {
47
47
  "accountSwitched": "Agora a usar {{name}}"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "查看更多{{count}}个",
46
46
  "status": {
47
47
  "accountSwitched": "正在使用{{name}}"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "عرض {{count}} المزيد",
46
46
  "status": {
47
47
  "accountSwitched": "استخدام {{name}} الآن"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "Veure {{count}} més",
46
46
  "status": {
47
47
  "accountSwitched": "Ara utilitzant {{name}}"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "{{count}} weitere anzeigen",
46
46
  "status": {
47
47
  "accountSwitched": "Verwende jetzt {{name}}"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "Voir {{count}} de plus",
46
46
  "status": {
47
47
  "accountSwitched": "Utilisation de {{name}}"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "Visualizza {{count}} altri",
46
46
  "status": {
47
47
  "accountSwitched": "Ora usando {{name}}"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "さらに{{count}}件を表示",
46
46
  "status": {
47
47
  "accountSwitched": "{{name}}を使用中"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "{{count}}개 더 보기",
46
46
  "status": {
47
47
  "accountSwitched": "{{name}} 사용 중"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "Ver mais {{count}}",
46
46
  "status": {
47
47
  "accountSwitched": "Agora a usar {{name}}"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "查看更多{{count}}个",
46
46
  "status": {
47
47
  "accountSwitched": "正在使用{{name}}"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxyhq/core",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "OxyHQ SDK Foundation — API client, authentication, cryptographic identity, and shared utilities",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -81,4 +81,4 @@
81
81
  "@types/node": "^20.19.9",
82
82
  "typescript": "^5.9.2"
83
83
  }
84
- }
84
+ }
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "عرض {{count}} المزيد",
46
46
  "status": {
47
47
  "accountSwitched": "استخدام {{name}} الآن"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "Veure {{count}} més",
46
46
  "status": {
47
47
  "accountSwitched": "Ara utilitzant {{name}}"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "{{count}} weitere anzeigen",
46
46
  "status": {
47
47
  "accountSwitched": "Verwende jetzt {{name}}"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "Voir {{count}} de plus",
46
46
  "status": {
47
47
  "accountSwitched": "Utilisation de {{name}}"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "Visualizza {{count}} altri",
46
46
  "status": {
47
47
  "accountSwitched": "Ora usando {{name}}"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "さらに{{count}}件を表示",
46
46
  "status": {
47
47
  "accountSwitched": "{{name}}を使用中"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "{{count}}개 더 보기",
46
46
  "status": {
47
47
  "accountSwitched": "{{name}} 사용 중"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "Ver mais {{count}}",
46
46
  "status": {
47
47
  "accountSwitched": "Agora a usar {{name}}"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -45,7 +45,7 @@
45
45
  "viewAllAccounts": "查看更多{{count}}个",
46
46
  "status": {
47
47
  "accountSwitched": "正在使用{{name}}"
48
- },
48
+ }
49
49
  },
50
50
  "signup": {
51
51
  "welcome": {
@@ -0,0 +1,236 @@
1
+ import {
2
+ isRequiredString,
3
+ isRequiredNumber,
4
+ isRequiredBoolean,
5
+ isValidArray,
6
+ isValidObject,
7
+ isValidEmail,
8
+ isValidUsername,
9
+ isValidPassword,
10
+ isValidUUID,
11
+ isValidDate,
12
+ isValidFileSize,
13
+ isValidFileType,
14
+ sanitizeString,
15
+ sanitizeHTML,
16
+ validateAndSanitizeUserInput
17
+ } from '../validationUtils';
18
+
19
+ describe('Validation Utils', () => {
20
+ describe('isRequiredString', () => {
21
+ it('should return true for valid non-empty strings', () => {
22
+ expect(isRequiredString('hello')).toBe(true);
23
+ expect(isRequiredString(' hello ')).toBe(true); // trims whitespace
24
+ });
25
+
26
+ it('should return false for invalid or empty strings', () => {
27
+ expect(isRequiredString('')).toBe(false);
28
+ expect(isRequiredString(' ')).toBe(false); // only whitespace
29
+ expect(isRequiredString(null)).toBe(false);
30
+ expect(isRequiredString(undefined)).toBe(false);
31
+ expect(isRequiredString(123)).toBe(false);
32
+ });
33
+ });
34
+
35
+ describe('isRequiredNumber', () => {
36
+ it('should return true for valid numbers', () => {
37
+ expect(isRequiredNumber(123)).toBe(true);
38
+ expect(isRequiredNumber(0)).toBe(true);
39
+ expect(isRequiredNumber(-456)).toBe(true);
40
+ expect(isRequiredNumber(3.14)).toBe(true);
41
+ });
42
+
43
+ it('should return false for invalid numbers', () => {
44
+ expect(isRequiredNumber(Number.NaN)).toBe(false);
45
+ expect(isRequiredNumber('123')).toBe(false);
46
+ expect(isRequiredNumber(null)).toBe(false);
47
+ expect(isRequiredNumber(undefined)).toBe(false);
48
+ });
49
+ });
50
+
51
+ describe('isRequiredBoolean', () => {
52
+ it('should return true for boolean values', () => {
53
+ expect(isRequiredBoolean(true)).toBe(true);
54
+ expect(isRequiredBoolean(false)).toBe(true);
55
+ });
56
+
57
+ it('should return false for non-boolean values', () => {
58
+ expect(isRequiredBoolean('true')).toBe(false);
59
+ expect(isRequiredBoolean(1)).toBe(false);
60
+ expect(isRequiredBoolean(0)).toBe(false);
61
+ expect(isRequiredBoolean(null)).toBe(false);
62
+ expect(isRequiredBoolean(undefined)).toBe(false);
63
+ });
64
+ });
65
+
66
+ describe('isValidArray', () => {
67
+ it('should return true for arrays', () => {
68
+ expect(isValidArray([])).toBe(true);
69
+ expect(isValidArray([1, 2, 3])).toBe(true);
70
+ expect(isValidArray(['a', 'b'])).toBe(true);
71
+ });
72
+
73
+ it('should return false for non-arrays', () => {
74
+ expect(isValidArray({})).toBe(false);
75
+ expect(isValidArray('[]')).toBe(false);
76
+ expect(isValidArray(null)).toBe(false);
77
+ expect(isValidArray(undefined)).toBe(false);
78
+ });
79
+ });
80
+
81
+ describe('isValidObject', () => {
82
+ it('should return true for plain objects', () => {
83
+ expect(isValidObject({})).toBe(true);
84
+ expect(isValidObject({ key: 'value' })).toBe(true);
85
+ });
86
+
87
+ it('should return false for non-objects', () => {
88
+ expect(isValidObject([])).toBe(false);
89
+ expect(isValidObject(null)).toBe(false);
90
+ expect(isValidObject(undefined)).toBe(false);
91
+ expect(isValidObject('object')).toBe(false);
92
+ expect(isValidObject(123)).toBe(false);
93
+ });
94
+ });
95
+
96
+ describe('isValidEmail', () => {
97
+ it('should return true for valid email addresses', () => {
98
+ expect(isValidEmail('test@example.com')).toBe(true);
99
+ expect(isValidEmail('user.name+tag@domain.co.uk')).toBe(true);
100
+ expect(isValidEmail('simple@test.io')).toBe(true);
101
+ });
102
+
103
+ it('should return false for invalid email addresses', () => {
104
+ expect(isValidEmail('invalid-email')).toBe(false);
105
+ expect(isValidEmail('test@')).toBe(false);
106
+ expect(isValidEmail('@domain.com')).toBe(false);
107
+ expect(isValidEmail('test.domain.com')).toBe(false);
108
+ expect(isValidEmail('')).toBe(false);
109
+ });
110
+ });
111
+
112
+ describe('isValidUsername', () => {
113
+ it('should return true for valid usernames', () => {
114
+ expect(isValidUsername('user123')).toBe(true);
115
+ expect(isValidUsername('test_user')).toBe(true);
116
+ expect(isValidUsername('john-doe')).toBe(true);
117
+ });
118
+
119
+ it('should return false for invalid usernames', () => {
120
+ expect(isValidUsername('')).toBe(false);
121
+ expect(isValidUsername('a')).toBe(false); // too short
122
+ expect(isValidUsername('ab')).toBe(false); // too short
123
+ expect(isValidUsername('user@domain')).toBe(false); // invalid characters
124
+ expect(isValidUsername('user with spaces')).toBe(false); // spaces
125
+ });
126
+ });
127
+
128
+ describe('isValidPassword', () => {
129
+ it('should return true for valid passwords', () => {
130
+ expect(isValidPassword('password123')).toBe(true);
131
+ expect(isValidPassword('mySecurePass')).toBe(true);
132
+ expect(isValidPassword('12345678')).toBe(true);
133
+ });
134
+
135
+ it('should return false for invalid passwords', () => {
136
+ expect(isValidPassword('')).toBe(false);
137
+ expect(isValidPassword('short')).toBe(false); // too short
138
+ expect(isValidPassword('1234567')).toBe(false); // too short
139
+ });
140
+ });
141
+
142
+ describe('isValidUUID', () => {
143
+ it('should return true for valid UUIDs', () => {
144
+ expect(isValidUUID('123e4567-e89b-12d3-a456-426614174000')).toBe(true);
145
+ expect(isValidUUID('550e8400-e29b-41d4-a716-446655440000')).toBe(true);
146
+ });
147
+
148
+ it('should return false for invalid UUIDs', () => {
149
+ expect(isValidUUID('invalid-uuid')).toBe(false);
150
+ expect(isValidUUID('123-456-789')).toBe(false);
151
+ expect(isValidUUID('')).toBe(false);
152
+ });
153
+ });
154
+
155
+ describe('isValidDate', () => {
156
+ it('should return true for valid date strings', () => {
157
+ expect(isValidDate('2024-01-01')).toBe(true);
158
+ expect(isValidDate('2024-12-31T23:59:59.999Z')).toBe(true);
159
+ expect(isValidDate('January 1, 2024')).toBe(true);
160
+ });
161
+
162
+ it('should return false for invalid date strings', () => {
163
+ expect(isValidDate('invalid-date')).toBe(false);
164
+ expect(isValidDate('2024-13-01')).toBe(false); // invalid month
165
+ expect(isValidDate('')).toBe(false);
166
+ });
167
+ });
168
+
169
+ describe('isValidFileSize', () => {
170
+ const maxSize = 1024 * 1024; // 1MB
171
+
172
+ it('should return true for valid file sizes', () => {
173
+ expect(isValidFileSize(1024, maxSize)).toBe(true);
174
+ expect(isValidFileSize(maxSize, maxSize)).toBe(true);
175
+ expect(isValidFileSize(1, maxSize)).toBe(true);
176
+ });
177
+
178
+ it('should return false for invalid file sizes', () => {
179
+ expect(isValidFileSize(0, maxSize)).toBe(false);
180
+ expect(isValidFileSize(-1, maxSize)).toBe(false);
181
+ expect(isValidFileSize(maxSize + 1, maxSize)).toBe(false);
182
+ });
183
+ });
184
+
185
+ describe('isValidFileType', () => {
186
+ const allowedTypes = ['jpg', 'png', 'gif', 'pdf'];
187
+
188
+ it('should return true for allowed file types', () => {
189
+ expect(isValidFileType('image.jpg', allowedTypes)).toBe(true);
190
+ expect(isValidFileType('document.PDF', allowedTypes)).toBe(true); // case insensitive
191
+ expect(isValidFileType('photo.png', allowedTypes)).toBe(true);
192
+ });
193
+
194
+ it('should return false for disallowed file types', () => {
195
+ expect(isValidFileType('script.js', allowedTypes)).toBe(false);
196
+ expect(isValidFileType('data.txt', allowedTypes)).toBe(false);
197
+ expect(isValidFileType('noextension', allowedTypes)).toBe(false);
198
+ });
199
+ });
200
+
201
+ describe('sanitizeString', () => {
202
+ it('should trim whitespace and remove dangerous characters', () => {
203
+ expect(sanitizeString(' hello ')).toBe('hello');
204
+ expect(sanitizeString('hello<script>alert("xss")</script>world')).toBe('helloalert("xss")world');
205
+ expect(sanitizeString('normal text')).toBe('normal text');
206
+ });
207
+ });
208
+
209
+ describe('sanitizeHTML', () => {
210
+ it('should escape HTML characters', () => {
211
+ expect(sanitizeHTML('<script>alert("xss")</script>')).toBe('&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;');
212
+ expect(sanitizeHTML('Hello & Goodbye')).toBe('Hello &amp; Goodbye');
213
+ expect(sanitizeHTML("It's a test")).toBe('It&#x27;s a test');
214
+ });
215
+ });
216
+
217
+ describe('validateAndSanitizeUserInput', () => {
218
+ it('should validate and sanitize email input', () => {
219
+ expect(validateAndSanitizeUserInput(' test@example.com ', 'email')).toBe('test@example.com');
220
+ expect(validateAndSanitizeUserInput('invalid-email', 'email')).toBeNull();
221
+ expect(validateAndSanitizeUserInput(123, 'email')).toBeNull();
222
+ });
223
+
224
+ it('should validate and sanitize username input', () => {
225
+ expect(validateAndSanitizeUserInput(' testuser ', 'username')).toBe('testuser');
226
+ expect(validateAndSanitizeUserInput('ab', 'username')).toBeNull(); // too short
227
+ expect(validateAndSanitizeUserInput(123, 'username')).toBeNull();
228
+ });
229
+
230
+ it('should validate and sanitize string input', () => {
231
+ expect(validateAndSanitizeUserInput(' hello world ', 'string')).toBe('hello world');
232
+ expect(validateAndSanitizeUserInput('', 'string')).toBeNull();
233
+ expect(validateAndSanitizeUserInput(123, 'string')).toBeNull();
234
+ });
235
+ });
236
+ });