{"id":25703214,"url":"https://github.com/sneko/hyperlink-middleware","last_synced_at":"2025-04-30T06:45:47.595Z","repository":{"id":38617480,"uuid":"498291053","full_name":"sneko/hyperlink-middleware","owner":"sneko","description":"Modify hyperlinks on the fly with middlewares","archived":false,"fork":false,"pushed_at":"2024-11-04T16:35:37.000Z","size":616,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-15T13:28:08.978Z","etag":null,"topics":["analytics","anchor","append","convert","firebase","gtm","hyperlink","inject","link","listener","merge","middleware","observer","parameters","transform","url","utm","watch","wrap"],"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/sneko.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2022-05-31T10:35:48.000Z","updated_at":"2024-11-04T16:34:58.000Z","dependencies_parsed_at":"2022-09-26T21:01:56.103Z","dependency_job_id":null,"html_url":"https://github.com/sneko/hyperlink-middleware","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sneko%2Fhyperlink-middleware","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sneko%2Fhyperlink-middleware/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sneko%2Fhyperlink-middleware/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sneko%2Fhyperlink-middleware/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sneko","download_url":"https://codeload.github.com/sneko/hyperlink-middleware/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240609995,"owners_count":19828708,"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":["analytics","anchor","append","convert","firebase","gtm","hyperlink","inject","link","listener","merge","middleware","observer","parameters","transform","url","utm","watch","wrap"],"created_at":"2025-02-25T05:28:29.774Z","updated_at":"2025-02-25T05:28:30.818Z","avatar_url":"https://github.com/sneko.png","language":"TypeScript","readme":"# hyperlink-middleware\n\n[![npm package][npm-img]][npm-url]\n[![Build Status][build-img]][build-url]\n[![Downloads][downloads-img]][downloads-url]\n[![Issues][issues-img]][issues-url]\n[![Code Coverage][codecov-img]][codecov-url]\n[![Commitizen Friendly][commitizen-img]][commitizen-url]\n[![Semantic Release][semantic-release-img]][semantic-release-url]\n\n\u003e This package allows modifying on the fly the hyperlink destination without modifying the HTML thanks to middlewares. It includes some middlewares already but you are free to implement your own.\n\u003e\n\u003e Usage examples:\n\u003e\n\u003e - Automatically add UTM parameters when a user clicks a hyperlink to a third-party\n\u003e - Automatically wrap your links to keep track of the session across browsers flow (this can be done on your own, or by using known services like `Firebase Dynamic Links`, `branch.io`...)\n\u003e - Both at same time! (since they are simple middlewares that can be chained)\n\u003e - _... there is no limit, depends on your need :)_\n\u003e\n\u003e Ease of use:\n\u003e\n\u003e - It does not modify the HTML, so:\n\u003e   - the SEO crawlers will reference the right destination link\n\u003e   - if the user focuses on the link address or decide to copy it manually he will copy the original link\n\u003e - It handles at initialization all the existing hyperlinks (`\u003ca ...\u003e\u003c/a\u003e` of your HTML), and it will also watch any new hyperlink added after the initialization\n\u003e - It can be used within your own framework logic if you are dealing with either custom hyperlinks or JavaScript redirections\n\u003e - If you don't access the full source code you could include a remote script in your CMS/blog to set it up, same if you are dealing with tools like `Google Tag Manager`\n\u003e - This package may already embeds the middleware you are looking for! If the community adopts/develops a middleware for a common usage, we will do our best to embed it in the library\n\n## Install\n\nWith NPM:\n\n```bash\nnpm install hyperlink-middleware\n```\n\nWith Yarn:\n\n```bash\nyarn add hyperlink-middleware\n```\n\n## Usage\n\n### In a Node.js environment\n\nHere a basic example with any middleware that you can chain. It's just to give a taste of what's possible :)\n\n```ts\nimport {\n  HyperlinkWatcher,\n  MiddlewareComposition,\n  SetUtmParametersMiddleware,\n} from 'hyperlink-middleware';\n\n// Here it's just a fake middleware, import the ones you want to use (you can create your own)\nimport { YourFirstMiddleware } from './your-own-middlewares';\n\n// Declare which middlewares you want to chain\nconst composition = new MiddlewareComposition(\n  YourFirstMiddleware(),\n  SetUtmParametersMiddleware({\n    params: {\n      utm_source: 'your-website',\n      utm_medium: 'referral',\n      utm_campaign: 'my-campaign',\n    },\n  })\n);\n\n// To watch all hyperlinks from the HTML, we use the default watcher\n// Note: the composition can be used directly and without any `HyperlinkWatcher` instance if you don't want to watch HTML hyperlinks, you could use for example `const transformedLink = composition.applyToLink('https://example.com')`\nconst watcher = new HyperlinkWatcher({\n  composition: composition,\n});\nwatcher.watch();\n```\n\n**For a deeper overview of the usage please have a look at [./examples/set-utm-on-specific-links.ts](./examples/set-utm-on-specific-links.ts).**\n\n_More examples are available into [the example folder](examples/) or into [the test folder](examples/)._\n\n### Included directly in the HTML\n\nIf you are just able to append a script to a blog or a CMS, or if you are using Google Tag Manager you could follow this example:\n\n```html\n\u003cscript src=\"https://unpkg.com/hyperlink-middleware@latest/dist/umd/index.min.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n  var composition = new HyperlinkMiddleware.MiddlewareComposition(\n    HyperlinkMiddleware.SetUtmParametersMiddleware({\n      params: {\n        utm_source: 'your-website',\n        utm_medium: 'referral',\n        utm_campaign: 'my-campaign',\n      },\n    })\n  );\n\n  var watcher = new HyperlinkMiddleware.HyperlinkWatcher({\n    composition: composition,\n  });\n  watcher.watch();\n\u003c/script\u003e\n```\n\n_Note: adjust the `latest` version if you want to stick to a specific one :)_\n\n## Available middlewares inside this library\n\n- `SetUtmParametersMiddleware(...)`: hyperlinks will be merged with specified UTM parameters. It makes easier tagging all links with parameters that identify your frontend as the origin. **It's likely you would use the `FilterWrapper(...)` to wrap this middleware** to be sure it's not applied on your own website links or other websites of your company that is watched in the same \"analytics account property\".\n\n- `FormatFirebaseDynamicLinksMiddleware(...)`: allows generating a Firebase Dynamic Link to keep a consistent flow for cross-browsers sessions. You should use it with `FilterWrapper(...)` because the generation should only apply for specific links that are targeting your native application.\n\n- `IgnoreFollowingsMiddleware(...)`: in case you want to stop the middlewares chain based on the hyperlink input. It avoids using multiple `FilterWrapper(...)` with the same rules around all following middlewares\n\n- `SetMissingUrlProtocolMiddleware(...)`: some websites used links starting with `//example.com` so it would probably break following middlewares. This middleware will add a protocol to the links so it does not throw an error in the following middlewares. _It should be used before all other middlewares._\n\n- `FilterWrapper(...)`: it's used to wrap any of the middlewares in this list to specify on which hyperlinks it should apply or not. It uses the new `URLPattern` standard that offers the ease to manage match URLs. Example: `FilterWrapper(yourMiddleware, { applyPatterns: [new URLPattern({ hostname: 'example.com' })]})`\n\n_Do not hesitate to share yours so we can add it to the list!_\n\n## API \u0026 documentation\n\nYou can find all available methods and definitions [by clicking here](docs/TYPINGS.md)\n\n_Note: this technical documentation is auto-generated_\n\n## Compatibility with custom hyperlinks from frameworks\n\nIn case your framework does not use the standard HTML element `\u003ca\u003e\u003c/a\u003e` it's likely you will have to make the bridge between the framework and this library.\n\nIf you do integrate the `MiddlewareComposition` class with a specific framework please do not hesitate to share your work, we may publish it!\n\n## Advanced usage\n\n### Development \u0026 pull requests\n\nIf you are willing to contribute to this library, you can easily watch tests while developing:\n\n```bash\nyarn run test:watch\n```\n\nIn you intend while developing on this library to test directly into a parent project (thanks to `yarn link ...`), you can use the following so modifications are reflected with just a page refresh (it can be used in parallel to the previous command):\n\n```\nyarn run dev\n```\n\n_Note: in case your \"parent project\" uses CommonJS it's required to use `yarn run dev:cjs`_\n\n**[IMPORTANT] To develop, and in case your package manager is `npm` you should be able to install dependencies to do some testing... but to submit a pull request please use `yarn` because our dependency tree is managed through `yarn.lock` (and not `package-lock.json` from `npm`).**\n\nThanks in advance! 🚀\n\n[build-img]: https://github.com/sneko/hyperlink-middleware/actions/workflows/release.yml/badge.svg\n[build-url]: https://github.com/sneko/hyperlink-middleware/actions/workflows/release.yml\n[downloads-img]: https://img.shields.io/npm/dt/hyperlink-middleware\n[downloads-url]: https://www.npmtrends.com/hyperlink-middleware\n[npm-img]: https://img.shields.io/npm/v/hyperlink-middleware\n[npm-url]: https://www.npmjs.com/package/hyperlink-middleware\n[issues-img]: https://img.shields.io/github/issues/sneko/hyperlink-middleware\n[issues-url]: https://github.com/sneko/hyperlink-middleware/issues\n[codecov-img]: https://codecov.io/gh/sneko/hyperlink-middleware/branch/main/graph/badge.svg\n[codecov-url]: https://codecov.io/gh/sneko/hyperlink-middleware\n[semantic-release-img]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg\n[semantic-release-url]: https://github.com/semantic-release/semantic-release\n[commitizen-img]: https://img.shields.io/badge/commitizen-friendly-brightgreen.svg\n[commitizen-url]: http://commitizen.github.io/cz-cli/\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsneko%2Fhyperlink-middleware","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsneko%2Fhyperlink-middleware","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsneko%2Fhyperlink-middleware/lists"}