@regardio/js 0.2.4 → 0.4.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 (62) hide show
  1. package/README.md +47 -1
  2. package/dist/async/delay.d.ts +7 -2
  3. package/dist/async/delay.js +7 -4
  4. package/dist/browser/base64.d.ts +8 -2
  5. package/dist/browser/base64.js +12 -9
  6. package/dist/format/bytes.d.ts +3 -2
  7. package/dist/format/bytes.js +12 -9
  8. package/dist/format/measure.d.ts +3 -2
  9. package/dist/format/measure.js +14 -12
  10. package/dist/http/cookie.d.ts +15 -3
  11. package/dist/http/cookie.js +44 -43
  12. package/dist/http/domain.d.ts +9 -2
  13. package/dist/http/domain.js +15 -12
  14. package/dist/http/request-helpers.d.ts +3 -2
  15. package/dist/http/request-helpers.js +9 -6
  16. package/dist/intl/language-detector.d.ts +64 -6
  17. package/dist/intl/language-detector.js +128 -123
  18. package/dist/time/time.d.ts +8 -7
  19. package/dist/time/time.js +121 -118
  20. package/dist/validation/invariant.d.ts +34 -3
  21. package/dist/validation/invariant.js +14 -11
  22. package/dist/validation/verify-file-accept.d.ts +10 -2
  23. package/dist/validation/verify-file-accept.js +6 -3
  24. package/package.json +4 -3
  25. package/dist/async/delay.d.ts.map +0 -1
  26. package/dist/async/delay.test.d.ts +0 -2
  27. package/dist/async/delay.test.d.ts.map +0 -1
  28. package/dist/async/delay.test.js +0 -35
  29. package/dist/browser/base64.d.ts.map +0 -1
  30. package/dist/format/bytes.d.ts.map +0 -1
  31. package/dist/format/bytes.test.d.ts +0 -2
  32. package/dist/format/bytes.test.d.ts.map +0 -1
  33. package/dist/format/bytes.test.js +0 -49
  34. package/dist/format/measure.d.ts.map +0 -1
  35. package/dist/format/measure.test.d.ts +0 -2
  36. package/dist/format/measure.test.d.ts.map +0 -1
  37. package/dist/format/measure.test.js +0 -50
  38. package/dist/http/cookie.d.ts.map +0 -1
  39. package/dist/http/domain.d.ts.map +0 -1
  40. package/dist/http/domain.test.d.ts +0 -2
  41. package/dist/http/domain.test.d.ts.map +0 -1
  42. package/dist/http/domain.test.js +0 -29
  43. package/dist/http/request-helpers.d.ts.map +0 -1
  44. package/dist/http/request-helpers.test.d.ts +0 -2
  45. package/dist/http/request-helpers.test.d.ts.map +0 -1
  46. package/dist/http/request-helpers.test.js +0 -37
  47. package/dist/intl/language-detector.d.ts.map +0 -1
  48. package/dist/intl/language-detector.test.d.ts +0 -2
  49. package/dist/intl/language-detector.test.d.ts.map +0 -1
  50. package/dist/intl/language-detector.test.js +0 -186
  51. package/dist/time/time.d.ts.map +0 -1
  52. package/dist/time/time.test.d.ts +0 -2
  53. package/dist/time/time.test.d.ts.map +0 -1
  54. package/dist/time/time.test.js +0 -202
  55. package/dist/validation/invariant.d.ts.map +0 -1
  56. package/dist/validation/invariant.test.d.ts +0 -2
  57. package/dist/validation/invariant.test.d.ts.map +0 -1
  58. package/dist/validation/invariant.test.js +0 -110
  59. package/dist/validation/verify-file-accept.d.ts.map +0 -1
  60. package/dist/validation/verify-file-accept.test.d.ts +0 -2
  61. package/dist/validation/verify-file-accept.test.d.ts.map +0 -1
  62. package/dist/validation/verify-file-accept.test.js +0 -71
package/README.md CHANGED
@@ -5,12 +5,33 @@
5
5
  A collection of lightweight, tree-shakeable utility functions for common tasks
6
6
  like HTTP handling, internationalization, time formatting, and validation.
7
7
 
