{"id":26769877,"url":"https://github.com/mathiscode/gemini-dock","last_synced_at":"2025-03-28T22:46:19.130Z","repository":{"id":283846563,"uuid":"953088272","full_name":"mathiscode/gemini-dock","owner":"mathiscode","description":"An extensible Gemini server written in TypeScript","archived":false,"fork":false,"pushed_at":"2025-03-22T14:50:12.000Z","size":0,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-22T15:32:36.041Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mathiscode.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"mathiscode","patreon":"mathiscode","thanks_dev":"u/gh/mathiscode"}},"created_at":"2025-03-22T14:45:09.000Z","updated_at":"2025-03-22T14:57:18.000Z","dependencies_parsed_at":"2025-03-22T15:43:49.329Z","dependency_job_id":null,"html_url":"https://github.com/mathiscode/gemini-dock","commit_stats":null,"previous_names":["mathiscode/gemini-dock"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mathiscode%2Fgemini-dock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mathiscode%2Fgemini-dock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mathiscode%2Fgemini-dock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mathiscode%2Fgemini-dock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mathiscode","download_url":"https://codeload.github.com/mathiscode/gemini-dock/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246112648,"owners_count":20725300,"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":[],"created_at":"2025-03-28T22:46:18.511Z","updated_at":"2025-03-28T22:46:19.122Z","avatar_url":"https://github.com/mathiscode.png","language":"TypeScript","funding_links":["https://github.com/sponsors/mathiscode","https://patreon.com/mathiscode","https://thanks.dev/u/gh/mathiscode"],"categories":["Servers"],"sub_categories":["Graphical"],"readme":"# Gemini Dock\n\n**An extensible Gemini server written in TypeScript**\n\nSee [gemini://dock.mathis.network](gemini://dock.mathis.network) for a demo of [@gemini-dock/site-dock](https://npmjs.com/package/@gemini-dock/site-dock) served by Gemini Dock.\n\n\u003e API is not stable until v1.0.0; expect breaking changes on any upgrade.\n\n*There is an unfortunate problem in the tech world where a lot of projects want to be called Gemini. This project is in the ecosystem of the [Gemini protocol](https://geminiprotocol.net), unrelated to the exchange, Google AI, or any other Gemini product.*\n\n## Gemini Protocol\n\n[Excerpt from geminiprotocol.net](https://geminiprotocol.net):\n\n\u003e Gemini is a group of technologies similar to the ones that lie behind your familiar web browser. Using Gemini, you can explore an online collection of written documents which can link to other written documents. The main difference is that Gemini approaches this task with a strong philosophy of \"keep it simple\" and \"less is enough\". This allows Gemini to simply sidestep, rather than try and probably fail to solve, many of the problems plaguing the modern web, which just seem to get worse and worse no matter how many browser add-ons or well meaning regulations get thrown at them.\n\n- [Protocol Specification](https://geminiprotocol.net/docs/protocol-specification.gmi)\n- [Gemtext Specification](https://geminiprotocol.net/docs/gemtext-specification.gmi)\n- [Wikipedia](https://en.wikipedia.org/wiki/Gemini_(protocol))\n\n---\n\n## Prerequisites\n\n- Linux or macOS\n- Node.js 20+\n- openssl CLI\n\n---\n\n## Quick Start\n\n```bash\ncd /path/to/server/data\nnpx @gemini-dock/server certificate generate localhost\nnpx @gemini-dock/server site generate localhost\nnpx @gemini-dock/server migrate\nnpx @gemini-dock/server start\n```\n\nThen visit [`gemini://localhost`](gemini://localhost) to see the server in action.\n\n## Installation\n\n```bash\nnpm install -g @gemini-dock/server # or your package manager's equivalent\ngemini-dock --help\n```\n\n## Upgrade\n\n```bash\nnpm install -g @gemini-dock/server@latest\n# or npx @gemini-dock/server@latest\ngemini-dock migrate\n```\n\n---\n\n## Concepts\n\n### Sites\n\nA site can be constructed in almost any way you want, as long as it exports a default object of routes, which are functions that return a response.\n\nA route key should only be the top-level path, and you should handle subpaths in the route handler with the `options.url` object.\n\nSee the [Dock site source](./packages/sites/localhost) for a full-featured example with authentication, posts, comments, messages, profiles, and more.\n\nA site can be very simple, here is the source for [`gemini://gem.mathis.network`](gemini://gem.mathis.network):\n\n```js\nconst fs = require('fs')\nconst body = fs.readFileSync('sites/gem.mathis.network/index.gmi', 'utf8')\n\nmodule.exports = {\n  '/': async () =\u003e ({ code: 20, type: 'text/gemini', body })\n}\n```\n\nSites can also be installed from npm, like plugins:\n\n```bash\ngemini-dock site install \u003cname\u003e \u003cdomain\u003e\n```\n\nTo install [Dock](https://npmjs.com/package/@gemini-dock/site-dock) (`gemini://dock.mathis.network`), the default development community site, run:\n\n```bash\ngemini-dock site install @gemini-dock/site-dock localhost\nnpm i drizzle-orm # your server data directory will need this dependency\n```\n\nTo customize the Dock site, you may edit the source directly or use environment variables:\n\n```bash\nexport DOCK_SITE_NAME=\"My Community\"\nexport DOCK_SITE_DESCRIPTION=\"A community for my users\"\ngemini-dock start\n```\n\nTo uninstall a site, run:\n\n```bash\ngemini-dock site uninstall \u003cname\u003e\n```\n\nTo generate a minimal site, run:\n\n```bash\ngemini-dock site generate \u003cname\u003e\n```\n\n```js\nexport default {\n  '/': () =\u003e {{ code: 20, type: 'text/gemini', body: 'Hello, world!\\r\\n=\u003e /login Please login' }},\n\n  '/login': options =\u003e {\n    const { certificate, db, input, url } = options\n    // On non-success codes, \"type\" is our response content\n    if (!certificate?.subject) return { code: 60, type: 'Certificate required for this route' }\n    return { code: 20, type: 'text/gemini', body: 'Welcome back!' }\n  },\n\n  '/image': options =\u003e {\n    const fs = require('fs')\n    const image = fs.readFileSync('./image.png')\n    return { code: 20, type: 'image/png', body: image }\n  }\n}\n```\n\nFor a better development experience, use the [@gemini-dock/protocol](https://npmjs.com/package/@gemini-dock/protocol) and [@gemini-dock/types](https://npmjs.com/package/@gemini-dock/types) packages:\n\n```ts\nimport { CODES, respond } from '@gemini-dock/protocol'\nimport type { SiteOptions } from '@gemini-dock/types'\n\nexport default {\n  '/': (options: SiteOptions) =\u003e respond(CODES.SUCCESS, 'Hello, world!'),\n  '/bad': (options: SiteOptions) =\u003e respond(CODES.FAIL_NOT_FOUND, 'Route not found'),\n}\n```\n\n### Database\n\nThere is a SQLite database that is used to store data for sites. The schema is handled by the server, and sites can store arbitrary data in the `metadata` columns or in the `data` table.\n\nSites are expected to use the `site` column of each table to differentiate data between sites. There is no private data between sites, unless implemented by the site itself.\n\nSites can of course use their own database solution for more advanced use cases.\n\nThe current database schema can be found in the [packages/lib/schema/src/index.ts](packages/lib/schema/src/index.ts) file.\n\n- `users` - A table for storing user accounts\n- `sessions` - A table for storing sessions\n- `posts` - A table for storing posts\n- `comments` - A table for storing comments on posts\n- `messages` - A table for storing messages between users\n- `notifications` - A table for storing notifications\n- `likes` - A table for storing likes on posts\n- `data` - A table for storing arbitrary data\n\n### Modules\n\nModules are a way to extend the functionality of Gemini Dock at buildtime. Examples can be found in the [packages/modules](./packages/modules) directory.\n\n### Plugins\n\nPlugins are a way to extend the functionality of Gemini Dock at runtime, and is simply a default export of a function that returns an object with listeners (see below). Examples can be found in the [packages/plugins](./packages/plugins) directory.\n\nTo install a plugin, run:\n\n```bash\nnpx @gemini-dock/server plugin install \u003cname\u003e\n```\n\nTo uninstall a plugin, run:\n\n```bash\nnpx @gemini-dock/server plugin uninstall \u003cname\u003e\n```\n\nTo generate a minimal plugin, run:\n\n```bash\nnpx @gemini-dock/server plugin generate \u003cname\u003e\n```\n\n```js\nexport default function plugin(options) {\n  return {\n    on: {\n      request: [(event) =\u003e {\n        console.log(event.data)\n        return {\n          modifiedRequest: event.data.request\n        }\n      }],\n\n      response: [(event) =\u003e {\n        console.log(event.data)\n        return {\n          modifiedResponse: event.data.response\n        }\n      }]\n    }\n  }\n}\n```\n\n\n\n---\n\n## Setup Certificates\n\nThe server will need a certificate for each site you want to serve, and they are stored in the `CERTS_PATH` environment variable path (or `./.certs` by default) with the subdirectory being the domain, e.g. `.certs/example.com`. It should contain a `certificate.pem`, `csr.pem`, and `private.key` file.\n\n### Generate a Certificate\n\n```bash\ngemini-dock certificate generate \u003cdomain\u003e\n```\n\n---\n\n## Development\n\n```bash\n# Clone the repository\ngit clone https://github.com/mathiscode/gemini-dock.git\ncd gemini-dock\n# Install dependencies\npnpm install\n# Generate a certificate for localhost\npnpm run --filter @gemini-dock/server cert:complete\n# Start the server and watch for changes\npnpm dev\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmathiscode%2Fgemini-dock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmathiscode%2Fgemini-dock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmathiscode%2Fgemini-dock/lists"}