@libs-ui/utils
v0.2.356-1
Published
> Thư viện tập trung toàn bộ **utility functions** dùng chung cho các libs-ui trong project.
Downloads
4,073
Readme
@libs-ui/utils
Thư viện tập trung toàn bộ utility functions dùng chung cho các libs-ui trong project.
Version: 0.2.355-10
Giới thiệu
Thư viện @libs-ui/utils cung cấp các hàm tiện ích dùng chung (format, transform, validate...) để:
- Giảm trùng lặp code utility trong nhiều libs khác nhau
- Dễ bảo trì và mở rộng khi cần thêm utility mới
- Chuẩn hóa cách xử lý dữ liệu trong toàn bộ project
Cài đặt
npm install @libs-ui/utils
# hoặc
yarn add @libs-ui/utilsSử dụng
Import
import {
isNil,
isEmpty,
get,
set,
cloneDeep,
keyBy,
groupBy,
range,
isEqual,
uniqBy,
base64Encode,
base64Decode,
convertBase64ToBlob,
convertFileToBase64,
UtilsCache,
addArrayToSet,
convertSetToArray,
colorContrastFromOrigin,
getColorById,
detectAndCleanNearWhiteColors,
UtilsCommunicateMicro,
encrypt3rd,
decrypt3rd,
setKeyCrypto3rd,
encrypt,
decrypt,
setKeyCrypto,
md5,
isDangerousObject,
isPrimitiveType,
isDOMObject,
isFrameworkObject,
getObjectSize,
getDayjs,
formatDate,
isDifferenceDay,
setDefaultTimeZone,
getDeviceInfo,
isTouchDevice,
getViewport,
setStylesElement,
downloadFileByUrl,
downloadFileByUrlUseXmlRequest,
} from '@libs-ui/utils';Ví dụ cơ bản
Base64 & File
import { base64Encode, base64Decode, convertFileToBase64 } from '@libs-ui/utils';
// Mã hóa Unicode an toàn
const encoded = base64Encode('Xin chào 👋');
const decoded = base64Decode(encoded); // 'Xin chào 👋'
// Chuyển File sang Base64 để preview
const base64 = await convertFileToBase64(file);
// data:image/png;base64,iVBORw...
#### Language
```typescript
import { UtilsLanguageConstants } from '@libs-ui/utils';
// Dùng hằng số thay vì hardcode chuỗi
const viCode = UtilsLanguageConstants.VI; // 'vi'
const enCode = UtilsLanguageConstants.EN; // 'en'
const jaCode = UtilsLanguageConstants.JA; // 'ja'
// Tự động phát hiện ngôn ngữ trình duyệt (fallback về 'en')
const lang = UtilsLanguageConstants.defaultLang();
// Kiểm tra hỗ trợ
UtilsLanguageConstants.isSupported('vi'); // true
UtilsLanguageConstants.isSupported('xx'); // false
// Tùy chỉnh danh sách ngôn ngữ hỗ trợ (gọi một lần lúc khởi động)
UtilsLanguageConstants.setSupportedLanguages(['vi', 'en']);
#### Random & String Protection
```typescript
import { protectString, revealString, createUniqueRandomIntGenerator } from '@libs-ui/utils';
// Obfuscate nhẹ cổng giao tiếp
const hidden = protectString('user-token-abc123');
const plain = revealString(hidden); // 'user-token-abc123'
// Round-trip luôn trả về cỗi gốc
console.log(revealString(protectString('Xin chào')) === 'Xin chào'); // true
// Tạo số ngẫu nhiên không trùng trong 10 lần gần nhất
const nextId = createUniqueRandomIntGenerator(1, 100);
console.log(nextId()); // 42
console.log(nextId()); // 17 (khác 42)
#### Cache
```typescript
import { UtilsCache } from '@libs-ui/utils';
// LocalStorage (Đồng bộ)
UtilsCache.Set('key', { a: 1 }, 3600); // 1 giờ
const data = UtilsCache.Get('key');
// IndexedDB (Bất đồng bộ)
await UtilsCache.SetAsync('large_key', data);
const asyncData = await UtilsCache.GetAsync('large_key');
#### Collection
```typescript
import { addArrayToSet, convertSetToArray } from '@libs-ui/utils';
const s = new Set([1]);
addArrayToSet(s, [1, 2, 3]); // Set {1, 2, 3}
const arr = convertSetToArray(s, v => `Item ${v}`); // ["Item 1", "Item 2", "Item 3"]
#### Color
```typescript
import { colorContrastFromOrigin, getColorById } from '@libs-ui/utils';
// Tạo bảng màu
const palette = colorContrastFromOrigin('#226FF5');
// Lấy màu định danh theo ID
const userColor = getColorById('user_id_123');
/* ... */
#### Communicate Micro
```typescript
import { UtilsCommunicateMicro } from '@libs-ui/utils';
// Khởi tạo tại AppComponent
UtilsCommunicateMicro.initEvent(window, destroyRef);
// Lắng nghe
UtilsCommunicateMicro.GetMessage('DATA_SYNC').subscribe(e => {
console.log(e.data.response);
});
// Gửi cho cha (ví dụ từ Iframe)
UtilsCommunicateMicro.PostMessageToParent({ type: 'DATA_SYNC', response: { id: 1 } });
#### Crypto 3rd
```typescript
import { encrypt3rd, decrypt3rd, setKeyCrypto3rd } from '@libs-ui/utils';
// Setup key (một lần)
setKeyCrypto3rd('12345678901234567890123456789012');
// Mã hóa
const secret = encrypt3rd('My Secret Data');
// Giải mã
const original = decrypt3rd(secret);
#### Crypto
```typescript
import { encrypt, decrypt, md5 } from '@libs-ui/utils';
// AES Internal
const secureData = encrypt('Secret');
const plain = decrypt(secureData);
// MD5 Hash
const hash = md5('hello');
#### Dangerous Object
```typescript
import { isDangerousObject, isPrimitiveType } from '@libs-ui/utils';
isDangerousObject(window); // true
isDangerousObject(document.body); // true
isPrimitiveType(123); // true
isPrimitiveType({}); // false
#### Data
```typescript
import { getObjectSize } from '@libs-ui/utils';
const size = getObjectSize({ a: 1 }); // "10 bytes"
#### Date
```typescript
import { formatDate, getDayjs } from '@libs-ui/utils';
// Format tiếng Việt
formatDate('2024-05-20', 'dmy', 'vi'); // "20 Thg 5, 2024"
// Lấy đối tượng Day.js (local timezone)
const now = getDayjs();
#### DOM
```typescript
import { getViewport, isTouchDevice } from '@libs-ui/utils';
const { width, height } = getViewport();
const isTouch = isTouchDevice();
#### Download
```typescript
import { downloadFileByUrl } from '@libs-ui/utils';
// Tải file PDF từ server
await downloadFileByUrl('https://example.com/report.pdf', 'report.pdf');
// Chỉ mở tầ mới (không download)
await downloadFileByUrl('https://example.com/doc.pdf', 'preview.pdf', true);
#### Regex Patterns
```typescript
import { patternEmail, patternMobilePhone, patternUrl } from '@libs-ui/utils';
// Kiểm tra email
const emailRe = patternEmail();
emailRe.test('[email protected]'); // true
// Kiểm tra số điện thoại VN
patternMobilePhone().test('0987654321'); // true
// Match pattern cụ thể
const templateRe = patternRuleFieldReplace(); // /[{]{2}[a-zA-Z_-]+[}]{2}/g
'hello {{name}}'.match(templateRe); // ['{{name}}']
```
#### Trace Stack
```typescript
import { traceStack } from '@libs-ui/utils';
function a() {
b();
}
function b() {
console.log(traceStack());
// Output: ["a", "b"] (đã lọc các frame rác)
}
```
#### Two-Way Signal Object
```typescript
import { convertObjectToSignal, convertSignalToObject } from '@libs-ui/utils';
const obj = { name: 'Alice' };
const reactive = convertObjectToSignal<any>(obj);
reactive().name.set('Bob');
const plain = convertSignalToObject(reactive);
console.log(plain.name); // 'Bob'
```
#### URI
```typescript
import { encodeURI, decodeURI, endCodeUrl } from '@libs-ui/utils';
// Mã hóa/Giải mã
const encoded = encodeURI('Xin chào & Hẹn gặp lại!');
const decoded = decodeURI(encoded);
// Query String builder
const qs = endCodeUrl({ id: 1, q: 'tag' }, false); // "?id=1&q=tag"
#### URL
```typescript
import { normalizeUrl } from '@libs-ui/utils';
// Chuẩn hóa đường dẫn URL (gộp dấu // dư thừa)
const clean = normalizeUrl('http://example.com//api///users');
// Output: "http://example.com/api/users"
```
#### UUID
```typescript
import { uuid } from '@libs-ui/utils';
// Tạo unique ID (MD5 hash - 32 character)
const newId = uuid();
// Output: "a1b2c3d4..."
```
#### XSS Filter
```typescript
import { updateFunctionXssFilter, xssFilter } from '@libs-ui/utils';
import DOMPurify from 'dompurify';
// 1. Cấu hình ban đầu (Ví dụ: trong app.component.ts)
updateFunctionXssFilter(async (data: string) => DOMPurify.sanitize(data));
// 2. Sử dụng ở mọi nơi để làm sạch HTML
const cleanHTML = await xssFilter('<script>evil()</script><b>Good</b>');
// Output: "<b>Good</b>"
```
#### URL Search Params
```typescript
import { UtilsUrlSearchParams } from '@libs-ui/utils';
const usp = new UtilsUrlSearchParams('?id=1&name=test');
console.log(usp.get('id')); // "1"
usp.set('page', '2');
console.log(usp.toString()); // "id=1&name=test&page=2"
```
```
```
```
```
```
```
```
```
```
#### Kiểm tra giá trị
```typescript
import { isNil, isEmpty, isTruthy, isFalsy } from '@libs-ui/utils';
// Kiểm tra null/undefined
isNil(null); // true
isNil(undefined); // true
isNil(0); // false
// Kiểm tra rỗng
isEmpty(null); // true
isEmpty(''); // true
isEmpty({}); // true
isEmpty([]); // true
isEmpty({ a: 1 }); // false
```
#### Thao tác Object
```typescript
import { get, set, cloneDeep } from '@libs-ui/utils';
const user = {
profile: {
name: 'John',
address: { city: 'Hanoi' },
},
};
// Lấy giá trị theo path
get(user, 'profile.name'); // 'John'
get(user, 'profile.address.city'); // 'Hanoi'
get(user, 'profile.email', 'N/A'); // 'N/A' (default value)
// Thiết lập giá trị theo path
set(user, 'profile.name', 'Jane');
set(user, 'profile.age', 25);
// Clone sâu
const cloned = cloneDeep(user);
cloned.profile.name = 'Bob'; // Không ảnh hưởng user gốc
```
#### Thao tác Array
```typescript
import { keyBy, groupBy, range, uniqBy, isEqual } from '@libs-ui/utils';
const users = [
{ id: 1, name: 'John', type: 'admin' },
{ id: 2, name: 'Jane', type: 'user' },
{ id: 3, name: 'Bob', type: 'admin' },
];
// Chuyển array thành object
keyBy(users, 'id');
// { "1": {id:1,name:"John",type:"admin"}, "2": {...}, "3": {...} }
// Nhóm theo type
groupBy(users, 'type');
// { "admin": [{...}, {...}], "user": [{...}] }
// Tạo mảng số
range(5); // [0, 1, 2, 3, 4]
range(1, 5); // [1, 2, 3, 4]
range(0, 10, 2); // [0, 2, 4, 6, 8]
// Loại bỏ trùng lặp
uniqBy([{ id: 1 }, { id: 2 }, { id: 1 }], 'id'); // [{id:1}, {id:2}]
// So sánh deep equality
isEqual({ a: 1, b: 2 }, { a: 1, b: 2 }); // true
isEqual([1, 2, 3], [1, 2, 3]); // true
```
#### HTTP Query Params (Type-Safe)
```typescript
import { UtilsHttpParamsRequest, UtilsHttpParamsRequestInstance } from '@libs-ui/utils';
// Định nghĩa interface cho params
interface SearchParams {
keyword: string;
page: number;
size: number;
}
// 1. Dùng fromObject với type safety
const params = new UtilsHttpParamsRequest<SearchParams>({
fromObject: { keyword: 'Angular', page: 1, size: 20 },
});
params.toString(); // keyword=Angular&page=1&size=20
// 2. Factory function (không cần new)
const params2 = UtilsHttpParamsRequestInstance<SearchParams>({
fromObject: { keyword: 'Angular', page: 1, size: 20 },
});
// 3. Method chaining
const params3 = new UtilsHttpParamsRequest().set('page', 1).set('size', 10).set('sort', 'name');
params3.delete('sort');
params3.toString(); // page=1&size=10
// 4. Wrap HttpParams có sẵn
import { HttpParams } from '@angular/common/http';
const base = new HttpParams().set('version', 'v2');
const wrapped = new UtilsHttpParamsRequest(undefined, base);
wrapped.get('version'); // 'v2'
```
#### GET_PATH_VARIABLE — Type-Safe Path Params
```typescript
import { GET_PATH_VARIABLE } from '@libs-ui/utils';
interface UserResource {
userId: number;
orgId: string;
}
// Tạo type với pattern "pathVariable-{key}"
type UserPathParams = GET_PATH_VARIABLE<UserResource>;
// Tương đương: { "pathVariable-userid": number; "pathVariable-orgid": string }
const pathParams: UserPathParams = {
'pathVariable-userid': 123,
'pathVariable-orgid': 'org-abc',
};
```
## Important Notes
⚠️ **Lưu ý quan trọng khi sử dụng**:
- Các functions hỗ trợ unwrap Signal tự động (trừ khi dùng option `ignoreUnWrapSignal`).
- `get()` và `set()` hỗ trợ path dạng string (vd: `"user.profile.name"`) hoặc array (vd: `["user", "profile", "name"]`).
- `cloneDeep()` có thể clone Signal, Date, RegExp, Map, Set và các object phức tạp khác.
- `isEqual()` có thể so sánh deep equality cho objects và arrays.
- `UtilsHttpParamsRequest` kế thừa `HttpParams` — compatible 100% với Angular HttpClient.
- `HttpParams` của Angular là **immutable**; `UtilsHttpParamsRequest` xử lý điều này nội bộ (tự assign lại `this.params` sau mỗi mutation).
## API Reference
Xem chi tiết API tại [Documentation](./docs/utils/utils.md) hoặc [Demo Live](http://localhost:4500/utils/helpers).
### Các Functions chính
| Function | Mô tả |
| ------------------------------------------------------- | -------------------------------------------- |
| `isNil(value, options?)` | Kiểm tra giá trị có phải null hoặc undefined |
| `isEmpty(value, options?)` | Kiểm tra giá trị có rỗng không |
| `isTruthy(value, options?)` | Kiểm tra giá trị truthy |
| `isFalsy(value, options?)` | Kiểm tra giá trị falsy |
| `get(obj, path, defaultValue?, keepLastValueIfSignal?)` | Lấy giá trị theo path |
| `set(obj, path, value, options?)` | Thiết lập giá trị theo path |
| `cloneDeep(data, options?, seen?)` | Clone sâu object/array |
| `keyBy(data, key)` | Chuyển array thành object |
| `groupBy(data, key)` | Nhóm array theo key |
| `range(start, end?, step?)` | Tạo mảng số |
| `isEqual(value1, value2, options?)` | So sánh deep equality |
| `uniqBy(data, key?)` | Loại bỏ trùng lặp |
| `omitBy(objData, predicate)` | Loại bỏ thuộc tính theo điều kiện |
| `generateInterface(obj, interfaceName)` | Tạo interface từ object |
| `base64Encode(value)` | Mã hóa Base64 (hỗ trợ Unicode) |
| `base64Decode(value)` | Giải mã Base64 (hỗ trợ Unicode) |
| `convertBase64ToBlob(data)` | Chuyển Base64 sang Blob |
| `convertFileToBase64(file)` | Chuyển File sang Base64 string |
| `UtilsCache` | Quản lý Cache (Sync & Async) |
| `addArrayToSet(set, data)` | Thêm mảng vào Set |
| `convertSetToArray(set, map?)` | Chuyển Set sang Array |
| `colorContrastFromOrigin(color)` | Tạo bảng sắc độ (shades/tints) |
| `getColorById(str)` | Hash chuỗi thành màu cố định |
| `detectAndCleanNearWhiteColors(style)` | Làm sạch CSS style khỏi màu gần trắng |
| `UtilsCommunicateMicro` | Giao tiếp Cross-window (mã hóa) |
| `encrypt3rd(data)` | Mã hóa AES-CBC |
| `decrypt3rd(data)` | Giải mã AES-CBC |
| `encrypt(data)` | Mã hóa AES nội bộ |
| `md5(data)` | Hash MD5 |
| `isDangerousObject(obj)` | Kiểm tra Window/DOM/Global |
| `isPrimitiveType(val)` | Kiểm tra kiểu dữ liệu nguyên thủy |
| `getObjectSize(obj)` | Đo dung lượng object |
| `formatDate(date, format?)` | Định dạng ngày tháng |
| `getDayjs(config?)` | Khởi tạo Day.js instance |
| `getDeviceInfo()` | Lấy thông tin thiết bị |
| `isTouchDevice()` | Kiểm tra thiết bị cảm ứng |
| `getViewport()` | Lấy kích thước Viewport |
| `downloadFileByUrl(url, name, onlyOpen?)` | Tải file từ URL |
| `downloadFileByUrlUseXmlRequest(url, name)` | Tải file bằng XMLHttpRequest |
| `downloadImageFromELement(img, type?, name?)` | Lưu ảnh từ thẻ img |
| `isTypeImage(file)` | Kiểm tra Blob/File là ảnh |
| `isTypeVideo(file)` | Kiểm tra Blob/File là video |
| `getFileExtension(file)` | Lấy extension của file |
| `getLabelBySizeFile(size, toFixed?)` | Format kích thước byte |
| `convertBlobToFile(blob, name?)` | Chuyển Blob thành File |
| `formatNumber(value)` | Chuẩn hóa chuỗi số theo locale |
| `viewDataNumberByLanguage(val, neg, fixed?, ...)` | Định dạng số theo VI/EN locale |
| `UtilsLanguageConstants.{KEY}` | Hằng số mã ngôn ngữ ISO 639-1 (27 ngôn ngữ) |
| `UtilsLanguageConstants.defaultLang()` | Tự dò ngôn ngữ trình duyệt, fallback 'en' |
| `UtilsLanguageConstants.isSupported(lang)` | Kiểm tra ngôn ngữ có được hỗ trợ |
| `UtilsLanguageConstants.setSupportedLanguages(langs)` | Ghi đè danh sách ngôn ngữ hỗ trợ |
| `protectString(input)` | XOR + reverse + base64 encode (obfuscation) |
| `revealString(encoded)` | Giải mã ngược lại protectString |
| `createUniqueRandomIntGenerator(min, max)` | Factory tạo số ngẫu nhiên không trùng (10 lần) |
| `patternEmail()` | Regex kiểm tra email chuẩn |
| `patternUrl()` | Regex kiểm tra URL đầy đủ |
| `patternMobilePhone()` | Regex kiểm tra SĐT di động Việt Nam |
| `patternNameUtf8()` | Regex hỗ trợ tên tiếng Việt có dấu |
| `patternEmoji()` | Regex phát hiện ký tự emoji (global) |
| `traceStack()` | Trích xuất call stack sạch (lọc rác) |
| `convertObjectToSignal()` | Biến object thành cấu trúc Signals lồng nhau |
| `convertSignalToObject()` | Chuyển cấu trúc signals về plain object |
| `unwrapSignal()` | Lấy giá trị cuối cùng từ (lồng) signal |
| `normalizeUrl(rawUrl)` | Chuẩn hóa URL, gộp dấu // trong pathname |
| `uuid()` | Tạo chuỗi định danh duy nhất (MD5 hash) |
| `xssFilter(data)` | Lọc chuỗi HTML khỏi XSS thông qua hàm custom |
| `updateFunctionXssFilter(fn)` | Cập nhật custom implementation cho xssFilter |
## Demo
- **Local Utilities**: [http://localhost:4500/utils/helpers](http://localhost:4500/utils/helpers)
- **Local Base64**: [http://localhost:4500/utils/base64](http://localhost:4500/utils/base64)
- **Local Cache**: [http://localhost:4500/utils/cache](http://localhost:4500/utils/cache)
- **Local Collection**: [http://localhost:4500/utils/collection](http://localhost:4500/utils/collection)
- **Local Color**: [http://localhost:4500/utils/color](http://localhost:4500/utils/color)
- **Local Micro Comms**: [http://localhost:4500/utils/communicate-micro](http://localhost:4500/utils/communicate-micro)
- **Local Crypto 3rd**: [http://localhost:4500/utils/crypto-3rd](http://localhost:4500/utils/crypto-3rd)
- **Local Crypto**: [http://localhost:4500/utils/crypto](http://localhost:4500/utils/crypto)
- **Local Dangerous Object**: [http://localhost:4500/utils/dangerous-object](http://localhost:4500/utils/dangerous-object)
- **Local Data**: [http://localhost:4500/utils/data](http://localhost:4500/utils/data)
- **Local Date**: [http://localhost:4500/utils/date](http://localhost:4500/utils/date)
- **Local DOM**: [http://localhost:4500/utils/dom](http://localhost:4500/utils/dom)
- **Local Download**: [http://localhost:4500/utils/download](http://localhost:4500/utils/download)
- **Local File**: [http://localhost:4500/utils/file](http://localhost:4500/utils/file)
- **Local Format Number**: [http://localhost:4500/utils/format-number](http://localhost:4500/utils/format-number)
- **Local Format Text**: [http://localhost:4500/utils/format-text](http://localhost:4500/utils/format-text)
- **Local Embed Frame**: [http://localhost:4500/utils/embed-frame](http://localhost:4500/utils/embed-frame)
- **Local Smart Axis Scale**: [http://localhost:4500/utils/smart-axis-scale](http://localhost:4500/utils/smart-axis-scale)
- **Local Language**: [http://localhost:4500/utils/language](http://localhost:4500/utils/language)
- **Local Random & String Protection**: [http://localhost:4500/utils/random](http://localhost:4500/utils/random)
- **Local Patterns (Regex)**: [http://localhost:4500/utils/pattern](http://localhost:4500/utils/pattern)
- **Local Trace Stack**: [http://localhost:4500/utils/trace](http://localhost:4500/utils/trace)
- **Local Two-Way Signal Object**: [http://localhost:4500/utils/two-way-signal-object](http://localhost:4500/utils/two-way-signal-object)
- **Local URI Utilities**: [http://localhost:4500/utils/uri](http://localhost:4500/utils/uri)
- **Local URL Utilities**: [http://localhost:4500/utils/url](http://localhost:4500/utils/url)
- **Local URL Search Params**: [http://localhost:4500/utils/url-search-params](http://localhost:4500/utils/url-search-params)
- **Local UUID Utilities**: [http://localhost:4500/utils/uuid](http://localhost:4500/utils/uuid)
- **Local Xss Filter Utilities**: [http://localhost:4500/utils/xss-filter](http://localhost:4500/utils/xss-filter)
### HTTP Params
| Class / Type | Mô tả |
| ----------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `UtilsHttpParamsRequest<Type>` | Wrapper type-safe cho Angular HttpParams — hỗ trợ method chaining, fromObject với generic type |
| `UtilsHttpParamsRequestInstance<Type>()` | Factory function tạo `UtilsHttpParamsRequest` không cần `new` |
| `GET_PATH_VARIABLE<TypePath, TypeOther?>` | Utility type tạo map path-variable từ interface (pattern: `pathVariable-{key}`) |
| `HttpParamsOptions<Type>` | Interface options cho constructor (`fromString`, `fromObject`, `encoder`) |
### InjectionTokens
| Token | Mô tả |
| -------------------------------------------------- | ----------------------------------------------------- |
| `LINK_IMAGE_ERROR_TOKEN_INJECT` | InjectionToken cho link ảnh fallback |
| `PROCESS_BAR_STANDARD_CONFIG_DEFAULT_TOKEN_INJECT` | InjectionToken cấu hình mặc định process bar standard |
| `PROCESS_BAR_STEPS_CONFIG_DEFAULT_TOKEN_INJECT` | InjectionToken cấu hình mặc định process bar steps |
## Demo
- **Helpers utilities**: [http://localhost:4500/utils/helpers](http://localhost:4500/utils/helpers)
- **HTTP Params**: [http://localhost:4500/utils/http-params](http://localhost:4500/utils/http-params)
- **Injection Tokens**: [http://localhost:4500/utils/inject-token](http://localhost:4500/utils/inject-token)
- **Key Cache**: [http://localhost:4500/utils/key-cache](http://localhost:4500/utils/key-cache)
- **Key Code**: [http://localhost:4500/utils/key-code](http://localhost:4500/utils/key-code)
- **Production**: (Chưa có)
## Công nghệ sử dụng
- **Angular**: >=18.0.0
- **TypeScript**: Latest
- **RxJS**: ~7.8.0
- **dayjs**: 1.11.5
- **crypto-es**: ^2.1.0
## Tài liệu
Xem thêm tài liệu chi tiết tại [docs/utils/utils.md](../../docs/utils/utils.md).