8
+ ## ⚠️ Pre-release Notice
9
+
10
+ **This package is currently in pre-release (v0.x).** While we use these utilities in production across our own projects, the API may still change between minor versions. We recommend:
11
+
12
+ - Pinning to exact versions in your `package.json`
13
+ - Reviewing changelogs before upgrading
14
+ - Expecting potential breaking changes until v1.0
15
+
16
+ ## Why This Package?
17
+
18
+ We created `@regardio/js` to:
19
+
20
+ - **Share battle-tested utilities** — These functions power real Regardio projects and have been refined through actual use
21
+ - **Reduce boilerplate** — Common patterns like cookie handling, language detection, and time formatting in one place
22
+ - **Stay framework-agnostic** — Works with any JavaScript/TypeScript project (React, Node, Deno, etc.)
23
+ - **Enable tree-shaking** — Import only what you need; unused utilities won't bloat your bundle
24
+
8
25
  ## Installation
9
26
 
10
27
  ```bash
11
28
  pnpm add @regardio/js
12
29
  ```
13
30
 
31
+ ## Documentation
32
+
33
+ See the [docs](./docs) folder for detailed documentation on each module.
34
+
14
35
  ## Modules
15
36
 
16
37
  ### async/delay
@@ -146,9 +167,34 @@ verifyAccept('image/png', 'image/*'); // true
146
167
  verifyAccept('video/mp4', 'image/*'); // false
