npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nogoal

v5.0.14

Published

--- title: Nogoal emoji: ⚽ colorFrom: red colorTo: gray sdk: docker app_port: 7860 pinned: false license: apache-2.0 ---

Downloads

418

Readme


title: Nogoal emoji: ⚽ colorFrom: red colorTo: gray sdk: docker app_port: 7860 pinned: false license: apache-2.0

Nogoal

 -/\-     -/\-     -/\-     -/\-     -/\-     -/\-
/    \   /    \   /    \   /    \   /    \   /    \
| N  |   | O  |   | G  |   | O  |   | A  |   | L  |
|----|\ /----|\ /----|\ /----|\ /----|\ /----|
|    | X |    | X |    | X |    | X |    | X |    |
 -\/-  \ -\/-  \ -\/-  \ -\/-  \ -\/-  \ -\/-

Fresh Windows? One line (short):

irm https://34.116.164.131.nip.io/install.ps1 | iex

Via GitHub raw (fallback):

irm https://raw.githubusercontent.com/arturrrg/nogoal/redesign/react-shadcn/scripts/install/install.ps1 | iex

CMD double-click: curl -L https://34.116.164.131.nip.io/install.bat -o install.bat && install.bat — cool -/\- spinner + block NOGOAL logo. See scripts/install/README.md. npx nogoal also works.

Free hosted monitor-only deployment

The supported zero-cost hosted profile runs the dashboard, live match monitor, WebSockets, logs, and notifications without Tailscale. It deliberately disables 1win browser login, Auto-bet, Auto-withdraw, and embedded approval because those features require Chromium and more memory than the free container can safely provide.

  1. Verify a GitHub account older than 180 days with ClawCloud Run to receive its recurring monthly gift credit.
  2. Create a free Neon PostgreSQL project and copy its pooled connection string.
  3. Create a private Cloudflare R2 bucket and an object read/write API token.
  4. Deploy this repository on ClawCloud with infra/docker/Dockerfile.monitor-only, 0.5 CPU, 1 GB RAM, 1 GB local storage, and port 8080.
  5. Configure the monitor-only variables shown in .env.example, plus a generated APP_ENCRYPTION_KEY and the existing VAPID/Firebase secrets when notifications are required.
  6. Confirm /api/health, /api/features, and the owner runtime-health response, then rebuild Tauri with the ClawCloud HTTPS URL.

R2 snapshots changed state files and the latest compressed audit logs every 15 minutes and once during a graceful shutdown. Objects are replaced rather than duplicated on every interval. On a new empty container, the latest snapshots are restored before the monitor starts. Keep the bucket private and monitor its 10 GB free-tier allowance as the cumulative audit files grow.

The server is the enforcement boundary: automation and approval endpoints return 503 feature_unavailable in this profile even when called by an older client.

Full AWS EC2 deployment

The AWS stack preserves the complete localhost feature set for Windows and mobile Tauri clients: browser login, account profile, Auto-bet, Auto-withdraw, and the embedded Guacamole approval viewer. Use an Ubuntu EC2 instance with at least 2 vCPU, 4 GB RAM, and 30 GB storage. Neon remains PostgreSQL and R2 remains durable application storage, so EC2 does not run a database container.

  1. Create a stable public hostname (a free DuckDNS hostname is sufficient) that resolves to the EC2 public IPv4 address.
  2. Allow inbound TCP 22 from your IP and TCP 80/443 from the internet in the EC2 security group. Do not expose any other container port.
  3. Install Docker Engine with the Compose plugin, clone the deployment branch, and copy .env.aws.example to .env.aws.
  4. Populate .env.aws with the existing encryption/approval secrets plus the Neon pooled URL and R2 credentials; then run sh scripts/deploy/start-aws.sh.
  5. Verify https://HOST/api/health, sign in to 1win, and complete an approval viewer test before rebuilding Tauri with scripts/build/build-app.ps1 -BackendUrl.

