{"_id":"just-secrets","_rev":"2-f3938d20b2514348807d11c869832eb2","name":"just-secrets","dist-tags":{"latest":"0.0.2"},"versions":{"0.0.1":{"name":"just-secrets","version":"0.0.1","keywords":["secrets","keychain","keyring","credentials","keytar","nodejs"],"license":"MIT","_id":"just-secrets@0.0.1","maintainers":[{"name":"andrewbarba","email":"barba@hey.com"}],"homepage":"https://github.com/vercel-labs/just-secrets#readme","bugs":{"url":"https://github.com/vercel-labs/just-secrets/issues"},"dist":{"shasum":"f127615c0d43edca061d31dbbc97281cf822da98","tarball":"https://registry.npmjs.org/just-secrets/-/just-secrets-0.0.1.tgz","fileCount":13,"integrity":"sha512-0yBVR9k5Jkt6eOkPjsTAMNmhT9WcMEdsRW839hgKOBNY5krgDoPaeAtTfvxTXOLHP61d5K4Fl53cz5mF1vCXoA==","signatures":[{"sig":"MEUCIDx6PNYSTgUjjHV851Ma4JTBBkeDLlIDptNHWIBA6w/bAiEAvOBlNMw5g83BAHzDkMm3yY0nySd1rd58p3WNPDFCa5k=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":36563},"main":"./src/index.js","type":"module","types":"./src/index.d.ts","engines":{"node":">=24"},"exports":{".":{"types":"./src/index.d.ts","default":"./src/index.js"},"./package.json":"./package.json"},"gitHead":"c4e7a19c2ef0b24d5442d5883616bc4af3a56875","scripts":{"test":"node --test test/*.test.js","prepack":"npm test","test:package":"node --test test/package.integration.js","test:coverage":"node --test --experimental-test-coverage test/*.test.js","test:integration":"node --test --test-concurrency=1 test/native.integration.js"},"_npmUser":{"name":"andrewbarba","email":"barba@hey.com"},"repository":{"url":"git+https://github.com/vercel-labs/just-secrets.git","type":"git"},"_npmVersion":"11.19.0","description":"Native OS secret storage for Node.js. Zero dependencies.","directories":{},"sideEffects":false,"_nodeVersion":"24.20.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/just-secrets_0.0.1_1788880230454_0.18055159472883875","host":"s3://npm-registry-packages-npm-production"}},"0.0.2":{"name":"just-secrets","version":"0.0.2","description":"Native OS secret storage for Node.js. Zero dependencies.","type":"module","main":"./src/index.js","types":"./src/index.d.ts","exports":{".":{"types":"./src/index.d.ts","default":"./src/index.js"},"./package.json":"./package.json"},"sideEffects":false,"engines":{"node":">=22"},"scripts":{"test":"node --test test/*.test.js","test:integration":"node --test --test-concurrency=1 test/native.integration.js","test:package":"node --test test/package.integration.js","test:coverage":"node --test --experimental-test-coverage test/*.test.js","prepack":"npm test"},"repository":{"type":"git","url":"git+https://github.com/vercel-labs/just-secrets.git"},"homepage":"https://github.com/vercel-labs/just-secrets#readme","bugs":{"url":"https://github.com/vercel-labs/just-secrets/issues"},"license":"MIT","keywords":["secrets","keychain","keyring","credentials","keytar","nodejs"],"publishConfig":{"access":"public"},"gitHead":"31719436bccf5ecfee621391e94c771b7484c0cf","_id":"just-secrets@0.0.2","_nodeVersion":"24.20.0","_npmVersion":"11.19.0","dist":{"integrity":"sha512-8Zh2rbEtvRQN6OJnHNO39g5E7MR80GpSxfezrAhre3wzhgCnmdK1oismE1qMW3S+aaIQ3REIoramtIqHVTDavA==","shasum":"427f4883e5cadf7b915bece9a4a9e0f1948ad4a4","tarball":"https://registry.npmjs.org/just-secrets/-/just-secrets-0.0.2.tgz","fileCount":13,"unpackedSize":36723,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIChhAiZfQtmJ7Ne3gtv0j5R7QhqbvNPBZO3dzDC9bo6fAiAG7cIuXMe0O3BGobHNf+J0XQbEk7anuQdtb7o6MgZI/A=="}]},"_npmUser":{"name":"andrewbarba","email":"barba@hey.com"},"directories":{},"maintainers":[{"name":"andrewbarba","email":"barba@hey.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/just-secrets_0.0.2_1788882024218_0.3496766169838841"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-08T15:10:30.298Z","modified":"2026-09-08T15:40:24.514Z","0.0.1":"2026-09-08T15:10:30.612Z","0.0.2":"2026-09-08T15:40:24.341Z"},"bugs":{"url":"https://github.com/vercel-labs/just-secrets/issues"},"license":"MIT","homepage":"https://github.com/vercel-labs/just-secrets#readme","keywords":["secrets","keychain","keyring","credentials","keytar","nodejs"],"repository":{"type":"git","url":"git+https://github.com/vercel-labs/just-secrets.git"},"description":"Native OS secret storage for Node.js. Zero dependencies.","maintainers":[{"name":"andrewbarba","email":"barba@hey.com"}],"readme":"# just-secrets\n\nNative OS secret storage for Node.js 22+. Zero dependencies, native addons, or install scripts.\n\n```sh\nnpm install just-secrets\n```\n\n```js\nimport { secrets } from 'just-secrets';\n\nawait secrets.set({\n  service: 'com.example.cli',\n  name: 'api-token',\n  value: 'your-api-token',\n});\n\nconst token = await secrets.get({ service: 'com.example.cli', name: 'api-token' });\nconst deleted = await secrets.delete({ service: 'com.example.cli', name: 'api-token' });\n```\n\nNode 22.12+ also supports `const { secrets } = require('just-secrets')` without flags. On earlier Node 22 releases, use ESM `import` or asynchronous `import()` from CommonJS. TypeScript declarations ship with the package. There is no build step.\n\n## API\n\nEvery operation is asynchronous and returns a Promise. Object and positional forms are interchangeable:\n\n```js\nawait secrets.set({ service, name, value }); // Promise<void>\nawait secrets.set(service, name, value);\n\nawait secrets.get({ service, name });        // Promise<string | null>\nawait secrets.get(service, name);\n\nawait secrets.delete({ service, name });     // Promise<boolean>\nawait secrets.delete(service, name);\n```\n\n- `set` creates a credential or replaces its value.\n- `get` returns `null` when the credential is absent.\n- `delete` returns `true` on deletion, or `false` when absent.\n- Unavailable stores, denied access, unexpected responses, and timeouts reject. They are not treated as missing credentials.\n- Empty values, whitespace, newlines, NUL, and Unicode are preserved exactly. Service and name are case-sensitive and are not normalized.\n- Service and name must be nonempty strings, each at most 256 UTF-8 bytes. Values must be strings of at most 2,560 UTF-8 bytes. Unpaired Unicode surrogates are rejected. Invalid arguments reject with `TypeError` or `RangeError`.\n\nmacOS also has a 4,096-byte interactive-command buffer. A combination of long identifiers and a maximum-size value can exceed it; just-secrets rejects before starting the operation. Smaller identifiers or values are then required.\n\njust-secrets uses its own namespaced identifiers and storage representation; it does not discover or migrate credentials written by other libraries.\n\n## Platform requirements\n\n| OS | Native store | Bridge | Requirements |\n| --- | --- | --- | --- |\n| macOS | Login Keychain | `/usr/bin/security` | An accessible login keychain; macOS may prompt for access or unlock |\n| Linux | Secret Service, such as GNOME Keyring or compatible KWallet | `/usr/bin/secret-tool` | libsecret tools, a session D-Bus, and a running Secret Service provider |\n| Windows | Credential Manager | Windows PowerShell and the Windows Credentials API | Windows PowerShell 5.1 with `Add-Type` permitted and a credential-capable user logon session |\n\nThe JavaScript package contains no native binaries. Windows uses a bundled PowerShell script with an embedded C# P/Invoke bridge, compiled by the OS's `Add-Type`. This requires no downloaded module or developer toolchain, but is not JavaScript-only execution. Restricted PowerShell environments may block it; just-secrets does not bypass those restrictions.\n\nOn Debian/Ubuntu, install Linux prerequisites with:\n\n```sh\nsudo apt-get install libsecret-tools gnome-keyring\n```\n\nInstalling the tools is not enough: a session bus and unlocked credential service must also be available. Headless containers, SSH sessions, and WSL often lack these. WSL uses the Linux backend; just-secrets does not automatically forward secrets to Windows. Unsupported operating systems reject without starting a subprocess.\n\nWindows credentials use `CRED_PERSIST_ENTERPRISE`: credentials persist for the user and may roam when supported by the account configuration.\n\n## Security model\n\nSecrets are encrypted at rest by the OS credential store. just-secrets never writes a plaintext vault, generates a file-encryption key, or falls back to weaker storage. It invokes known OS executables without a shell and sends secret input over pipes, not command-line arguments or environment variables. Internal encodings preserve exact strings; they are not encryption.\n\nEach subprocess has a 60-second timeout and a combined 1 MiB output limit. Child-process errors and output are not attached to thrown errors. Values are not cached between calls or logged by the library.\n\nThis does not isolate secrets from malicious code running as the same OS user. On macOS, Keychain access is associated with `/usr/bin/security`, not a unique just-secrets application identity. Other programs invoking that tool can access items permitted to it. See [GitHub CLI's discussion of this tradeoff](https://github.com/cli/cli/blob/trunk/docs/macos-keyring.md). Windows and Linux access boundaries also depend on the user's session and store configuration.\n\nJavaScript and PowerShell strings cannot be reliably zeroized. Secrets exist in process memory while in use and may be exposed through debuggers, memory dumps, or compromised processes. Node copies some data internally; clearing individual buffers is not a complete memory-erasure guarantee. See [SECURITY.md](SECURITY.md).\n\nLinux explicitly checks and unlocks matching items before reading or deleting, rather than mistaking a locked item for absence. These multi-command operations are not transactional. Concurrent changes can cause rejection, and a timed-out or failed mutation may already have taken effect. Do not automatically retry mutations without checking the result.\n\n## Handling unavailable storage\n\nStorage failures never silently fall back to files. Applications can offer session-only credentials, ask the user to unlock their keychain, or explicitly accept an environment variable for CI:\n\n```js\nconst token = process.env.MY_API_TOKEN ?? await secrets.get('com.example.cli', 'api-token');\n```\n\nDo not log secret values or arbitrary upstream error objects. just-secrets's operational errors carry a `code`:\n\n| Code | Meaning |\n| --- | --- |\n| `ERR_SECRETS_UNSUPPORTED` | Unsupported operating system |\n| `ERR_SECRETS_UNAVAILABLE` | Required executable or credential session unavailable |\n| `ERR_SECRETS_ACCESS_DENIED` | Access denied where the platform exposes a distinct status |\n| `ERR_SECRETS_TIMEOUT` | Credential operation exceeded its time limit |\n| `ERR_SECRETS_OUTPUT_LIMIT` | Unexpectedly large credential-tool output |\n| `ERR_SECRETS_STORE` | Other store failure or unexpected response |\n\nNot every backend can distinguish locked, denied, and unavailable states; these can surface as `ERR_SECRETS_STORE`. Callers should provide an unlock/setup recovery path rather than interpreting this code as absence.\n\n## Development\n\nUse the latest patch release of Node.js 22, 24, or 26 and npm for development. There are no runtime or development npm dependencies.\n\n```sh\nnpm ci\nnpm test                  # node:test; injected adapters and real subprocess transport tests\nnpm run test:coverage     # Node's built-in coverage\nnpm run test:integration  # real native credential-store lifecycle\nnpm run test:package      # pack, offline install, ESM/CommonJS import checks\n```\n\nIntegration tests use a disposable keychain on macOS and UUID-namespaced credentials on Linux/Windows, with cleanup. They cover create, read, overwrite, delete, missing entries, Unicode, empty values, case-sensitive identity, and persistence across Node processes. They do not prove persistence across reboot.\n\nThe GitHub Actions matrix runs Node 22, 24, and 26 on Linux x64/ARM64, macOS Intel/Apple Silicon, and Windows x64 (15 combinations). Linux CI starts an isolated GNOME Keyring session. Native Windows tests require the Windows runner; macOS and Linux mocks alone cannot validate the PowerShell bridge.\n\n## Publishing\n\nRepository: [vercel-labs/just-secrets](https://github.com/vercel-labs/just-secrets).\n\nAfter the full CI matrix passes, review the version and package contents, then publish using an npm account authorized for `just-secrets`:\n\n```sh\nnpm run test:package\nnpm pack --dry-run\nnpm publish --access public\n```\n\nPublishing credentials and npm package ownership must be configured separately. This repository does not automatically publish on push.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}