# url-unshort

> Expand urls provided by url shortening services.

Latest version **6.1.0** (published 2022-10-21) · MIT license · 0 weekly downloads

## Install

```sh
npm install url-unshort
pnpm add url-unshort
yarn add url-unshort
bun add url-unshort
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 6.1.0 |
| Published | 2022-10-21 |
| First published | 2015-08-16 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | CommonJS |
| Node | >=14 |
| Dependencies | 8 |
| Unpacked size | 24.1 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 116 |
| Maintainers | vitaly |
| Keywords | unshort, expand, url |

## Links

- npm: https://www.npmjs.com/package/url-unshort
- Repository: https://github.com/nodeca/url-unshort
- Homepage: https://github.com/nodeca/url-unshort#readme
- Issues: https://github.com/nodeca/url-unshort/issues
- npm.io page: https://npm.io/package/url-unshort

## Dependencies (8)

- [got](https://npm.io/package/got.md) ^11.8.3
- [mdurl](https://npm.io/package/mdurl.md) ^1.0.0
- [cheerio](https://npm.io/package/cheerio.md) ^1.0.0-rc.12
- [js-yaml](https://npm.io/package/js-yaml.md) ^4.1.0
- [punycode](https://npm.io/package/punycode.md) ^2.0.1
- [lodash.merge](https://npm.io/package/lodash.merge.md) ^4.6.2
- [is-google-domain](https://npm.io/package/is-google-domain.md) ^1.0.0
- [escape-string-regexp](https://npm.io/package/escape-string-regexp.md) ^4.0.0

## Alternatives

- [base64url](https://npm.io/package/base64url.md) — 6.1M weekly downloads
- [get-installed-path](https://npm.io/package/get-installed-path.md) — 502.9K weekly downloads
- [@uppy/url](https://npm.io/package/@uppy/url.md) — 185.8K weekly downloads
- [@d3fc/d3fc-shape](https://npm.io/package/@d3fc/d3fc-shape.md) — 16.2K weekly downloads
- [localizer](https://npm.io/package/localizer.md) — 226 weekly downloads

## Recent versions

- 6.1.0 (latest) — 2022-10-21
- 6.0.0 — 2022-05-17
- 5.0.0 — 2017-06-08
- 4.1.0 — 2017-06-08
- 4.0.0 — 2016-12-08
- 3.1.0 — 2016-12-05
- 3.0.0 — 2016-11-27
- 2.1.0 — 2016-07-15
- 2.0.0 — 2016-05-24
- 1.1.3 — 2016-01-17
- 1.1.2 — 2015-12-07
- 1.1.1 — 2015-11-27
- 1.1.0 — 2015-11-25
- 1.0.1 — 2015-10-28
- 1.0.0 — 2015-08-16

## README

# url-unshort

[![CI](https://github.com/nodeca/url-unshort/actions/workflows/ci.yml/badge.svg)](https://github.com/nodeca/url-unshort/actions/workflows/ci.yml)
[![NPM version](https://img.shields.io/npm/v/url-unshort.svg?style=flat)](https://www.npmjs.org/package/url-unshort)

> This library expands urls provided by url shortening services (see [full list](https://github.com/nodeca/url-unshort/blob/master/domains.yml)).


## Why should I use it?

It has been [argued](http://joshua.schachter.org/2009/04/on-url-shorteners) that
“shorteners are bad for the ecosystem as a whole”. In particular, if you're
running a forum or a blog, such services might cause trouble for your users:

 - such links load slower than usual (shortening services require an extra DNS
   and HTTP request)
 - it adds another point of failure (should this service go down, the links will
   die; [301works](https://archive.org/details/301works) tries to solve this,
   but it's better to avoid the issue in the first place)
 - users don't see where the link points to (tinyurl previews don't *really*
   solve this)
 - it can be used for user activity tracking
 - certain shortening services are displaying ads before redirect
 - shortening services can be malicious or be hacked so they could redirect to
   a completely different place next month

Also, short links are used to bypass the spam filters. So if you're implementing
a domain black list for your blog comments, you might want to check where all
those short links *actually* point to.


## Installation

```js
$ npm install url-unshort
```

## Basic usage

```js
const uu = require('url-unshort')()

try {
  const url = await uu.expand('http://goo.gl/HwUfwd')

  if (url) console.log('Original url is: ${url}')
  else console.log('This url can\'t be expanded')

} catch (err) {
  console.log(err);
}
```

## Retrying errors

Temporary network errors are retried automatically once (`options.request.retry=1` by default).

You may choose to retry some errors after an extended period of time using code like this:

```js
const uu = require('url-unshort')()
const { isErrorFatal } = require('url-unshort')
let tries = 0