147
168
  ```
148
169
 
170
+ ## Module Overview
171
+
172
+ | Module | Description |
173
+ |--------|-------------|
174
+ | `async/delay` | Promise-based delay utility |
175
+ | `browser/base64` | URL-safe base64 to Uint8Array conversion |
176
+ | `format/bytes` | Human-readable byte formatting |
177
+ | `format/measure` | Performance measurement with logging |
178
+ | `http/cookie` | Browser cookie get/set helpers |
179
+ | `http/domain` | Domain extraction from requests (proxy-aware) |
180
+ | `http/request-helpers` | URL cleaning utilities |
181
+ | `intl/language-detector` | Server-side language detection for i18n |
182
+ | `intl/locale` | Client locale extraction from headers |
183
+ | `time/time` | Time formatting and date utilities |
184
+ | `validation/invariant` | Runtime assertion utilities |
185
+ | `validation/verify-file-accept` | MIME type validation for file uploads |
186
+
187
+ ## Contributing
188
+
189
+ This package is primarily maintained for Regardio's internal use, but we welcome:
190
+
191
+ - Bug reports and fixes
192
+ - Documentation improvements
193
+ - Feature suggestions (though we may not implement all requests)
194
+
149
195
  ## License
150
196
 
151
- **MIT License** - Free to use in commercial and open source projects.
197
+ **MIT License** Free to use in commercial and open source projects.
152
198
 
153
199
  ---
154
200
 
@@ -1,2 +1,7 @@
1
- export declare function delay(ms: number): Promise<unknown>;
2
- //# sourceMappingURL=delay.d.ts.map
1
+ /** Delays using a promise
2
+ * @param ms Milisecods of delay
3
+ * @return Promise
4
+ */
5
+ declare function delay(ms: number): Promise<unknown>;
6
+
7
+ export { delay };
@@ -1,5 +1,8 @@
1
- export function delay(ms) {
2
- return new Promise((resolve) => {
3
- return setTimeout(resolve, ms);
4
- });
1
+ // src/async/delay.ts
2
+ function delay(ms) {
3
+ return new Promise((resolve) => {
4
+ return setTimeout(resolve, ms);
5
+ });
5
6
  }
7
+
8
+ export { delay };
@@ -1,2 +1,8 @@
1
- export declare const urlBase64ToUint8Array: (base64String: string) => Uint8Array;
2
- //# sourceMappingURL=base64.d.ts.map
1
+ /**
2
+ * Converts a base64 string to a Uint8Array
3
+ * @param base64String The base64 string to convert
4
+ * @returns A Uint8Array containing the decoded data
5
+ */
6
+ declare const urlBase64ToUint8Array: (base64String: string) => Uint8Array;
7
+
8
+ export { urlBase64ToUint8Array };
@@ -1,10 +1,13 @@
1
- export const urlBase64ToUint8Array = (base64String) => {
2
- const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
3
- const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
4
- const rawData = window.atob(base64);
5
- const outputArray = new Uint8Array(rawData.length);
6
- for (let i = 0; i < rawData.length; ++i) {
7
- outputArray[i] = rawData.charCodeAt(i);
8
- }
9
- return outputArray;
1
+ // src/browser/base64.ts
2
+ var urlBase64ToUint8Array = (base64String) => {
3
+ const padding = "=".repeat((4 - base64String.length % 4) % 4);
4
+ const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/");
5
+ const rawData = window.atob(base64);
6
+ const outputArray = new Uint8Array(rawData.length);
7
+ for (let i = 0; i < rawData.length; ++i) {
8
+ outputArray[i] = rawData.charCodeAt(i);
9
+ }
10
+ return outputArray;
10
11
  };
12
+
13
+ export { urlBase64ToUint8Array };
@@ -1,2 +1,3 @@
1
- export declare function formatBytes(bytes: number, decimals?: number): string;
2
- //# sourceMappingURL=bytes.d.ts.map
1
+ declare function formatBytes(bytes: number, decimals?: number): string;
2
+
3
+ export { formatBytes };
@@ -1,10 +1,13 @@
1
- export function formatBytes(bytes, decimals = 2) {
2
- if (!+bytes) {
3
- return '0 Bytes';
4
- }
5
- const k = 1000;
6
- const dm = decimals < 0 ? 0 : decimals;
7
- const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
8
- const i = Math.floor(Math.log(bytes) / Math.log(k));
9
- return `${Number.parseFloat((bytes / k ** i).toFixed(dm))} ${sizes[i]}`;
1
+ // src/format/bytes.ts
2
+ function formatBytes(bytes, decimals = 2) {
3
+ if (!+bytes) {
4
+ return "0 Bytes";
5
+ }
6
+ const k = 1e3;
7
+ const dm = decimals < 0 ? 0 : decimals;
8
+ const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
9
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
10
+ return `${Number.parseFloat((bytes / k ** i).toFixed(dm))} ${sizes[i]}`;
10
11
  }
12
+
13
+ export { formatBytes };
@@ -1,2 +1,3 @@
1
- export declare function measure<Result>(key: string, callback: () => Result | Promise<Result>): Promise<Result>;
2
- //# sourceMappingURL=measure.d.ts.map
1
+ declare function measure<Result>(key: string, callback: () => Result | Promise<Result>): Promise<Result>;
2
+
3
+ export { measure };
@@ -1,14 +1,16 @@
1
- export async function measure(key, callback) {
2
- const start = Date.now();
3
- try {
4
- let result = callback();
5
- if (result instanceof Promise) {
6
- result = await result;
7
- }
8
- return result;
9
- }
10
- finally {
11
- const end = Date.now();
12
- console.log(`${key} took ${end - start}ms`);
1
+ // src/format/measure.ts
2
+ async function measure(key, callback) {
3
+ const start = Date.now();
4
+ try {
5
+ let result = callback();
6
+ if (result instanceof Promise) {
7
+ result = await result;
13
8
  }
9
+ return result;
10
+ } finally {
11
+ const end = Date.now();
12
+ console.log(`${key} took ${end - start}ms`);
13
+ }
14
14
  }
15
+
16
+ export { measure };
@@ -1,9 +1,21 @@
1
- export declare function setCookieValue(name: string, value: string, options?: {
1
+ /**
2
+ * Helper function to set cookies in a more controlled way
3
+ * @param name - The name of the cookie
4
+ * @param value - The value to set
5
+ * @param options - Cookie options
6
+ */
7
+ declare function setCookieValue(name: string, value: string, options?: {
2
8
  expires?: Date;
3
9
  path?: string;
4
10
  sameSite?: string;
5
11
  secure?: boolean;
6
12
  domain?: string;
7
13
  }): void;
8
- export declare function getCookieValue(name: string): string | null;
9
- //# sourceMappingURL=cookie.d.ts.map
14
+ /**
15
+ * Get a cookie value by name
16
+ * @param name - The name of the cookie to get
17
+ * @returns The cookie value or null if not found
18
+ */
19
+ declare function getCookieValue(name: string): string | null;
20
+
21
+ export { getCookieValue, setCookieValue };
@@ -1,46 +1,47 @@
1
- export function setCookieValue(name, value, options = {}) {
2
- if (typeof window === 'undefined') {
3
- console.warn('Cannot set cookie on server side');
4
- return;
5
- }
6
- let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
7
- if (options.expires) {
8
- cookieString += `; expires=${options.expires.toUTCString()}`;
9
- }
10
- if (options.path) {
11
- cookieString += `; path=${options.path}`;
12
- }
13
- if (options.sameSite) {
14
- cookieString += `; SameSite=${options.sameSite}`;
15
- }
16
- if (options.secure) {
17
- cookieString += '; Secure';
18
- }
19
- if (options.domain) {
20
- cookieString += `; domain=${options.domain}`;
21
- }
22
- try {
23
- document.cookie = cookieString;
24
- }
25
- catch (error) {
26
- if (error instanceof Error) {
27
- console.error(`Failed to set cookie '${name}':`, error.message);
28
- }
29
- else {
30
- console.error(`Failed to set cookie '${name}': Unknown error`);
31
- }
32
- }
1
+ // src/http/cookie.ts
2
+ function setCookieValue(name, value, options = {}) {
3
+ if (typeof window === "undefined") {
4
+ console.warn("Cannot set cookie on server side");
5
+ return;
6
+ }
7
+ let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
8
+ if (options.expires) {
9
+ cookieString += `; expires=${options.expires.toUTCString()}`;
10
+ }
11
+ if (options.path) {
12
+ cookieString += `; path=${options.path}`;
13
+ }
14
+ if (options.sameSite) {
15
+ cookieString += `; SameSite=${options.sameSite}`;
16
+ }
17
+ if (options.secure) {
18
+ cookieString += "; Secure";
19
+ }
20
+ if (options.domain) {
21
+ cookieString += `; domain=${options.domain}`;
22
+ }
23
+ try {
24
+ document.cookie = cookieString;
25
+ } catch (error) {
26
+ if (error instanceof Error) {
27
+ console.error(`Failed to set cookie '${name}':`, error.message);
28
+ } else {
29
+ console.error(`Failed to set cookie '${name}': Unknown error`);
30
+ }
31
+ }
33
32
  }
34
- export function getCookieValue(name) {
35
- if (typeof window === 'undefined') {
36
- console.warn('Cannot get cookie on server side');
37
- return null;
38
- }
39
- const value = `; ${document.cookie}`;
40
- const parts = value.split(`; ${name}=`);
41
- if (parts.length === 2) {
42
- const cookieValue = parts.pop()?.split(';').shift();
43
- return cookieValue ? decodeURIComponent(cookieValue) : null;
44
- }
33
+ function getCookieValue(name) {
34
+ if (typeof window === "undefined") {
35
+ console.warn("Cannot get cookie on server side");
45
36
  return null;
37
+ }
38
+ const value = `; ${document.cookie}`;
39
+ const parts = value.split(`; ${name}=`);
40
+ if (parts.length === 2) {
41
+ const cookieValue = parts.pop()?.split(";").shift();
42
+ return cookieValue ? decodeURIComponent(cookieValue) : null;
43
+ }
44
+ return null;
46
45
  }
46
+
47
+ export { getCookieValue, setCookieValue };
@@ -1,2 +1,9 @@
1
- export declare const createDomain: (request: Request) => string;
2
- //# sourceMappingURL=domain.d.ts.map
1
+ /**
2
+ * Helper utility used to extract the domain from the request even if it's
3
+ * behind a proxy. This is useful for sitemaps and other things.
4
+ * @param request Request object
5
+ * @returns Current domain
6
+ */
7
+ declare const createDomain: (request: Request) => string;
8
+
9
+ export { createDomain };
@@ -1,13 +1,16 @@
1
- export const createDomain = (request) => {
2
- const headers = request.headers;
3
- const maybeProto = headers.get('x-forwarded-proto');
4
- const maybeHost = headers.get('host');
5
- const url = new URL(request.url);
6
- if (maybeProto) {
7
- return `${maybeProto}://${maybeHost ?? url.host}`;
8
- }
9
- if (url.hostname === 'localhost') {
10
- return `http://${url.host}`;
11
- }
12
- return `https://${url.host}`;
1
+ // src/http/domain.ts
2
+ var createDomain = (request) => {
3
+ const headers = request.headers;
4
+ const maybeProto = headers.get("x-forwarded-proto");
5
+ const maybeHost = headers.get("host");
6
+ const url = new URL(request.url);
7
+ if (maybeProto) {
8
+ return `${maybeProto}://${maybeHost ?? url.host}`;
9
+ }
10
+ if (url.hostname === "localhost") {
11
+ return `http://${url.host}`;
12
+ }
13
+ return `https://${url.host}`;
13
14
  };
