{"_id":"@applura/ouroboros","_rev":"6-3e7dda9005f746bf1f186be080523a07","name":"@applura/ouroboros","dist-tags":{"latest":"1.0.0-rc1"},"versions":{"0.0.0":{"name":"@applura/ouroboros","version":"0.0.0","author":{"name":"Applura, Inc"},"license":"MIT","_id":"@applura/ouroboros@0.0.0","maintainers":[{"name":"gabesullice","email":"gabriel@sullice.com"}],"homepage":"https://github.com/applura/ouroboros#readme","bugs":{"url":"https://github.com/applura/ouroboros/issues"},"dist":{"shasum":"67f1e41cc2c9feacbdd43ac09bc3ee9891083083","tarball":"https://registry.npmjs.org/@applura/ouroboros/-/ouroboros-0.0.0.tgz","fileCount":17,"integrity":"sha512-lkrqlKvmCxdO3XNED/9qtxgara5i6bf0OibSBsGDoSvpqkgCjGGcNclrI2BV42OQ6gi7gIuhBsWwnNElmuSRPw==","signatures":[{"sig":"MEQCIAp3QI/s/hbwGOOxSnhHawVDX6aYfNlAlpmDm/YKkv50AiBF7f8Ij+wdhLEdpG+JS2fa1n5EOJRvThYVn7W25vw1Rg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":28918},"type":"module","module":"dist/ouroboros.js","gitHead":"4335380761965ffb20917e1908ecc6105e58a4cc","scripts":{"test":"NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" npx jest","build":"npx rollup --config","check":"npm run sniff && npm run test","sniff":"npx eslint src && npx prettier . --check","prettier":"npx prettier . --write"},"_npmUser":{"name":"gabesullice","email":"gabriel@sullice.com"},"repository":{"url":"git+https://github.com/applura/ouroboros.git","type":"git"},"_npmVersion":"10.9.2","description":"Easily read JSON:API resource object and included object attributes","directories":{},"_nodeVersion":"22.14.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^9.22.0","rollup":"^4.35.0","globals":"^16.0.0","prettier":"3.5.3","@eslint/js":"^9.22.0"},"_npmOperationalInternal":{"tmp":"tmp/ouroboros_0.0.0_1742373914409_0.028028553731022754","host":"s3://npm-registry-packages-npm-production"}},"0.0.0-alpha0":{"name":"@applura/ouroboros","version":"0.0.0-alpha0","author":{"name":"Applura, Inc"},"license":"MIT","_id":"@applura/ouroboros@0.0.0-alpha0","maintainers":[{"name":"gabesullice","email":"gabriel@sullice.com"}],"homepage":"https://github.com/applura/ouroboros#readme","bugs":{"url":"https://github.com/applura/ouroboros/issues"},"dist":{"shasum":"2d90117f0f93a83ad008353de09d2b54aa10473a","tarball":"https://registry.npmjs.org/@applura/ouroboros/-/ouroboros-0.0.0-alpha0.tgz","fileCount":16,"integrity":"sha512-eq3fQq8QDtxOPiAegAY5xIj9Vwy6nS+MQCP2Dwo67AWdAdex9//hAFx19MDWjTyCeczqfIq5obR63Nhbez2epA==","signatures":[{"sig":"MEQCIAflZhDHfILBd6zb0FGVYlGJ8gQ4XFVuD5mE4SJ9srXSAiAOhMaBh/FBfUbjhOObnxU1YXlULZEaUsy9Re5FzTwczw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":21976},"type":"module","module":"dist/ouroboros.js","gitHead":"94c7cdd8f41dd7e3c653bedbcb0297e36b5795c4","scripts":{"test":"NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" npx jest","build":"npx rollup --config","check":"npm run sniff && npm run test","sniff":"npx eslint src && npx prettier . --check","prettier":"npx prettier . --write"},"_npmUser":{"name":"gabesullice","email":"gabriel@sullice.com"},"repository":{"url":"git+https://github.com/applura/ouroboros.git","type":"git"},"_npmVersion":"10.9.2","description":"Easily read JSON:API resource object and included object attributes","directories":{},"_nodeVersion":"22.14.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^9.22.0","rollup":"^4.35.0","globals":"^16.0.0","prettier":"3.5.3","@eslint/js":"^9.22.0"},"_npmOperationalInternal":{"tmp":"tmp/ouroboros_0.0.0-alpha0_1742389426208_0.19264633324758051","host":"s3://npm-registry-packages-npm-production"}},"0.0.0-alpha1":{"name":"@applura/ouroboros","version":"0.0.0-alpha1","author":{"name":"Applura, Inc"},"license":"MIT","_id":"@applura/ouroboros@0.0.0-alpha1","maintainers":[{"name":"gabesullice","email":"gabriel@sullice.com"}],"homepage":"https://github.com/applura/ouroboros#readme","bugs":{"url":"https://github.com/applura/ouroboros/issues"},"dist":{"shasum":"081f933c0fd251ea14030cb59cc38bcfae13986a","tarball":"https://registry.npmjs.org/@applura/ouroboros/-/ouroboros-0.0.0-alpha1.tgz","fileCount":12,"integrity":"sha512-lDhC4IVUnaaH567aKPtDh/wIKyQfn6NpgjsIaoqr5i8546k3JtjTonXXGAfojwZpFt43HzQ+EOU2JTxshe9ivA==","signatures":[{"sig":"MEQCIFMZXlVxmd4/oR9MBFX3nMT9dJH3oldOajGX+wc1nSShAiBmUAFGcGcM2hqGEN4wT/D2WlxHeijikzp04uaPzuYxNQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@applura%2fouroboros@0.0.0-alpha1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":20961},"type":"module","module":"dist/ouroboros.js","gitHead":"5e94a9780a81cf8562a2451c5c9495c11c769873","scripts":{"test":"NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" npx jest","build":"npx rollup --config","check":"npm run sniff && npm run test","sniff":"npx eslint src && npx prettier . --check","prettier":"npx prettier . --write"},"_npmUser":{"name":"gabesullice","email":"gabriel@sullice.com"},"repository":{"url":"git+https://github.com/Applura/ouroboros.git","type":"git"},"_npmVersion":"10.9.2","description":"Easily read JSON:API resource object and included object attributes","directories":{},"_nodeVersion":"22.14.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^9.22.0","rollup":"^4.35.0","globals":"^16.0.0","prettier":"3.5.3","@eslint/js":"^9.22.0"},"_npmOperationalInternal":{"tmp":"tmp/ouroboros_0.0.0-alpha1_1742390258447_0.2544673200611087","host":"s3://npm-registry-packages-npm-production"}},"0.0.0-alpha2":{"name":"@applura/ouroboros","version":"0.0.0-alpha2","author":{"name":"Applura, Inc"},"license":"MIT","_id":"@applura/ouroboros@0.0.0-alpha2","maintainers":[{"name":"gabesullice","email":"gabriel@sullice.com"}],"homepage":"https://github.com/applura/ouroboros#readme","bugs":{"url":"https://github.com/applura/ouroboros/issues"},"dist":{"shasum":"ccf9b6a2f8d14d96ea0358135237f03303c71f76","tarball":"https://registry.npmjs.org/@applura/ouroboros/-/ouroboros-0.0.0-alpha2.tgz","fileCount":12,"integrity":"sha512-lOGnt00MccUXESvg7fJyzJhyVGxgVMKtP9x6Id5LlpxujVyrIKtY/ptzZM4HcSgA6kFAbCOB+lUlW+kjfJPC3w==","signatures":[{"sig":"MEUCIFL5AcxpKFzBfJRzU285ziobdJyRb/CMIlxZ4JN08T4cAiEAo52d785QT2Cxpk2oY6FAdsXmnaxk4pPNNE8hpN8A0FM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@applura%2fouroboros@0.0.0-alpha2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":20961},"type":"module","module":"dist/ouroboros.js","gitHead":"5e94a9780a81cf8562a2451c5c9495c11c769873","scripts":{"test":"NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" npx jest","build":"npx rollup --config","check":"npm run sniff && npm run test","sniff":"npx eslint src && npx prettier . --check","prettier":"npx prettier . --write"},"_npmUser":{"name":"gabesullice","email":"gabriel@sullice.com"},"repository":{"url":"git+https://github.com/Applura/ouroboros.git","type":"git"},"_npmVersion":"10.9.2","description":"Easily read JSON:API resource object and included object attributes","directories":{},"_nodeVersion":"22.14.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^9.22.0","rollup":"^4.35.0","globals":"^16.0.0","prettier":"3.5.3","@eslint/js":"^9.22.0"},"_npmOperationalInternal":{"tmp":"tmp/ouroboros_0.0.0-alpha2_1742390454871_0.42966893284100194","host":"s3://npm-registry-packages-npm-production"}},"0.0.0-alpha3":{"name":"@applura/ouroboros","version":"0.0.0-alpha3","author":{"name":"Applura, Inc"},"license":"MIT","_id":"@applura/ouroboros@0.0.0-alpha3","maintainers":[{"name":"gabesullice","email":"gabriel@sullice.com"}],"homepage":"https://github.com/applura/ouroboros#readme","bugs":{"url":"https://github.com/applura/ouroboros/issues"},"dist":{"shasum":"989560cef1bfdbf3e0293fd99fa4a5434d267508","tarball":"https://registry.npmjs.org/@applura/ouroboros/-/ouroboros-0.0.0-alpha3.tgz","fileCount":12,"integrity":"sha512-P8IPDDCdz4bhVwQ17D+lejnsaR7kpien627BWAxwWtz0Gk9AbvdIVJyrKFvj2Xk+GCxTMHSFBsrAbuQ6BXtPIw==","signatures":[{"sig":"MEYCIQCoO5Swl/IT2S1A3mZGZhqGP8fOBsbUFlrgxELsT3JCcwIhAJg6VCwf/TU1ZwsYig+6yqjP4WkxNNskpYTPEnWwf40E","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@applura%2fouroboros@0.0.0-alpha3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":20481},"main":"dist/ouroboros.js","type":"module","module":"dist/ouroboros.js","gitHead":"fdb9425c8e722ea67e3f51f5f34746cd36ef285b","scripts":{"test":"NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" npx jest","build":"npx rollup --config","check":"npm run sniff && npm run test","sniff":"npx eslint src && npx prettier . --check","prettier":"npx prettier . --write"},"_npmUser":{"name":"gabesullice","email":"gabriel@sullice.com"},"repository":{"url":"git+https://github.com/Applura/ouroboros.git","type":"git"},"_npmVersion":"10.9.2","description":"Easily read JSON:API resource object and included object attributes","directories":{},"_nodeVersion":"22.14.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^9.22.0","rollup":"^4.35.0","globals":"^16.0.0","prettier":"3.5.3","@eslint/js":"^9.22.0"},"_npmOperationalInternal":{"tmp":"tmp/ouroboros_0.0.0-alpha3_1742391802589_0.5244648835689212","host":"s3://npm-registry-packages-npm-production"}},"1.0.0-rc1":{"name":"@applura/ouroboros","type":"module","description":"Easily read JSON:API resource object and included object attributes","main":"dist/ouroboros.js","module":"dist/ouroboros.js","scripts":{"build":"npx rollup --config","check":"npm run sniff && npm run test","prettier":"npx prettier . --write","sniff":"npx eslint src && npx prettier . --check","test":"NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" npx jest"},"repository":{"type":"git","url":"git+https://github.com/Applura/ouroboros.git"},"author":{"name":"Applura, Inc"},"license":"MIT","bugs":{"url":"https://github.com/applura/ouroboros/issues"},"homepage":"https://github.com/applura/ouroboros#readme","devDependencies":{"@eslint/js":"^9.22.0","eslint":"^9.22.0","globals":"^16.0.0","jest":"^29.7.0","prettier":"3.5.3","rollup":"^4.35.0"},"version":"1.0.0-rc1","_id":"@applura/ouroboros@1.0.0-rc1","gitHead":"c71a0e4fabc328bec417ea1233960280526c45e9","_nodeVersion":"22.14.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-ZxqUO6HArryrVhWPsVB9Ix9A4a8DRtsP4nvkEvMZCXKkFimGX+cW87gvs4MrCtRcWZzVY7ZRBb3Kc1xk7bJo8Q==","shasum":"8f1020a33d5f37c2c154cc1ca21ef04815e6c22a","tarball":"https://registry.npmjs.org/@applura/ouroboros/-/ouroboros-1.0.0-rc1.tgz","fileCount":12,"unpackedSize":20486,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@applura%2fouroboros@1.0.0-rc1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCYkziN2hz5ziRq+e3Tt91Bm82zMXpXqHi2HPmgFuGM2QIhAN0Q40a98pRDWRVtbTQg+0vNAka8DkdEr2rHu9JroWSQ"}]},"_npmUser":{"name":"gabesullice","email":"gabriel@sullice.com"},"directories":{},"maintainers":[{"name":"gabesullice","email":"gabriel@sullice.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ouroboros_1.0.0-rc1_1742925961066_0.45526805726732045"},"_hasShrinkwrap":false}},"time":{"created":"2025-03-19T08:45:14.283Z","modified":"2025-03-25T18:06:01.715Z","0.0.0":"2025-03-19T08:45:14.593Z","0.0.0-alpha0":"2025-03-19T13:03:46.371Z","0.0.0-alpha1":"2025-03-19T13:17:38.623Z","0.0.0-alpha2":"2025-03-19T13:20:55.101Z","0.0.0-alpha3":"2025-03-19T13:43:22.860Z","1.0.0-rc1":"2025-03-25T18:06:01.264Z"},"bugs":{"url":"https://github.com/applura/ouroboros/issues"},"author":{"name":"Applura, Inc"},"license":"MIT","homepage":"https://github.com/applura/ouroboros#readme","repository":{"type":"git","url":"git+https://github.com/Applura/ouroboros.git"},"description":"Easily read JSON:API resource object and included object attributes","maintainers":[{"name":"gabesullice","email":"gabriel@sullice.com"}],"readme":"# ∞ ouroboros ∞\n\nOuroboros decouples your business logic from the intricacies of\nthe [JSON:API specification's][spec] [document structure][structure] by\ntransforming a complex JSON:API document object into a simplified object with\neasy-to-access properties.\n\nOuroboros is **not** a JSON:API client. We recommend you use the [Fetch \nAPI][fetch] or another library to make HTTP requests and Ouroboros to consume \nthe response body.\n\n[profiles]: https://jsonapi.org/extensions/#existing-profiles\n\n### API\n\nOuroboros exports two mutually-exclusive functions: `parse` and `consume`. Use\n`parse` if you have a raw JSON:API string. Use `consume` if your JSON object has\nalready been parsed with `JSON.parse()`.\n\n```js\nimport { parse, consume } from \"@applura/ouroboros\";\n\n// If you have raw JSON, use parse.\nconst json = \"{/* example shown below */}\";\nconst parsedArticle = parse(json);\n\n// If you have a parsed object, use consume.\nconst doc = JSON.parse(json);\nconst consumedArticle = consume(doc);\n\nconsole.log(parsedArticle.title === consumedArticle.title); // true.\n```\n\n### Example\n\nFor example, notice that the code below doesn't need to repetitively access the\n`data.attributes` property or know the difference between an `attributes` or\n`relationships` [field][fields]—nor does is it need to search for the `people`\nobject in the [`included` member][included]—Ouroboros does it transparently.\n\n```js\nconst article = parse(/* shown below */);\nconst author = article.author;\nconst comments = article.comments;\n\nconsole.log(`\"${article.title}\" by ${author.firstName} ${author.lastName}`);\n\nfor (const comment of comments) {\n  const {body, author: commenter} = comment;\n  console.log(`-- ${commenter.firstName} commented: \"${body}\"`);\n}\n\n// Prints…\n// \"JSON:API paints my bikeshed!\" by Dan Gebhardt\n// -- Dan commented: \"First!\"\n```\n\n```json\n{\n  \"data\": {\n    \"type\": \"articles\",\n    \"id\": \"1\",\n    \"attributes\": {\n      \"title\": \"JSON:API paints my bikeshed!\"\n    },\n    \"links\": {\n      \"describedby\": \"http://example.com/schemas/article-resource\",\n      \"self\": \"http://example.com/articles/1\"\n    },\n    \"meta\": {\n      \"description\": \"A single article.\"\n    },\n    \"relationships\": {\n      \"author\": {\n        \"links\": {\n          \"self\": \"http://example.com/articles/1/relationships/author\",\n          \"related\": \"http://example.com/articles/1/author\"\n        },\n        \"data\": { \"type\": \"people\", \"id\": \"9\" }\n      },\n      \"comments\": {\n        \"links\": {\n          \"self\": \"http://example.com/articles/1/relationships/comments\",\n          \"related\": \"http://example.com/articles/1/comments\"\n        },\n        \"data\": [{ \"type\": \"comments\", \"id\": \"5\" }]\n      }\n    }\n  },\n  \"links\": {\n    \"describedby\": \"http://example.com/schemas/article-document\"\n  },\n  \"meta\": {\n    \"description\": \"Document containing a single article and its related resources.\"\n  },\n  \"included\": [\n    {\n      \"type\": \"people\",\n      \"id\": \"9\",\n      \"attributes\": {\n        \"firstName\": \"Dan\",\n        \"lastName\": \"Gebhardt\",\n        \"twitter\": \"dgeb\"\n      },\n      \"links\": {\n        \"self\": \"http://example.com/people/9\"\n      },\n      \"relationships\": {\n        \"comments\": {\n          \"links\": {\n            \"self\": \"http://example.com/people/9/relationships/comments\",\n            \"related\": \"http://example.com/people/9/comments\"\n          },\n          \"data\": [{ \"type\": \"comments\", \"id\": \"5\" }]\n        }\n      }\n    },\n    {\n      \"type\": \"comments\",\n      \"id\": \"5\",\n      \"attributes\": {\n        \"body\": \"First!\"\n      },\n      \"relationships\": {\n        \"author\": {\n          \"data\": { \"type\": \"people\", \"id\": \"9\" }\n        }\n      },\n      \"links\": {\n        \"self\": \"http://example.com/comments/5\"\n      }\n    }\n  ]\n}\n```\n\n#### Why _Ouroboros_?\n\nConsuming a JSON:API document with a circular relationship causes Ouroboros to\nloop back on itself without breaking, like the [ancient symbol][serpent]\ndepicting a serpent consuming its own tail.\n\nFor example, using the example above, the following code works as one would\nexpect:\n\n```js\nconst { author } = parse(/* example shown above */);\n\nconsole.log(\n  author\n  .comments[0]\n  .author\n  .comments[0]\n  // ∞\n  .author\n  .comments[0]\n  .body\n);\n\n// Prints…\n// First!\n```\n\n#### What about links and metadata?\n\nAll `links` and `meta` members in the document are preserved.\n\nTo access `links` or `meta` object members from the\noriginal [top-level object][top-level], use the `top` property.\n\nTo access `links` or `meta` object members from one of the original\n[relationship objects][relationships], use the `relationships` property on the\nparent resource object.\n\n```js\nconst article = parse(/* example shown above */)\nconst { author } = article;\n\n// To access a resource object's links or meta members, access them directly.\nconsole.log(article.links.describedby); // \"http://example.com/schemas/article-resource\"\nconsole.log(article.meta.description); // \"A single article.\"\n\n// To access a top-level links or meta member, use the \"top\" property on any\n// resource.\nconsole.log(article.top.links.describedby); // \"http://example.com/schemas/article-document\"\nconsole.log(article.top.meta.description); // \"Document containing a single article and its related resources.\"\n\n// Article and author share the same \"top\" property.\nconsole.log(article.top.links.describedby === author.top.links.describedby); // true.\nconsole.log(article.top.meta.description === author.top.meta.description); // true.\n\n// To access a links or meta member on a relationship, use the \"relationships\"\n// property on the parent resource object *not* the related resource object. In\n// this example, article is the parent because it has a relationship to author.\nconsole.log(article.relationships.author.links.related); // \"http://example.com/articles/1/author\"\n```\n\n#### Limitations\n\nResource objects must not have any attribute or relationship fields with any of the\nfollowing names:\n\n- `type`\n- `id`\n- `relationships`\n- `meta`\n- `links`\n- `top`\n\n[serpent]: https://en.m.wikipedia.org/wiki/Ouroboros\n[fetch]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API\n[fields]: https://jsonapi.org/format/#document-resource-object-fields\n[included]: https://jsonapi.org/format/#document-compound-documents\n[relationships]: https://jsonapi.org/format/#document-resource-object-relationships\n[spec]: https://jsonapi.org/format/\n[structure]: https://jsonapi.org/format/#document-structure\n[top-level]: https://jsonapi.org/format/#document-top-level\n","readmeFilename":"README.md"}