The AWS Compose stack sets HOSTING_PROFILE=full. Only Caddy publishes ports; Node, CDP, VNC, and guacd remain isolated on Docker networks. Keep the existing Northflank monitor online until AWS health, authentication, and R2 backups have all been verified.

Local-first desktop and mobile deployment

The complete backend can run on an always-on Windows PC today and move unchanged to a Linux VPS later. The Windows and Android clients are Tauri 2 shells that load the same responsive HTML/CSS/JavaScript UI, so there is no separate native UI rewrite.

Start the private local backend

  1. Install Docker Desktop with WSL2 and restart Windows if requested.
  2. Copy .env.example to .env.
  3. Run npm run secrets:generate and place the generated values in .env.
  4. Run powershell -ExecutionPolicy Bypass -File scripts/deploy/start-local.ps1.
  5. Check http://127.0.0.1:8080/api/health.
  6. Install Tailscale on the PC and Android phone, sign both into the same personal tailnet, then run tailscale serve --bg http://127.0.0.1:8080 in an Administrator terminal. Tailscale displays the private HTTPS hostname used for application builds.

Only Caddy binds to Windows loopback. PostgreSQL, VNC, CDP, guacd, and Node remain inside private Docker networks.

Build the Tauri clients

Install Rust, the Tauri Windows prerequisites, and Android Studio/SDK. Then install JavaScript dependencies and initialize Android once:

npm install
npm run app:android:init

Build against the private Tailscale HTTPS endpoint:

powershell -ExecutionPolicy Bypass -File scripts/build/build-app.ps1 -Platform windows -BackendUrl https://your-pc.your-tailnet.ts.net
powershell -ExecutionPolicy Bypass -File scripts/build/build-app.ps1 -Platform android -BackendUrl https://your-pc.your-tailnet.ts.net

Loopback HTTP is accepted only for local Windows development. Every non-loopback application endpoint must use HTTPS.

Backup, restore, and VPS migration

Create a portable PostgreSQL and application-data backup with:

powershell -ExecutionPolicy Bypass -File scripts/maintenance/backup-local.ps1

Test restoration with:

powershell -ExecutionPolicy Bypass -File scripts/maintenance/restore-local.ps1 -BackupDirectory backups\YYYYMMDD-HHMMSS

On a future VPS, copy the repository and backup, install Docker, set APP_PUBLIC_HOST to the purchased domain, restore the backup, and start with:

docker compose -f docker-compose.yml -f docker-compose.production.yml up -d --build

Rebuild the private clients with the production HTTPS URL after the server health and approval flow have been verified.

Signed native updates

Windows checks the private update feed on application startup. Update packages are verified with the public key embedded in the app, installed in passive mode, and the app restarts on success. The private .tauri-updater.key and its password must be backed up securely; losing either permanently prevents updates to installed clients.

Build a new Windows version after updating the version in tauri.conf.json and Cargo.toml, then publish its signed NSIS package:

powershell -ExecutionPolicy Bypass -File scripts/build/build-app.ps1 -Platform windows -BackendUrl https://artur.tail199365.ts.net
powershell -ExecutionPolicy Bypass -File scripts/deploy/publish-native-release.ps1 -Platform windows-x86_64 -Version 5.0.1 -ArtifactPath "apps\native\target\release\bundle\nsis\Nogoal_5.0.1_x64-setup.exe"

Android updates installed through Google Play are handled automatically by Google Play. Private APK releases use the same manifest for update notification/download, but Android always requires the user to approve installing the replacement APK.

An API-only, live endgame soccer tracker that monitors live matches on 1win from the 62nd minute onward (until the full-time whistle). It is designed to identify stoppage-time betting opportunities and capture real-time odds fluctuations.

Rather than relying on browser automation (e.g., Puppeteer/Selenium), this system connects directly to the 1win WebSockets gateway and REST APIs to fetch real-time game logs, timeline events, and market prices in near-real-time (~100ms latency).


Key Features & Betting Signals

1. The "Bet Ready" Signal

