{"_id":"tokentally","_rev":"2-d008ffe55fb5fb831d3e8e06ab20ebdc","name":"tokentally","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"tokentally","version":"0.1.0","license":"MIT","_id":"tokentally@0.1.0","maintainers":[{"name":"steipete","email":"steipete@gmail.com"}],"homepage":"https://github.com/steipete/tokentally#readme","bugs":{"url":"https://github.com/steipete/tokentally/issues"},"dist":{"shasum":"489825c47503f6fd579e0fcf9e9eeb2da2dbd8aa","tarball":"https://registry.npmjs.org/tokentally/-/tokentally-0.1.0.tgz","fileCount":31,"integrity":"sha512-G2gJiIFz543bcyKHruXzV6D56RqIEmihht8IFGN3SvgYV4OJs7ZfaJqjyueD5sFjweWLHWMBh7tPhGIXlS0aUA==","signatures":[{"sig":"MEQCIDCwE+mioG/zsCKiI7Jeep/1c3Yg09GlJftHUUtGodn2AiBYle3oOadhxaqZ0+81PJ8xw8+mkX1Q9QGp/lyLRC5EJg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":33146},"type":"module","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./node":{"types":"./dist/node/index.d.ts","import":"./dist/node/index.js"}},"gitHead":"99865e5c16f5340c9589a2c5d85c3ea47dbcec82","scripts":{"lint":"biome check src tests package.json tsconfig.json tsconfig.build.json vitest.config.ts README.md","test":"vitest run","build":"tsc -p tsconfig.build.json","check":"pnpm lint && pnpm lint:oxlint:typeaware && pnpm typecheck && pnpm test:coverage","format":"biome format --write src tests package.json tsconfig.json tsconfig.build.json vitest.config.ts README.md","prepare":"pnpm build","lint:fix":"biome check --write src tests package.json tsconfig.json tsconfig.build.json vitest.config.ts README.md","typecheck":"tsc -p tsconfig.json --noEmit","lint:types":"pnpm lint:oxlint:typeaware && pnpm typecheck","lint:oxlint":"pnpm exec -- oxlint --deny-warnings --config .oxlintrc.json src tests","test:coverage":"vitest run --coverage","lint:oxlint:typeaware":"pnpm exec -- oxlint --deny-warnings --type-aware --tsconfig tsconfig.json --config .oxlintrc.json src tests"},"_npmUser":{"name":"steipete","email":"steipete@gmail.com"},"repository":{"url":"git+https://github.com/steipete/tokentally.git","type":"git"},"_npmVersion":"11.6.2","description":"Token usage in, dollar totals out.","directories":{},"_nodeVersion":"25.2.1","_hasShrinkwrap":false,"packageManager":"pnpm@10.25.0","devDependencies":{"oxlint":"^1.34.0","vitest":"^4.0.16","typescript":"^5.9.3","@types/node":"^25.0.3","@biomejs/biome":"^2.3.10","oxlint-tsgolint":"^0.9.2","@vitest/coverage-v8":"^4.0.16"},"_npmOperationalInternal":{"tmp":"tmp/tokentally_0.1.0_1766149663482_0.6765784511009489","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"tokentally","version":"0.1.1","description":"Token usage in, dollar totals out.","type":"module","license":"MIT","repository":{"type":"git","url":"git+https://github.com/steipete/tokentally.git"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./node":{"types":"./dist/node/index.d.ts","import":"./dist/node/index.js"}},"engines":{"node":">=20"},"packageManager":"pnpm@10.26.1","scripts":{"build":"tsc -p tsconfig.build.json","prepare":"pnpm build","typecheck":"tsc -p tsconfig.json --noEmit","format":"biome format --write src tests package.json tsconfig.json tsconfig.build.json vitest.config.ts README.md","lint":"biome check src tests package.json tsconfig.json tsconfig.build.json vitest.config.ts README.md","lint:oxlint":"pnpm exec -- oxlint --deny-warnings --config .oxlintrc.json src tests","lint:oxlint:typeaware":"pnpm exec -- oxlint --deny-warnings --type-aware --tsconfig tsconfig.json --config .oxlintrc.json src tests","lint:types":"pnpm lint:oxlint:typeaware && pnpm typecheck","lint:fix":"biome check --write src tests package.json tsconfig.json tsconfig.build.json vitest.config.ts README.md","test":"vitest run","test:coverage":"vitest run --coverage","check":"pnpm lint && pnpm lint:oxlint:typeaware && pnpm typecheck && pnpm test:coverage"},"devDependencies":{"@biomejs/biome":"^2.3.10","@types/node":"^25.0.3","@vitest/coverage-v8":"^4.0.16","oxlint":"^1.34.0","oxlint-tsgolint":"^0.9.2","typescript":"^5.9.3","vitest":"^4.0.16"},"gitHead":"6a44aeaa5b5cfd2e74a8b02148ccb6a0210b31ae","_id":"tokentally@0.1.1","bugs":{"url":"https://github.com/steipete/tokentally/issues"},"homepage":"https://github.com/steipete/tokentally#readme","_nodeVersion":"25.2.1","_npmVersion":"11.6.2","dist":{"integrity":"sha512-z1e4nTJe8/PWSoWCQmPMX5LoOWDVfj9IQ+rTChQcXrxYNhDxxjqloYSmOjnClyRdnTrawS+YNDfrk7bNuzsVKQ==","shasum":"aa3377050b49cf993a80a12b75c7bccd3118a5d8","tarball":"https://registry.npmjs.org/tokentally/-/tokentally-0.1.1.tgz","fileCount":31,"unpackedSize":33279,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIC/6HMhCgFruuKkmX92L0423c8mQJ3gV7IbcwYNabfTiAiBiwE5PXwxwlqwdQcVsW5xbBU831nNtnOQaLfWWtdafDQ=="}]},"_npmUser":{"name":"steipete","email":"steipete@gmail.com"},"directories":{},"maintainers":[{"name":"steipete","email":"steipete@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/tokentally_0.1.1_1766516367757_0.7207795168989173"},"_hasShrinkwrap":false}},"time":{"created":"2025-12-19T13:07:43.482Z","modified":"2025-12-23T18:59:28.064Z","0.1.0":"2025-12-19T13:07:43.622Z","0.1.1":"2025-12-23T18:59:27.899Z"},"bugs":{"url":"https://github.com/steipete/tokentally/issues"},"license":"MIT","homepage":"https://github.com/steipete/tokentally#readme","repository":{"type":"git","url":"git+https://github.com/steipete/tokentally.git"},"description":"Token usage in, dollar totals out.","maintainers":[{"name":"steipete","email":"steipete@gmail.com"}],"readme":"# 🧮 tokentally — One tiny lib for LLM token + cost math\n\nToken usage in, dollar totals out.\n\nSmall TypeScript library for:\n- Normalizing token usage across providers\n- Resolving per-token pricing (static maps, LiteLLM catalog, OpenRouter catalog)\n- Estimating and aggregating USD cost\n\n## Install\n\n```bash\npnpm add tokentally\n```\n\n## Core usage (browser-safe)\n\n```ts\nimport { estimateUsdCost, normalizeTokenUsage, pricingFromUsdPerMillion } from 'tokentally';\n\nconst usage = normalizeTokenUsage({ prompt_tokens: 1000, completion_tokens: 250 });\nconst pricing = pricingFromUsdPerMillion({ inputUsdPerMillion: 1.75, outputUsdPerMillion: 14 });\n\nconst cost = estimateUsdCost({ usage, pricing });\n// { inputUsd: ..., outputUsd: ..., totalUsd: ... }\n```\n\n## Node helpers (catalog sources)\n\n### LiteLLM pricing + limits\n\n```ts\nimport { loadLiteLlmCatalog, resolveLiteLlmPricing, resolveLiteLlmMaxOutputTokens } from 'tokentally/node';\n\nconst { catalog } = await loadLiteLlmCatalog({ env: process.env, fetchImpl: fetch });\nconst pricing = catalog ? resolveLiteLlmPricing(catalog, 'openai/gpt-5.2') : null;\nconst maxOut = catalog ? resolveLiteLlmMaxOutputTokens(catalog, 'openai/gpt-5.2') : null;\n```\n\n### OpenRouter pricing (optional)\n\n```ts\nimport { fetchOpenRouterPricingMap, resolvePricingFromMap } from 'tokentally/node';\n\nconst map = await fetchOpenRouterPricingMap({ apiKey: process.env.OPENROUTER_API_KEY!, fetchImpl: fetch });\nconst pricing = resolvePricingFromMap(map, 'openai/gpt-5.2');\n```\n\n## API\n\n- `normalizeTokenUsage(raw)` → `{ inputTokens, outputTokens, reasoningTokens, totalTokens } | null`\n- `pricingFromUsdPerMillion({ inputUsdPerMillion, outputUsdPerMillion })`\n- `estimateUsdCost({ usage, pricing })`\n- `tallyCosts(calls)` → totals + per-model breakdown\n\n## Non-goals\n\n- Perfect accounting. This is a **best-effort estimate** based on the pricing source you provide.\n- Provider-specific invoice reconciliation.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}