@regardio/js 0.2.3 → 0.3.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.
- package/README.md +47 -1
- package/dist/intl/language-detector.d.ts.map +1 -1
- package/dist/intl/language-detector.js +21 -1
- package/package.json +1 -5
- package/dist/intl/locale.d.ts +0 -4
- package/dist/intl/locale.d.ts.map +0 -1
- package/dist/intl/locale.js +0 -22
- package/dist/intl/locale.test.d.ts +0 -2
- package/dist/intl/locale.test.d.ts.map +0 -1
- package/dist/intl/locale.test.js +0 -75
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**
|
|
197
|
+
**MIT License** — Free to use in commercial and open source projects.
|
|
152
198
|
|
|
153
199
|
---
|
|
154
200
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"language-detector.d.ts","sourceRoot":"","sources":["../../src/intl/language-detector.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"language-detector.d.ts","sourceRoot":"","sources":["../../src/intl/language-detector.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,WAAW,sBAAsB;IAMrC,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAM7B,gBAAgB,EAAE,MAAM,CAAC;IAKzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAMhB,cAAc,CAAC,EAAE,cAAc,CAAC;IAMhC,UAAU,CAAC,EAAE,MAAM,CAAC;IAOpB,cAAc,CAAC,EAAE,MAAM,CAAC;IAWxB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,GAAG,cAAc,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC,CAAC;CAC7E;AAED,MAAM,WAAW,6BAA6B;IAC5C,SAAS,EAAE,sBAAsB,CAAC;CACnC;AAED,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,OAAO,CAAgC;gBAEnC,OAAO,EAAE,6BAA6B;IAgBrC,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;CAG1D;AAOD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,OAAO,CAAyB;gBAE5B,OAAO,EAAE,sBAAsB;IAM9B,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IAgCtD,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,WAAW;IAenB,OAAO,CAAC,gBAAgB;YAQV,UAAU;YAcV,kBAAkB;IAYhC,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,aAAa;CAYtB"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { parseAcceptLanguage } from 'intl-parse-accept-language';
|
|
2
|
-
import { getClientLocales } from './locale';
|
|
3
2
|
export class LanguageDetectorLingui {
|
|
4
3
|
detector;
|
|
5
4
|
options;
|
|
@@ -112,3 +111,24 @@ export class LanguageDetector {
|
|
|
112
111
|
return parsed[0] || this.options.fallbackLanguage;
|
|
113
112
|
}
|
|
114
113
|
}
|
|
114
|
+
function getClientLocales(requestOrHeaders) {
|
|
115
|
+
const headers = getHeaders(requestOrHeaders);
|
|
116
|
+
const acceptLanguage = headers.get('Accept-Language');
|
|
117
|
+
if (!acceptLanguage)
|
|
118
|
+
return undefined;
|
|
119
|
+
const locales = parseAcceptLanguage(acceptLanguage, {
|
|
120
|
+
ignoreWildcard: true,
|
|
121
|
+
validate: Intl.DateTimeFormat.supportedLocalesOf,
|
|
122
|
+
});
|
|
123
|
+
if (locales.length === 0)
|
|
124
|
+
return undefined;
|
|
125
|
+
if (locales.length === 1)
|
|
126
|
+
return locales[0];
|
|
127
|
+
return locales;
|
|
128
|
+
}
|
|
129
|
+
function getHeaders(requestOrHeaders) {
|
|
130
|
+
if (requestOrHeaders instanceof Request) {
|
|
131
|
+
return requestOrHeaders.headers;
|
|
132
|
+
}
|
|
133
|
+
return requestOrHeaders;
|
|
134
|
+
}
|
package/package.json
CHANGED
|
@@ -48,10 +48,6 @@
|
|
|
48
48
|
"import": "./dist/intl/language-detector.js",
|
|
49
49
|
"types": "./dist/intl/language-detector.d.ts"
|
|
50
50
|
},
|
|
51
|
-
"./intl/locale": {
|
|
52
|
-
"import": "./dist/intl/locale.js",
|
|
53
|
-
"types": "./dist/intl/locale.d.ts"
|
|
54
|
-
},
|
|
55
51
|
"./time/time": {
|
|
56
52
|
"import": "./dist/time/time.js",
|
|
57
53
|
"types": "./dist/time/time.d.ts"
|
|
@@ -108,5 +104,5 @@
|
|
|
108
104
|
},
|
|
109
105
|
"sideEffects": false,
|
|
110
106
|
"type": "module",
|
|
111
|
-
"version": "0.
|
|
107
|
+
"version": "0.3.0"
|
|
112
108
|
}
|
package/dist/intl/locale.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"locale.d.ts","sourceRoot":"","sources":["../../src/intl/locale.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;AAiBpD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;AAC5D,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC"}
|
package/dist/intl/locale.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { parseAcceptLanguage } from 'intl-parse-accept-language';
|
|
2
|
-
export function getClientLocales(requestOrHeaders) {
|
|
3
|
-
const headers = getHeaders(requestOrHeaders);
|
|
4
|
-
const acceptLanguage = headers.get('Accept-Language');
|
|
5
|
-
if (!acceptLanguage)
|
|
6
|
-
return undefined;
|
|
7
|
-
const locales = parseAcceptLanguage(acceptLanguage, {
|
|
8
|
-
ignoreWildcard: true,
|
|
9
|
-
validate: Intl.DateTimeFormat.supportedLocalesOf,
|
|
10
|
-
});
|
|
11
|
-
if (locales.length === 0)
|
|
12
|
-
return undefined;
|
|
13
|
-
if (locales.length === 1)
|
|
14
|
-
return locales[0];
|
|
15
|
-
return locales;
|
|
16
|
-
}
|
|
17
|
-
function getHeaders(requestOrHeaders) {
|
|
18
|
-
if (requestOrHeaders instanceof Request) {
|
|
19
|
-
return requestOrHeaders.headers;
|
|
20
|
-
}
|
|
21
|
-
return requestOrHeaders;
|
|
22
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"locale.test.d.ts","sourceRoot":"","sources":["../../src/intl/locale.test.ts"],"names":[],"mappings":""}
|
package/dist/intl/locale.test.js
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'vitest';
|
|
2
|
-
import { getClientLocales } from './locale';
|
|
3
|
-
describe('getClientLocales', () => {
|
|
4
|
-
describe('with Request object', () => {
|
|
5
|
-
test('should return undefined when Accept-Language header is missing', () => {
|
|
6
|
-
const request = new Request('https://example.com');
|
|
7
|
-
expect(getClientLocales(request)).toBeUndefined();
|
|
8
|
-
});
|
|
9
|
-
test('should return single locale when only one is provided', () => {
|
|
10
|
-
const request = new Request('https://example.com', {
|
|
11
|
-
headers: { 'Accept-Language': 'en-US' },
|
|
12
|
-
});
|
|
13
|
-
expect(getClientLocales(request)).toBe('en-US');
|
|
14
|
-
});
|
|
15
|
-
test('should return array of locales sorted by quality', () => {
|
|
16
|
-
const request = new Request('https://example.com', {
|
|
17
|
-
headers: { 'Accept-Language': 'en-US,de;q=0.9,fr;q=0.8' },
|
|
18
|
-
});
|
|
19
|
-
const result = getClientLocales(request);
|
|
20
|
-
expect(Array.isArray(result)).toBe(true);
|
|
21
|
-
expect(result).toContain('en-US');
|
|
22
|
-
expect(result).toContain('de');
|
|
23
|
-
});
|
|
24
|
-
test('should return undefined for invalid locales', () => {
|
|
25
|
-
const request = new Request('https://example.com', {
|
|
26
|
-
headers: { 'Accept-Language': 'invalid-locale-xyz' },
|
|
27
|
-
});
|
|
28
|
-
expect(getClientLocales(request)).toBeUndefined();
|
|
29
|
-
});
|
|
30
|
-
test('should ignore wildcard (*)', () => {
|
|
31
|
-
const request = new Request('https://example.com', {
|
|
32
|
-
headers: { 'Accept-Language': '*' },
|
|
33
|
-
});
|
|
34
|
-
expect(getClientLocales(request)).toBeUndefined();
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
describe('with Headers object', () => {
|
|
38
|
-
test('should return undefined when Accept-Language header is missing', () => {
|
|
39
|
-
const headers = new Headers();
|
|
40
|
-
expect(getClientLocales(headers)).toBeUndefined();
|
|
41
|
-
});
|
|
42
|
-
test('should return single locale when only one is provided', () => {
|
|
43
|
-
const headers = new Headers({ 'Accept-Language': 'de-DE' });
|
|
44
|
-
expect(getClientLocales(headers)).toBe('de-DE');
|
|
45
|
-
});
|
|
46
|
-
test('should return array of locales sorted by quality', () => {
|
|
47
|
-
const headers = new Headers({ 'Accept-Language': 'fr-FR,en;q=0.9,de;q=0.8' });
|
|
48
|
-
const result = getClientLocales(headers);
|
|
49
|
-
expect(Array.isArray(result)).toBe(true);
|
|
50
|
-
expect(result).toContain('fr-FR');
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
describe('quality value handling', () => {
|
|
54
|
-
test('should prioritize higher quality values', () => {
|
|
55
|
-
const request = new Request('https://example.com', {
|
|
56
|
-
headers: { 'Accept-Language': 'de;q=0.5,en;q=0.9' },
|
|
57
|
-
});
|
|
58
|
-
const result = getClientLocales(request);
|
|
59
|
-
expect(Array.isArray(result)).toBe(true);
|
|
60
|
-
if (Array.isArray(result)) {
|
|
61
|
-
expect(result[0]).toBe('en');
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
test('should handle locales without explicit quality (default q=1)', () => {
|
|
65
|
-
const request = new Request('https://example.com', {
|
|
66
|
-
headers: { 'Accept-Language': 'en,de;q=0.9' },
|
|
67
|
-
});
|
|
68
|
-
const result = getClientLocales(request);
|
|
69
|
-
expect(Array.isArray(result)).toBe(true);
|
|
70
|
-
if (Array.isArray(result)) {
|
|
71
|
-
expect(result[0]).toBe('en');
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
});
|