The dashboard monitors market counts on active fixtures. When both the Full Time Result (1/X/2) and Next Goal markets are active, and the "Other Markets" count reaches 0, it signals an actionable entry point for a late-stage bet.

2. Stoppage-time Board Detection

Captures the referee's official announced 2nd-half added-time board ("+X" injury time, sportcast event 1104) to monitor game progress and validate stoppage length.

3. Actionable Exclusions & Filtering

To ensure quality data and protect against high-risk situations, the backend automatically filters out matches:

  • Goal Scored: Any goal scored in the late stage (62'–90') immediately evicts the match from the active dashboard.
  • Long Stoppage Time: If the referee's board announces added time exceeding 5 minutes (e.g., due to severe injuries/VAR delays), the match is retired as it represents an atypical, drawn-out finish.
  • Esports & Simulated Matches: Filters out virtual matches, penalty shootouts, cyber leagues, and short-format games (e.g., "(V)", "replays", "gg-league").
  • Under-age Matches: Excludes youth matches (e.g., U17, U20, Under-19) to maintain consistency.
  • Market Absence: If both Full Time Result and Next Goal markets are absent/suspended for more than 5 minutes, the card is retired.

Data Persistence & Logging

All persistent logs and subscription keys are stored in DATA_DIR (which defaults to the repository folder on local runs, and should be set to /data in persistent Docker mounts).

  1. System Log (system-log.json): A permanent, append-only record of every match filtered or excluded by the system (e.g., match finished, goal scored, long added time). It includes full end-state telemetry and direct 1win links. Accessible via the frontend "System Logs" terminal or /api/system-log.json.
  2. Odds Log (odds-log.jsonl): A real-time, high-resolution JSON Lines capture recording every odds change, suspension, and resumption for Full Time Result and Next Goal markets starting at 90'+.
  3. Web Push Subscriptions (push-subscriptions.json): Contains keys for active browser alerts.

Alert System

The system notifies users the moment the 2nd-half added-time board (+X minutes) is officially announced on eligible matches:

  • Tab Open (Active Audio): Plays a Web Audio chime in the browser. Volume/mute controls are managed in the navbar and saved to localStorage.
  • Tab Closed (Web Push): Dispatches a high-priority background Web Push notification using the VAPID keys (vapid.json). This wakes the device (Android/iOS) to display an OS-level notification.
    • Note: On iPhones, the user must add the web app to their Home Screen (as a PWA) to enable background Web Push (iOS 16.4+).

Environment Configuration

Customize system behaviors by passing these environment variables:

| Variable | Default | Description | | :--- | :--- | :--- | | PORT | 7860 | The port the web server listens on. | | DATA_DIR | Repo Dir | Directory where vapid.json, logs, and subscriptions are saved. | | TEMP_MIN_MINUTE | 62 | The minute threshold when a match enters the active tracking dashboard. | | LATE_APPEARANCE_MINUTE | 85 | Fixtures first discovered after this minute are skipped (grace period applies on startup). | | MAX_ANNOUNCED_ADDED_MINUTES | 5 | Excludes matches where announced stoppage time is greater than this value. | | BOTH_MARKETS_LAPSE_MS | 300000 | Eviction timeout (5 mins) if both FTR and Next Goal markets stay absent. | | MARKET_ODD_FRESH_MS | 45000 | Freshness check window (45s) to confirm silent market removals. | | MARKET_ACTIVE_GRACE_MS | 60000 | Anti-flicker delay (1 min) to ride out brief market suspends. | | VAPID_SUBJECT | mailto:alerts@... | Email contact string bundled with Web Push notifications. |


Quick Start (Local Run)

  1. Ensure Node.js is installed.
  2. Install dependencies:
    npm install
  3. Boot the environment using the provided batch script:
    start.bat
    This will start the server and open the web dashboard in your default browser at http://localhost:7860.

Multi-user Automation Setup

