{"versions":{"0.0.1":{"name":"@pivanov/utils","version":"0.0.1","description":"A collection of personal utilities to live a happier life","type":"module","packageManager":"pnpm@9.0.0","repository":{"type":"git","url":"git://github.com/pivanov/utils.git"},"homepage":"https://github.com/pivanov/utils#readme","bugs":{"url":"https://github.com/pivanov/utils/issues"},"scripts":{"build":"rm -rf dist && pnpm rollup -c","test":"pnpm vitest","test:coverage":"pnpm vitest --coverage","test:ui":"pnpm vitest --ui","lint":"biome lint .","format":"biome format . --write","check":"biome check . --write","prepublishOnly":"pnpm build"},"author":{"name":"Pavel Ivanov","email":"iweb.ivanov@gmail.com","url":"https://github.com/pivanov"},"keywords":["utils","typescript","react","web-components","dom","cache","event-bus","string","object","promise","r2wc","react-to-web-component"],"license":"MIT","main":"dist/cjs/index.js","module":"dist/esm/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/esm/index.js","require":"./dist/cjs/index.js"}},"peerDependencies":{"react":">=18","react-dom":">=18"},"devDependencies":{"@biomejs/biome":"^1.9.4","@rollup/plugin-commonjs":"^28.0.0","@rollup/plugin-node-resolve":"^15.3.0","@rollup/plugin-typescript":"^12.1.1","@testing-library/dom":"^10.4.0","@testing-library/react":"^16.0.1","@testing-library/react-hooks":"^8.0.1","@types/node":"^22.9.0","@types/react":"^18.3.12","@types/react-dom":"^18.3.1","@vercel/ncc":"0.38.2","@vitest/coverage-v8":"^2.1.4","evt":"^2.4.18","glob":"^11.0.0","husky":"^4.3.0","jsdom":"^25.0.1","react":"^18.3.1","react-dom":"^18.3.1","rollup":"^4.23.0","rollup-plugin-dts":"^6.1.1","rollup-plugin-terser":"^7.0.2","tslib":"^2.7.0","typescript":"5.7.2","vitest":"^2.1.4"},"publishConfig":{"access":"public"},"_id":"@pivanov/utils@0.0.1","gitHead":"cbc575d4da80269acb05a2a1fd03e0a69526f0e4","_nodeVersion":"18.18.2","_npmVersion":"9.8.1","dist":{"integrity":"sha512-JQ/pXeG9/Yq3UuwH2Xp4F6bSAIDGzbxT0Vrg/82tMi3Yp+Ps9AYzjSDE+zfvBRqc7J11V6MMonUrWj4+2dYgrg==","shasum":"bd9f36849e42ae307e053d30168f4a1cd9b3892a","tarball":"http://123.232.10.234:8212/nexus/content/groups/npm-public/@pivanov/utils/-/utils-0.0.1.tgz","fileCount":6,"unpackedSize":63865,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIB31K+qjRljzQ0jxkvla2zVWPuMblonaGq3gQAm0zhj6AiAhkFulBwYs0cYbVS1RsMo3LGjXiSdxTXN5Z2s42PA3FQ=="}],"size":17257},"_npmUser":{"name":"anonymous","email":"pafelka@gmail.com"},"directories":{},"maintainers":[{"name":"anonymous","email":"pafelka@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/utils_0.0.1_1736299784044_0.061382709907555455"},"_hasShrinkwrap":false,"_cnpmcore_publish_time":"2025-01-08T01:29:44.218Z","publish_time":1736299784218,"_source_registry_name":"default","contributors":[]},"0.0.2":{"name":"@pivanov/utils","version":"0.0.2","description":"A collection of personal utilities to live a happier life","type":"module","packageManager":"pnpm@9.0.0","repository":{"type":"git","url":"git://github.com/pivanov/pivanov-utils.git"},"homepage":"https://github.com/pivanov/pivanov-utils#readme","bugs":{"url":"https://github.com/pivanov/pivanov-utils/issues"},"scripts":{"build":"rm -rf dist && pnpm rollup -c","test":"pnpm vitest","test:coverage":"pnpm vitest --coverage","test:ui":"pnpm vitest --ui","lint":"biome lint .","format":"biome format . --write","check":"biome check . --write","prepublishOnly":"pnpm build"},"author":{"name":"Pavel Ivanov","email":"iweb.ivanov@gmail.com","url":"https://github.com/pivanov"},"keywords":["utils","typescript","react","web-components","dom","cache","event-bus","string","object","promise","r2wc","react-to-web-component"],"license":"MIT","main":"dist/cjs/index.js","module":"dist/esm/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/esm/index.js","require":"./dist/cjs/index.js"}},"peerDependencies":{"react":">=18","react-dom":">=18"},"devDependencies":{"@biomejs/biome":"^1.9.4","@rollup/plugin-commonjs":"^28.0.0","@rollup/plugin-node-resolve":"^15.3.0","@rollup/plugin-typescript":"^12.1.1","@testing-library/dom":"^10.4.0","@testing-library/react":"^16.0.1","@testing-library/react-hooks":"^8.0.1","@types/node":"^22.9.0","@types/react":"^18.3.12","@types/react-dom":"^18.3.1","@vercel/ncc":"0.38.2","@vitest/coverage-v8":"^2.1.4","evt":"^2.4.18","glob":"^11.0.0","husky":"^4.3.0","jsdom":"^25.0.1","react":"^18.3.1","react-dom":"^18.3.1","rollup":"^4.23.0","rollup-plugin-dts":"^6.1.1","rollup-plugin-terser":"^7.0.2","tslib":"^2.7.0","typescript":"5.7.2","vitest":"^2.1.4"},"publishConfig":{"access":"public"},"_id":"@pivanov/utils@0.0.2","gitHead":"70eb8d9a98d9a6386e9c5268b3f9f3a75c47a576","_nodeVersion":"18.18.2","_npmVersion":"9.8.1","dist":{"integrity":"sha512-q9CN0bFWxWgMY5hVVYyBgez1jGiLBa6I+LkG37ycylPhFvEGOOeaADGtUSu46CaZasPnlY8fCdVJZmrgKb1EPA==","shasum":"32d7a381d6a837615d4ce6cd92878d4b050953b4","tarball":"http://123.232.10.234:8212/nexus/content/groups/npm-public/@pivanov/utils/-/utils-0.0.2.tgz","fileCount":6,"unpackedSize":64419,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCIbnnwHrvngUESoNBc9Og8YzlMx9L3UxkDqFmw+6GPewIhAPw5id2mGZafH2NHSv8d33hxP//DVQsRtzw0Y+wisRNi"}],"size":17323},"_npmUser":{"name":"anonymous","email":"pafelka@gmail.com"},"directories":{},"maintainers":[{"name":"anonymous","email":"pafelka@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/utils_0.0.2_1740783612488_0.112764635374351"},"_hasShrinkwrap":false,"_cnpmcore_publish_time":"2025-02-28T23:00:12.695Z","publish_time":1740783612695,"_source_registry_name":"default","contributors":[]},"0.0.3-rc.1":{"name":"@pivanov/utils","version":"0.0.3-rc.1","description":"A collection of personal utilities to live a happier life","type":"module","packageManager":"pnpm@9.0.0","repository":{"type":"git","url":"git://github.com/pivanov/pivanov-utils.git"},"homepage":"https://github.com/pivanov/pivanov-utils#readme","bugs":{"url":"https://github.com/pivanov/pivanov-utils/issues"},"scripts":{"build":"rm -rf dist && pnpm rollup -c","test":"pnpm vitest","test:coverage":"pnpm vitest --coverage","test:ui":"pnpm vitest --ui","lint":"biome lint .","format":"biome format . --write","check":"biome check . --write","prepublishOnly":"pnpm build"},"author":{"name":"Pavel Ivanov","email":"iweb.ivanov@gmail.com","url":"https://github.com/pivanov"},"keywords":["utils","typescript","react","web-components","dom","cache","event-bus","string","object","promise","r2wc","react-to-web-component"],"license":"MIT","main":"dist/cjs/index.js","module":"dist/esm/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/esm/index.js","require":"./dist/cjs/index.js"}},"peerDependencies":{"react":">=18","react-dom":">=18"},"devDependencies":{"@biomejs/biome":"^1.9.4","@rollup/plugin-commonjs":"^28.0.0","@rollup/plugin-node-resolve":"^15.3.0","@rollup/plugin-typescript":"^12.1.1","@testing-library/dom":"^10.4.0","@testing-library/react":"^16.0.1","@testing-library/react-hooks":"^8.0.1","@types/node":"^22.9.0","@types/react":"^18.3.12","@types/react-dom":"^18.3.1","@vercel/ncc":"0.38.2","@vitest/coverage-v8":"^2.1.4","evt":"^2.4.18","glob":"^11.0.0","husky":"^4.3.0","jsdom":"^25.0.1","react":"^18.3.1","react-dom":"^18.3.1","rollup":"^4.23.0","rollup-plugin-dts":"^6.1.1","rollup-plugin-terser":"^7.0.2","tslib":"^2.7.0","typescript":"5.7.2","vitest":"^2.1.4"},"publishConfig":{"access":"public"},"_id":"@pivanov/utils@0.0.3-rc.1","gitHead":"70eb8d9a98d9a6386e9c5268b3f9f3a75c47a576","_nodeVersion":"18.18.2","_npmVersion":"9.8.1","dist":{"integrity":"sha512-wUF/tGskvZuKveMkWJdrGk/K6xH5wPgkUWv8aHnyPH3YoO+qvUdQLbM5qKz0/ASyR33HCKQK3KFIC3Hx/YrFbg==","shasum":"48636130ab6c2981a2e81df8533ff1ddef52d32e","tarball":"http://123.232.10.234:8212/nexus/content/groups/npm-public/@pivanov/utils/-/utils-0.0.3-rc.1.tgz","fileCount":6,"unpackedSize":66240,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIGOqjhwUpoeRSiUzA4Jorsivw2KZprXFQkyycGMx06o6AiEA7Fa+/aP+ORy2enXnW7DADXEIyiKdnX7YLOgurSrxJUI="}],"size":17064},"_npmUser":{"name":"anonymous","email":"pafelka@gmail.com"},"directories":{},"maintainers":[{"name":"anonymous","email":"pafelka@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/utils_0.0.3-rc.1_1740863036001_0.8706552677499289"},"_hasShrinkwrap":false,"_cnpmcore_publish_time":"2025-03-01T21:03:56.244Z","publish_time":1740863036244,"_source_registry_name":"default","deprecated":"This version has been deprecated and will be replaced with a new version. Please update to the latest version.","contributors":[]},"0.0.3":{"name":"@pivanov/utils","version":"0.0.3","description":"A collection of personal utilities to live a happier life","type":"module","repository":{"type":"git","url":"git://github.com/pivanov/pivanov-utils.git"},"homepage":"https://github.com/pivanov/pivanov-utils#readme","bugs":{"url":"https://github.com/pivanov/pivanov-utils/issues"},"author":{"name":"Pavel Ivanov","email":"iweb.ivanov@gmail.com","url":"https://github.com/pivanov"},"keywords":["utils","typescript","react","dom","cache","browser cache api","event-bus","string","object","promise"],"license":"MIT","main":"dist/cjs/index.js","module":"dist/esm/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/esm/index.js","require":"./dist/cjs/index.js"}},"peerDependencies":{"react":">=18","react-dom":">=18"},"devDependencies":{"@biomejs/biome":"^1.9.4","@rollup/plugin-commonjs":"^28.0.0","@rollup/plugin-node-resolve":"^15.3.0","@rollup/plugin-typescript":"^12.1.1","@testing-library/dom":"^10.4.0","@testing-library/react":"^16.0.1","@testing-library/react-hooks":"^8.0.1","@types/node":"^22.9.0","@types/react":"^18.3.12","@types/react-dom":"^18.3.1","@vercel/ncc":"0.38.2","@vitest/coverage-v8":"^2.1.4","evt":"^2.4.18","glob":"^11.0.0","husky":"^4.3.0","jsdom":"^25.0.1","react":"^18.3.1","react-dom":"^18.3.1","rollup":"^4.23.0","rollup-plugin-dts":"^6.1.1","rollup-plugin-terser":"^7.0.2","tslib":"^2.7.0","typescript":"5.7.2","vitest":"^2.1.4"},"publishConfig":{"access":"public"},"scripts":{"build":"rm -rf dist && pnpm rollup -c","test":"pnpm vitest","test:coverage":"pnpm vitest --coverage","test:ui":"pnpm vitest --ui","lint":"biome lint .","format":"biome format . --write","check":"biome check . --write"},"_id":"@pivanov/utils@0.0.3","_integrity":"sha512-3Tm+9/vLTg0rSGfGjmduoeR5JKUk+iWB0vhSDMaadrcbo6+hHxCVZwvvzr7Yq1V9SEwsAQj+D6ffeQXsNWYwyw==","_resolved":"/private/var/folders/33/yx94zk4x45gf12snsr9qq4zw0000gn/T/d29a117b4e79b2845669d733fa4ee269/pivanov-utils-0.0.3.tgz","_from":"file:pivanov-utils-0.0.3.tgz","_nodeVersion":"20.19.5","_npmVersion":"10.8.2","dist":{"integrity":"sha512-3Tm+9/vLTg0rSGfGjmduoeR5JKUk+iWB0vhSDMaadrcbo6+hHxCVZwvvzr7Yq1V9SEwsAQj+D6ffeQXsNWYwyw==","shasum":"26199501b4b638cc5340e7608eff60623e009ec5","tarball":"http://123.232.10.234:8212/nexus/content/groups/npm-public/@pivanov/utils/-/utils-0.0.3.tgz","fileCount":6,"unpackedSize":53989,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQD1QX62GGktx/qDeU5yVQkcskFzxmdic0HIu0x40NsPrQIhAOVtYoRdBId7ZRXc7PYtT6p1AT0k9mT84TUpfmIR2naT"}],"size":14886},"_npmUser":{"name":"anonymous","email":"pafelka@gmail.com"},"directories":{},"maintainers":[{"name":"anonymous","email":"pafelka@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/utils_0.0.3_1766053326344_0.28572497795313767"},"_hasShrinkwrap":false,"_cnpmcore_publish_time":"2025-12-18T10:22:06.503Z","publish_time":1766053326503,"_source_registry_name":"default","contributors":[]}},"dist-tags":{"latest":"0.0.3"},"name":"@pivanov/utils","time":{"created":"2024-11-10T02:21:00.289Z","modified":"2025-12-18T10:22:26.661Z","0.0.1":"2025-01-08T01:29:44.218Z","0.0.2":"2025-02-28T23:00:12.695Z","0.0.3-rc.1":"2025-03-01T21:03:56.244Z","0.0.3":"2025-12-18T10:22:06.503Z"},"readme":"# @pivanov/utils\n\n<p align=\"center\">\n  <i>A comprehensive collection of TypeScript utilities for modern web development</i>\n  <br />\n  <br />\n  <img src=\"https://img.shields.io/npm/v/@pivanov/utils?logo=npm\" alt=\"NPM Version\" />\n  &nbsp;&nbsp;\n  <img src=\"https://img.shields.io/bundlephobia/minzip/@pivanov/utils\" alt=\"Bundle Size\" />\n  &nbsp;&nbsp;\n  <img src=\"https://github.com/pivanov/pivanov-utils/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI Status\" />\n  &nbsp;&nbsp;\n  <img src=\"https://codecov.io/github/pivanov/pivanov-utils/graph/badge.svg?token=EPRKTP7D79\" alt=\"Coverage Status\" />\n</p>\n\n## Features\n\n- 🔒 **Type-Safe** - Full TypeScript support with strict type checking and excellent type inference\n- 🎯 **Tree-Shakeable** - Import only what you need for minimal bundle size\n- ⚡ **Performance Focused** - Optimized implementations with no external dependencies\n- 🧪 **Well Tested** - Comprehensive test coverage for reliability\n- 📦 **Modular** - Organized into focused modules for easy navigation\n- 📝 **Well Documented** - Detailed JSDoc comments and examples\n\n## Installation\n\n```bash\npnpm add @pivanov/utils\n# or\nnpm install @pivanov/utils\n# or\nyarn add @pivanov/utils\n```\n\n## Quick Start\n\n```typescript\nimport { camelCase } from '@pivanov/utils/string';\nimport { pick } from '@pivanov/utils/object';\nimport { isString } from '@pivanov/utils/assertion';\n\ncamelCase('foo-bar'); // 'fooBar'\npick({ name: 'John', age: 30 }, ['name']); // { name: 'John' }\nisString('hello'); // true\n```\n\n## API Reference\n\n### Type Guards & Assertions\n\nRuntime type checking with TypeScript type narrowing.\n\n```typescript\nimport {\n  isString,\n  isNumber,\n  isBoolean,\n  isObject,\n  isFunction,\n  isNull,\n  isUndefined,\n} from '@pivanov/utils/assertion';\n\n// Type guards automatically narrow TypeScript types\nfunction processValue(value: unknown) {\n  if (isString(value)) {\n    return value.toUpperCase(); // TypeScript knows this is a string\n  }\n  if (isNumber(value)) {\n    return value.toFixed(2); // TypeScript knows this is a number\n  }\n}\n\n// Examples\nisString('hello'); // true\nisNumber(42); // true\nisBoolean(true); // true\nisObject({}); // true (plain objects only, not arrays)\nisFunction(() => {}); // true\nisNull(null); // true\nisUndefined(undefined); // true\n```\n\n### Object Utilities\n\nImmutable object manipulation with full type safety.\n\n```typescript\nimport { pick, omit, merge, deepMerge } from '@pivanov/utils/object';\n\n// Pick specific properties\nconst user = { name: 'John', age: 30, email: 'john@example.com' };\npick(user, ['name', 'email']);\n// { name: 'John', email: 'john@example.com' }\n\n// Omit specific properties\nomit(user, ['email']);\n// { name: 'John', age: 30 }\n\n// Shallow merge\nmerge({ a: 1, b: 2 }, { b: 3, c: 4 });\n// { a: 1, b: 3, c: 4 }\n\n// Deep merge with nested structures\ndeepMerge(\n  { user: { name: 'John', settings: { theme: 'dark' } } },\n  { user: { settings: { fontSize: 14 } } }\n);\n// { user: { name: 'John', settings: { theme: 'dark', fontSize: 14 } } }\n```\n\n### String Utilities\n\nString transformation utilities with TypeScript template literal types support.\n\n```typescript\nimport {\n  camelCase,\n  pascalCase,\n  kebabCase,\n  slugify,\n  capitalize,\n  uncapitalize,\n  capitalizeFirstLetter,\n} from '@pivanov/utils/string';\n\n// Case transformations\ncamelCase('foo-bar'); // 'fooBar'\ncamelCase('FOO_BAR'); // 'fooBar'\n\npascalCase('foo-bar'); // 'FooBar'\npascalCase('foo_bar_baz'); // 'FooBarBaz'\n\nkebabCase('fooBar'); // 'foo-bar'\nkebabCase('XMLHttpRequest'); // 'xml-http-request'\n\nslugify('Hello World!'); // 'hello-world'\nslugify('Über Café'); // 'uber-cafe'\n\n// Capitalization with TypeScript support\ncapitalize('hello'); // 'Hello' (type: Capitalize<'hello'>)\nuncapitalize('Hello'); // 'hello' (type: Uncapitalize<'Hello'>)\ncapitalizeFirstLetter('hello world'); // 'Hello world'\n```\n\n**When to use each:**\n\n- `camelCase`: JavaScript/TypeScript variables and properties\n- `pascalCase`: Class names, React components, TypeScript types\n- `kebabCase`: CSS classes, HTML attributes, file names\n- `slugify`: URL slugs (more aggressive than kebabCase)\n\n### Promise Utilities\n\nSimple async utilities for better promise handling.\n\n```typescript\nimport { sleep } from '@pivanov/utils/promise';\n\nasync function example() {\n  console.log('Start');\n  await sleep(1000); // Wait 1 second\n  console.log('Done');\n}\n```\n\n### Deep Clone & Equality\n\nHigh-performance deep cloning and comparison with circular reference handling.\n\n```typescript\nimport { deepClone, isEqual } from '@pivanov/utils/tools';\n\n// Deep clone complex structures\nconst original = {\n  nested: { array: [1, 2, { value: 3 }] },\n  date: new Date(),\n  map: new Map([['key', 'value']]),\n  set: new Set([1, 2, 3]),\n  circular: {} as any,\n};\noriginal.circular = original; // Circular reference\n\nconst cloned = deepClone(original);\n// Fully independent copy with circular references preserved\n\n// Deep equality comparison\nisEqual({ a: [1, 2, 3] }, { a: [1, 2, 3] }); // true\nisEqual(new Date('2024-01-01'), new Date('2024-01-01')); // true\nisEqual([1, 2, [3, 4]], [1, 2, [3, 4]]); // true\nisEqual(new Set([1, 2]), new Set([2, 1])); // false (Sets maintain order)\n```\n\n**Supported types:**\n\n- Primitives (string, number, boolean, null, undefined, symbol, bigint)\n- Arrays (including sparse arrays)\n- Plain objects (with getters/setters)\n- Date, RegExp, Map, Set\n- TypedArrays, ArrayBuffer, Buffer\n- Circular references\n\n### Event Bus\n\nType-safe, lightweight event bus with React hooks support.\n\n```typescript\nimport { busDispatch, busSubscribe, useEventBus } from '@pivanov/utils/tools';\n\n// Define your application events (optional but recommended)\ntype AppEvents = {\n  'user-logged-in': { id: number; name: string };\n  'data-updated': { timestamp: number };\n  'notification': { message: string; type: 'info' | 'error' };\n};\n\n// React hook usage (auto-unsubscribes on unmount)\nfunction UserProfile() {\n  useEventBus<AppEvents>('user-logged-in', (data) => {\n    console.log(`Welcome ${data.name}!`);\n  });\n\n  return <div>Profile</div>;\n}\n\n// Vanilla JavaScript usage\nconst unsubscribe = busSubscribe<AppEvents>('data-updated', (data) => {\n  console.log('Updated at:', data.timestamp);\n});\n\n// Later: cleanup\nunsubscribe();\n\n// Dispatch events anywhere in your app\nbusDispatch<AppEvents>('user-logged-in', { id: 1, name: 'John' });\nbusDispatch<AppEvents>('notification', {\n  message: 'Settings saved',\n  type: 'info',\n});\n```\n\n**Features:**\n\n- Fully type-safe with TypeScript\n- Works across React and vanilla JavaScript\n- Automatic cleanup with React hook\n- Uses hashed topic names to avoid collisions\n- Zero dependencies\n\n### Browser Cache API\n\nType-safe wrapper around the browser Cache API with expiration support.\n\n```typescript\nimport {\n  storageSetItem,\n  storageGetItem,\n  storageRemoveItem,\n  storageExists,\n  storageClear,\n  storageClearByPrefixOrSuffix,\n  storageGetAllKeys,\n  storageCalculateSize,\n} from '@pivanov/utils/tools';\n\nconst CACHE_NAME = 'my-app-cache';\n\n// Store data\nawait storageSetItem(CACHE_NAME, 'user-data', {\n  id: 1,\n  name: 'John',\n  bigNumber: BigInt(9007199254740991), // BigInt support!\n});\n\n// Retrieve data\nconst userData = await storageGetItem<{ id: number; name: string }>(\n  CACHE_NAME,\n  'user-data'\n);\n\n// Check existence\nconst exists = await storageExists(CACHE_NAME, 'user-data');\n\n// Remove specific item\nawait storageRemoveItem(CACHE_NAME, 'user-data');\n\n// Get all keys\nconst keys = await storageGetAllKeys(CACHE_NAME);\n\n// Clear items by prefix\nawait storageClearByPrefixOrSuffix(CACHE_NAME, 'temp-', true);\n\n// Clear items by suffix\nawait storageClearByPrefixOrSuffix(CACHE_NAME, '-cache', false);\n\n// Calculate cache size (in bytes)\nconst totalSize = await storageCalculateSize(CACHE_NAME);\nconst itemSize = await storageCalculateSize(CACHE_NAME, 'user-data');\n\n// Clear all cache\nawait storageClear(CACHE_NAME);\n```\n\n**Features:**\n\n- Automatic JSON serialization/deserialization\n- BigInt support (automatically converted to strings)\n- Type-safe with generics\n- Works with absolute URLs as keys\n- Size calculation utilities\n\n### DOM Utilities\n\nBrowser-safe DOM manipulation helpers.\n\n```typescript\nimport {\n  isBrowser,\n  checkVisibility,\n  setStyleProperties,\n  calculateRenderedTextWidth,\n} from '@pivanov/utils/tools';\n\n// Check if running in browser (SSR-safe)\nif (isBrowser()) {\n  // Browser-only code\n  window.addEventListener('scroll', handleScroll);\n}\n\n// Check element visibility in viewport\nconst element = document.querySelector('.my-element') as HTMLElement;\nif (checkVisibility(element)) {\n  element.classList.add('visible');\n}\n\n// Set CSS custom properties\nsetStyleProperties(element, {\n  '--primary-color': '#3b82f6',\n  '--spacing': '1rem',\n  '--border-radius': '8px',\n});\n\n// Calculate text width for dynamic layouts\nconst width = calculateRenderedTextWidth('Hello World', 16);\nconst widthUppercase = calculateRenderedTextWidth('Hello World', 16, true);\nconst widthCustomFont = calculateRenderedTextWidth(\n  'Hello World',\n  16,\n  false,\n  'Arial'\n);\n```\n\n## Tree Shaking\n\nImport only what you need to minimize bundle size:\n\n```typescript\n// ✅ Good: Import specific utilities\nimport { camelCase } from '@pivanov/utils/string';\nimport { deepClone } from '@pivanov/utils/tools';\n\n// ❌ Avoid: Importing everything\nimport * as utils from '@pivanov/utils';\n```\n\n## TypeScript Support\n\nAll utilities provide excellent type inference:\n\n```typescript\nimport { pick } from '@pivanov/utils/object';\nimport { capitalize } from '@pivanov/utils/string';\n\n// TypeScript infers exact types\nconst user = { name: 'John', age: 30, email: 'john@example.com' } as const;\nconst picked = pick(user, ['name', 'email']);\n// Type: { name: \"John\"; email: \"john@example.com\" }\n\nconst str = 'hello' as const;\nconst capitalized = capitalize(str);\n// Type: \"Hello\"\n```\n\n## Module Overview\n\n```text\n@pivanov/utils\n├── /assertion    - Type guards (isString, isNumber, etc.)\n├── /object       - Object utilities (pick, omit, merge, deepMerge)\n├── /promise      - Async utilities (sleep)\n├── /string       - String utilities (camelCase, kebabCase, etc.)\n└── /tools        - Various tools\n    ├── deepClone\n    ├── isEqual\n    ├── DOM utilities (isBrowser, checkVisibility, etc.)\n    ├── eventBus (busDispatch, busSubscribe, useEventBus)\n    └── Cache API (storageSetItem, storageGetItem, etc.)\n```\n\n## Browser Compatibility\n\n- Modern browsers with ES2015+ support\n- Cache API requires browser support (Chrome 40+, Firefox 41+, Safari 11.1+)\n- SSR-safe with browser environment detection\n\n## License\n\nMIT © [Pavel Ivanov](https://github.com/pivanov)","users":{}}