{"id":13496322,"url":"https://github.com/peerigon/parse-domain","last_synced_at":"2026-03-01T03:01:14.028Z","repository":{"id":16975320,"uuid":"19737984","full_name":"peerigon/parse-domain","owner":"peerigon","description":"Splits a hostname into subdomains, domain and (effective) top-level domains.","archived":false,"fork":false,"pushed_at":"2026-01-22T15:21:24.000Z","size":2682,"stargazers_count":514,"open_issues_count":4,"forks_count":72,"subscribers_count":11,"default_branch":"main","last_synced_at":"2026-02-23T10:43:14.114Z","etag":null,"topics":["domain","javascript","parse","publicsuffix","tld","typescript","url"],"latest_commit_sha":null,"homepage":"","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/peerigon.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,"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":"2014-05-13T12:25:42.000Z","updated_at":"2026-02-16T01:48:02.000Z","dependencies_parsed_at":"2023-01-13T19:06:08.698Z","dependency_job_id":"9596a4af-5e3c-4dd5-9469-12349cf73851","html_url":"https://github.com/peerigon/parse-domain","commit_stats":{"total_commits":179,"total_committers":25,"mean_commits":7.16,"dds":0.3016759776536313,"last_synced_commit":"b01598d26afeaff830af8d29947faf3d029d0f29"},"previous_names":[],"tags_count":52,"template":false,"template_full_name":null,"purl":"pkg:github/peerigon/parse-domain","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peerigon%2Fparse-domain","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peerigon%2Fparse-domain/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peerigon%2Fparse-domain/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peerigon%2Fparse-domain/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/peerigon","download_url":"https://codeload.github.com/peerigon/parse-domain/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peerigon%2Fparse-domain/sbom","scorecard":{"id":113897,"data":{"date":"2025-08-04","repo":{"name":"github.com/peerigon/parse-domain","commit":"32816606f30a3d9d0baf2078591af8ab8091081c"},"scorecard":{"version":"v5.2.1-28-gc1d103a9","commit":"c1d103a9bb9f635ec7260bf9aa0699466fa4be0e"},"score":5.7,"checks":[{"name":"Code-Review","score":0,"reason":"Found 1/26 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#code-review"}},{"name":"Maintained","score":9,"reason":"11 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 9","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#binary-artifacts"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":9,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: jobLevel 'contents' permission set to 'write': .github/workflows/test-and-release.yml:22","Warn: jobLevel 'packages' permission set to 'write': .github/workflows/test-and-release.yml:28","Warn: no topLevel permission defined: .github/workflows/test-and-release.yml:1"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":10,"reason":"all dependencies are pinned","details":["Info:   4 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   1 out of   1 third-party GitHubAction dependencies pinned","Info:   1 out of   1 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 21 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":9,"reason":"1 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-15T21:34:14.822Z","repository_id":16975320,"created_at":"2025-08-15T21:34:14.823Z","updated_at":"2025-08-15T21:34:14.823Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29959284,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-01T01:47:18.291Z","status":"online","status_checked_at":"2026-03-01T02:00:07.437Z","response_time":124,"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":["domain","javascript","parse","publicsuffix","tld","typescript","url"],"created_at":"2024-07-31T19:01:45.962Z","updated_at":"2026-03-01T03:01:13.954Z","avatar_url":"https://github.com/peerigon.png","language":"TypeScript","readme":"# parse-domain\n\n**Splits a hostname into subdomains, domain and (effective) top-level domains.**\n\n[![Version on NPM](https://img.shields.io/npm/v/parse-domain?style=for-the-badge)](https://www.npmjs.com/package/parse-domain)\n[![Semantically released](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=for-the-badge)](https://github.com/semantic-release/semantic-release)\n[![Monthly downloads on NPM](https://img.shields.io/npm/dm/parse-domain?style=for-the-badge)](https://www.npmjs.com/package/parse-domain)\u003cbr\u003e\n[![NPM Bundle size minified](https://img.shields.io/bundlephobia/min/parse-domain?style=for-the-badge)](https://bundlephobia.com/result?p=parse-domain)\n[![NPM Bundle size minified and gzipped](https://img.shields.io/bundlephobia/minzip/parse-domain?style=for-the-badge)](https://bundlephobia.com/result?p=parse-domain)\u003cbr\u003e\n[![License](https://img.shields.io/npm/l/parse-domain?style=for-the-badge)](./LICENSE)\n\nSince domain name registrars organize their namespaces in different ways, it's not straight-forward to split a hostname into subdomains, the domain and top-level domains. In order to do that **parse-domain** uses a [large list of known top-level domains](https://publicsuffix.org/list/public_suffix_list.dat) from [publicsuffix.org](https://publicsuffix.org/):\n\n```javascript\nimport { parseDomain, ParseResultType } from \"parse-domain\";\n\nconst parseResult = parseDomain(\n  // This should be a string with basic latin letters only.\n  // More information below.\n  \"www.some.example.co.uk\",\n);\n\n// Check if the domain is listed in the public suffix list\nif (parseResult.type === ParseResultType.Listed) {\n  const { subDomains, domain, topLevelDomains } = parseResult;\n\n  console.log(subDomains); // [\"www\", \"some\"]\n  console.log(domain); // \"example\"\n  console.log(topLevelDomains); // [\"co\", \"uk\"]\n} else {\n  // Read more about other parseResult types below...\n}\n```\n\nThis package has been designed for modern Node and browser environments with ECMAScript modules support. It assumes an ES2015 environment with [`Symbol()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol), [`URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL) and [`TextDecoder()`](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder) globally available. You need to transpile it down to ES5 (e.g. by using [Babel](https://babeljs.io/)) if you need to support older environments.\n\nThe list of top-level domains is stored in a [trie](https://en.wikipedia.org/wiki/Trie) data structure and serialization format to ensure the fastest lookup and the smallest possible library size.\n\n\u003cbr /\u003e\n\n## Installation\n\n```sh\nnpm install parse-domain\n```\n\n## Updates\n\n💡 **Please note:** [publicsuffix.org](https://publicsuffix.org/) is updated several times per month. This package comes with a prebuilt list that has been downloaded at the time of `npm publish`. In order to get an up-to-date list, you should run `npx parse-domain-update` everytime you start or build your application. This will download the latest list from `https://publicsuffix.org/list/public_suffix_list.dat`.\n\n\u003cbr /\u003e\n\n## Expected input\n\n**⚠️ [`parseDomain`](#api-js-parseDomain) does not parse whole URLs**. You should only pass the [puny-encoded](https://en.wikipedia.org/wiki/Punycode) hostname section of the URL:\n\n| ❌ Wrong                                       | ✅ Correct           |\n| ---------------------------------------------- | -------------------- |\n| `https://user@www.example.com:8080/path?query` | `www.example.com`    |\n| `münchen.de`                                   | `xn--mnchen-3ya.de`  |\n| `食狮.com.cn?query`                            | `xn--85x722f.com.cn` |\n\nThere is the utility function [`fromUrl`](#api-js-fromUrl) which tries to extract the hostname from a (partial) URL and puny-encodes it:\n\n```javascript\nimport { toUnicode } from \"punycode\";\nimport { fromUrl, parseDomain } from \"parse-domain\";\n\nconst { subDomains, domain, topLevelDomains } = parseDomain(\n  fromUrl(\"https://www.münchen.de?query\"),\n);\n\nconsole.log(subDomains); // [\"www\"]\nconsole.log(domain); // \"xn--mnchen-3ya\"\nconsole.log(topLevelDomains); // [\"de\"]\n\n// You can use the 'punycode' NPM package to decode the domain again\nconsole.log(toUnicode(domain)); // \"münchen\"\n```\n\n[`fromUrl`](#api-js-fromUrl) parses the URL using [`new URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL). Depending on your target environments you need to make sure that there is a [polyfill](https://www.npmjs.com/package/whatwg-url) for it. It's globally available in [all modern browsers](https://caniuse.com/#feat=url) (no IE) and in [Node v10](https://nodejs.org/api/url.html#url_class_url).\n\n## Expected output\n\nWhen parsing a hostname there are 5 possible results:\n\n- invalid\n- it is an ip address\n- it is formally correct and the domain is\n  - reserved\n  - not listed in the public suffix list\n  - listed in the public suffix list\n\n[`parseDomain`](#api-js-parseDomain) returns a [`ParseResult`](#api-ts-ParseResult) with a `type` property that allows to distinguish these cases.\n\n### 👉 Invalid domains\n\nThe given input is first validated against [RFC 3696](https://datatracker.ietf.org/doc/html/rfc3696#section-2) (the domain labels are limited to basic latin letters, numbers and hyphens). If the validation fails, `parseResult.type` will be `ParseResultType.Invalid`:\n\n```javascript\nimport { parseDomain, ParseResultType } from \"parse-domain\";\n\nconst parseResult = parseDomain(\"münchen.de\");\n\nconsole.log(parseResult.type === ParseResultType.Invalid); // true\n```\n\nCheck out the [API](#api-ts-ValidationError) if you need more information about the validation error.\n\nIf you don't want the characters to be validated (e.g. because you need to allow underscores in hostnames), there's also a more relaxed validation mode (according to [RFC 2181](https://www.rfc-editor.org/rfc/rfc2181#section-11)).\n\n```javascript\nimport { parseDomain, ParseResultType, Validation } from \"parse-domain\";\n\nconst parseResult = parseDomain(\"_jabber._tcp.gmail.com\", {\n  validation: Validation.Lax,\n});\n\nconsole.log(parseResult.type === ParseResultType.Listed); // true\n```\n\nSee also [#134](https://github.com/peerigon/parse-domain/issues/134) for the discussion.\n\n### 👉 IP addresses\n\nIf the given input is an IP address, `parseResult.type` will be `ParseResultType.Ip`:\n\n```javascript\nimport { parseDomain, ParseResultType } from \"parse-domain\";\n\nconst parseResult = parseDomain(\"192.168.2.1\");\n\nconsole.log(parseResult.type === ParseResultType.Ip); // true\nconsole.log(parseResult.ipVersion); // 4\n```\n\nIt's debatable if a library for parsing domains should also accept IP addresses. In fact, you could argue that [`parseDomain`](#api-js-parseDomain) should reject an IP address as invalid. While this is true from a technical point of view, we decided to report IP addresses in a special way because we assume that a lot of people are using this library to make sense from an arbitrary hostname (see [#102](https://github.com/peerigon/parse-domain/issues/102)).\n\n### 👉 Reserved domains\n\nThere are 5 top-level domains that are not listed in the public suffix list but reserved according to [RFC 6761](https://tools.ietf.org/html/rfc6761) and [RFC 6762](https://tools.ietf.org/html/rfc6762):\n\n- `localhost`\n- `local`\n- `example`\n- `invalid`\n- `test`\n\nIn these cases, `parseResult.type` will be `ParseResultType.Reserved`:\n\n```javascript\nimport { parseDomain, ParseResultType } from \"parse-domain\";\n\nconst parseResult = parseDomain(\"pecorino.local\");\n\nconsole.log(parseResult.type === ParseResultType.Reserved); // true\nconsole.log(parseResult.labels); // [\"pecorino\", \"local\"]\n```\n\n### 👉 Domains that are not listed\n\nIf the given hostname is valid, but not listed in the downloaded public suffix list, `parseResult.type` will be `ParseResultType.NotListed`:\n\n```javascript\nimport { parseDomain, ParseResultType } from \"parse-domain\";\n\nconst parseResult = parseDomain(\"this.is.not-listed\");\n\nconsole.log(parseResult.type === ParseResultType.NotListed); // true\nconsole.log(parseResult.labels); // [\"this\", \"is\", \"not-listed\"]\n```\n\nIf a domain is not listed, it can be caused by an outdated list. Make sure to [update the list once in a while](#installation).\n\n⚠️ **Do not treat parseDomain as authoritative answer.** It cannot replace a real DNS lookup to validate if a given domain is known in a certain network.\n\n### 👉 Effective top-level domains\n\nTechnically, the term _top-level domain_ describes the very last domain in a hostname (`uk` in `example.co.uk`). Most people, however, use the term _top-level domain_ for the _public suffix_ which is a namespace [\"under which Internet users can directly register names\"](https://publicsuffix.org/).\n\nSome examples for public suffixes:\n\n- `com` in `example.com`\n- `co.uk` in `example.co.uk`\n- `co` in `example.co`\n- but also `com.co` in `example.com.co`\n\nIf the hostname is listed in the public suffix list, the `parseResult.type` will be `ParseResultType.Listed`:\n\n```javascript\nimport { parseDomain, ParseResultType } from \"parse-domain\";\n\nconst parseResult = parseDomain(\"example.co.uk\");\n\nconsole.log(parseResult.type === ParseResultType.Listed); // true\nconsole.log(parseResult.labels); // [\"example\", \"co\", \"uk\"]\n```\n\nNow `parseResult` will also provide a `subDomains`, `domain` and `topLevelDomains` property:\n\n```javascript\nconst { subDomains, domain, topLevelDomains } = parseResult;\n\nconsole.log(subDomains); // []\nconsole.log(domain); // \"example\"\nconsole.log(topLevelDomains); // [\"co\", \"uk\"]\n```\n\n### 👉 Switch over `parseResult.type` to distinguish between different parse results\n\nWe recommend switching over the `parseResult.type`:\n\n```javascript\nswitch (parseResult.type) {\n  case ParseResultType.Listed: {\n    const { hostname, topLevelDomains } = parseResult;\n\n    console.log(`${hostname} belongs to ${topLevelDomains.join(\".\")}`);\n    break;\n  }\n  case ParseResultType.Reserved:\n  case ParseResultType.NotListed: {\n    const { hostname } = parseResult;\n\n    console.log(`${hostname} is a reserved or unknown domain`);\n    break;\n  }\n  default:\n    throw new Error(`${hostname} is an ip address or invalid domain`);\n}\n```\n\n### ⚠️ Effective TLDs !== TLDs acknowledged by ICANN\n\nWhat's surprising to a lot of people is that the definition of public suffix means that regular user domains can become effective top-level domains:\n\n```javascript\nconst { subDomains, domain, topLevelDomains } = parseDomain(\n  \"parse-domain.github.io\",\n);\n\nconsole.log(subDomains); // []\nconsole.log(domain); // \"parse-domain\"\nconsole.log(topLevelDomains); // [\"github\", \"io\"] 🤯\n```\n\nIn this case, `github.io` is nothing else than a private domain name registrar. `github.io` is the _effective_ top-level domain and browsers are treating it like that (e.g. for setting [`document.domain`](https://developer.mozilla.org/en-US/docs/Web/API/Document/domain)).\n\nIf you want to deviate from the browser's understanding of a top-level domain and you're only interested in top-level domains acknowledged by [ICANN](https://en.wikipedia.org/wiki/ICANN), there's an `icann` property:\n\n```javascript\nconst parseResult = parseDomain(\"parse-domain.github.io\");\nconst { subDomains, domain, topLevelDomains } = parseResult.icann;\n\nconsole.log(subDomains); // [\"parse-domain\"]\nconsole.log(domain); // \"github\"\nconsole.log(topLevelDomains); // [\"io\"]\n```\n\n### ⚠️ `domain` can also be `undefined`\n\n```javascript\nconst { subDomains, domain, topLevelDomains } = parseDomain(\"co.uk\");\n\nconsole.log(subDomains); // []\nconsole.log(domain); // undefined\nconsole.log(topLevelDomains); // [\"co\", \"uk\"]\n```\n\n### ⚠️ `\"\"` is a valid (but reserved) domain\n\nThe empty string `\"\"` represents the [DNS root](https://en.wikipedia.org/wiki/DNS_root_zone) and is considered to be valid. `parseResult.type` will be `ParseResultType.Reserved` in that case:\n\n```javascript\nconst { type, subDomains, domain, topLevelDomains } = parseDomain(\"\");\n\nconsole.log(type === ParseResultType.Reserved); // true\nconsole.log(subDomains); // []\nconsole.log(domain); // undefined\nconsole.log(topLevelDomains); // []\n```\n\n## API\n\n🧩 = JavaScript export\u003cbr\u003e\n🧬 = TypeScript export\n\n\u003ch3 id=\"api-js-parseDomain\"\u003e\n🧩 \u003ccode\u003eexport parseDomain(hostname: string | typeof \u003ca href=\"#api-js-NO_HOSTNAME\"\u003eNO_HOSTNAME\u003c/a\u003e, options?: \u003ca href=\"#api-ts-ParseDomainOptions\"\u003eParseDomainOptions\u003c/a\u003e): \u003ca href=\"#api-ts-ParseResult\"\u003eParseResult\u003c/a\u003e\u003c/code\u003e\n\u003c/h3\u003e\n\nTakes a hostname (e.g. `\"www.example.com\"`) and returns a [`ParseResult`](#api-ts-ParseResult). The hostname must only contain basic latin letters, digits, hyphens and dots. International hostnames must be puny-encoded. Does not throw an error, even with invalid input.\n\n```javascript\nimport { parseDomain } from \"parse-domain\";\n\nconst parseResult = parseDomain(\"www.example.com\");\n```\n\nUse `Validation.Lax` if you want to allow all characters:\n\n```javascript\nimport { parseDomain, Validation } from \"parse-domain\";\n\nconst parseResult = parseDomain(\"_jabber._tcp.gmail.com\", {\n  validation: Validation.Lax,\n});\n```\n\n\u003ch3 id=\"api-js-fromUrl\"\u003e\n🧩 \u003ccode\u003eexport fromUrl(input: string): string | typeof \u003ca href=\"#api-js-NO_HOSTNAME\"\u003eNO_HOSTNAME\u003c/a\u003e\u003c/code\u003e\n\u003c/h3\u003e\n\nTakes a URL-like string and tries to extract the hostname. Requires the global [`URL` constructor](https://developer.mozilla.org/en-US/docs/Web/API/URL) to be available on the platform. Returns the [`NO_HOSTNAME`](#api-js-NO_HOSTNAME) symbol if the input was not a string or the hostname could not be extracted. Take a look [at the test suite](/src/from-url.test.ts) for some examples. Does not throw an error, even with invalid input.\n\n\u003ch3 id=\"api-js-NO_HOSTNAME\"\u003e\n🧩 \u003ccode\u003eexport NO_HOSTNAME: unique symbol\u003c/code\u003e\n\u003c/h3\u003e\n\n`NO_HOSTNAME` is a symbol that is returned by [`fromUrl`](#api-js-fromUrl) when it was not able to extract a hostname from the given string. When passed to [`parseDomain`](#api-js-parseDomain), it will always yield a [`ParseResultInvalid`](#api-ts-ParseResultInvalid).\n\n\u003ch3 id=\"api-ts-ParseDomainOptions\"\u003e\n🧬 \u003ccode\u003eexport type ParseDomainOptions\u003c/code\u003e\n\u003c/h3\u003e\n\n```ts\nexport type ParseDomainOptions = {\n  /** If no validation is specified, Validation.Strict will be used. */\n  validation?: Validation;\n};\n```\n\n\u003ch3 id=\"api-js-Validation\"\u003e\n🧩 \u003ccode\u003eexport Validation\u003c/code\u003e\n\u003c/h3\u003e\n\nAn object that holds all possible [Validation](#api-ts-Validation) `validation` values:\n\n```javascript\nexport const Validation = {\n  /**\n   * Allows any octets as labels but still restricts the length of labels and\n   * the overall domain.\n   *\n   * @see https://www.rfc-editor.org/rfc/rfc2181#section-11\n   */\n  Lax: \"LAX\",\n\n  /**\n   * Only allows ASCII letters, digits and hyphens (aka LDH), forbids hyphens at\n   * the beginning or end of a label and requires top-level domain names not to\n   * be all-numeric.\n   *\n   * This is the default if no validation is configured.\n   *\n   * @see https://datatracker.ietf.org/doc/html/rfc3696#section-2\n   */\n  Strict: \"STRICT\",\n};\n```\n\n\u003ch3 id=\"api-ts-Validation\"\u003e\n🧬 \u003ccode\u003eexport Validation\u003c/code\u003e\n\u003c/h3\u003e\n\nThis type represents all possible `validation` values.\n\n\u003ch3 id=\"api-ts-ParseResult\"\u003e\n🧬 \u003ccode\u003eexport ParseResult\u003c/code\u003e\n\u003c/h3\u003e\n\nA `ParseResult` is either a [`ParseResultInvalid`](#api-ts-ParseResultInvalid), [`ParseResultIp`](#api-ts-ParseResultIp), [`ParseResultReserved`](#api-ts-ParseResultReserved), [`ParseResultNotListed`](#api-ts-ParseResultNotListed) or [`ParseResultListed`](#api-ts-ParseResultListed).\n\nAll parse results have a `type` property that is either `\"INVALID\"`, `\"IP\"`,`\"RESERVED\"`,`\"NOT_LISTED\"`or`\"LISTED\"`. Use the exported [ParseResultType](#api-js-ParseResultType) to check for the type instead of checking against string literals.\n\nAll parse results also have a `hostname` property that provides access to the sanitized hostname that was passed to [`parseDomain`](#api-js-parseDomain).\n\n\u003ch3 id=\"api-js-ParseResultType\"\u003e\n🧩 \u003ccode\u003eexport ParseResultType\u003c/code\u003e\n\u003c/h3\u003e\n\nAn object that holds all possible [ParseResult](#api-ts-ParseResult) `type` values:\n\n```javascript\nconst ParseResultType = {\n  Invalid: \"INVALID\",\n  Ip: \"IP\",\n  Reserved: \"RESERVED\",\n  NotListed: \"NOT_LISTED\",\n  Listed: \"LISTED\",\n};\n```\n\n\u003ch3 id=\"api-ts-ParseResultType\"\u003e\n🧬 \u003ccode\u003eexport ParseResultType\u003c/code\u003e\n\u003c/h3\u003e\n\nThis type represents all possible [ParseResult](#api-ts-ParseResult) `type` values.\n\n\u003ch3 id=\"api-ts-ParseResultInvalid\"\u003e\n🧬 \u003ccode\u003eexport ParseResultInvalid\u003c/code\u003e\n\u003c/h3\u003e\n\nDescribes the shape of the parse result that is returned when the given hostname does not adhere to [RFC 1034](https://tools.ietf.org/html/rfc1034):\n\n- The hostname is not a string\n- The hostname is longer than 253 characters\n- A domain label is shorter than 1 character\n- A domain label is longer than 63 characters\n- A domain label contains a character that is not a basic latin character, digit or hyphen\n\n```ts\ntype ParseResultInvalid = {\n  type: ParseResultType.INVALID;\n  hostname: string | typeof NO_HOSTNAME;\n  errors: Array\u003cValidationError\u003e;\n};\n```\n\n\u003ch3 id=\"api-ts-ValidationError\"\u003e\n🧬 \u003ccode\u003eexport ValidationError\u003c/code\u003e\n\u003c/h3\u003e\n\nDescribes the shape of a validation error as returned by [`parseDomain`](#api-js-parseDomain)\n\n```ts\ntype ValidationError = {\n  type: ValidationErrorType;\n  message: string;\n  column: number;\n};\n```\n\n\u003ch3 id=\"api-js-ValidationErrorType\"\u003e\n🧩 \u003ccode\u003eexport ValidationErrorType\u003c/code\u003e\n\u003c/h3\u003e\n\nAn object that holds all possible [ValidationError](#api-ts-ValidationError) `type` values:\n\n```javascript\nconst ValidationErrorType = {\n  NoHostname: \"NO_HOSTNAME\",\n  DomainMaxLength: \"DOMAIN_MAX_LENGTH\",\n  LabelMinLength: \"LABEL_MIN_LENGTH\",\n  LabelMaxLength: \"LABEL_MAX_LENGTH\",\n  LabelInvalidCharacter: \"LABEL_INVALID_CHARACTER\",\n  LastLabelInvalid: \"LAST_LABEL_INVALID\",\n};\n```\n\n\u003ch3 id=\"api-ts-ValidationErrorType\"\u003e\n🧬 \u003ccode\u003eexport ValidationErrorType\u003c/code\u003e\n\u003c/h3\u003e\n\nThis type represents all possible `type` values of a [ValidationError](#api-ts-ValidationError).\n\n\u003ch3 id=\"api-ts-ParseResultIp\"\u003e\n🧬 \u003ccode\u003eexport ParseResultIp\u003c/code\u003e\n\u003c/h3\u003e\n\nThis type describes the shape of the parse result that is returned when the given hostname was an IPv4 or IPv6 address.\n\n```ts\ntype ParseResultIp = {\n  type: ParseResultType.Ip;\n  hostname: string;\n  ipVersion: 4 | 6;\n};\n```\n\nAccording to [RFC 3986](https://tools.ietf.org/html/rfc3986#section-3.2.2), IPv6 addresses need to be surrounded by `[` and `]` in URLs. [`parseDomain`](#api-js-parseDomain) accepts both IPv6 address with and without square brackets:\n\n```js\n// Recognized as IPv4 address\nparseDomain(\"192.168.0.1\");\n// Both are recognized as proper IPv6 addresses\nparseDomain(\"::\");\nparseDomain(\"[::]\");\n```\n\n\u003ch3 id=\"api-ts-ParseResultReserved\"\u003e\n🧬 \u003ccode\u003eexport ParseResultReserved\u003c/code\u003e\n\u003c/h3\u003e\n\nThis type describes the shape of the parse result that is returned when the given hostname\n\n- is the root domain (the empty string `\"\"`)\n- belongs to the top-level domain `localhost`, `local`, `example`, `invalid` or `test`\n\n```ts\ntype ParseResultReserved = {\n  type: ParseResultType.Reserved;\n  hostname: string;\n  labels: Array\u003cstring\u003e;\n};\n```\n\n⚠️ Reserved IPs, such as `127.0.0.1`, will not be reported as reserved, but as \u003ca href=\"#-export-parseresultip\"\u003e`ParseResultIp`\u003c/a\u003e. See [#117](https://github.com/peerigon/parse-domain/issues/117).\n\n\u003ch3 id=\"api-ts-ParseResultNotListed\"\u003e\n🧬 \u003ccode\u003eexport ParseResultNotListed\u003c/code\u003e\n\u003c/h3\u003e\n\nDescribes the shape of the parse result that is returned when the given hostname is valid and does not belong to a reserved top-level domain, but is not listed in the downloaded public suffix list.\n\n```ts\ntype ParseResultNotListed = {\n  type: ParseResultType.NotListed;\n  hostname: string;\n  labels: Array\u003cstring\u003e;\n};\n```\n\n\u003ch3 id=\"api-ts-ParseResultListed\"\u003e\n🧬 \u003ccode\u003eexport ParseResultListed\u003c/code\u003e\n\u003c/h3\u003e\n\nDescribes the shape of the parse result that is returned when the given hostname belongs to a top-level domain that is listed in the public suffix list.\n\n```ts\ntype ParseResultListed = {\n  type: ParseResultType.Listed;\n  hostname: string;\n  labels: Array\u003cstring\u003e;\n  subDomains: Array\u003cstring\u003e;\n  domain: string | undefined;\n  topLevelDomains: Array\u003cstring\u003e;\n  icann: {\n    subDomains: Array\u003cstring\u003e;\n    domain: string | undefined;\n    topLevelDomains: Array\u003cstring\u003e;\n  };\n};\n```\n\n## License\n\nMIT\n\n## Sponsors\n\n[\u003cimg src=\"https://assets.peerigon.com/peerigon/logo/peerigon-logo-flat-spinat.png\" width=\"150\" /\u003e](https://peerigon.com)\n","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeerigon%2Fparse-domain","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpeerigon%2Fparse-domain","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeerigon%2Fparse-domain/lists"}