oss-clarity 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.
- oss_clarity-0.1.2/.github/workflows/ci.yml +133 -0
- oss_clarity-0.1.2/.github/workflows/publish.yml +45 -0
- oss_clarity-0.1.2/.gitignore +28 -0
- oss_clarity-0.1.2/CHANGELOG.md +81 -0
- oss_clarity-0.1.2/LICENSE +21 -0
- oss_clarity-0.1.2/PKG-INFO +188 -0
- oss_clarity-0.1.2/README.md +150 -0
- oss_clarity-0.1.2/THIRD_PARTY_NOTICES.md +85 -0
- oss_clarity-0.1.2/docs/api.md +30 -0
- oss_clarity-0.1.2/docs/images/heatmap-clicks.png +0 -0
- oss_clarity-0.1.2/docs/images/heatmap-scroll.png +0 -0
- oss_clarity-0.1.2/docs/images/replay.png +0 -0
- oss_clarity-0.1.2/docs/jobs.md +59 -0
- oss_clarity-0.1.2/docs/settings.md +93 -0
- oss_clarity-0.1.2/docs/signals.md +64 -0
- oss_clarity-0.1.2/docs/storage.md +71 -0
- oss_clarity-0.1.2/docs/thresholds.md +76 -0
- oss_clarity-0.1.2/docs/upgrading.md +23 -0
- oss_clarity-0.1.2/example/README.md +26 -0
- oss_clarity-0.1.2/example/example_project/__init__.py +0 -0
- oss_clarity-0.1.2/example/example_project/management/__init__.py +0 -0
- oss_clarity-0.1.2/example/example_project/management/commands/__init__.py +0 -0
- oss_clarity-0.1.2/example/example_project/management/commands/example_site.py +19 -0
- oss_clarity-0.1.2/example/example_project/settings.py +81 -0
- oss_clarity-0.1.2/example/example_project/templates/page.html +38 -0
- oss_clarity-0.1.2/example/example_project/urls.py +19 -0
- oss_clarity-0.1.2/example/manage.py +9 -0
- oss_clarity-0.1.2/js/README.md +19 -0
- oss_clarity-0.1.2/js/package-lock.json +673 -0
- oss_clarity-0.1.2/js/package.json +21 -0
- oss_clarity-0.1.2/js/player/index.ts +569 -0
- oss_clarity-0.1.2/js/player/player.css +223 -0
- oss_clarity-0.1.2/js/recorder/build.mjs +84 -0
- oss_clarity-0.1.2/js/recorder/index.ts +536 -0
- oss_clarity-0.1.2/js/tests/recorder.test.mjs +191 -0
- oss_clarity-0.1.2/js/tsconfig.json +12 -0
- oss_clarity-0.1.2/js/types.d.ts +1 -0
- oss_clarity-0.1.2/pyproject.toml +73 -0
- oss_clarity-0.1.2/src/oss_clarity/__init__.py +6 -0
- oss_clarity-0.1.2/src/oss_clarity/admin.py +346 -0
- oss_clarity-0.1.2/src/oss_clarity/analysis.py +154 -0
- oss_clarity-0.1.2/src/oss_clarity/apps.py +20 -0
- oss_clarity-0.1.2/src/oss_clarity/choices.py +81 -0
- oss_clarity-0.1.2/src/oss_clarity/collect.py +207 -0
- oss_clarity-0.1.2/src/oss_clarity/conf.py +173 -0
- oss_clarity-0.1.2/src/oss_clarity/core/__init__.py +25 -0
- oss_clarity-0.1.2/src/oss_clarity/core/events.py +43 -0
- oss_clarity-0.1.2/src/oss_clarity/core/measure.py +211 -0
- oss_clarity-0.1.2/src/oss_clarity/core/mirror.py +315 -0
- oss_clarity-0.1.2/src/oss_clarity/core/navigation.py +90 -0
- oss_clarity-0.1.2/src/oss_clarity/core/sampling.py +34 -0
- oss_clarity-0.1.2/src/oss_clarity/core/signals.py +595 -0
- oss_clarity-0.1.2/src/oss_clarity/core/thresholds.py +63 -0
- oss_clarity-0.1.2/src/oss_clarity/core/useragent.py +86 -0
- oss_clarity-0.1.2/src/oss_clarity/heatmaps.py +309 -0
- oss_clarity-0.1.2/src/oss_clarity/jobs.py +119 -0
- oss_clarity-0.1.2/src/oss_clarity/management/__init__.py +0 -0
- oss_clarity-0.1.2/src/oss_clarity/management/commands/__init__.py +0 -0
- oss_clarity-0.1.2/src/oss_clarity/management/commands/oss_clarity_erase_visitor.py +37 -0
- oss_clarity-0.1.2/src/oss_clarity/management/commands/oss_clarity_measure.py +134 -0
- oss_clarity-0.1.2/src/oss_clarity/management/commands/oss_clarity_prune.py +14 -0
- oss_clarity-0.1.2/src/oss_clarity/management/commands/oss_clarity_run_jobs.py +46 -0
- oss_clarity-0.1.2/src/oss_clarity/middleware.py +54 -0
- oss_clarity-0.1.2/src/oss_clarity/migrations/0001_initial.py +288 -0
- oss_clarity-0.1.2/src/oss_clarity/migrations/__init__.py +0 -0
- oss_clarity-0.1.2/src/oss_clarity/models.py +437 -0
- oss_clarity-0.1.2/src/oss_clarity/reading.py +182 -0
- oss_clarity-0.1.2/src/oss_clarity/record.py +318 -0
- oss_clarity-0.1.2/src/oss_clarity/retention.py +144 -0
- oss_clarity-0.1.2/src/oss_clarity/static/oss_clarity/player.css +2 -0
- oss_clarity-0.1.2/src/oss_clarity/static/oss_clarity/player.js +130 -0
- oss_clarity-0.1.2/src/oss_clarity/static/oss_clarity/recorder.js +79 -0
- oss_clarity-0.1.2/src/oss_clarity/storage.py +83 -0
- oss_clarity-0.1.2/src/oss_clarity/tasks.py +64 -0
- oss_clarity-0.1.2/src/oss_clarity/templates/admin/oss_clarity/recording/change_form.html +13 -0
- oss_clarity-0.1.2/src/oss_clarity/templates/admin/oss_clarity/site/change_form.html +6 -0
- oss_clarity-0.1.2/src/oss_clarity/templates/admin/oss_clarity/site/heatmap.html +61 -0
- oss_clarity-0.1.2/src/oss_clarity/throttle.py +127 -0
- oss_clarity-0.1.2/src/oss_clarity/tracker.py +547 -0
- oss_clarity-0.1.2/src/oss_clarity/urls/__init__.py +1 -0
- oss_clarity-0.1.2/src/oss_clarity/urls/api.py +25 -0
- oss_clarity-0.1.2/src/oss_clarity/urls/converters.py +24 -0
- oss_clarity-0.1.2/src/oss_clarity/urls/public.py +26 -0
- oss_clarity-0.1.2/src/oss_clarity/views/__init__.py +0 -0
- oss_clarity-0.1.2/src/oss_clarity/views/api.py +134 -0
- oss_clarity-0.1.2/src/oss_clarity/views/public.py +226 -0
- oss_clarity-0.1.2/tests/__init__.py +0 -0
- oss_clarity-0.1.2/tests/conftest.py +4 -0
- oss_clarity-0.1.2/tests/core/__init__.py +0 -0
- oss_clarity-0.1.2/tests/core/stream.py +143 -0
- oss_clarity-0.1.2/tests/core/test_docs.py +21 -0
- oss_clarity-0.1.2/tests/core/test_measure.py +106 -0
- oss_clarity-0.1.2/tests/core/test_navigation.py +80 -0
- oss_clarity-0.1.2/tests/core/test_no_django.py +37 -0
- oss_clarity-0.1.2/tests/core/test_sampling.py +66 -0
- oss_clarity-0.1.2/tests/core/test_signals.py +474 -0
- oss_clarity-0.1.2/tests/core/test_useragent.py +75 -0
- oss_clarity-0.1.2/tests/django/__init__.py +0 -0
- oss_clarity-0.1.2/tests/django/conftest.py +76 -0
- oss_clarity-0.1.2/tests/django/middleware.py +11 -0
- oss_clarity-0.1.2/tests/django/settings.py +68 -0
- oss_clarity-0.1.2/tests/django/test_admin.py +167 -0
- oss_clarity-0.1.2/tests/django/test_analysis.py +164 -0
- oss_clarity-0.1.2/tests/django/test_api.py +176 -0
- oss_clarity-0.1.2/tests/django/test_collect.py +312 -0
- oss_clarity-0.1.2/tests/django/test_conf.py +72 -0
- oss_clarity-0.1.2/tests/django/test_docs.py +13 -0
- oss_clarity-0.1.2/tests/django/test_heatmaps.py +91 -0
- oss_clarity-0.1.2/tests/django/test_jobs.py +165 -0
- oss_clarity-0.1.2/tests/django/test_measure_command.py +50 -0
- oss_clarity-0.1.2/tests/django/test_models.py +90 -0
- oss_clarity-0.1.2/tests/django/test_record.py +269 -0
- oss_clarity-0.1.2/tests/django/test_retention.py +207 -0
- oss_clarity-0.1.2/tests/django/test_throttle.py +134 -0
- oss_clarity-0.1.2/tests/django/test_tracker.py +243 -0
- oss_clarity-0.1.2/tests/django/urls.py +8 -0
- oss_clarity-0.1.2/tests/django/urls_admin_only.py +4 -0
- oss_clarity-0.1.2/tests/vectors/sampling.json +50 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: ci-${{ github.ref }}
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
lint:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
- uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: "3.13"
|
|
23
|
+
- run: pip install "ruff>=0.6"
|
|
24
|
+
- run: ruff check .
|
|
25
|
+
- run: ruff format --check .
|
|
26
|
+
|
|
27
|
+
# The core library must install and pass its tests with Django absent.
|
|
28
|
+
core:
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
strategy:
|
|
31
|
+
fail-fast: false
|
|
32
|
+
matrix:
|
|
33
|
+
python: ["3.11", "3.14"]
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
- uses: actions/setup-python@v5
|
|
37
|
+
with:
|
|
38
|
+
python-version: ${{ matrix.python }}
|
|
39
|
+
- run: pip install -e . pytest
|
|
40
|
+
- name: Django is not installed
|
|
41
|
+
run: python -c "import importlib.util, sys; sys.exit(importlib.util.find_spec('django') is not None)"
|
|
42
|
+
- run: pytest -q
|
|
43
|
+
|
|
44
|
+
django:
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
strategy:
|
|
47
|
+
fail-fast: false
|
|
48
|
+
matrix:
|
|
49
|
+
include:
|
|
50
|
+
- { django: "5.2", python: "3.11", db: sqlite }
|
|
51
|
+
- { django: "5.2", python: "3.12", db: sqlite }
|
|
52
|
+
- { django: "5.2", python: "3.13", db: sqlite }
|
|
53
|
+
- { django: "5.2", python: "3.14", db: sqlite }
|
|
54
|
+
- { django: "5.2", python: "3.14", db: postgres }
|
|
55
|
+
- { django: "6.0", python: "3.12", db: sqlite }
|
|
56
|
+
- { django: "6.0", python: "3.13", db: sqlite }
|
|
57
|
+
- { django: "6.0", python: "3.14", db: sqlite }
|
|
58
|
+
- { django: "6.0", python: "3.14", db: postgres }
|
|
59
|
+
- { django: "6.1", python: "3.12", db: sqlite }
|
|
60
|
+
- { django: "6.1", python: "3.13", db: sqlite }
|
|
61
|
+
- { django: "6.1", python: "3.14", db: sqlite }
|
|
62
|
+
- { django: "6.1", python: "3.14", db: postgres }
|
|
63
|
+
services:
|
|
64
|
+
postgres:
|
|
65
|
+
image: postgres:17
|
|
66
|
+
env:
|
|
67
|
+
POSTGRES_USER: oc
|
|
68
|
+
POSTGRES_PASSWORD: oc
|
|
69
|
+
POSTGRES_DB: oc
|
|
70
|
+
ports: ["5432:5432"]
|
|
71
|
+
options: >-
|
|
72
|
+
--health-cmd pg_isready --health-interval 5s --health-timeout 5s --health-retries 10
|
|
73
|
+
env:
|
|
74
|
+
DATABASE_URL: ${{ matrix.db == 'postgres' && 'postgres://oc:oc@localhost:5432/oc' || '' }}
|
|
75
|
+
steps:
|
|
76
|
+
- uses: actions/checkout@v4
|
|
77
|
+
- uses: actions/setup-python@v5
|
|
78
|
+
with:
|
|
79
|
+
python-version: ${{ matrix.python }}
|
|
80
|
+
# The tracker tests run the served tracker in Node.
|
|
81
|
+
- uses: actions/setup-node@v4
|
|
82
|
+
with:
|
|
83
|
+
node-version: "24"
|
|
84
|
+
- run: pip install -e ".[django,celery]" "Django~=${{ matrix.django }}.0" pytest pytest-django
|
|
85
|
+
- if: matrix.db == 'postgres'
|
|
86
|
+
run: pip install "psycopg[binary]>=3.2"
|
|
87
|
+
- run: python -m django --version
|
|
88
|
+
- run: pytest -q
|
|
89
|
+
- name: The example project passes its checks
|
|
90
|
+
working-directory: example
|
|
91
|
+
run: python manage.py check
|
|
92
|
+
- name: Migrations match the models
|
|
93
|
+
run: >-
|
|
94
|
+
PYTHONPATH=. DJANGO_SETTINGS_MODULE=tests.django.settings
|
|
95
|
+
django-admin makemigrations oss_clarity --check --dry-run
|
|
96
|
+
|
|
97
|
+
# The committed bundles must be exactly what the lockfile builds.
|
|
98
|
+
js:
|
|
99
|
+
runs-on: ubuntu-latest
|
|
100
|
+
defaults:
|
|
101
|
+
run:
|
|
102
|
+
working-directory: js
|
|
103
|
+
steps:
|
|
104
|
+
- uses: actions/checkout@v4
|
|
105
|
+
- uses: actions/setup-node@v4
|
|
106
|
+
with:
|
|
107
|
+
node-version: "24"
|
|
108
|
+
cache: npm
|
|
109
|
+
cache-dependency-path: js/package-lock.json
|
|
110
|
+
- run: npm ci
|
|
111
|
+
- run: npm run typecheck
|
|
112
|
+
- run: npm test
|
|
113
|
+
- run: npm run build
|
|
114
|
+
- name: Committed bundles match a fresh build
|
|
115
|
+
run: git diff --exit-code -- ../src/oss_clarity/static
|
|
116
|
+
|
|
117
|
+
package:
|
|
118
|
+
runs-on: ubuntu-latest
|
|
119
|
+
steps:
|
|
120
|
+
- uses: actions/checkout@v4
|
|
121
|
+
- uses: actions/setup-python@v5
|
|
122
|
+
with:
|
|
123
|
+
python-version: "3.13"
|
|
124
|
+
- run: pip install build
|
|
125
|
+
- run: python -m build
|
|
126
|
+
- name: The wheel carries the bundles, migrations, templates and notices
|
|
127
|
+
run: |
|
|
128
|
+
unzip -l dist/*.whl > contents.txt
|
|
129
|
+
for f in static/oss_clarity/recorder.js static/oss_clarity/player.js \
|
|
130
|
+
static/oss_clarity/player.css migrations/0001_initial.py \
|
|
131
|
+
templates/admin/oss_clarity/site/heatmap.html THIRD_PARTY_NOTICES.md; do
|
|
132
|
+
grep -q "$f" contents.txt || { echo "missing from wheel: $f"; exit 1; }
|
|
133
|
+
done
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
# Pushing a version tag (v0.1.2) builds the release and uploads it to PyPI through a
|
|
4
|
+
# trusted publisher: no API token is stored anywhere.
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
tags: ["v*"]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.13"
|
|
20
|
+
- name: The tag matches the package version
|
|
21
|
+
run: |
|
|
22
|
+
version=$(python -c "import re; print(re.search(r'__version__ = \"(.+)\"', open('src/oss_clarity/__init__.py').read())[1])")
|
|
23
|
+
[ "v$version" = "$GITHUB_REF_NAME" ] || { echo "tag $GITHUB_REF_NAME, version $version"; exit 1; }
|
|
24
|
+
- run: pip install build
|
|
25
|
+
- run: python -m build
|
|
26
|
+
- uses: actions/upload-artifact@v4
|
|
27
|
+
with:
|
|
28
|
+
name: dist
|
|
29
|
+
path: dist/
|
|
30
|
+
|
|
31
|
+
publish:
|
|
32
|
+
needs: build
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
# Must match the environment on the PyPI trusted publisher.
|
|
35
|
+
environment:
|
|
36
|
+
name: pypi
|
|
37
|
+
url: https://pypi.org/p/oss-clarity
|
|
38
|
+
permissions:
|
|
39
|
+
id-token: write
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/download-artifact@v4
|
|
42
|
+
with:
|
|
43
|
+
name: dist
|
|
44
|
+
path: dist/
|
|
45
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Private build brief — never committed.
|
|
2
|
+
PLAN.md
|
|
3
|
+
|
|
4
|
+
# Python
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
*.egg-info/
|
|
8
|
+
.venv/
|
|
9
|
+
venv/
|
|
10
|
+
build/
|
|
11
|
+
dist/
|
|
12
|
+
.pytest_cache/
|
|
13
|
+
.ruff_cache/
|
|
14
|
+
.coverage
|
|
15
|
+
htmlcov/
|
|
16
|
+
|
|
17
|
+
# JS
|
|
18
|
+
node_modules/
|
|
19
|
+
|
|
20
|
+
# Editors and OS
|
|
21
|
+
.idea/
|
|
22
|
+
.vscode/
|
|
23
|
+
.DS_Store
|
|
24
|
+
|
|
25
|
+
# Example project
|
|
26
|
+
example/db.sqlite3
|
|
27
|
+
example/media/
|
|
28
|
+
example/.cache/
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.2 — 2026-09-27
|
|
4
|
+
|
|
5
|
+
First release on PyPI.
|
|
6
|
+
|
|
7
|
+
Changed
|
|
8
|
+
|
|
9
|
+
- The README installs from PyPI, and its links and images point at the v0.1.2 tag on GitHub,
|
|
10
|
+
so they work on the PyPI project page.
|
|
11
|
+
|
|
12
|
+
## 0.1.1 — 2026-09-26
|
|
13
|
+
|
|
14
|
+
Fixed
|
|
15
|
+
|
|
16
|
+
- The recorder lost the events buffered when a page was hidden or closed: it compressed
|
|
17
|
+
the last chunk before sending it, and a page going away gets no further turn for the
|
|
18
|
+
compression to finish. Up to five seconds at the end of every page were missing, and a
|
|
19
|
+
page left within five seconds of loading was missing from its recording altogether. The
|
|
20
|
+
recorder now sends as soon as the page is hidden or closed, uncompressed, in parts that fit
|
|
21
|
+
the browser's 64 KB keepalive budget. Chunks sent while the page stays open are still
|
|
22
|
+
gzipped. The recorder's URL carries a new digest, so browsers fetch the fixed bundle.
|
|
23
|
+
- The example page sets its own background, so it stays readable when the browser prefers a
|
|
24
|
+
dark colour scheme.
|
|
25
|
+
|
|
26
|
+
Added
|
|
27
|
+
|
|
28
|
+
- `npm test` in `js/`: the recorder's uploads, run in Node with rrweb stubbed out. CI runs it.
|
|
29
|
+
|
|
30
|
+
## 0.1.0 — 2026-09-26
|
|
31
|
+
|
|
32
|
+
First release.
|
|
33
|
+
|
|
34
|
+
- `oss_clarity.core`: rules-based signal analysis of rrweb recordings (`analyze`), frozen
|
|
35
|
+
`Thresholds`, quick backs and loops from page views (`navigation`), a user-agent classifier
|
|
36
|
+
with a bot test, and a threshold measuring tool (`measure`). No Django required.
|
|
37
|
+
- Django app `oss_clarity`: models for sites, recording settings, hits, recordings and their
|
|
38
|
+
chunks, heatmap buckets, visit navigation and job runs, in one initial migration. No IP
|
|
39
|
+
address or raw user agent is stored.
|
|
40
|
+
- `OSS_CLARITY` settings dict with defaults for every key, checked by `manage.py check`.
|
|
41
|
+
- Admin: sites with their recording settings and refusal counters, read-only hits, recordings
|
|
42
|
+
filterable by signal, favourites, and job runs.
|
|
43
|
+
- Public collector (`oss_clarity.urls.public`): the tracker script per site, the recorder
|
|
44
|
+
bundle under a content digest, page views, clicks and page leaves, and recording chunks
|
|
45
|
+
(gzip accepted). Host allow-list, crawler refusal for recordings, sampling by session-id
|
|
46
|
+
hash, size and session caps, and per-address, per-site and global rate limits. Every
|
|
47
|
+
refusal answers 204.
|
|
48
|
+
- Client IP for rate limits resolved by `TRUSTED_PROXY_COUNT`, `CLIENT_IP_HEADER` or
|
|
49
|
+
`CLIENT_IP_FUNCTION`; used in memory only.
|
|
50
|
+
- The tracker honours Global Privacy Control for recording, supports a consent gate, and
|
|
51
|
+
exposes `ossClarity("visitorId")` and `ossClarity("forget")`. Clicks carry position and a
|
|
52
|
+
selector only; credential-shaped query values are redacted before any URL is stored.
|
|
53
|
+
- Recorder bundle built from `js/recorder` with esbuild; third-party notices in
|
|
54
|
+
`THIRD_PARTY_NOTICES.md`.
|
|
55
|
+
- Optional `PublicEndpointsMiddleware` for hosts whose CORS or cache middleware would
|
|
56
|
+
override the public endpoints' headers.
|
|
57
|
+
- Background jobs in `oss_clarity.jobs`: finalize and analyse quiet recordings, store visits'
|
|
58
|
+
quick backs and loops, roll up heatmaps per UTC day, and prune by retention window. Each
|
|
59
|
+
run is claimed in `JobRun` with one conditional update, so overlapping runs never repeat
|
|
60
|
+
a job. Run them with `manage.py oss_clarity_run_jobs` from cron, or the optional Celery
|
|
61
|
+
tasks and `BEAT_SCHEDULE` in `oss_clarity.tasks`.
|
|
62
|
+
- Visitor erasure: `retention.erase_visitor`, `manage.py oss_clarity_erase_visitor` and an
|
|
63
|
+
admin action. Stored chunks are always deleted before rows; a failed delete keeps the rows
|
|
64
|
+
for the next run.
|
|
65
|
+
- `manage.py oss_clarity_measure` reports how many signals each threshold setting would
|
|
66
|
+
find, with moments to watch. It writes nothing.
|
|
67
|
+
- Recordings can be deleted from the admin, stored chunks first.
|
|
68
|
+
- Read-only JSON API (`oss_clarity.urls.api`): recordings filterable by any-of signals and
|
|
69
|
+
favourites, one recording with its pages, a page's events, heatmap pages, one heatmap,
|
|
70
|
+
and sessions with quick backs and loops on every row. Staff only unless
|
|
71
|
+
`API_PERMISSION` says otherwise.
|
|
72
|
+
- Admin viewer: a replay on each recording's page, with signals on the timeline and as a
|
|
73
|
+
list, and a heatmap page per site (page, device and range pickers; click and scroll-depth
|
|
74
|
+
maps drawn over the newest recorded snapshot of that page). Built from `js/player` on
|
|
75
|
+
rrweb's replayer, sandboxed without scripts.
|
|
76
|
+
- The replay strips inline event handlers from recorded pages, and the heatmap
|
|
77
|
+
measures the rebuilt page only after it has been laid out.
|
|
78
|
+
- Documentation (`docs/`), a README with the privacy stance, an example project, and CI
|
|
79
|
+
for lint, the core without Django, the Django × Python matrix on SQLite and PostgreSQL,
|
|
80
|
+
bundle reproducibility and the wheel's contents.
|
|
81
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Meharaj Ul Mahmmud
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: oss-clarity
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Self-hosted session replay, heatmaps and rules-based behaviour signals for Django
|
|
5
|
+
Project-URL: Homepage, https://github.com/meharaj-007/oss-clarity
|
|
6
|
+
Project-URL: Documentation, https://github.com/meharaj-007/oss-clarity/tree/main/docs
|
|
7
|
+
Project-URL: Changelog, https://github.com/meharaj-007/oss-clarity/blob/main/CHANGELOG.md
|
|
8
|
+
Author: Meharaj Ul Mahmmud
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
License-File: THIRD_PARTY_NOTICES.md
|
|
12
|
+
Keywords: analytics,django,heatmaps,privacy,rrweb,session-replay
|
|
13
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
14
|
+
Classifier: Framework :: Django
|
|
15
|
+
Classifier: Framework :: Django :: 5.2
|
|
16
|
+
Classifier: Framework :: Django :: 6.0
|
|
17
|
+
Classifier: Framework :: Django :: 6.1
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Provides-Extra: celery
|
|
25
|
+
Requires-Dist: celery>=5.3; extra == 'celery'
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: build>=1; extra == 'dev'
|
|
28
|
+
Requires-Dist: celery>=5.3; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-django>=4.9; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
31
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
32
|
+
Provides-Extra: django
|
|
33
|
+
Requires-Dist: django>=5.2; extra == 'django'
|
|
34
|
+
Requires-Dist: rjsmin>=1.2; extra == 'django'
|
|
35
|
+
Provides-Extra: s3
|
|
36
|
+
Requires-Dist: django-storages[s3]>=1.14; extra == 's3'
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
|
|
39
|
+
# oss-clarity
|
|
40
|
+
|
|
41
|
+
Self-hosted session replay, heatmaps and rules-based behaviour signals for Django.
|
|
42
|
+
|
|
43
|
+
Add one script tag to your site. oss-clarity counts page views, clicks and scroll
|
|
44
|
+
depth, records sampled visits with [rrweb](https://github.com/rrweb-io/rrweb), and
|
|
45
|
+
marks where people struggled: rage clicks, dead clicks, hesitations, form
|
|
46
|
+
abandons and more. You watch the replays and heatmaps in your Django admin. Every
|
|
47
|
+
byte stays on your servers.
|
|
48
|
+
|
|
49
|
+
> Early release (0.1.2).
|
|
50
|
+
> Settings and the JSON API may still change.
|
|
51
|
+
|
|
52
|
+

|
|
53
|
+
|
|
54
|
+
## What you get
|
|
55
|
+
|
|
56
|
+
- **Tracking**: page views (including single-page-app route changes), clicks with
|
|
57
|
+
their position, and how far each page was scrolled. About 10 KB of JavaScript
|
|
58
|
+
(4 KB gzipped), reporting after the page loads, with no cookies.
|
|
59
|
+
- **Recording**: sampled session replay, masked in the visitor's browser before
|
|
60
|
+
anything is sent. Capped per visit by size, pages and minutes.
|
|
61
|
+
- **Signals**: 15 rules, each a documented, deterministic check with named
|
|
62
|
+
thresholds, and a tool to measure those thresholds against your own recordings.
|
|
63
|
+
See [signals](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/signals.md).
|
|
64
|
+
- **Heatmaps**: clicks and scroll depth per page and device, drawn over a recorded
|
|
65
|
+
snapshot of the page.
|
|
66
|
+
- **Viewer**: replay and heatmap pages inside Django admin, and a read-only
|
|
67
|
+
[JSON API](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/api.md).
|
|
68
|
+
|
|
69
|
+

|
|
70
|
+
|
|
71
|
+
## Privacy
|
|
72
|
+
|
|
73
|
+
- **No AI.** Signals are plain rules you can read. Recordings are never sent to
|
|
74
|
+
any third party or model.
|
|
75
|
+
- **Masked by default.** Form fields are masked in every mode and cannot be
|
|
76
|
+
unmasked. The default mode also blanks digits and email addresses, and `data:`
|
|
77
|
+
and `blob:` images (a photo a visitor just picked, say) are never recorded.
|
|
78
|
+
- **Global Privacy Control is honoured.** A browser that sends it is never
|
|
79
|
+
recorded; its page views are still counted.
|
|
80
|
+
- **Optional consent gate.** Per site, nothing is recorded until your page calls
|
|
81
|
+
`ossClarity("consent", true)`.
|
|
82
|
+
- **No IP addresses stored.** The address is used in memory for rate limits only.
|
|
83
|
+
Raw user agents are not stored either, only coarse device, browser and OS.
|
|
84
|
+
- **No text from clicks.** A click records where it landed and a selector for the
|
|
85
|
+
element, never the element's text or link. Password, token and similar values in
|
|
86
|
+
page URLs are replaced before storage.
|
|
87
|
+
- **Crawlers are not recorded.** Bots that run JavaScript are refused by the
|
|
88
|
+
tracker and again by the collector.
|
|
89
|
+
- **Erase on request.** `ossClarity("visitorId")` gives a visitor their id;
|
|
90
|
+
`manage.py oss_clarity_erase_visitor <id>` deletes everything held about them.
|
|
91
|
+
`ossClarity("forget")` clears the ids in their browser.
|
|
92
|
+
- **Retention.** Hits and recordings are deleted after 30 days by default.
|
|
93
|
+
|
|
94
|
+
## Install
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
pip install "oss-clarity[django]"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Python 3.11 to 3.14, Django 5.2, 6.0 and 6.1, SQLite or PostgreSQL.
|
|
101
|
+
|
|
102
|
+
## Set up
|
|
103
|
+
|
|
104
|
+
**1. Settings**
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
INSTALLED_APPS = [..., "oss_clarity"]
|
|
108
|
+
|
|
109
|
+
MIDDLEWARE = [
|
|
110
|
+
"oss_clarity.middleware.PublicEndpointsMiddleware", # first
|
|
111
|
+
...,
|
|
112
|
+
]
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The middleware is only needed if something else in your stack (django-cors-headers,
|
|
116
|
+
a no-store cache policy) would override the public endpoints' headers. It is safe
|
|
117
|
+
to always include. Every other setting has a default; see
|
|
118
|
+
[settings](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/settings.md).
|
|
119
|
+
|
|
120
|
+
**2. URLs**
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
urlpatterns = [
|
|
124
|
+
...,
|
|
125
|
+
path("oc/", include("oss_clarity.urls.public")), # tracker and collector
|
|
126
|
+
path("oc-api/", include("oss_clarity.urls.api")), # read-only API, optional
|
|
127
|
+
]
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Then `python manage.py migrate`.
|
|
131
|
+
|
|
132
|
+
**3. Jobs**, every five minutes from cron (or use the
|
|
133
|
+
[Celery tasks](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/jobs.md)):
|
|
134
|
+
|
|
135
|
+
```cron
|
|
136
|
+
*/5 * * * * cd /srv/app && python manage.py oss_clarity_run_jobs
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**4. The snippet.** Add a site in the admin (Session replay and heatmaps → Sites),
|
|
140
|
+
switch recording on in its recording settings if you want replays, and paste the
|
|
141
|
+
snippet it shows into your pages' `<head>`:
|
|
142
|
+
|
|
143
|
+
```html
|
|
144
|
+
<script async src="https://your-app.example.com/oc/t/<site key>.js"></script>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Visits appear as hits straight away. Recordings are analysed a few minutes after a
|
|
148
|
+
visit ends, and heatmaps update hourly.
|
|
149
|
+
|
|
150
|
+
To see it all working on your own machine first, run the
|
|
151
|
+
[example project](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/example/README.md).
|
|
152
|
+
|
|
153
|
+
## Documentation
|
|
154
|
+
|
|
155
|
+
- [Signals](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/signals.md): what each one means
|
|
156
|
+
- [Thresholds](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/thresholds.md): the numbers, and how to measure them
|
|
157
|
+
- [Settings](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/settings.md): every key
|
|
158
|
+
- [Storage](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/storage.md): local disk or S3
|
|
159
|
+
- [Jobs](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/jobs.md): cron or Celery
|
|
160
|
+
- [JSON API](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/api.md)
|
|
161
|
+
- [Upgrading](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/upgrading.md)
|
|
162
|
+
|
|
163
|
+
## Limits
|
|
164
|
+
|
|
165
|
+
- One recording per visit, at most 10 MiB, 128 pages and 120 minutes by default.
|
|
166
|
+
- Replays load images, fonts and styles from your live site, so ones changed or
|
|
167
|
+
removed since render differently.
|
|
168
|
+
- Heatmaps group pages by path (query strings ignored, trailing slashes folded)
|
|
169
|
+
and by device class. Clicks are placed on the element when the snapshot still
|
|
170
|
+
has it, and by position otherwise.
|
|
171
|
+
- Automated browsers (`navigator.webdriver`, headless Chrome) are treated as
|
|
172
|
+
crawlers and never recorded.
|
|
173
|
+
- No multi-tenant accounts, billing or quotas: that is your project's business.
|
|
174
|
+
|
|
175
|
+
## Development
|
|
176
|
+
|
|
177
|
+
```sh
|
|
178
|
+
pip install -e ".[django,dev]"
|
|
179
|
+
pytest
|
|
180
|
+
ruff check . && ruff format --check .
|
|
181
|
+
cd js && npm ci && npm run typecheck && npm run build # rebuilds the committed bundles
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Licence
|
|
185
|
+
|
|
186
|
+
MIT. See [LICENSE](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/LICENSE).
|
|
187
|
+
The bundled rrweb and its dependencies are listed in
|
|
188
|
+
[THIRD_PARTY_NOTICES.md](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/THIRD_PARTY_NOTICES.md).
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# oss-clarity
|
|
2
|
+
|
|
3
|
+
Self-hosted session replay, heatmaps and rules-based behaviour signals for Django.
|
|
4
|
+
|
|
5
|
+
Add one script tag to your site. oss-clarity counts page views, clicks and scroll
|
|
6
|
+
depth, records sampled visits with [rrweb](https://github.com/rrweb-io/rrweb), and
|
|
7
|
+
marks where people struggled: rage clicks, dead clicks, hesitations, form
|
|
8
|
+
abandons and more. You watch the replays and heatmaps in your Django admin. Every
|
|
9
|
+
byte stays on your servers.
|
|
10
|
+
|
|
11
|
+
> Early release (0.1.2).
|
|
12
|
+
> Settings and the JSON API may still change.
|
|
13
|
+
|
|
14
|
+

|
|
15
|
+
|
|
16
|
+
## What you get
|
|
17
|
+
|
|
18
|
+
- **Tracking**: page views (including single-page-app route changes), clicks with
|
|
19
|
+
their position, and how far each page was scrolled. About 10 KB of JavaScript
|
|
20
|
+
(4 KB gzipped), reporting after the page loads, with no cookies.
|
|
21
|
+
- **Recording**: sampled session replay, masked in the visitor's browser before
|
|
22
|
+
anything is sent. Capped per visit by size, pages and minutes.
|
|
23
|
+
- **Signals**: 15 rules, each a documented, deterministic check with named
|
|
24
|
+
thresholds, and a tool to measure those thresholds against your own recordings.
|
|
25
|
+
See [signals](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/signals.md).
|
|
26
|
+
- **Heatmaps**: clicks and scroll depth per page and device, drawn over a recorded
|
|
27
|
+
snapshot of the page.
|
|
28
|
+
- **Viewer**: replay and heatmap pages inside Django admin, and a read-only
|
|
29
|
+
[JSON API](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/api.md).
|
|
30
|
+
|
|
31
|
+

|
|
32
|
+
|
|
33
|
+
## Privacy
|
|
34
|
+
|
|
35
|
+
- **No AI.** Signals are plain rules you can read. Recordings are never sent to
|
|
36
|
+
any third party or model.
|
|
37
|
+
- **Masked by default.** Form fields are masked in every mode and cannot be
|
|
38
|
+
unmasked. The default mode also blanks digits and email addresses, and `data:`
|
|
39
|
+
and `blob:` images (a photo a visitor just picked, say) are never recorded.
|
|
40
|
+
- **Global Privacy Control is honoured.** A browser that sends it is never
|
|
41
|
+
recorded; its page views are still counted.
|
|
42
|
+
- **Optional consent gate.** Per site, nothing is recorded until your page calls
|
|
43
|
+
`ossClarity("consent", true)`.
|
|
44
|
+
- **No IP addresses stored.** The address is used in memory for rate limits only.
|
|
45
|
+
Raw user agents are not stored either, only coarse device, browser and OS.
|
|
46
|
+
- **No text from clicks.** A click records where it landed and a selector for the
|
|
47
|
+
element, never the element's text or link. Password, token and similar values in
|
|
48
|
+
page URLs are replaced before storage.
|
|
49
|
+
- **Crawlers are not recorded.** Bots that run JavaScript are refused by the
|
|
50
|
+
tracker and again by the collector.
|
|
51
|
+
- **Erase on request.** `ossClarity("visitorId")` gives a visitor their id;
|
|
52
|
+
`manage.py oss_clarity_erase_visitor <id>` deletes everything held about them.
|
|
53
|
+
`ossClarity("forget")` clears the ids in their browser.
|
|
54
|
+
- **Retention.** Hits and recordings are deleted after 30 days by default.
|
|
55
|
+
|
|
56
|
+
## Install
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
pip install "oss-clarity[django]"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Python 3.11 to 3.14, Django 5.2, 6.0 and 6.1, SQLite or PostgreSQL.
|
|
63
|
+
|
|
64
|
+
## Set up
|
|
65
|
+
|
|
66
|
+
**1. Settings**
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
INSTALLED_APPS = [..., "oss_clarity"]
|
|
70
|
+
|
|
71
|
+
MIDDLEWARE = [
|
|
72
|
+
"oss_clarity.middleware.PublicEndpointsMiddleware", # first
|
|
73
|
+
...,
|
|
74
|
+
]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The middleware is only needed if something else in your stack (django-cors-headers,
|
|
78
|
+
a no-store cache policy) would override the public endpoints' headers. It is safe
|
|
79
|
+
to always include. Every other setting has a default; see
|
|
80
|
+
[settings](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/settings.md).
|
|
81
|
+
|
|
82
|
+
**2. URLs**
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
urlpatterns = [
|
|
86
|
+
...,
|
|
87
|
+
path("oc/", include("oss_clarity.urls.public")), # tracker and collector
|
|
88
|
+
path("oc-api/", include("oss_clarity.urls.api")), # read-only API, optional
|
|
89
|
+
]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Then `python manage.py migrate`.
|
|
93
|
+
|
|
94
|
+
**3. Jobs**, every five minutes from cron (or use the
|
|
95
|
+
[Celery tasks](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/jobs.md)):
|
|
96
|
+
|
|
97
|
+
```cron
|
|
98
|
+
*/5 * * * * cd /srv/app && python manage.py oss_clarity_run_jobs
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**4. The snippet.** Add a site in the admin (Session replay and heatmaps → Sites),
|
|
102
|
+
switch recording on in its recording settings if you want replays, and paste the
|
|
103
|
+
snippet it shows into your pages' `<head>`:
|
|
104
|
+
|
|
105
|
+
```html
|
|
106
|
+
<script async src="https://your-app.example.com/oc/t/<site key>.js"></script>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Visits appear as hits straight away. Recordings are analysed a few minutes after a
|
|
110
|
+
visit ends, and heatmaps update hourly.
|
|
111
|
+
|
|
112
|
+
To see it all working on your own machine first, run the
|
|
113
|
+
[example project](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/example/README.md).
|
|
114
|
+
|
|
115
|
+
## Documentation
|
|
116
|
+
|
|
117
|
+
- [Signals](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/signals.md): what each one means
|
|
118
|
+
- [Thresholds](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/thresholds.md): the numbers, and how to measure them
|
|
119
|
+
- [Settings](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/settings.md): every key
|
|
120
|
+
- [Storage](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/storage.md): local disk or S3
|
|
121
|
+
- [Jobs](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/jobs.md): cron or Celery
|
|
122
|
+
- [JSON API](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/api.md)
|
|
123
|
+
- [Upgrading](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/upgrading.md)
|
|
124
|
+
|
|
125
|
+
## Limits
|
|
126
|
+
|
|
127
|
+
- One recording per visit, at most 10 MiB, 128 pages and 120 minutes by default.
|
|
128
|
+
- Replays load images, fonts and styles from your live site, so ones changed or
|
|
129
|
+
removed since render differently.
|
|
130
|
+
- Heatmaps group pages by path (query strings ignored, trailing slashes folded)
|
|
131
|
+
and by device class. Clicks are placed on the element when the snapshot still
|
|
132
|
+
has it, and by position otherwise.
|
|
133
|
+
- Automated browsers (`navigator.webdriver`, headless Chrome) are treated as
|
|
134
|
+
crawlers and never recorded.
|
|
135
|
+
- No multi-tenant accounts, billing or quotas: that is your project's business.
|
|
136
|
+
|
|
137
|
+
## Development
|
|
138
|
+
|
|
139
|
+
```sh
|
|
140
|
+
pip install -e ".[django,dev]"
|
|
141
|
+
pytest
|
|
142
|
+
ruff check . && ruff format --check .
|
|
143
|
+
cd js && npm ci && npm run typecheck && npm run build # rebuilds the committed bundles
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Licence
|
|
147
|
+
|
|
148
|
+
MIT. See [LICENSE](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/LICENSE).
|
|
149
|
+
The bundled rrweb and its dependencies are listed in
|
|
150
|
+
[THIRD_PARTY_NOTICES.md](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/THIRD_PARTY_NOTICES.md).
|