url-sanitize 0.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. url_sanitize-0.1.2/.changeset/config.json +11 -0
  2. url_sanitize-0.1.2/.github/ISSUE_TEMPLATE/broken-url.yml +34 -0
  3. url_sanitize-0.1.2/.github/ISSUE_TEMPLATE/rule-source-request.yml +25 -0
  4. url_sanitize-0.1.2/.github/workflows/auto-tag.yml +35 -0
  5. url_sanitize-0.1.2/.github/workflows/ci.yml +63 -0
  6. url_sanitize-0.1.2/.github/workflows/release.yml +203 -0
  7. url_sanitize-0.1.2/.github/workflows/sync-clearurls.yml +64 -0
  8. url_sanitize-0.1.2/.gitignore +23 -0
  9. url_sanitize-0.1.2/.husky/pre-commit +4 -0
  10. url_sanitize-0.1.2/.husky/pre-push +4 -0
  11. url_sanitize-0.1.2/.npmrc +1 -0
  12. url_sanitize-0.1.2/AGENTS.md +95 -0
  13. url_sanitize-0.1.2/CLAUDE.md +1 -0
  14. url_sanitize-0.1.2/CONTRIBUTING.md +47 -0
  15. url_sanitize-0.1.2/Cargo.lock +403 -0
  16. url_sanitize-0.1.2/Cargo.toml +26 -0
  17. url_sanitize-0.1.2/LICENSE +21 -0
  18. url_sanitize-0.1.2/PKG-INFO +42 -0
  19. url_sanitize-0.1.2/README.md +154 -0
  20. url_sanitize-0.1.2/biome.json +29 -0
  21. url_sanitize-0.1.2/catalog/clearurls.json +10811 -0
  22. url_sanitize-0.1.2/conformance/clearurls-corpus.jsonl +46 -0
  23. url_sanitize-0.1.2/conformance/conformance.test.ts +168 -0
  24. url_sanitize-0.1.2/conformance/inputs/corpus.txt +69 -0
  25. url_sanitize-0.1.2/conformance/inputs/vectors.jsonl +32 -0
  26. url_sanitize-0.1.2/conformance/manifest.json +17 -0
  27. url_sanitize-0.1.2/conformance/properties.md +96 -0
  28. url_sanitize-0.1.2/conformance/schema.json +81 -0
  29. url_sanitize-0.1.2/conformance/vectors.jsonl +32 -0
  30. url_sanitize-0.1.2/crates/url-sanitize/Cargo.toml +22 -0
  31. url_sanitize-0.1.2/crates/url-sanitize/README.md +22 -0
  32. url_sanitize-0.1.2/crates/url-sanitize/catalog/clearurls.json +10811 -0
  33. url_sanitize-0.1.2/crates/url-sanitize/src/main.rs +241 -0
  34. url_sanitize-0.1.2/crates/url-sanitize/tests/conformance.rs +194 -0
  35. url_sanitize-0.1.2/crates/url-sanitize-core/Cargo.toml +20 -0
  36. url_sanitize-0.1.2/crates/url-sanitize-core/README.md +21 -0
  37. url_sanitize-0.1.2/crates/url-sanitize-core/src/catalog.rs +55 -0
  38. url_sanitize-0.1.2/crates/url-sanitize-core/src/compile.rs +165 -0
  39. url_sanitize-0.1.2/crates/url-sanitize-core/src/lib.rs +14 -0
  40. url_sanitize-0.1.2/crates/url-sanitize-core/src/sanitize.rs +194 -0
  41. url_sanitize-0.1.2/crates/url-sanitize-core/src/types.rs +113 -0
  42. url_sanitize-0.1.2/docs/clearurls-compat.md +65 -0
  43. url_sanitize-0.1.2/docs/license-model.md +39 -0
  44. url_sanitize-0.1.2/docs/non-goals.md +48 -0
  45. url_sanitize-0.1.2/docs/roadmap.md +309 -0
  46. url_sanitize-0.1.2/docs/spec.md +273 -0
  47. url_sanitize-0.1.2/docs/threat-model.md +37 -0
  48. url_sanitize-0.1.2/package.json +63 -0
  49. url_sanitize-0.1.2/packages/clearurls/LICENSE +33 -0
  50. url_sanitize-0.1.2/packages/clearurls/NOTICE +14 -0
  51. url_sanitize-0.1.2/packages/clearurls/README.md +40 -0
  52. url_sanitize-0.1.2/packages/clearurls/data/data.json +1984 -0
  53. url_sanitize-0.1.2/packages/clearurls/data/metadata.json +6 -0
  54. url_sanitize-0.1.2/packages/clearurls/package.json +38 -0
  55. url_sanitize-0.1.2/packages/clearurls/src/adapter.ts +84 -0
  56. url_sanitize-0.1.2/packages/clearurls/src/index.ts +18 -0
  57. url_sanitize-0.1.2/packages/clearurls/src/raw.ts +6 -0
  58. url_sanitize-0.1.2/packages/clearurls/src/types.ts +21 -0
  59. url_sanitize-0.1.2/packages/clearurls/tsconfig.json +9 -0
  60. url_sanitize-0.1.2/packages/cli/README.md +32 -0
  61. url_sanitize-0.1.2/packages/cli/package.json +28 -0
  62. url_sanitize-0.1.2/packages/cli/src/bin.ts +195 -0
  63. url_sanitize-0.1.2/packages/cli/tsconfig.json +9 -0
  64. url_sanitize-0.1.2/packages/core/README.md +47 -0
  65. url_sanitize-0.1.2/packages/core/package.json +31 -0
  66. url_sanitize-0.1.2/packages/core/src/index.ts +10 -0
  67. url_sanitize-0.1.2/packages/core/src/sanitize.ts +292 -0
  68. url_sanitize-0.1.2/packages/core/src/types.ts +84 -0
  69. url_sanitize-0.1.2/packages/core/test/sanitize.test.ts +83 -0
  70. url_sanitize-0.1.2/packages/core/tsconfig.json +9 -0
  71. url_sanitize-0.1.2/pnpm-lock.yaml +2694 -0
  72. url_sanitize-0.1.2/pnpm-workspace.yaml +5 -0
  73. url_sanitize-0.1.2/pyproject.toml +34 -0
  74. url_sanitize-0.1.2/python/README.md +20 -0
  75. url_sanitize-0.1.2/python/url_sanitize/__init__.py +55 -0
  76. url_sanitize-0.1.2/python/url_sanitize/__main__.py +15 -0
  77. url_sanitize-0.1.2/python/url_sanitize/bin/.gitkeep +1 -0
  78. url_sanitize-0.1.2/scripts/build-catalog.ts +34 -0
  79. url_sanitize-0.1.2/scripts/build-conformance.ts +163 -0
  80. url_sanitize-0.1.2/scripts/bump-version.mjs +40 -0
  81. url_sanitize-0.1.2/scripts/install.ps1 +25 -0
  82. url_sanitize-0.1.2/scripts/install.sh +29 -0
  83. url_sanitize-0.1.2/scripts/pre-push.sh +13 -0
  84. url_sanitize-0.1.2/sources/clearurls/sync.ts +104 -0
  85. url_sanitize-0.1.2/tsconfig.base.json +22 -0
  86. url_sanitize-0.1.2/tsconfig.json +5 -0
  87. url_sanitize-0.1.2/vitest.config.ts +7 -0
