{"_id":"@0xsarwagya/ghost","name":"@0xsarwagya/ghost","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@0xsarwagya/ghost","version":"0.1.0","description":"Persistent cryptographic identity for web apps without accounts.","type":"module","license":"MIT","repository":{"type":"git","url":"git+https://github.com/0xsarwagya/ghost.git"},"homepage":"https://oss.sarwagya.wtf/ghost","keywords":["identity","webcrypto","ed25519","indexeddb","challenge-response","continuity","typescript"],"sideEffects":false,"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.js"}},"publishConfig":{"access":"public"},"devDependencies":{"@playwright/test":"1.61.1","@types/node":"^22.15.3","tsup":"^8.3.5","typescript":"5.9.2","vite":"^5.4.11","vitest":"^3.0.0"},"scripts":{"build":"tsup && tsc -p tsconfig.build.json","check-types":"tsc --noEmit","test":"vitest run","test:unit":"vitest run","test:e2e":"playwright test","test:e2e:identity":"playwright test --project=chromium-identity --project=firefox-identity --project=webkit-identity","test:e2e:protocol":"playwright test --project=chromium-protocol --project=firefox-protocol --project=webkit-protocol","test:e2e:unsupported":"playwright test --project=chromium-unsupported","test:e2e:install":"playwright install --with-deps"},"_id":"@0xsarwagya/ghost@0.1.0","bugs":{"url":"https://github.com/0xsarwagya/ghost/issues"},"_integrity":"sha512-K3fdSg8eNM22DYLyGlf3G+pZZ+4tHeISlBvysvYiUG+1m4W2u5sGnei93me3naUROu6C7gdx9eBIqBfAjPrvFQ==","_resolved":"/tmp/0e02b8f9c530608186a77cfb4d9e7f5d/0xsarwagya-ghost-0.1.0.tgz","_from":"file:0xsarwagya-ghost-0.1.0.tgz","_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-K3fdSg8eNM22DYLyGlf3G+pZZ+4tHeISlBvysvYiUG+1m4W2u5sGnei93me3naUROu6C7gdx9eBIqBfAjPrvFQ==","shasum":"ec6d88ebe2e121d9f6074f225f54e2948e144716","tarball":"https://registry.npmjs.org/@0xsarwagya/ghost/-/ghost-0.1.0.tgz","fileCount":37,"unpackedSize":129921,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCJW24FndcV7bsPHZ+SE4Zm0Dod3bi0mU/5QwUY9FTKIgIgcOFGTHYe/uXSEXxovngbSsbOTuxA1ugI6nl+oo44RIY="}]},"_npmUser":{"name":"0xsarwagya","email":"sarwagyasingh69@gmail.com"},"directories":{},"maintainers":[{"name":"0xsarwagya","email":"sarwagyasingh69@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ghost_0.1.0_1783285502418_0.790127769843832"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-05T21:05:02.284Z","0.1.0":"2026-07-05T21:05:02.549Z","modified":"2026-07-05T21:05:02.735Z"},"maintainers":[{"name":"0xsarwagya","email":"sarwagyasingh69@gmail.com"}],"description":"Persistent cryptographic identity for web apps without accounts.","homepage":"https://oss.sarwagya.wtf/ghost","keywords":["identity","webcrypto","ed25519","indexeddb","challenge-response","continuity","typescript"],"repository":{"type":"git","url":"git+https://github.com/0xsarwagya/ghost.git"},"bugs":{"url":"https://github.com/0xsarwagya/ghost/issues"},"license":"MIT","readme":"# Ghost\n\nPersistent cryptographic identity for web apps without accounts.\n\nA TypeScript library that gives a browser a keypair instead of giving your\napplication a user database. The private key never leaves the browser. The\nbrowser gets a stable Ghost ID, and the active public key becomes a\ncredential for that Ghost. Your server verifies signatures.\n\nGhost authenticates a key, not a person.\n\n## Install\n\n```sh\npnpm add @0xsarwagya/ghost\n```\n\n## First identity\n\nIn the browser:\n\n```ts\nimport { createGhost } from \"@0xsarwagya/ghost\";\n\nconst ghost = await createGhost();\nconsole.log(ghost.id); // ghost_1_crhgcniramqtgfpib5uiaautocwdigbt\nconsole.log(ghost.credentialId); // cred_1_…\n\n// Later, prove possession of a server-issued challenge:\nconst proof = await ghost.sign(challenge);\n```\n\nOn your server:\n\n```ts\nimport {\n  createChallenge,\n  InMemoryChallengeStore,\n  InMemoryGhostCredentialStore,\n  verifyGhostProof,\n} from \"@0xsarwagya/ghost/server\";\n\nconst store = new InMemoryChallengeStore();\nconst credentials = new InMemoryGhostCredentialStore();\ncredentials.register(ghost); // persist this in your own database in production\n\n// 1. Issue a one-time challenge.\nconst challenge = createChallenge({ audience: \"https://app.example\", action: \"login\" });\n\n// 2. Verify the browser's proof.\nconst result = await verifyGhostProof(proof, {\n  expectedAudience: \"https://app.example\",\n  challengeStore: store,\n  credentialStore: credentials,\n});\n\nif (result.ok) {\n  console.log(\"same ghost as before:\", result.ghostId);\n}\n```\n\nNo email. No password. No OAuth. No user table.\n\n## Optional recovery\n\nGhost is usable without recovery. When a Ghost owns durable value, ask the\nuser whether to make it recoverable:\n\n```ts\nconst { recoverySecret, recoveryRecord } = await ghost.enableRecovery();\n// Show recoverySecret once. Store recoveryRecord with your app's Ghost row.\n```\n\nIf the browser profile is lost, the user supplies the secret and your app\nsupplies the recovery record:\n\n```ts\nimport { recoverGhost } from \"@0xsarwagya/ghost\";\n\nconst ghost = await recoverGhost({ recoverySecret, recoveryRecord });\n// Same ghost.id, fresh non-extractable credential.\n```\n\n## Status\n\nExperimental. The protocol is versioned and the v1 wire format is pinned by\ntest vectors, but the API may still change before 1.0. Read the\n[security model](https://oss.sarwagya.wtf/ghost/docs/security) before\nrelying on it — especially what Ghost does not prove.\n\n## Documentation\n\nhttps://oss.sarwagya.wtf/ghost/docs\n\n## License\n\n[MIT](./LICENSE)\n","readmeFilename":"README.md","_rev":"1-58ae7844ebee5649955cde1c7fb0788f"}