{"id":32501049,"url":"https://github.com/smikhalevski/whoopie","last_synced_at":"2026-07-02T18:33:06.395Z","repository":{"id":320753824,"uuid":"1083232748","full_name":"smikhalevski/whoopie","owner":"smikhalevski","description":"🍪 Super-fast cookie parser and storage that works on both server and client.","archived":false,"fork":false,"pushed_at":"2025-12-03T09:14:47.000Z","size":486,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-05-13T23:15:23.676Z","etag":null,"topics":["client","cookie","json","server"],"latest_commit_sha":null,"homepage":"https://smikhalevski.github.io/whoopie/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/smikhalevski.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-25T15:55:33.000Z","updated_at":"2025-12-03T09:14:51.000Z","dependencies_parsed_at":"2025-11-17T00:02:43.241Z","dependency_job_id":null,"html_url":"https://github.com/smikhalevski/whoopie","commit_stats":null,"previous_names":["smikhalevski/whoopie"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/smikhalevski/whoopie","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smikhalevski%2Fwhoopie","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smikhalevski%2Fwhoopie/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smikhalevski%2Fwhoopie/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smikhalevski%2Fwhoopie/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/smikhalevski","download_url":"https://codeload.github.com/smikhalevski/whoopie/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smikhalevski%2Fwhoopie/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35059245,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-02T02:00:06.368Z","response_time":173,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["client","cookie","json","server"],"created_at":"2025-10-27T16:28:52.892Z","updated_at":"2026-07-02T18:33:06.386Z","avatar_url":"https://github.com/smikhalevski.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\u003cimg src=\"./assets/logo.png\" alt=\"Whoopie\" width=\"500\" /\u003e\u003c/p\u003e\n\nSuper-fast cookie parser and storage that works on both server and client.\n\n[Just 1 kB gzipped](https://bundlephobia.com/package/whoopie) with zero dependencies.\n\n```shell\nnpm install --save-prod whoopie\n```\n\n🔰 [API documentation is available here.](https://smikhalevski.github.io/whoopie)\n\n# Usage\n\nUse [`documentCookieStorage`](https://smikhalevski.github.io/whoopie/variables/documentCookieStorage.html) to read and\nwrite cookies from `document.cookie`:\n\n```ts\nimport { documentCookieStorage } from 'whoopie';\n\ndocumentCookieStorage.set('hello', 'world');\n\ndocumentCookieStorage.get('hello');\n// ⮕ 'world'\n```\n\nJSON cookies are supported out of the box:\n\n```ts\ndocumentCookieStorage.set('users', ['bob', 'bill', 'barry']);\n\ndocumentCookieStorage.get('users');\n// ⮕ ['bob', 'bill', 'barry']\n```\n\nUse [`createCookieStorage`](https://smikhalevski.github.io/whoopie/functions/createCookieStorage.html) to create\na custom cookie storage:\n\n```ts\nimport { createCookieStorage, jsonCookieSerializer } from 'whoopie';\n\nconst myStorage = createCookieStorage({\n  getCookie() {\n    return document.cookie;\n  },\n\n  setCookie(cookie) {\n    document.cookie = cookie;\n  },\n\n  serializer: jsonCookieSerializer,\n});\n\nmyStorage.set('hello', 'world');\n\nmyStorage.get('hello');\n// ⮕ 'world'\n```\n\nHere, [`jsonCookieSerializer`](https://smikhalevski.github.io/whoopie/variables/jsonCookieSerializer.html) is a built-in\ncookie value serializer that supports JSON values. This serializer never throws errors during parsing. If a cookie value\nisn't valid JSON, it's returned as a string.\n\n```ts\n// Unambiguous strings aren't wrapped in double quotes\njsonCookieSerializer.stringify('hello');\n// ⮕ 'hello'\n\njsonCookieSerializer.parse('hello');\n// ⮕ 'hello'\n\n// Ambiguous strings are wrapped in double quotes\njsonCookieSerializer.stringify('true');\n// ⮕ '\"true\"'\n\njsonCookieSerializer.stringify(42);\n// ⮕ '42'\n\njsonCookieSerializer.parse('42');\n// ⮕ 42\n```\n\nYou can create server-side cookie storage that reads cookies from a request and writes to the response:\n\n```ts\nimport { createCookieStorage, jsonCookieSerializer } from 'whoopie';\n\nfunction createServerCookieStorage(requestHeaders: Headers, responseHeaders: Headers): CookieStorage {\n  return createCookieStorage({\n    getCookie() {\n      return requestHeaders.get('Cookie');\n    },\n\n    setCookie(cookie) {\n      responseHeaders.set('Set-Cookie', cookie);\n    },\n\n    serializer: jsonCookieSerializer,\n  });\n}\n```\n\nBe sure to create a new cookie store for each request.\n\n```ts\nexport function handleRequest(request: Request): Response {\n  const responseHeaders = new Headers();\n\n  const myStorage = createServerCookieStorage(request.headers, responseHeaders);\n\n  myStorage.set('hello', 'world');\n\n  myStorage.get('hello');\n\n  return Response.json({}, { headers: responseHeaders });\n}\n```\n\n# Signed cookies\n\nSigned cookies are needed to ensure integrity and authenticity of data stored in the browser. Ordinary cookies are\nstored and sent by the browser, but the user can modify them using developer tools.\n\nSigned cookies guarantee that the cookies value wasn't forged by adding a signature to the cookie value and verifying\nthis signature when cookie is read:\n\n```ts\nimport { documentCookieStorage } from 'whoopie';\n\nconst SECRET_KEY = 'my_secret_key';\n\ndocumentCookieStorage.setSigned('hello', 'world', SECRET_KEY);\n\ndocumentCookieStorage.getSigned('hello', SECRET_KEY);\n// ⮕ 'world'\n```\n\nMake sure that secret key cannot be accessed by the user.\n\n# Utilities\n\nWhoopie exports a set of functional utilities that streamline working with cookies without the need to create a storage.\n\nParse [`Cookie`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cookie) header value or\n`document.cookie` as a key-value mapping:\n\n```ts\nparseCookies('hello=world');\n// ⮕ { hello: 'world' }\n```\n\nGet names of all cookies:\n\n```ts\ngetCookieNames('hello=world');\n// ⮕ ['hello']\n```\n\nGet value of a cookie by its name:\n\n```ts\ngetCookieValue('hello=world', 'hello');\n// ⮕ 'world'\n```\n\nStringify a cookie, so it can be used as\na [`Set-Cookie`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie) header value or\nassigned to `document.cookie`:\n\n```ts\nstringifyCookie('hello', 'world', { maxAge: 24 * 60 * 60 });\n// ⮕ 'hello=world; Max-Age=86400'\n```\n\n# Type-safe cookies\n\nAdd typings to the `documentCookieStorage`:\n\n```ts\ninterface MyCookies {\n  userAge?: number;\n}\n\nexport const myStorage: CookieStorage\u003cMyCookies\u003e = documentCookieStorage;\n```\n\n`myStorage` doesn't provide runtime type-safety, but provides compile-time type safety:\n\n```ts\nmyStorage.set('userAge', 'hello');\n// ❌ TypeScript error: userAge must be of type number\n\nmyStorage.get('userAge');\n// 🟡 Ooops, type isn't guaranteed at runtime\n```\n\nThe types of JSON cookies cannot be guaranteed at runtime, as cookies can be altered by the user or directly mutated via\n`document.cookie`. To mitigate this issue, use a validation library such as [Doubter](https://megastack.dev/doubter):\n\n```ts\nimport * as d from 'doubter';\n\n// ✅ Runtime type-safety is ensured\nconst userAge = d.number().catch().parse(myStorage.get('userAge'));\n// ⮕ number | undefined\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmikhalevski%2Fwhoopie","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsmikhalevski%2Fwhoopie","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmikhalevski%2Fwhoopie/lists"}