Skip to content

Commit a3dcd49

Browse files
authored
Added url-referrer-parser package (#516)
ref https://linear.app/ghost/issue/PROD-4/ The URL parsing logic previously contained within TryGhost/Ghost's member-attribution package has been pulled out into a more generic library for url referrer parsing. This makes it available to ancillary services while maintaining the same mapping/logic across Ghost.
1 parent 2d09a1c commit a3dcd49

19 files changed

+40371
-2063
lines changed

package-lock.json

Lines changed: 26095 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
module.exports = {
2+
extends: [
3+
'eslint:recommended',
4+
'plugin:@typescript-eslint/recommended'
5+
],
6+
parser: '@typescript-eslint/parser',
7+
plugins: ['@typescript-eslint'],
8+
parserOptions: {
9+
ecmaVersion: 2022,
10+
sourceType: 'module',
11+
},
12+
env: {
13+
node: true,
14+
es2022: true
15+
},
16+
ignorePatterns: ['dist', '*.config.ts'],
17+
rules: {
18+
'no-console': 'warn',
19+
'@typescript-eslint/explicit-function-return-type': 'off',
20+
'@typescript-eslint/no-explicit-any': 'warn',
21+
'@typescript-eslint/no-unused-vars': ['error', {
22+
'argsIgnorePattern': '^_',
23+
'varsIgnorePattern': '^_'
24+
}]
25+
}
26+
};
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Build output
2+
dist/
3+
4+
# Coverage directory
5+
coverage/
6+
7+
# Test artifacts
8+
.vitest/
9+
10+
# Log files
11+
*.log
12+
npm-debug.log*
13+
yarn-debug.log*
14+
yarn-error.log*
15+
16+
# Editor directories and files
17+
.vscode/
18+
.idea/
19+
*.sublime-*
20+
21+
# OS specific files
22+
.DS_Store
23+
Thumbs.db
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Source files
2+
*.ts
3+
!*.d.ts
4+
lib/*.ts
5+
!lib/*.d.ts
6+
7+
# Development files
8+
test/
9+
coverage/
10+
.eslintrc.js
11+
.eslintcache
12+
tsconfig.json
13+
.editorconfig
14+
.github
15+
.npmignore
16+
.gitignore
17+
18+
# GitHub files
19+
.github/
20+
*.md
21+
!README.md
22+
23+
# Configuration
24+
.eslintignore
25+
.travis.yml
26+
.vscode
27+
28+
# Logs
29+
logs
30+
*.log
31+
npm-debug.log*
32+
yarn-debug.log*
33+
yarn-error.log*
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Referrer Parser
2+
3+
A simple library for parsing referrer URLs to identify their source and medium.
4+
5+
## Installation
6+
7+
```bash
8+
npm install @tryghost/referrer-parser
9+
# or
10+
yarn add @tryghost/referrer-parser
11+
```
12+
13+
## Usage
14+
15+
### Basic Usage
16+
17+
```javascript
18+
const { parse } = require('@tryghost/referrer-parser');
19+
20+
// Parse a referrer URL
21+
const result = parse('https://www.google.com/search?q=ghost+cms');
22+
console.log(result);
23+
// {
24+
// referrerSource: 'Google',
25+
// referrerMedium: 'search',
26+
// referrerUrl: 'www.google.com'
27+
// }
28+
```
29+
30+
### With Site Configuration
31+
32+
```javascript
33+
const { parse } = require('@tryghost/referrer-parser');
34+
35+
// Parse with site configuration to detect internal traffic
36+
const result = parse(
37+
'https://example.com/blog?utm_source=newsletter&utm_medium=email',
38+
{
39+
siteUrl: 'https://example.com',
40+
adminUrl: 'https://example.com/ghost'
41+
}
42+
);
43+
```
44+
45+
### Using the ReferrerParser Class
46+
47+
For more advanced usage, you can use the `ReferrerParser` class directly:
48+
49+
```javascript
50+
const { ReferrerParser } = require('@tryghost/referrer-parser');
51+
52+
// Create a parser instance
53+
const parser = new ReferrerParser({
54+
siteUrl: 'https://example.com',
55+
adminUrl: 'https://example.com/ghost'
56+
});
57+
58+
// Parse multiple URLs with the same configuration
59+
const result1 = parser.parse('https://www.google.com/search?q=ghost+cms');
60+
const result2 = parser.parse('https://twitter.com/ghostcms');
61+
```
62+
63+
## Features
64+
65+
- Identifies sources and mediums from known referrers
66+
- Handles special cases for Ghost Explore and Ghost Newsletters
67+
- Detects UTM parameters
68+
- Works with or without site/admin URL configuration
69+
- TypeScript support
70+
71+
## TypeScript Support
72+
73+
This package is fully written in TypeScript and provides its own type definitions.
74+
75+
```typescript
76+
import { parse, ReferrerParser, ReferrerData, ParserOptions } from '@tryghost/referrer-parser';
77+
78+
// Parse a referrer URL with type safety
79+
const result: ReferrerData = parse('https://www.google.com/search?q=ghost+cms');
80+
console.log(result.referrerSource); // 'Google'
81+
console.log(result.referrerMedium); // 'search'
82+
console.log(result.referrerUrl); // 'www.google.com'
83+
84+
// Configure the parser with typed options
85+
const options: ParserOptions = {
86+
siteUrl: 'https://example.com',
87+
adminUrl: 'https://example.com/ghost'
88+
};
89+
90+
// Create a parser instance with TypeScript
91+
const parser = new ReferrerParser(options);
92+
const customResult = parser.parse('https://example.com/blog?utm_source=newsletter');
93+
```
94+
95+
## License
96+
97+
MIT
98+
99+
## Testing
100+
101+
Run the tests with:
102+
103+
```bash
104+
yarn test
105+
```
106+
107+
This will run the test suite using Mocha and report on test coverage.

packages/url-referrer-parser/index.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { ReferrerParser } from './lib/ReferrerParser';
2+
import type { ReferrerData, ParserOptions } from './lib/ReferrerParser';
3+
4+
/**
5+
* Parse a referrer URL to get source, medium and hostname
6+
*
7+
* @param referrerUrl - URL of the referrer to parse
8+
* @param options - Configuration options
9+
* @returns Parsed referrer data with source, medium and URL
10+
*
11+
* @example
12+
* // Basic usage
13+
* const result = parse('https://www.google.com/search?q=ghost+cms');
14+
* // result: { referrerSource: 'Google', referrerMedium: 'search', referrerUrl: 'www.google.com' }
15+
*
16+
* @example
17+
* // With site configuration
18+
* const result = parse('https://example.com/blog?utm_source=newsletter', {
19+
* siteUrl: 'https://example.com'
20+
* });
21+
*/
22+
function parse(referrerUrl: string, options: ParserOptions = {}): ReferrerData {
23+
const parser = new ReferrerParser(options);
24+
return parser.parse(referrerUrl);
25+
}
26+
27+
export {
28+
parse,
29+
ReferrerParser
30+
};
31+
32+
export type {
33+
ReferrerData,
34+
ParserOptions
35+
};

0 commit comments

Comments
 (0)