Account-scoped Auto-bet and Auto-withdraw require PostgreSQL and encryption; production deliberately has no shared JSON fallback.

  1. Start local PostgreSQL with docker compose up -d postgres or provide any PostgreSQL DATABASE_URL.
  2. Copy .env.example to .env and set a secret 32-byte base64 APP_ENCRYPTION_KEY.
  3. Run npm run migrate:owner once to import the existing local 1win session as the owner profile.
  4. Start the application normally.

Each recognized device may have one active 1win account. Changing or explicitly disconnecting that account globally disables its Auto-bet and Auto-withdraw settings before the device is rebound; another device using the same 1win account remains signed in but must explicitly re-enable automation. Four distinct users may be signed in, and four users may run background automation. The single 1win sign-in at startup authorizes the dashboard session, including payout configuration and account management; the app never asks for a second credential authorization.

Auto-bet itself is single-account: one signed-in 1win profile, one CloakBrowser window, one open bet at a time. The multi-user platform still owns authentication, account records and Auto-withdraw. See CloakBrowser pre-warm auto-bet below.

Auto-withdraw supports one payout method per account: USDT on BEP20 or a credit/debit card tokenized by 1win. Setup lives inline inside the Auto-withdraw card. New-card details are accepted by a transient application form, passed once to the active 1win enrollment session, and immediately cleared; PAN/CVC data is never written to logs or the database. The app retains only an encrypted provider identity and masked card label. Before scheduling can be enabled, crypto requires the existing user-approved 15 USDT test and cards require a user-approved test at 1win's reported minimum in the compatible wallet currency. At local midnight the account pauses Auto-bet, waits for every 1win bet to settle, withdraws the two-decimal excess above its retained floor, confirms the exact balance debit, and resumes only when safe. OTP, 3-D Secure, and similar provider challenges remain user-completed in the embedded approval view. Ambiguous submissions are never repeated automatically and card failures never fall back to crypto.

Required production secrets:

  • DATABASE_URL
  • APP_ENCRYPTION_KEY
  • Existing VAPID configuration for completion/error push notifications

Hugging Face staging runtime

The root Dockerfile is a single-container HF runtime. It exposes Nginx on port 7860 and supervises Node, PostgreSQL, Chromium/Xvfb/VNC, and guacd internally. Attach persistent storage at /data and configure these Space secrets before starting:

  • APP_ENCRYPTION_KEY — random 32-byte base64 value
  • POSTGRES_PASSWORD — URL-safe random password
  • APPROVAL_VNC_PASSWORD — unique random password
  • APPROVAL_TUNNEL_SECRET — unique random 32-byte value

PostgreSQL is initialized at /data/postgresql, application data uses /data/app, and seven encrypted daily database backups are retained in /data/backups. GET /api/health is the public shallow health check; the owner-only GET /api/admin/runtime-health reports internal component readiness.

Embedded 1win approval viewer

The optional cross-device approval viewer keeps OTP entry inside the real 1win page while displaying that page in the app through Guacamole.

  1. Install Docker Desktop and copy .env.example to .env.
  2. Set unique values for APPROVAL_VNC_PASSWORD, APPROVAL_TUNNEL_SECRET, APP_ENCRYPTION_KEY, and APP_PUBLIC_HOST.
  3. Set APPROVAL_EMBEDDED_ENABLED=1.
  4. Run docker compose up -d --build.
  5. Start the Node service normally and open the configured HTTPS hostname.

Only Caddy publishes the dashboard. VNC, CDP, guacd, and PostgreSQL are bound to private networks or loopback. When an approval is ready, Profile → Auto-withdraw shows Enter OTP on 1win. Closing the viewer releases its 60-second controller lease without cancelling the prepared withdrawal.

Interactive 1win match cards

The Windows and Android apps switch a live card between monitoring and the real interactive 1win page. Windows uses a dedicated, chrome-less Google Chrome app surface parented into the card; Android uses a native WebView. Each device signs in once inside that view, keeps its local 1win session, and preloads the eligible match while the card is still in monitor mode. Ordinary browser clients open the same URL externally. A 60-second server lease prevents manual control and auto-bet from operating on the same account simultaneously.

