{"id":15661224,"url":"https://github.com/ricardoboss/pubnet","last_synced_at":"2025-04-14T10:11:21.340Z","repository":{"id":66582796,"uuid":"587642179","full_name":"ricardoboss/PubNet","owner":"ricardoboss","description":"Self-hosted Dart \u0026 Flutter package service","archived":false,"fork":false,"pushed_at":"2025-04-08T21:31:44.000Z","size":2976,"stargazers_count":39,"open_issues_count":12,"forks_count":3,"subscribers_count":3,"default_branch":"develop","last_synced_at":"2025-04-14T09:08:57.063Z","etag":null,"topics":["api","dart","dart-packages","help-wanted","package-manager","up-for-grabs"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ricardoboss.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-01-11T08:32:00.000Z","updated_at":"2025-04-10T09:35:45.000Z","dependencies_parsed_at":"2024-03-09T23:31:21.025Z","dependency_job_id":"7be218c1-ac7a-4d6e-9271-aecf3137498c","html_url":"https://github.com/ricardoboss/PubNet","commit_stats":{"total_commits":169,"total_committers":4,"mean_commits":42.25,"dds":0.5029585798816568,"last_synced_commit":"aa80ce60a842cd5290b996ae73c3a7b4219ec95d"},"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ricardoboss%2FPubNet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ricardoboss%2FPubNet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ricardoboss%2FPubNet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ricardoboss%2FPubNet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ricardoboss","download_url":"https://codeload.github.com/ricardoboss/PubNet/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248860213,"owners_count":21173342,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","dart","dart-packages","help-wanted","package-manager","up-for-grabs"],"created_at":"2024-10-03T13:26:32.750Z","updated_at":"2025-04-14T10:11:21.296Z","avatar_url":"https://github.com/ricardoboss.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![.NET](https://github.com/ricardoboss/PubNet/actions/workflows/dotnet.yml/badge.svg)](https://github.com/ricardoboss/PubNet/actions/workflows/dotnet.yml)\n[![Docker](https://github.com/ricardoboss/PubNet/actions/workflows/docker-publish.yml/badge.svg)](https://github.com/ricardoboss/PubNet/actions/workflows/docker-publish.yml)\n\n# PubNet\n\nSelf-hosted pub.dev alternative.\n\n## Contents\n\n- [Development](#development)\n  - [Architecture](#architecture)\n  - [Debugging](#debugging)\n- [Contributions](#contributions)\n- [Hosting](#hosting)\n  - [Using `docker-compose.yml`](#using-docker-composeyml)\n  - [Other approaches](#other-approaches)\n- [License](#license)\n- [Screenshots](#screenshots)\n\n---\n\n![PubNet Homepage](.github/media/homepage.png)\n\n## Development\n\nThe root of this repository contains a `docker-compose.yml`, which contains three services used to aid in debugging `PubNet`:\n\n- `database`: A postgres database (user: 'pubnet', password: 'pubnet')\n- `adminer`: A webinterface for managing the database\n- `seq`: A useful logging service\n\nThe only service you need to start is `database`, though the other services help during development.\n\n\u003e **Note**\n\u003e\n\u003e You can also use a database you set up on your host, but currently only postgres is supported.\n\n### Architecture\n\nThe solution consists of a few projects, three of them compose the whole PubNet service:\n\n- `PubNet.API`: provides the API used by the `dart pub` command line tool to fetch and upload new packages\n- `PubNet.Frontend`: contains a Blazor WebAssembly project to act as a frontend for the API\n- `PubNet.Worker`: executes tasks (scheduled and unscheduled) to analyze packages and do general housekeeping\n\n### Debugging\n\nYou can use any IDE you want, as long as it supports debugging .NET 8 or higher.\n\nFor the `PubNet.Frontend` project, it is recommended to run it using `dotnet-watch`.\n\n#### Database migrations\n\nThis project uses Entity Framework Core with the code-first approach, so migrations are added using `dotnet ef migrations add \u003cname\u003e` and executed using `dotnet ef database update` in the `PubNet.Database` project folder.\nCurrently, the database project expects the credentials and database name to all be equal to 'pubnet'.\n\n## Contributions\n\nIf you want to contribute improvements or bugfixes, fork this repository, create a branch, commit your changes to it and open a pull request here on GitHub.\n\n## Hosting\n\n\u003e **Note**\n\u003e\n\u003e In case you only need a simple, privately hosted pub package API, the API project alone is sufficient.\n\nWhen you are ready to deploy `PubNet`, you may want to review the `OpenRegistration` setting in the `backend-appsettings.json` to toggle whether anyone is able to register an account.\nThis setting can be changed at runtime.\n\n### Using `docker-compose.yml`\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ccode\u003edocker-compose.yml\u003c/code\u003e template\u003c/summary\u003e\n\nCreate a `docker-compose.yml` with the following contents:\n\n```yaml\nversion: '3.9'\n\nvolumes:\n  postgres_data:\n  pubnet_packages:\n  caddy_data:\n  caddy_config:\n\nservices:\n  database:\n    image: postgres:latest\n    restart: always\n    environment:\n      POSTGRES_USER: \"pubnet\"\n      POSTGRES_PASSWORD: \"pubnet\"\n    volumes:\n      - postgres_data:/var/lib/postgresql/data\n\n  backend:\n    image: ghcr.io/ricardoboss/pubnet/api:main\n    restart: always\n    volumes:\n      - \"./backend-appsettings.json:/app/appsettings.Production.json\"\n      - \"pubnet_packages:/app/packages\"\n    depends_on:\n      - database\n      - caddy\n\n  worker:\n    image: ghcr.io/ricardoboss/pubnet/worker:main\n    restart: always\n    volumes:\n      - \"./worker-appsettings.json:/app/appsettings.Production.json\"\n      - \"pubnet_packages:/app/packages\"\n    depends_on:\n      - database\n\n  frontend:\n    image: ghcr.io/ricardoboss/pubnet/frontend:main\n    restart: always\n    depends_on:\n      - backend\n      - caddy\n\n  # you can choose any reverse proxy you want, Caddy is not required\n  caddy:\n    image: caddy\n    restart: always\n    volumes:\n      - \"./Caddyfile:/etc/caddy/Caddyfile\"\n      - \"caddy_data:/data\"\n      - \"caddy_config:/config\"\n    ports:\n      - \"80:80\"\n      - \"443:443\"\n      - \"443:443/udp\"\n```\n\n\u003c/details\u003e\n\n\u003e **Note**\n\u003e\n\u003e In this example, caddy is used as a reverse-proxy.\n\u003e\n\u003e You can also host the backend and frontend on different ports, and publish them directly, removing the need to configure a reverse proxy entirely.\n\n\u003cdetails\u003e\n  \u003csummary\u003eReverse proxy configuration (\u003ccode\u003eCaddyfile\u003c/code\u003e)\u003c/summary\u003e\n\nIn case you want a reverse proxy, configure it appropriately (in this case using a Caddyfile):\n\n```Caddyfile\n*:80, *:443 {\n    reverse_proxy /api/* backend:80\n    reverse_proxy /* frontend:80\n}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ccode\u003ebackend-appsettings.json\u003c/code\u003e template\u003c/summary\u003e\n\n```json\n{\n  \"AllowedOrigins\": [\n    \"http://localhost\"\n  ],\n  \"ConnectionStrings\": {\n    \"PubNet\": \"Host=database;Database=pubnet;Username=pubnet;Password=pubnet\"\n  },\n  \"Jwt\": {\n    \"Issuer\": \"http://localhost\",\n    \"Audience\": \"http://localhost\",\n    \"SecretKey\": \"GenerateASecureKey!\"\n  },\n  \"PackageStorage\": {\n    \"Path\": \"./packages\"\n  },\n  \"OpenRegistration\": true\n}\n\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ccode\u003eworker-appsettings.json\u003c/code\u003e template\u003c/summary\u003e\n\nAdd a `worker-appsettings.json`:\n\n\u003e You could use the same appsettings for the worker and the backend as their options shouldn't interfere.\n\n```json\n{\n  \"ConnectionStrings\": {\n    \"PubNet\": \"Host=database;Database=pubnet;Username=pubnet;Password=pubnet\"\n  },\n  \"PackageStorage\": {\n    \"Path\": \"./packages\",\n    \"PendingMaxAge\": \"00:05:00\"\n  }\n}\n\n```\n\n\u003c/details\u003e\n\nFinally, start your own `PubNet` using\n\n```bash\ndocker-compose up -d\n```\n\nand access it at [`https://localhost`](https://localhost).\n\n### Other approaches\n\nIt _should_ be possible to host the API using IIS, but it is not supported.\n\nSame goes for the Worker: it _should_ be possible to run it as a Windows service/systemd unit, but is not supported.\n\nThe frontend can be hosted from anywhere, as long as the `backend-appsettings.json` contains the domain to allow CORS.\n\n## License\n\nThis project is licensed under the Apache 2.0 license. For more information, see [LICENSE](./LICENSE).\n\n## Screenshots\n\nThis is a screenshot of how a package looks like after uploading and analysis:\n\n![Page for the package 'nmea'](.github/media/package_nmea.png)\n\nThis screenshot shows different versions in a table:\n\n![Page for the package 'nmea' versions](.github/media/package_nmea_versions.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fricardoboss%2Fpubnet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fricardoboss%2Fpubnet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fricardoboss%2Fpubnet/lists"}