{"id":13448538,"url":"https://github.com/nuxt-contrib/devalue","last_synced_at":"2025-03-22T09:31:26.766Z","repository":{"id":43776138,"uuid":"151407323","full_name":"nuxt-contrib/devalue","owner":"nuxt-contrib","description":"Gets the job done when JSON.stringify can't","archived":false,"fork":true,"pushed_at":"2023-05-02T20:03:58.000Z","size":356,"stargazers_count":75,"open_issues_count":6,"forks_count":9,"subscribers_count":7,"default_branch":"main","last_synced_at":"2024-04-23T23:20:51.662Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://npm.runkit.com/devalue","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"Rich-Harris/devalue","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nuxt-contrib.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-10-03T12:14:58.000Z","updated_at":"2024-04-23T23:20:51.662Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/nuxt-contrib/devalue","commit_stats":null,"previous_names":["nuxt/devalue","nuxt-community/devalue"],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nuxt-contrib%2Fdevalue","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nuxt-contrib%2Fdevalue/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nuxt-contrib%2Fdevalue/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nuxt-contrib%2Fdevalue/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nuxt-contrib","download_url":"https://codeload.github.com/nuxt-contrib/devalue/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244937751,"owners_count":20535124,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2024-07-31T05:01:48.365Z","updated_at":"2025-03-22T09:31:25.962Z","avatar_url":"https://github.com/nuxt-contrib.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# @nuxt/devalue\n\n[![npm version][npm-version-src]][npm-version-href]\n[![npm downloads][npm-downloads-src]][npm-downloads-href]\n[![codecov][codecov-src]][codecov-href]\n[![package phobia][package-phobia-src]][package-phobia-href]\n[![bundle phobia][bundle-phobia-src]][bundle-phobia-href]\n\n\u003e Forked from [devalue](https://github.com/Rich-Harris/devalue) to log errors on non-serializable properties rather than throwing `Error`.\n\nLike `JSON.stringify`, but handles\n\n* cyclical references (`obj.self = obj`)\n* repeated references (`[value, value]`)\n* `undefined`, `Infinity`, `NaN`, `-0`\n* regular expressions\n* dates\n* `Map` and `Set`\n* `.toJSON()` method for non-POJOs\n\nTry it out on [runkit.com](https://npm.runkit.com/@nuxt/devalue).\n\n## Goals:\n\n* Performance\n* Security (see [XSS mitigation](#xss-mitigation))\n* Compact output\n\n\n## Non-goals:\n\n* Human-readable output\n* Stringifying functions or arbritary non-POJOs\n\n\n## Usage\n\n```js\nimport devalue from '@nuxt/devalue';\n\nlet obj = { a: 1, b: 2 };\nobj.c = 3;\n\ndevalue(obj); // '{a:1,b:2,c:3}'\n\nobj.self = obj;\ndevalue(obj); // '(function(a){a.a=1;a.b=2;a.c=3;a.self=a;return a}({}))'\n```\n\nIf `devalue` encounters a function or a non-POJO, it will throw an error.\n\n\n## XSS mitigation\n\nSay you're server-rendering a page and want to serialize some state, which could include user input. `JSON.stringify` doesn't protect against XSS attacks:\n\n```js\nconst state = {\n  userinput: `\u003c/script\u003e\u003cscript src='https://evil.com/mwahaha.js'\u003e`\n};\n\nconst template = `\n\u003cscript\u003e\n  // NEVER DO THIS\n  var preloaded = ${JSON.stringify(state)};\n\u003c/script\u003e`;\n```\n\nWhich would result in this:\n\n```html\n\u003cscript\u003e\n  // NEVER DO THIS\n  var preloaded = {\"userinput\":\"\u003c/script\u003e\u003cscript src='https://evil.com/mwahaha.js'\u003e\"};\n\u003c/script\u003e\n```\n\nUsing `devalue`, we're protected against that attack:\n\n```js\nconst template = `\n\u003cscript\u003e\n  var preloaded = ${devalue(state)};\n\u003c/script\u003e`;\n```\n\n```html\n\u003cscript\u003e\n  var preloaded = {userinput:\"\\\\u003C\\\\u002Fscript\\\\u003E\\\\u003Cscript src=\\'https:\\\\u002F\\\\u002Fevil.com\\\\u002Fmwahaha.js\\'\\\\u003E\"};\n\u003c/script\u003e\n```\n\nThis, along with the fact that `devalue` bails on functions and non-POJOs, stops attackers from executing arbitrary code. Strings generated by `devalue` can be safely deserialized with `eval` or `new Function`:\n\n```js\nconst value = (0,eval)('(' + str + ')');\n```\n\n\n## Other security considerations\n\nWhile `devalue` prevents the XSS vulnerability shown above, meaning you can use it to send data from server to client, **you should not send user data from client to server** using the same method. Since it has to be evaluated, an attacker that successfully submitted data that bypassed `devalue` would have access to your system.\n\nWhen using `eval`, ensure that you call it *indirectly* so that the evaluated code doesn't have access to the surrounding scope:\n\n```js\n{\n  const sensitiveData = 'Setec Astronomy';\n  eval('sendToEvilServer(sensitiveData)'); // pwned :(\n  (0,eval)('sendToEvilServer(sensitiveData)'); // nice try, evildoer!\n}\n```\n\nUsing `new Function(code)` is akin to using indirect eval.\n\n\n## See also\n\n* [lave](https://github.com/jed/lave) by Jed Schmidt\n* [arson](https://github.com/benjamn/arson) by Ben Newman\n* [tosource](https://github.com/marcello3d/node-tosource) by Marcello Bastéa-Forte\n* [serialize-javascript](https://github.com/yahoo/serialize-javascript) by Eric Ferraiuolo\n\n\n## License\n\n[MIT](LICENSE)\n\n\u003c!-- Refs --\u003e\n[npm-version-src]: https://flat.badgen.net/npm/v/@nuxt/devalue/latest\n[npm-version-href]: https://www.npmjs.com/package/@nuxt/devalue\n\n[npm-downloads-src]: https://flat.badgen.net/npm/dm/@nuxt/devalue\n[npm-downloads-href]: https://www.npmjs.com/package/@nuxt/devalue\n\n[circleci-src]: https://flat.badgen.net/circleci/github/nuxt-contrib/devalue\n[circleci-href]: https://circleci.com/gh/nuxt-contrib/devalue\n\n[package-phobia-src]: https://flat.badgen.net/packagephobia/install/@nuxt/devalue\n[package-phobia-href]: https://packagephobia.now.sh/result?p=@nuxt/devalue\n\n[bundle-phobia-src]: https://flat.badgen.net/bundlephobia/minzip/@nuxt/devalue\n[bundle-phobia-href]: https://bundlephobia.com/result?p=@nuxt/devalue\n\n[codecov-src]: https://flat.badgen.net/codecov/c/github/nuxt-contrib/devalue/master\n[codecov-href]: https://codecov.io/gh/nuxt-contrib/devalue\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnuxt-contrib%2Fdevalue","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnuxt-contrib%2Fdevalue","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnuxt-contrib%2Fdevalue/lists"}