@@ -0,0 +1,11 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
3
+ "changelog": "@changesets/cli/changelog",
4
+ "commit": false,
5
+ "fixed": [],
6
+ "linked": [],
7
+ "access": "public",
8
+ "baseBranch": "main",
9
+ "updateInternalDependencies": "patch",
10
+ "ignore": []
11
+ }
@@ -0,0 +1,34 @@
1
+ name: Broken URL / bad cleanup
2
+ description: A URL produces wrong output (over-strips, under-strips, garbles)
3
+ title: '[broken-url] '
4
+ labels: [bug, broken-url]
5
+ body:
6
+ - type: input
7
+ id: input-url
8
+ attributes:
9
+ label: Input URL
10
+ description: Paste the URL fed to url-sanitize.
11
+ validations:
12
+ required: true
13
+ - type: input
14
+ id: expected
15
+ attributes:
16
+ label: Expected output URL
17
+ validations:
18
+ required: true
19
+ - type: input
20
+ id: actual
21
+ attributes:
22
+ label: Actual output URL
23
+ validations:
24
+ required: true
25
+ - type: input
26
+ id: version
27
+ attributes:
28
+ label: '@url-sanitize/clearurls version (from metadata.json)'
29
+ validations:
30
+ required: true
31
+ - type: textarea
32
+ id: notes
33
+ attributes:
34
+ label: Notes
@@ -0,0 +1,25 @@
1
+ name: Rule source request
2
+ description: Request support for a non-ClearURLs rule source (AdGuard, Brave, Firefox, custom)
3
+ title: '[source] '
4
+ labels: [enhancement, rule-source]
5
+ body:
6
+ - type: input
7
+ id: source
8
+ attributes:
9
+ label: Source name
10
+ description: e.g. AdGuard URL Tracking Protection, Brave Debouncer
11
+ validations:
12
+ required: true
13
+ - type: input
14
+ id: source-url
15
+ attributes:
16
+ label: Upstream URL
17
+ validations:
18
+ required: true
19
+ - type: textarea
20
+ id: use-case
21
+ attributes:
22
+ label: Use case
23
+ description: What does this source cover that ClearURLs doesn't?
24
+ validations:
25
+ required: true
@@ -0,0 +1,35 @@
1
+ name: auto-tag
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths:
7
+ - 'packages/core/package.json'
8
+
9
+ permissions:
10
+ actions: write
11
+ contents: write
12
+
13
+ jobs:
14
+ tag:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Read version
20
+ id: version
21
+ run: echo "version=$(node -p "require('./packages/core/package.json').version")" >> "$GITHUB_OUTPUT"
22
+
23
+ - name: Create and push tag if missing
24
+ env:
25
+ TAG: v${{ steps.version.outputs.version }}
26
+ run: |
27
+ if git ls-remote --tags origin "$TAG" | grep -q "$TAG"; then
28
+ echo "Tag $TAG already exists — skipping"
29
+ else
30
+ git config user.name "github-actions[bot]"
31
+ git config user.email "github-actions[bot]@users.noreply.github.com"
32
+ git tag -a "$TAG" -m "release $TAG"
33
+ git push origin "$TAG"
34
+ gh workflow run release.yml --ref "$TAG"
35
+ fi
@@ -0,0 +1,63 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths-ignore:
7
+ - '**/*.md'
8
+ - 'docs/**'
9
+ - 'AGENTS.md'
10
+ - 'LICENSE'
11
+ - 'NOTICE'
12
+ pull_request:
13
+ paths-ignore:
14
+ - '**/*.md'
15
+ - 'docs/**'
16
+ - 'AGENTS.md'
17
+ - 'LICENSE'
18
+ - 'NOTICE'
19
+
20
+ jobs:
21
+ ts:
22
+ name: TypeScript engine + conformance
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ - uses: pnpm/action-setup@v4
27
+ - uses: actions/setup-node@v4
28
+ with:
29
+ node-version: '22'
30
+ cache: 'pnpm'
31
+ - run: pnpm install --frozen-lockfile
32
+ - run: pnpm build
33
+ - name: Verify generated catalog matches checked-in catalog
34
+ run: |
35
+ pnpm build:catalog
36
+ git diff --exit-code catalog/clearurls.json \
37
+ || (echo "catalog/clearurls.json is stale — run \`pnpm build:catalog\` and commit" && exit 1)
38
+ - name: Verify generated conformance corpus matches checked-in files
39
+ run: |
40
+ pnpm build:conformance
41
+ git diff --exit-code conformance/vectors.jsonl conformance/clearurls-corpus.jsonl conformance/manifest.json \
42
+ || (echo "conformance corpus is stale — run \`pnpm build:conformance\` and commit" && exit 1)
43
+ - run: pnpm typecheck
44
+ - run: pnpm test
45
+ - run: pnpm lint
46
+
47
+ rust:
48
+ name: Rust engine + conformance
49
+ runs-on: ubuntu-latest
50
+ steps:
51
+ - uses: actions/checkout@v4
52
+ - uses: dtolnay/rust-toolchain@stable
53
+ - uses: Swatinem/rust-cache@v2
54
+ - run: cargo build --workspace --all-targets
55
+ - run: cargo test --workspace
56
+ - name: Release binary size check
57
+ run: |
58
+ cargo build --release -p url-sanitize
59
+ ls -lh target/release/url-sanitize
60
+ size=$(stat -c%s target/release/url-sanitize)
61
+ echo "release binary size: $size bytes"
62
+ # M1 soft cap: 1.5 MB. M3 target: < 1 MB.
63
+ test "$size" -lt 1572864 || (echo "binary exceeded 1.5 MB soft cap" && exit 1)
@@ -0,0 +1,203 @@
1
+ name: release
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ push:
6
+ tags:
7
+ - 'v*'
8
+
9
+ permissions:
10
+ contents: write
11
+ id-token: write
12
+
13
+ jobs:
14
+ verify:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: pnpm/action-setup@v4
19
+ - uses: actions/setup-node@v4
20
+ with:
21
+ node-version: '22'
22
+ cache: 'pnpm'
23
+ registry-url: 'https://registry.npmjs.org'
24
+ - uses: dtolnay/rust-toolchain@stable
25
+ - uses: Swatinem/rust-cache@v2
26
+ - run: pnpm install --frozen-lockfile
27
+ - run: pnpm build
28
+ - run: pnpm typecheck
29
+ - run: pnpm test
30
+ - run: pnpm lint
31
+ - run: cargo build --workspace --all-targets
32
+ - run: cargo test --workspace
33
+ - run: cargo package -p url-sanitize-core
34
+
35
+ build-native:
36
+ needs: verify
37
+ strategy:
38
+ fail-fast: false
39
+ matrix:
40
+ include:
41
+ - os: ubuntu-latest
42
+ target: x86_64-unknown-linux-gnu
43
+ archive: url-sanitize-x86_64-unknown-linux-gnu.tar.gz
44
+ binary: url-sanitize
45
+ - os: ubuntu-24.04-arm
46
+ target: aarch64-unknown-linux-gnu
47
+ archive: url-sanitize-aarch64-unknown-linux-gnu.tar.gz
48
+ binary: url-sanitize
49
+ - os: macos-14
50
+ target: aarch64-apple-darwin
51
+ archive: url-sanitize-aarch64-apple-darwin.tar.gz
52
+ binary: url-sanitize
53
+ - os: windows-latest
54
+ target: x86_64-pc-windows-msvc
55
+ archive: url-sanitize-x86_64-pc-windows-msvc.zip
56
+ binary: url-sanitize.exe
57
+ runs-on: ${{ matrix.os }}
58
+ steps:
59
+ - uses: actions/checkout@v4
60
+ - uses: dtolnay/rust-toolchain@stable
61
+ with:
62
+ targets: ${{ matrix.target }}
63
+ - uses: Swatinem/rust-cache@v2
64
+ - name: Build native binary
65
+ run: cargo build --release -p url-sanitize --target "${{ matrix.target }}"
66
+ shell: bash
67
+ - name: Stage binary
68
+ run: |
69
+ set -euo pipefail
70
+ src="target/${{ matrix.target }}/release/${{ matrix.binary }}"
71
+ mkdir -p "dist/${{ matrix.target }}"
72
+ cp "$src" "dist/${{ matrix.target }}/${{ matrix.binary }}"
73
+ chmod +x "dist/${{ matrix.target }}/${{ matrix.binary }}" || true
74
+ shell: bash
75
+ - name: Smoke native binary
76
+ run: |
77
+ set -euo pipefail
78
+ "dist/${{ matrix.target }}/${{ matrix.binary }}" --version
79
+ "dist/${{ matrix.target }}/${{ matrix.binary }}" --json "https://example.com/?utm_source=x"
80
+ printf '%s\n' "https://example.com/?utm_source=x" | "dist/${{ matrix.target }}/${{ matrix.binary }}" -
81
+ shell: bash
82
+ - name: Build release archive
83
+ run: |
84
+ set -euo pipefail
85
+ mkdir -p release-assets
86
+ if [[ "${{ matrix.archive }}" == *.zip ]]; then
87
+ powershell -NoProfile -Command "Compress-Archive -Path 'dist/${{ matrix.target }}/*' -DestinationPath 'release-assets/${{ matrix.archive }}'"
88
+ else
89
+ tar -czf "release-assets/${{ matrix.archive }}" -C "dist/${{ matrix.target }}" .
90
+ fi
91
+ shell: bash
92
+ - uses: actions/upload-artifact@v4
93
+ with:
94
+ name: release-${{ matrix.target }}
95
+ path: release-assets/*
96
+ github-release:
97
+ needs: build-native
98
+ runs-on: ubuntu-latest
99
+ steps:
100
+ - uses: actions/checkout@v4
101
+ - uses: actions/download-artifact@v4
102
+ with:
103
+ pattern: release-*
104
+ path: release-assets
105
+ merge-multiple: true
106
+ - name: Add installer scripts and checksums
107
+ run: |
108
+ cp scripts/install.sh release-assets/url-sanitize-installer.sh
109
+ cp scripts/install.ps1 release-assets/url-sanitize-installer.ps1
110
+ chmod +x release-assets/url-sanitize-installer.sh
111
+ (cd release-assets && sha256sum * > SHA256SUMS)
112
+ - uses: softprops/action-gh-release@v2
113
+ with:
114
+ files: release-assets/*
115
+ generate_release_notes: true
116
+
117
+ publish-npm:
118
+ needs: verify
119
+ runs-on: ubuntu-latest
120
+ steps:
121
+ - uses: actions/checkout@v4
122
+ - uses: pnpm/action-setup@v4
123
+ - uses: actions/setup-node@v4
124
+ with:
125
+ node-version: '22.14'
126
+ cache: 'pnpm'
127
+ registry-url: 'https://registry.npmjs.org'
128
+ - run: npm install -g 'npm@^11.5.1'
129
+ - run: pnpm install --frozen-lockfile
130
+ - run: pnpm build
131
+ - name: Publish TypeScript npm packages
132
+ run: |
133
+ set -euo pipefail
134
+ VERSION="$(node -p "require('./packages/core/package.json').version")"
135
+ mkdir -p npm-packages
136
+
137
+ publish_pkg() {
138
+ pkg="$1"
139
+ filter="$2"
140
+ if npm view "$pkg@$VERSION" version >/dev/null 2>&1; then
141
+ echo "$pkg@$VERSION already published; skipping"
142
+ return
143
+ fi
144
+ rm -f npm-packages/*.tgz
145
+ pnpm --filter "$filter" pack --pack-destination "$PWD/npm-packages"
146
+ npm publish "$PWD"/npm-packages/*.tgz --access public
147
+ }
148
+
149
+ publish_pkg "@url-sanitize/core" "@url-sanitize/core"
150
+ publish_pkg "@url-sanitize/clearurls" "@url-sanitize/clearurls"
151
+ publish_pkg "@url-sanitize/cli" "@url-sanitize/cli"
152
+
153
+ publish-crates:
154
+ needs: verify
155
+ runs-on: ubuntu-latest
156
+ steps:
157
+ - uses: actions/checkout@v4
158
+ - uses: dtolnay/rust-toolchain@stable
159
+ - uses: Swatinem/rust-cache@v2
160
+ - uses: rust-lang/crates-io-auth-action@v1
161
+ id: auth
162
+ - name: Read crate version
163
+ id: version
164
+ run: |
165
+ version="$(python3 -c 'import json, subprocess; data=json.loads(subprocess.check_output(["cargo", "metadata", "--no-deps", "--format-version=1"])); print(next(p["version"] for p in data["packages"] if p["name"] == "url-sanitize-core"))')"
166
+ echo "version=$version" >> "$GITHUB_OUTPUT"
167
+ - name: Publish url-sanitize-core to crates.io
168
+ run: |
169
+ if curl -fsSA "url-sanitize-release" "https://crates.io/api/v1/crates/url-sanitize-core/${{ steps.version.outputs.version }}" >/dev/null; then
170
+ echo "url-sanitize-core ${{ steps.version.outputs.version }} already published; skipping"
171
+ else
172
+ cargo publish -p url-sanitize-core
173
+ fi
174
+ env:
175
+ CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
176
+ - name: Wait for crates.io index propagation
177
+ run: sleep 30
178
+ - name: Publish url-sanitize to crates.io
179
+ run: |
180
+ if curl -fsSA "url-sanitize-release" "https://crates.io/api/v1/crates/url-sanitize/${{ steps.version.outputs.version }}" >/dev/null; then
181
+ echo "url-sanitize ${{ steps.version.outputs.version }} already published; skipping"
182
+ else
183
+ cargo publish -p url-sanitize
184
+ fi
185
+ env:
186
+ CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
187
+
188
+ publish-pypi:
189
+ needs: verify
190
+ runs-on: ubuntu-latest
191
+ environment: pypi
192
+ steps:
193
+ - uses: actions/checkout@v4
194
+ - uses: actions/setup-python@v5
195
+ with:
196
+ python-version: '3.x'
197
+ - name: Build Python package
198
+ run: |
199
+ python -m pip install --upgrade build
200
+ python -m build
201
+ - uses: pypa/gh-action-pypi-publish@release/v1
202
+ with:
203
+ skip-existing: true
@@ -0,0 +1,64 @@
1
+ name: sync-clearurls
2
+
3
+ on:
4
+ schedule:
5
+ - cron: '17 4 * * *'
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: write
10
+ pull-requests: write
11
+
12
+ jobs:
13
+ sync:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: pnpm/action-setup@v4
18
+ - uses: actions/setup-node@v4
19
+ with:
20
+ node-version: '22'
21
+ cache: 'pnpm'
22
+ - run: pnpm install --frozen-lockfile
23
+
24
+ - name: Fetch and verify upstream rules
25
+ run: pnpm sync:clearurls
26
+
27
+ - name: Detect changes
28
+ id: diff
29
+ run: |
30
+ if git diff --quiet packages/clearurls/data; then
31
+ echo "changed=false" >> "$GITHUB_OUTPUT"
32
+ else
33
+ echo "changed=true" >> "$GITHUB_OUTPUT"
34
+ fi
35
+
36
+ - name: Bump patch version
37
+ if: steps.diff.outputs.changed == 'true'
38
+ run: |
39
+ CURRENT=$(node -p "require('./packages/core/package.json').version")
40
+ IFS='.' read -r major minor patch <<< "$CURRENT"
41
+ NEW_VERSION="$major.$minor.$((patch + 1))"
42
+ node scripts/bump-version.mjs "$NEW_VERSION"
43
+ echo "new_version=$NEW_VERSION" >> "$GITHUB_OUTPUT"
44
+ id: bump
45
+
46
+ - name: Open PR
47
+ if: steps.diff.outputs.changed == 'true'
48
+ id: cpr
49
+ uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
50
+ with:
51
+ commit-message: 'release: v${{ steps.bump.outputs.new_version }}'
52
+ title: 'chore(clearurls): sync upstream rules → v${{ steps.bump.outputs.new_version }}'
53
+ body: |
54
+ Automated daily sync of ClearURLs rule catalog from
55
+ https://rules2.clearurls.xyz/data.minify.json.
56
+ SHA256 verified against rules.minify.hash.
57
+ branch: clearurls-sync
58
+ delete-branch: true
59
+
60
+ - name: Enable auto-merge
61
+ if: steps.diff.outputs.changed == 'true' && steps.cpr.outputs.pull-request-number != ''
62
+ env:
63
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
64
+ run: gh pr merge --auto --squash "${{ steps.cpr.outputs.pull-request-number }}"
@@ -0,0 +1,23 @@
1
+ node_modules/
2
+ dist/
3
+ *.tsbuildinfo
4
+ .turbo/
5
+ coverage/
6
+ .DS_Store
7
+ *.log
8
+ .env
9
+ .env.local
10
+
11
+ # Python
12
+ __pycache__/
13
+ *.py[cod]
14
+ *.egg-info/
15
+
16
+ .idea/
17
+ .vscode/*
18
+ !.vscode/extensions.json
19
+
20
+ # Rust
21
+ target/
22
+ Cargo.lock.bak
23
+ **/*.rs.bk
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env sh
2
+ set -eu
3
+
4
+ pnpm lint
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env sh
2
+ set -eu
3
+
4
+ sh scripts/pre-push.sh
@@ -0,0 +1 @@
1
+ confirm-modules-purge=false
@@ -0,0 +1,95 @@
1
+ # url-sanitize — agent context
2
+
3
+ ClearURLs-compatible URL tracking cleanup toolkit. Removes tracking parameters and unwraps tracking redirects from TypeScript, Rust, npm CLI, native binaries, and Python wrapper surfaces.
4
+
5
+ ## Package layout
6
+
7
+ ```
8
+ packages/
9
+ core/ @url-sanitize/core pure algorithm, zero deps, MIT
10
+ clearurls/ @url-sanitize/clearurls ClearURLs catalog + pre-compiled sanitize(), LGPL-3.0 data
11
+ cli/ @url-sanitize/cli pure TypeScript npm CLI, MIT
12
+ crates/
13
+ url-sanitize-core/ Rust implementation
14
+ url-sanitize/ native CLI with embedded catalog
15
+ python/
16
+ url_sanitize/ PyPI wrapper around native CLI / PATH binary
17
+ sources/
18
+ clearurls/ upstream sync script (pnpm sync:clearurls)
19
+ docs/ threat model, license model, roadmap, compat notes
20
+ ```
21
+
22
+ ## Common workflows
23
+
24
+ ```bash
25
+ pnpm install # install all workspace deps
26
+ pnpm sync:clearurls # fetch + SHA256-verify upstream rules → packages/clearurls/data/
27
+ pnpm build # tsup build all packages (must run before typecheck)
28
+ pnpm test # vitest run
29
+ pnpm lint # biome check . (also enforces import order)
30
+ pnpm format # biome format --write .
31
+ pnpm typecheck # tsc --noEmit across all packages
32
+ cargo fmt --all --check # Rust formatting check
33
+ cargo clippy --workspace --all-targets -- -D warnings
34
+ cargo test --workspace # Rust conformance + unit tests
35
+ cargo package -p url-sanitize-core
36
+ cargo package -p url-sanitize
37
+ ```
38
+
39
+ Pre-push hook runs: `pnpm build && pnpm lint && pnpm test`
40
+
41
+ ## Key conventions
42
+
43
+ - **Linter/formatter**: Biome — not ESLint/Prettier. Run `pnpm lint` to check, `pnpm format` to fix.
44
+ - **Build**: tsup (ESM only, `.d.ts` emitted). `dist/` is gitignored, included in npm via `"files"`.
45
+ - **Test runner**: vitest. Single test file: `bunx vitest run packages/core/test/sanitize.test.ts`
46
+ - **Imports**: must be alphabetically ordered (Biome enforces). Use `.js` extensions in source imports.
47
+ - **Versions**: npm packages, Rust workspace, and PyPI wrapper version-bump together on every release.
48
+ - **Roadmap**: `docs/roadmap.md` is canonical. Do not recreate `PLAN.md`.
49
+ - **npm native packages**: intentionally not used in v0.2. They create one package/trusted-publisher setup per platform. Keep npm CLI pure TypeScript unless this tradeoff is explicitly reopened.
50
+
51
+ ## Publishing
52
+
53
+ Publish is fully automated from `v*` tags:
54
+
55
+ - npm packages use npm trusted publishing (OIDC).
56
+ - crates.io uses `rust-lang/crates-io-auth-action` trusted publishing.
57
+ - PyPI uses trusted publishing with the `pypi` GitHub environment.
58
+ - GitHub Releases receive native archives, SHA256SUMS, and installer scripts.
59
+
60
+ No long-lived registry token should be required after trusted publishers are configured.
61
+
62
+ ```bash
63
+ # bump versions in packages/*/package.json, Cargo.toml, pyproject.toml
64
+ git commit -m "release: vX.Y.Z"
65
+ git tag -a vX.Y.Z -m "release X.Y.Z"
66
+ git push --follow-tags
67
+ # .github/workflows/release.yml publishes npm, crates, PyPI, and native assets
68
+ ```
69
+
70
+ ## Architecture
71
+
72
+ `compileSanitizer(catalog, opts?) → Sanitizer` — factory pattern. Compiles all RegExp at factory time. Call once at module init, reuse the returned function.
73
+
74
+ `@url-sanitize/clearurls` exports `sanitize` (pre-compiled with default options) for one-import usage:
75
+ ```ts
76
+ import { sanitize } from '@url-sanitize/clearurls';
77
+ ```
78
+
79
+ Result is a discriminated union: `{ kind: 'unchanged' } | { kind: 'cleaned', strippedParams, matchedRules } | { kind: 'redirected', via } | { kind: 'blocked', via }`
80
+
81
+ ## Daily sync
82
+
83
+ `.github/workflows/sync-clearurls.yml` runs at 04:17 UTC, opens a PR on change, auto-merges via squash. No manual action needed.
84
+
85
+ ## Adding a new package
86
+
87
+ 1. Create `packages/<name>/` with `package.json` (`"name": "@url-sanitize/<name>"`, `"publishConfig": { "access": "public" }`)
88
+ 2. Add `tsconfig.json` extending `../../tsconfig.base.json`
89
+ 3. Add `"build"` script using tsup
90
+ 4. Add `"files": ["dist"]`
91
+ 5. `pnpm install` to link workspace
92
+
93
+ ## Non-goals
94
+
95
+ No browser extension UI, HTTP interception, DNS blocking, or telemetry. See `docs/non-goals.md`.
@@ -0,0 +1 @@
1
+ AGENTS.md
@@ -0,0 +1,47 @@
1
+ # Contributing
2
+
3
+ ## Dev setup
4
+
5
+ ```sh
6
+ pnpm install
7
+ pnpm sync:clearurls # populate packages/clearurls/data/
8
+ pnpm build
9
+ pnpm test
10
+ ```
11
+
12
+ ## Layout
13
+
14
+ This is a pnpm + changesets monorepo.
15
+
16
+ ```
17
+ packages/
18
+ core/ @url-sanitize/core pure algorithm, zero deps
19
+ clearurls/ @url-sanitize/clearurls ClearURLs catalog adapter + bundled data
20
+ cli/ @url-sanitize/cli command-line tool
21
+ sources/
22
+ clearurls/ sync script + test fixtures
23
+ docs/ public docs (threat model, license, roadmap)
24
+ ```
25
+
26
+ ## Workflow
27
+
28
+ 1. Open an issue first for non-trivial changes.
29
+ 2. Branch from `main`.
30
+ 3. Run `pnpm changeset` to declare a version bump for any package you change.
31
+ 4. Open PR. CI must pass (typecheck + lint + test + build).
32
+
33
+ ## Adding a rule fixture
34
+
35
+ ClearURLs ruleset changes upstream. To pin a behavior:
36
+
37
+ 1. Add a fixture under `sources/clearurls/fixtures/<provider>.json` with input + expected output URLs
38
+ 2. Reference it in `packages/core/test/sanitize.test.ts`
39
+ 3. PR
40
+
41
+ ## Reporting a broken URL
42
+
43
+ Use the `broken-url.yml` issue template. Include: input URL, expected output, actual output, `@url-sanitize/clearurls` version (from `metadata.json`).
44
+
45
+ ## Scope
46
+
47
+ See [docs/non-goals.md](docs/non-goals.md). PRs that add browser-extension UI, HTTP interception, DNS blocking, or telemetry will be closed.