{"id":12776,"library":"thingies","title":"Thingies: TypeScript Utility Library","description":"Thingies is a versatile TypeScript utility library providing a collection of small, focused, and performant helpers for common programming tasks. It covers areas such as caching (LruCache, LruMap, LruTtlMap), promise management (Defer, of, promiseMap, until, tick, timeout), string manipulation (base64, hash, randomStr, normalizeEmail, dataUri), and concurrency control (Locks, codeMutex, concurrency, FanOut). The current stable version is 2.6.0, with frequent minor and patch releases introducing new features and performance improvements. Its key differentiator lies in its breadth of specific, often low-level, utilities, all designed with a TypeScript-first approach, offering strong typing and a comprehensive API for various Node.js and browser environments.","status":"active","version":"2.6.0","language":"javascript","source_language":"en","source_url":"https://github.com/streamich/thingies","tags":["javascript","typescript"],"install":[{"cmd":"npm install thingies","lang":"bash","label":"npm"},{"cmd":"yarn add thingies","lang":"bash","label":"yarn"},{"cmd":"pnpm add thingies","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Runtime helper library for TypeScript, often required by TypeScript builds for features like decorators and async/await.","package":"tslib","optional":false}],"imports":[{"note":"Since v2.0.0, the library targets ES2020 modules, primarily designed for ESM environments. CommonJS `require()` will not work directly for named exports.","wrong":"const { LruCache } = require('thingies');","symbol":"LruCache","correct":"import { LruCache } from 'thingies';"},{"note":"All public utilities are exposed as named exports. There are no default exports in this library.","wrong":"import of from 'thingies';","symbol":"of","correct":"import { of } from 'thingies';"},{"note":"Useful for synchronizing asynchronous operations to prevent race conditions.","symbol":"codeMutex","correct":"import { codeMutex } from 'thingies';"},{"note":"While `import * as thingies` works, direct named imports are preferred for tree-shaking and clarity.","wrong":"import * as thingies from 'thingies'; const queue = new thingies.TimedQueue();","symbol":"TimedQueue","correct":"import { TimedQueue } from 'thingies';"}],"quickstart":{"code":"import { LruCache, of, codeMutex, TimedQueue } from 'thingies';\n\n// 1. Using LruCache for efficient data storage\nconst userCache = new LruCache<string, { id: string; name: string }>({\n  limit: 100, // Cache up to 100 users\n  ttl: 60 * 1000, // Items expire after 60 seconds\n});\nuserCache.set('user-1', { id: 'user-1', name: 'Alice' });\nconsole.log('Cached user:', userCache.get('user-1'));\n\n// 2. Safely handling Promise results with `of`\nasync function fetchData(shouldSucceed: boolean) {\n  const [data, error] = await of(new Promise<string>((resolve, reject) => {\n    setTimeout(() => {\n      if (shouldSucceed) {\n        resolve('Data fetched successfully');\n      } else {\n        reject(new Error('Failed to fetch data'));\n      }\n    }, 100);\n  }));\n\n  if (error) {\n    console.error('Error fetching data:', error.message);\n  } else {\n    console.log('Data:', data);\n  }\n}\n\nfetchData(true); // Should log data\nfetchData(false); // Should log error\n\n// 3. Using codeMutex for synchronized execution\nconst mutex = codeMutex();\nlet sharedResource = 0;\n\nasync function incrementResource(id: number) {\n  await mutex(async () => {\n    const current = sharedResource;\n    await new Promise(resolve => setTimeout(resolve, Math.random() * 50)); // Simulate work\n    sharedResource = current + 1;\n    console.log(`Worker ${id}: sharedResource is now ${sharedResource}`);\n  });\n}\n\nPromise.all([incrementResource(1), incrementResource(2), incrementResource(3)]);\n\n// 4. Batching operations with TimedQueue\nconst eventQueue = new TimedQueue<string>({\n  limit: 3, // Flush after 3 items\n  timeout: 100, // Or flush after 100ms\n  flush: async (items) => {\n    console.log(`Flushing ${items.length} events: ${items.join(', ')}`);\n    // In a real app, this would send to an external service or database\n  },\n});\n\neventQueue.push('event-A');\neventQueue.push('event-B');\neventQueue.push('event-C'); // This push should trigger a flush immediately\n\neventQueue.push('event-D');\neventQueue.push('event-E');\n// Wait for timeout to flush remaining items\nsetTimeout(() => eventQueue.flush(), 200);\n","lang":"typescript","description":"This quickstart demonstrates the usage of `LruCache` for in-memory caching, `of` for robust promise error handling, `codeMutex` for synchronizing concurrent operations, and `TimedQueue` for batching events based on count or time thresholds."},"warnings":[{"fix":"Ensure your project is configured for ES modules, or use a bundler/transpiler like Webpack or Rollup to convert the library to CommonJS if strictly necessary. For Node.js, ensure your `package.json` has `\"type\": \"module\"` or use `.mjs` files.","message":"Version 2.0.0 introduced a breaking change by targeting `es2020` modules exclusively, meaning CommonJS environments will require additional transpilation or specific Node.js `--experimental-modules` flags for direct usage.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Explicitly install `tslib` in your project with a version compatible with your TypeScript setup (e.g., `npm install tslib@^2`).","message":"The library declares `tslib` as a peer dependency. While npm/yarn often resolve peer dependencies automatically, an incompatible or missing `tslib` version can lead to runtime errors, especially with TypeScript features like decorators or async/await.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"When using `codeMutex` or `@mutex`, ensure you are aware of the scope of synchronization. If global process-wide or distributed locking is needed, consider external solutions like Redis or a database-based lock.","message":"Utilities like `codeMutex` and the `@mutex` decorator create mutexes that are scoped to the specific instance or function call. They do not provide global synchronization across different instances or processes.","severity":"gotcha","affected_versions":">=1.20.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Change `const { Symbol } = require('thingies');` to `import { Symbol } from 'thingies';` and ensure your environment supports ES modules (e.g., `\"type\": \"module\"` in `package.json` for Node.js).","cause":"Attempting to use `require()` to import `thingies` after version 2.0.0, which switched to ES modules.","error":"ReferenceError: require is not defined in ES module scope"},{"fix":"Verify that `tslib` is installed in your project (`npm list tslib`) and that its version is compatible with your TypeScript compiler and runtime environment. Try `npm install tslib@^2`.","cause":"This error often indicates a problem with `tslib` not being found or an incompatible version being used, especially when TypeScript features like class extension or decorators are involved.","error":"TypeError: Class extends value undefined is not a constructor or null"},{"fix":"Ensure your build system (Webpack, Rollup, TypeScript compiler) is correctly configured for ES module output and consumption, especially when targeting older environments or using CommonJS. Prefer direct `import { LruCache } from 'thingies';` and verify `tsconfig.json` module settings.","cause":"This typically occurs in transpiled JavaScript when an ES module's named export (like `LruCache`) is incorrectly handled during CommonJS interop, often due to mismatched module systems or incorrect bundler configuration.","error":"TypeError: (0 , thingies_1.LruCache) is not a constructor"}],"ecosystem":"npm"}