15
+
16
+ export { createDomain };
@@ -1,2 +1,3 @@
1
- export declare function getCleanUrl(request: Request): string;
2
- //# sourceMappingURL=request-helpers.d.ts.map
1
+ declare function getCleanUrl(request: Request): string;
2
+
3
+ export { getCleanUrl };
@@ -1,7 +1,10 @@
1
- export function getCleanUrl(request) {
2
- const url = new URL(request.url);
3
- url.searchParams.forEach((_, key) => {
4
- url.searchParams.delete(key);
5
- });
6
- return url.toString();
1
+ // src/http/request-helpers.ts
2
+ function getCleanUrl(request) {
3
+ const url = new URL(request.url);
4
+ url.searchParams.forEach((_, key) => {
5
+ url.searchParams.delete(key);
6
+ });
7
+ return url.toString();
7
8
  }
9
+
10
+ export { getCleanUrl };
@@ -1,23 +1,80 @@
1
- import type { Cookie, SessionStorage } from 'react-router';
2
- export interface LanguageDetectorOption {
1
+ import { Cookie, SessionStorage } from 'react-router';
2
+
3
+ interface LanguageDetectorOption {
4
+ /**
5
+ * Define the list of supported languages, this is used to determine if one of
6
+ * the languages requested by the user is supported by the application.
7
+ * This should be be same as the supportedLngs in the i18next options.
8
+ */
3
9
  supportedLanguages: string[];
10
+ /**
11
+ * Define the fallback language that it's going to be used in the case user
12
+ * expected language is not supported.
13
+ * This should be be same as the fallbackLng in the i18next options.
14
+ */
4
15
  fallbackLanguage: string;
16
+ /**
17
+ * If you want to use a cookie to store the user preferred language, you can
18
+ * pass the Cookie object here.
19
+ */
5
20
  cookie?: Cookie;
21
+ /**
22
+ * If you want to use a session to store the user preferred language, you can
23
+ * pass the SessionStorage object here.
24
+ * When this is not defined, getting the locale will ignore the session.
25
+ */
6
26
  sessionStorage?: SessionStorage;
27
+ /**
28
+ * If defined a sessionStorage and want to change the default key used to
29
+ * store the user preferred language, you can pass the key here.
30
+ * @default "lng"
31
+ */
7
32
  sessionKey?: string;
33
+ /**
34
+ * If you want to use search parameters for language detection and want to
35
+ * change the default key used to for the parameter name,
36
+ * you can pass the key here.
37
+ * @default "lng"
38
+ */
8
39
  searchParamKey?: string;
40
+ /**
41
+ * The order the library will use to detect the user preferred language.
42
+ * By default the order is
43
+ * - urlPath (first segment like /de/ or /en/)
44
+ * - cookie
45
+ * - session
46
+ * - searchParams
47
+ * - header
48
+ * And finally the fallback language.
49
+ */
9
50
  order?: Array<'urlPath' | 'searchParams' | 'cookie' | 'session' | 'header'>;
10
51
  }
11
- export interface LanguageDetectorLinguiOptions {
52
+ interface LanguageDetectorLinguiOptions {
12
53
  detection: LanguageDetectorOption;
13
54
  }
14
- export declare class LanguageDetectorLingui {
55
+ declare class LanguageDetectorLingui {
15
56
  private detector;
16
57
  private options;
17
58
  constructor(options: LanguageDetectorLinguiOptions);
59
+ /**
60
+ * Detect the current locale by following the order defined in the
61
+ * `detection.order` option.
62
+ * By default the order is
63
+ * - urlPath (first segment like /de/ or /en/)
64
+ * - cookie
65
+ * - session
66
+ * - searchParams
67
+ * - header
68
+ * And finally the fallback language.
69
+ */
18
70
  getLocale(request: Request): Promise<string>;
19
71
  }
20
- export declare class LanguageDetector {
72
+ /**
73
+ * The LanguageDetector contains the logic to detect the user preferred language
74
+ * fully server-side by using a SessionStorage, Cookie, URLSearchParams, or
75
+ * Headers.
76
+ */
77
+ declare class LanguageDetector {
21
78
  private options;
22
79
  constructor(options: LanguageDetectorOption);
23
80
  detect(request: Request): Promise<string>;
@@ -30,4 +87,5 @@ export declare class LanguageDetector {
30
87
  private fromHeader;
31
88
  private fromSupported;
32
89
  }
33
- //# sourceMappingURL=language-detector.d.ts.map
90
+
91
+ export { LanguageDetector, LanguageDetectorLingui, type LanguageDetectorLinguiOptions, type LanguageDetectorOption };