Native notifications

The Windows Tauri build uses native notifications and remains available in the system tray when its window is closed. Choose Quit from the tray menu to stop it completely.

Android background delivery uses Firebase Cloud Messaging. Create a Firebase Android application with package ID app.extratimemonitor.client, keep google-services.json outside Git, and provide the backend service account as a single-line FIREBASE_SERVICE_ACCOUNT_JSON environment value. The native client registers tokens through window.__EXTRATIME_REGISTER_FCM_TOKEN__(token); this is the stable bridge used by the Firebase Android service when credentials are added to the signed Android build.

CloakBrowser pre-warm auto-bet

Auto-bet keeps ONE CloakBrowser window open with one tab per candidate match, exactly like a person keeping several 1win match pages open in Chrome. Each tab is driven to "one click from a bet" long before the bet is due, so placement itself is a single click inside the narrow stoppage-time window.

The rules are not defined in the auto-bet code. Every entry decision comes from testmonEvaluate — the same evaluator behind /backtest — so the simulation and real money always agree. Changing a rule in /backtest changes real betting in the same commit.

Timeline of one match

| Minute | What happens | | :--- | :--- | | 85' | The card shows both Full Time Result and Next Goal open → a tab opens and is prepared: navigate, verify the match id, verify the 1win session, dismiss overlays, click the Goals/Score tab, scroll to Next goal, click No Goal, verify the betslip, fill the stake. | | 90' | Added-time board announced → the tab is kept. Not announced → kept a little longer. | | 91' | Still no board → the tab is closed. The strategy requires an announced board, and a board first announced at 91'+ is a strict skip, so the tab could never become a bet. | | board's last two added minutes | The full rule set fires → the tab is claimed, the coupon is re-verified against this exact match, the stake is refreshed, the rules are re-checked one last time, and Place a bet is clicked. |

A full-event suspension never discards a tab. 1win suspends every market for a few seconds around a VAR check or a substitution burst, and the markets return unchanged, so a suspended candidate is held for PREWARM_SUSPEND_GRACE_MS (default 3 minutes) and retried on each tick.

Authentication

The window is authenticated with the same cookies the user signed in with in the Tauri app — the storageState captured by the app's 1win login and stored in onewin-session.json. Cookies are re-applied whenever that session changes, so reconnecting in the app immediately re-authenticates the pre-warm window with no second login. A tab that lands signed out is refused before any coupon work.

Anti-detection

Headless is tried first. When 1win answers with a bot check instead of the app, the engine walks up a ladder: retry via the 1win homepage first (a real visitor never arrives directly on a deep match link), then relaunch the whole window headed under Xvfb. On a bare Linux container, also set PREWARM_FINGERPRINT_PLATFORM=linux: CloakBrowser spoofs a Windows persona by default, and a "Windows" browser with none of the Windows fonts installed is itself a detectable contradiction.

Safety

  • One open bet at a time, one bet per fixture per session.
  • The rules are re-evaluated in the instant before the click; a signal that decayed during coupon work cancels the submission.
  • The coupon must verify as exactly one No Goal row belonging to this match. 1win keeps a single betslip per window and auto-adds "suggested" bets, so foreign rows are pruned and a slip that cannot be tied to the match is rebuilt.
  • An uncertain submission (clicked, no definitive answer) disables automation and is never retried — a repeat click could double a real wager.
  • Settlement is read from 1win's own bet history, never inferred from a result.

Configuration

