noflare 1.0.0__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.
@@ -0,0 +1,221 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ # Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ # poetry.lock
109
+ # poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ # pdm.lock
116
+ # pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ # pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # Redis
135
+ *.rdb
136
+ *.aof
137
+ *.pid
138
+
139
+ # RabbitMQ
140
+ mnesia/
141
+ rabbitmq/
142
+ rabbitmq-data/
143
+
144
+ # ActiveMQ
145
+ activemq-data/
146
+
147
+ # SageMath parsed files
148
+ *.sage.py
149
+
150
+ # Environments
151
+ .env
152
+ .envrc
153
+ .venv
154
+ env/
155
+ venv/
156
+ ENV/
157
+ env.bak/
158
+ venv.bak/
159
+
160
+ # Spyder project settings
161
+ .spyderproject
162
+ .spyproject
163
+
164
+ # Rope project settings
165
+ .ropeproject
166
+
167
+ # mkdocs documentation
168
+ /site
169
+
170
+ # mypy
171
+ .mypy_cache/
172
+ .dmypy.json
173
+ dmypy.json
174
+
175
+ # Pyre type checker
176
+ .pyre/
177
+
178
+ # pytype static type analyzer
179
+ .pytype/
180
+
181
+ # Cython debug symbols
182
+ cython_debug/
183
+
184
+ # PyCharm
185
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
186
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
187
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
188
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
189
+ # .idea/
190
+
191
+ # Abstra
192
+ # Abstra is an AI-powered process automation framework.
193
+ # Ignore directories containing user credentials, local state, and settings.
194
+ # Learn more at https://abstra.io/docs
195
+ .abstra/
196
+
197
+ # Visual Studio Code
198
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
199
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
200
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
201
+ # you could uncomment the following to ignore the entire vscode folder
202
+ # .vscode/
203
+ # Temporary file for partial code execution
204
+ tempCodeRunnerFile.py
205
+
206
+ # Ruff stuff:
207
+ .ruff_cache/
208
+
209
+ # PyPI configuration file
210
+ .pypirc
211
+
212
+ # Marimo
213
+ marimo/_static/
214
+ marimo/_lsp/
215
+ __marimo__/
216
+
217
+ # Streamlit
218
+ .streamlit/secrets.toml
219
+
220
+ # Additional
221
+ .env
@@ -0,0 +1,107 @@
1
+ # ---------------------
2
+ # Global Ruff Settings
3
+ # ---------------------
4
+ fix = false
5
+ indent-width = 4
6
+ line-length = 120 # Wider code readability
7
+ target-version = "py314" # Set your Python version
8
+ preview = false # Disable experimental rules (safe default)
9
+
10
+ extend-exclude = [
11
+ ".git", ".venv", "venv", "env",
12
+ "build", "dist", "__pycache__",
13
+ ".mypy_cache", ".ruff_cache", ".pytest_cache",
14
+ ".run", ".idea", ".github", "__pycache__",
15
+ ]
16
+
17
+ [format]
18
+ indent-style = "space" # Use spaces over tabs
19
+ quote-style = "double" # Use double quotes consistently
20
+ line-ending = "auto" # Match the OS default (LF/CRLF)
21
+ docstring-code-format = true # Format code examples inside docstrings
22
+ docstring-code-line-length = 99 # Tighter line length for embedded docs
23
+ skip-magic-trailing-comma = false # Add trailing commas when useful
24
+
25
+
26
+ [lint]
27
+
28
+ select = [
29
+ "E", # pycodestyle: code formatting
30
+ "F", # pyflakes: undefined vars, unused imports
31
+ "B", # bugbear: common bugs and anti-patterns
32
+ "I", # import sorting (built-in, replaces isort)
33
+ "N", # pep8-naming: function/class naming
34
+ "D", # pydocstyle: docstring format
35
+ "UP", # pyupgrade: modernize Python syntax
36
+ "C4", # flake8-comprehensions: simplify comprehensions
37
+ "SIM", # flake8-simplify: remove redundant code
38
+ "TID", # tidy imports: disallow relative imports
39
+ "RUF", # Ruff-native: performance, cleanup
40
+ ]
41
+
42
+ # Ignore overly strict or stylistic docstring rules
43
+ ignore = [
44
+ "B013", # Allow One length tuple in the exception handlers
45
+ "D100", # Missing docstring in public modules
46
+ "D101", # Missing docstring in public class
47
+ "D102", # Missing docstring in public method
48
+ "D103", # Missing docstring in public function
49
+ "D104", # Missing docstring in public packages
50
+ "D105", # Missing docstring in magic methods
51
+ "D107", # Missing docstring in __init__
52
+ "D203", # 1 blank line required before class docstring
53
+ "D205", # 1 blank line required between summary line and description
54
+ "D212", # Multi-line docstring summary should start at the first line
55
+ "D213", # Multi-line docstring summary should start at the second line
56
+ "D401", # The first line should be in imperative mode
57
+ "D404", # The First word of docstring should not be "This"
58
+ "D405", # Section name should be properly capitalized
59
+ "D406", # The section name should end with a newline
60
+ "D407", # Missing dashed underline after section
61
+ "D408", # Section underline is too short
62
+ "D409", # Section underline is too long
63
+ "D410", # Missing blank line after a section
64
+ "D411", # Missing blank line before a section
65
+ "D413", # Missing blank line after the last section
66
+ "N812", # Allow lowercase imports to be aliased as non-lowercase
67
+ "N802", # Allow mixed case function name
68
+ "N803", # Allow mixed case variable name in function argumets
69
+ "N8", # Aloow all naming violations
70
+ "ANN", # Allow all missing annotations
71
+ "ERA001", # Keep commented out codes, linter hack: write comments docstring
72
+ "T201", # Allow print statements
73
+ "T203", # Allow pprint statements
74
+ "Q000", # Allow single quotes
75
+ "F401", # Keep unused imports **for now**
76
+ "F841", # Allow unused variables **for now**
77
+ "ANN204", # Docstring missing in special __dunder__ method
78
+ "COM812", # Missing trailing comma in a multi-line collection
79
+ "Q000", # Allow quotation violation
80
+ "Q003", # Allow quotation violation
81
+ "S104", # Allow binding to all interfaces (0.0.0.0)
82
+ "PERF401", # Ignore suggestion to use `extend` to create a transformed list,
83
+ "INP001", # Ignore implcit namespace package
84
+ ]
85
+
86
+ fixable = ["ALL"] # Allow Ruff to fix all enabled rules
87
+ unfixable = [] # Block nothing from fixing
88
+
89
+ # Import Sorting
90
+ [lint.isort]
91
+ length-sort = true
92
+ order-by-type = true # Group by type (class, func, const, etc.)
93
+ combine-as-imports = true # Prefer: `import mod as alias` (one line)
94
+ force-single-line = false # Allow grouping imports on one line
95
+ section-order = [
96
+ "future", "standard-library", "third-party", "first-party", "local-folder"
97
+ ]
98
+
99
+ [lint.flake8-annotations]
100
+ allow-star-arg-any = true # Allow `*args: Any` and `**kwargs: Any`
101
+
102
+ [lint.pep8-naming]
103
+ ignore-names = ["foo", "bar"] # Ignore naming rules for these names
104
+
105
+ # Docstring Style
106
+ [lint.pydocstyle]
107
+ convention = "google" # Options: google, numpy, pep257
noflare-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 BitByteLab
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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 BitByteLab
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.
noflare-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,105 @@
1
+ Metadata-Version: 2.5
2
+ Name: noflare
3
+ Version: 1.0.0
4
+ Summary: alternative to flaresolverr and Byparr. Once both of those stopped working for me, the snake convinced me to write this one.
5
+ Project-URL: Homepage, https://noflare.github.io/
6
+ Project-URL: GitHub, https://github.com/bitbytelab/noflare
7
+ Project-URL: PyPI, https://pypi.org/project/noflare/
8
+ Project-URL: Author-GitHub, https://github.com/rsmahmud
9
+ Project-URL: Author-LinkedIn, https://www.linkedin.com/in/rsmahmud
10
+ Project-URL: Author-Portfolio, https://rsmahmud.github.io/
11
+ Author-email: Hasan Rasel <rrss.mahmud@gmail.com>
12
+ Maintainer-email: Hasan Rasel <rrss.mahmud@gmail.com>
13
+ License-Expression: MIT
14
+ License-File: LICENSE
15
+ License-File: LICENSE.txt
16
+ Keywords: Byparr,bitbytelab,bot detection bypass,cloudflare bypass,flare,flaresolverr,noflare
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.11
22
+ Requires-Dist: fastapi
23
+ Requires-Dist: nodriver
24
+ Requires-Dist: python-dotenv
25
+ Requires-Dist: uvicorn
26
+ Description-Content-Type: text/markdown
27
+
28
+ # NoFlare - lightweight Cloudflare bypass service
29
+
30
+ Once FlareSolverr and Byparr stopped working for me, the snake convinced me write my own!
31
+
32
+ NoFlare is a small, async-first Python service that automates solving Cloudflare JavaScript challenges and Turnstile checks. It is built as a drop-in, modern alternative to projects like FlareSolverr and Byparr, using an undetected Chromium backend via `nodriver` and an async FastAPI HTTP API.
33
+
34
+ ### Why NoFlare?
35
+ - Minimal, async-first design for handling many concurrent requests.
36
+ - Designed to be a drop-in replacement for FlareSolverr/Byparr with a single HTTP endpoint.
37
+ - Packaged for PyPI and Docker for easy deployment.
38
+
39
+ ### Features
40
+ - Single POST `/v1` endpoint that accepts a JSON payload with `url` and `timeout`.
41
+ - Returns page HTML, cookies (including `cf_clearance`/Turnstile solutions), and user-agent.
42
+ - Configurable concurrency, headless mode, language, user data directory, and proxy via environment variables.
43
+
44
+ ### Quickstart - PyPI
45
+ 1. Install from PyPI:
46
+
47
+ `pip install noflare`
48
+
49
+ 2. Run the service:
50
+
51
+ `python -m noflare`
52
+
53
+ 3. Example request with `httpie`:
54
+ ```
55
+ http ://localhost:8191/v1 url="https://1337x.to"
56
+ ```
57
+
58
+ ### Environment variables
59
+ See `.env.example` for a full list. Notable variables:
60
+ - `PORT` - HTTP port (default: `8191`)
61
+ - `MAX_TABS` - Max concurrent Chromium tabs (default: `10`)
62
+ - `HEADLESS` - `true`/`false` to run Chromium headless (default: `false`)
63
+ - `DATA_DIR` - Path to persistent user-data directory (default: `~/.noflare/data`)
64
+ - `LANGUAGE` - Browser language/locale (default: `en-US`)
65
+ - `PROXY_SERVER` - Proxy server URL (e.g. `http://1.2.3.4:3128`)
66
+
67
+ ### Docker
68
+ Build and run locally with Docker:
69
+
70
+ ```bash
71
+ docker build -t noflare:local .
72
+ docker run --rm -p 8191:8191 \
73
+ -v /path/to/data:/data/noflare \
74
+ --env-file .env \
75
+ noflare:local
76
+ ```
77
+
78
+ ### Docker Compose
79
+ Use the provided `compose.yml` for local development. Copy `.env.example` to `.env` and edit values before launching.
80
+
81
+ ### Development
82
+ - Python 3.11+
83
+ - Install dev deps (project uses `pyproject.toml`):
84
+
85
+ ```bash
86
+ pip install -e .[dev]
87
+ ```
88
+
89
+ Run with reload for development:
90
+
91
+ ```bash
92
+ python -m noflare --debug
93
+ ```
94
+
95
+ ## Contributing
96
+ - Contributions, PRs and issues are welcome. Please open issues for bugs or feature requests.
97
+ - Follow the repository `CODEOWNERS` and maintainers' guidelines where provided.
98
+
99
+ ## License
100
+ MIT - see `LICENSE` for details.
101
+
102
+ Credits & Dependencies
103
+ - FastAPI - high-performance async API framework
104
+ - nodriver - Chromium automation backend (undetected/stealth)
105
+ - uvicorn - ASGI server
@@ -0,0 +1,78 @@
1
+ # NoFlare - lightweight Cloudflare bypass service
2
+
3
+ Once FlareSolverr and Byparr stopped working for me, the snake convinced me write my own!
4
+
5
+ NoFlare is a small, async-first Python service that automates solving Cloudflare JavaScript challenges and Turnstile checks. It is built as a drop-in, modern alternative to projects like FlareSolverr and Byparr, using an undetected Chromium backend via `nodriver` and an async FastAPI HTTP API.
6
+
7
+ ### Why NoFlare?
8
+ - Minimal, async-first design for handling many concurrent requests.
9
+ - Designed to be a drop-in replacement for FlareSolverr/Byparr with a single HTTP endpoint.
10
+ - Packaged for PyPI and Docker for easy deployment.
11
+
12
+ ### Features
13
+ - Single POST `/v1` endpoint that accepts a JSON payload with `url` and `timeout`.
14
+ - Returns page HTML, cookies (including `cf_clearance`/Turnstile solutions), and user-agent.
15
+ - Configurable concurrency, headless mode, language, user data directory, and proxy via environment variables.
16
+
17
+ ### Quickstart - PyPI
18
+ 1. Install from PyPI:
19
+
20
+ `pip install noflare`
21
+
22
+ 2. Run the service:
23
+
24
+ `python -m noflare`
25
+
26
+ 3. Example request with `httpie`:
27
+ ```
28
+ http ://localhost:8191/v1 url="https://1337x.to"
29
+ ```
30
+
31
+ ### Environment variables
32
+ See `.env.example` for a full list. Notable variables:
33
+ - `PORT` - HTTP port (default: `8191`)
34
+ - `MAX_TABS` - Max concurrent Chromium tabs (default: `10`)
35
+ - `HEADLESS` - `true`/`false` to run Chromium headless (default: `false`)
36
+ - `DATA_DIR` - Path to persistent user-data directory (default: `~/.noflare/data`)
37
+ - `LANGUAGE` - Browser language/locale (default: `en-US`)
38
+ - `PROXY_SERVER` - Proxy server URL (e.g. `http://1.2.3.4:3128`)
39
+
40
+ ### Docker
41
+ Build and run locally with Docker:
42
+
43
+ ```bash
44
+ docker build -t noflare:local .
45
+ docker run --rm -p 8191:8191 \
46
+ -v /path/to/data:/data/noflare \
47
+ --env-file .env \
48
+ noflare:local
49
+ ```
50
+
51
+ ### Docker Compose
52
+ Use the provided `compose.yml` for local development. Copy `.env.example` to `.env` and edit values before launching.
53
+
54
+ ### Development
55
+ - Python 3.11+
56
+ - Install dev deps (project uses `pyproject.toml`):
57
+
58
+ ```bash
59
+ pip install -e .[dev]
60
+ ```
61
+
62
+ Run with reload for development:
63
+
64
+ ```bash
65
+ python -m noflare --debug
66
+ ```
67
+
68
+ ## Contributing
69
+ - Contributions, PRs and issues are welcome. Please open issues for bugs or feature requests.
70
+ - Follow the repository `CODEOWNERS` and maintainers' guidelines where provided.
71
+
72
+ ## License
73
+ MIT - see `LICENSE` for details.
74
+
75
+ Credits & Dependencies
76
+ - FastAPI - high-performance async API framework
77
+ - nodriver - Chromium automation backend (undetected/stealth)
78
+ - uvicorn - ASGI server
@@ -0,0 +1,66 @@
1
+ [build-system]
2
+ requires = ["hatchling", "uv-dynamic-versioning"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "noflare"
7
+ dynamic = ["version"]
8
+ description = """alternative to flaresolverr and Byparr. Once both of those stopped working for me, the snake convinced me to write this one."""
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICEN[CS]E*"]
12
+ requires-python = ">=3.11"
13
+ keywords = ["bitbytelab", "noflare", "flare", "flaresolverr", "Byparr", "cloudflare bypass", "bot detection bypass"]
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: OS Independent",
18
+ "Topic :: Software Development :: Libraries :: Python Modules",
19
+ ]
20
+
21
+ authors = [
22
+ { name = "Hasan Rasel", email = "rrss.mahmud@gmail.com" },
23
+ ]
24
+
25
+ maintainers = [
26
+ { name = "Hasan Rasel", email = "rrss.mahmud@gmail.com" },
27
+ ]
28
+
29
+ dependencies = [
30
+ "fastapi",
31
+ "uvicorn",
32
+ "nodriver",
33
+ "python-dotenv",
34
+ ]
35
+
36
+ [project.urls]
37
+ Homepage = "https://noflare.github.io/"
38
+ GitHub = "https://github.com/bitbytelab/noflare"
39
+ PyPI = "https://pypi.org/project/noflare/"
40
+
41
+ Author-GitHub = "https://github.com/rsmahmud"
42
+ Author-LinkedIn = "https://www.linkedin.com/in/rsmahmud"
43
+ Author-Portfolio = "https://rsmahmud.github.io/"
44
+
45
+ [tool.hatch.version]
46
+ source = "uv-dynamic-versioning"
47
+
48
+ [tool.hatch.metadata]
49
+ allow-direct-references = true
50
+
51
+ [tool.hatch.build.targets.wheel]
52
+ sources = ["src"]
53
+ only-include = ["src/noflare"]
54
+
55
+ [tool.hatch.build.targets.sdist]
56
+ only-include = [
57
+ "src",
58
+ "uv.lock",
59
+ "README.md",
60
+ ".gitignore",
61
+ ".ruff.toml",
62
+ "pyproject.toml"
63
+ ]
64
+
65
+ [project.scripts]
66
+ noflare = "noflare.__main__:main"
@@ -0,0 +1,19 @@
1
+ """NoFlare package
2
+
3
+ Expose the ASGI `app` from the core module and provide package
4
+ metadata for runtime import and packaging.
5
+
6
+ This module intentionally keeps imports minimal so importing the
7
+ package does not eagerly start the browser process; the FastAPI
8
+ app is imported on demand by ASGI servers such as `uvicorn`.
9
+ """
10
+ from importlib.metadata import version, PackageNotFoundError
11
+
12
+ try:
13
+ __version__ = version("noflare")
14
+ except PackageNotFoundError:
15
+ __version__ = "0.0.0"
16
+
17
+ from .noflare import app
18
+
19
+ __all__ = ["app", "__version__"]
@@ -0,0 +1,54 @@
1
+ """Command line entrypoint for the `noflare` package.
2
+
3
+ Provides a simple CLI wrapper around `uvicorn` so the package can
4
+ be executed after `pip install .` as `python -m noflare` or (if a
5
+ console script is added) as `noflare`.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import os
10
+ import argparse
11
+
12
+ import uvicorn
13
+
14
+ DEFAULT_PORT = int(os.getenv("PORT", "8191"))
15
+
16
+
17
+ def parse_args(argv=None):
18
+ p = argparse.ArgumentParser(prog="noflare")
19
+ p.add_argument("--host", default="0.0.0.0", help="Host to bind to")
20
+ p.add_argument("--port", type=int, default=DEFAULT_PORT, help="Port to listen on")
21
+ p.add_argument("--headless", action="store_true", help="Run browser in headless mode")
22
+ p.add_argument("--data-dir", dest="data_dir", help="User data directory for browser profile")
23
+ p.add_argument("--lang", dest="lang", help="Language/locale to use, e.g. en-US")
24
+ p.add_argument("--proxy", dest="proxy", help="Proxy server URL (e.g. http://host:port)")
25
+ p.add_argument("--debug", action="store_true", help="Run with reload and debug logging")
26
+ return p.parse_args(argv)
27
+
28
+
29
+ def main(argv=None):
30
+ args = parse_args(argv)
31
+
32
+ if args.headless:
33
+ os.environ["HEADLESS"] = "true"
34
+ if args.data_dir:
35
+ os.environ["DATA_DIR"] = args.data_dir
36
+ if args.lang:
37
+ os.environ["LANGUAGE"] = args.lang
38
+ if args.proxy:
39
+ os.environ["PROXY_SERVER"] = args.proxy
40
+
41
+ log_level = "debug" if args.debug else os.getenv("LOG_LEVEL", "info").lower()
42
+
43
+ uvicorn.run(
44
+ "noflare.noflare:app",
45
+ host=args.host,
46
+ port=args.port,
47
+ log_level=log_level,
48
+ reload=args.debug,
49
+ )
50
+
51
+
52
+ if __name__ == "__main__":
53
+ main()
54
+