while (true) {
  try {
    tries++
    const url = await uu.expand('http://goo.gl/HwUfwd')

    // If url is expanded, it returns string (expanded url);
    // "undefined" is returned if service is unknown
    if (url) console.log(`Original url is: ${url}`)
    else console.log("This url can't be expanded")
    break

  } catch (err) {
    // use isErrorFatal function to check if url can be retried or not
    if (isErrorFatal(err)) {
      // this url can't be expanded (e.g. 404 error)
      console.log(`Unshort error (fatal): ${err}`)
      break
    }

    // Temporary error, trying again in 10 minutes
    // (5xx errors, ECONNRESET, etc.)
    console.log(`Unshort error (retrying): ${err}`)
    if (tries >= 3) {
      console.log(`Too many errors, aborting`)
      break
    }
    await new Promise(resolve => setTimeout(resolve, 10 * 60 * 1000))
  }
}
```


## API

### Creating an instance

When you create an instance, you can pass an options object to fine-tune unshortener behavior.

```js
const uu = require('url-unshort')({
  nesting: 3,
  cache: {
    get: async key => {},
    set: async (key, value) => {}
  }
});
```

Available options are:

- **nesting** (Number, default: `3`) - stop resolving urls
  when `nesting` amount of redirects is reached.

  It happens if one shortening service refers to a link belonging to
  another shortening service which in turn points to yet another one
  and so on.

  If this limit is reached, `expand()` will return an error.

- **cache** (Object) - set a custom cache implementation (e.g. if you wish
  to store urls in Redis).

  You need to specify 2 promise-based functions, `set(key, value)` & `get(key)`.

- **request** (Object) - default options for
  [got](https://github.com/sindresorhus/got) in `.request()` method. Can be
  used to set custom `User-Agent` and other headers.


### uu.expand(url) -> Promise

Expand an URL supplied. If we don't know how to expand it, returns `null`.

```js
const uu = require('url-unshort')();

try {
  const url = await uu.expand('http://goo.gl/HwUfwd')

  if (url) console.log('Original url is: ${url}')
  // no shortening service or an unknown one is used
  else console.log('This url can\'t be expanded')

} catch (err) {
  console.log(err)
}
```

### uu.add(domain [, options])

Add a new url shortening service (domain name or an array of them) to the white
list of domains we know how to expand.

```js
uu.add([ 'tinyurl.com', 'bit.ly' ])
```

The default behavior will be to follow the URL with a HEAD request and check
the status code. If it's `3xx`, return the `Location` header. You can override
this behavior by supplying your own function in options.

Options:

- **aliases** (Array) - Optional. List of alternate domaine names, if exist.
- **match** (String|RegExp) - Optional. Custom regexp to use for URL match.
  For example, if you need to match wildcard prefixes or country-specific
  suffixes. If used with `validate`, then regexp may be not precise, only to
  filter out noise. If `match` not passed, then exact value auto-generated from
  `domain` & `aliases`.
- **validate** (Function) - Optional. Does exact URL check, when complex logic
  required and regexp is not enouth (when `match` is only preliminary). See
  `./lib/providers/*` for example.
- **fetch**  (Function) - Optional. Specifies custom function to retrieve expanded
  url, see `./lib/providers/*` for examples. If not set - default method used
  (it checks 30X redirect codes & `<meta http-equiv="refresh" content='...'>`
  in HTML).
- **link_selector** (String) - Optional. Some sites may return HTML pages instead
  of 302 redirects. This option allows use jquery-like selector to extract
  `<a href="...">` value.

Example:

```js
const uu = require('url-unshort')()

uu.add('notlong.com', {
  match: '^(https?:)//[a-zA-Z0-9_-]+[.]notlong[.]com/'
})

uu.add('tw.gs', {
  link_selector: '#lurllink > a'
})
```

### uu.remove(domain)

(String|Array|Undefined). Opposite to `.add()`. Remove selected domains from
instance config. If no params passed - remove everything.


## Security considerations

Only `http` and `https` protocols are allowed in the output. Browsers technically
support redirects to other protocols (like `ftp` or `magnet`), but most url
shortening services limit redirects to `http` and `https` anyway. In case
service redirects to an unknown protocol, `expand()` will return an error.

`expand()` function returns url from the url shortening **as is** without any
escaping or even ensuring that the url is valid. If you want to guarantee a
valid url as an output, you're encouraged to re-encode it like this:

```js
var URL = require('url');

url = await uu.expand('http://goo.gl/HwUfwd')

if (url) url = URL.format(URL.parse(url, null, true))

console.log(url));
```

## License

[MIT](https://raw.github.com/nodeca/url-unshort/master/LICENSE)

---
_Source: https://npm.io/package/url-unshort · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