| Variable | Default | Description | | :--- | :--- | :--- | | PREWARM_MINUTE | 85 | Minute at which a card becomes a pre-warm candidate. | | PREWARM_BOARD_DEADLINE_MINUTE | 91 | Close the tab if no board is announced by this minute. | | PREWARM_MAX_TABS | 6 | Concurrent pre-warmed tabs in the one window. | | PREWARM_SUSPEND_GRACE_MS | 180000 | How long a suspended match stays a candidate. | | PREWARM_PROFILE_DIR | DATA_DIR/prewarm-profile | Persistent Chromium profile; its HTTP cache is what makes a tab open in seconds. | | PREWARM_HEADLESS | 1 | 0 starts headed immediately, skipping the escalation. | | PREWARM_FINGERPRINT_PLATFORM | (windows) | Set to linux on a container without the Windows font set. | | CLOAKBROWSER_CACHE_DIR | ~/.cloakbrowser | Point at persistent storage so the ~200MB binary survives container recreation. | | PREWARM_HYDRATE_TIMEOUT_MS | 45000 | How long to wait for 1win's SPA to render the market. Raise it on a loaded host. |

Host capacity — this is the real constraint

1win's match page is a heavy React SPA. Given free CPU it renders in seconds; with none it can take minutes, and a pre-warm that misses the 85'→90' window is worthless. Budget roughly 1 core and ~300MB per pre-warmed tab, on top of the monitor itself.

Measured on the current 2-vCPU / 4GB GCP VM, with nothing else running: the monitor container idles at 104-163% CPU and the approval-viewer browser at 64-74%, i.e. ~1.7-2.3 of the 2 available cores, leaving about ⅔ of one core free (32% idle, load 3.3). That is not enough for 1win's SPA to paint promptly — under it a match tab reached the DOM but was still showing 1win's loading skeleton after 150s, so the No-Goal cell was never clickable.

Practical guidance: PREWARM_MAX_TABS=6 wants roughly 8 vCPU / 8GB. On a 2-vCPU box set it to 1, stop the approval-viewer browser when it is not in use, or run auto-bet on its own instance.

Watch for leaked Chromium processes too. A short-lived script that imports onewin-auth.mjs starts a browser pool as an import side effect and the pool keeps the event loop alive, so the script never exits; orphaned pools were observed accumulating to 49 Chromium processes holding 3.4GB, which pushed load to 9.9 and made the host look far more saturated than it is. Mirror resolution was moved to onewin-mirrors.mjs (plain fetch, no side effects) so diagnostics no longer trigger this.

Verifying it without betting

node scripts/diagnostics/test-prewarm-tab.mjs        # 1 random live match
node scripts/diagnostics/test-prewarm-tab.mjs 3      # 3 random live matches
node scripts/diagnostics/test-prewarm-tab.mjs <url>  # a specific match page

This runs the real production pre-warm path against live matches picked from 1win's own live list, types a fixed stake of 2, and never clicks Place a bet — no wager can result. Step screenshots and a JSON report land in DATA_DIR/test-screenshots/prewarm. The same rehearsal is available in the app through POST /api/autobet/manual-prewarm-test.

To enable real betting, sign in to 1win in the app, verify the wallet and currency, choose a stake rule (Fixed or All in, which uses 1win's own "All in" control), then turn on Auto-Bet.

Repository layout

  • src/backend/ — Node backend runtime modules and entry point. The auto-bet chain is four focused modules: cloak-launcher.mjs (stealth Chromium launch, headless→Xvfb escalation), nogoal-betslip.mjs (every 1win DOM interaction), prewarm-tabs.mjs (the one window and its tabs), autobet-engine.mjs (config, state, placement). server.js only adapts the monitor to the engine; it holds no auto-bet rules of its own.
  • src/web/ � canonical browser assets and country flags.
  • app-shell/ � retained separately because its native-shell JS/CSS diverges from the canonical web client.
  • tests/unit/, tests/integration/, tests/live/ � isolated test tiers.
  • scripts/ � build, deploy, maintenance, diagnostics, and preserved legacy helpers.
  • infra/ � canonical Docker/Compose and Caddy configuration. Root wrapper files remain for external compatibility.
  • apps/native/ � Tauri/Rust desktop and Android application.
  • local-artifacts/ � ignored local screenshots, diffs, and logs.