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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@gemini-dock/server

v0.1.10

Published

An extensible Gemini server written in TypeScript

Readme

Gemini Dock

An extensible Gemini server written in TypeScript

See gemini://dock.mathis.network for a demo of @gemini-dock/site-dock served by Gemini Dock.

API is not stable until v1.0.0; expect breaking changes on any upgrade.

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, unrelated to the exchange, Google AI, or any other Gemini product.

Gemini Protocol

Excerpt from geminiprotocol.net:

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.


Prerequisites

  • Linux or macOS
  • Node.js 20+
  • openssl CLI

Quick Start

cd /path/to/server/data
npx @gemini-dock/server certificate generate localhost
npx @gemini-dock/server site generate localhost
npx @gemini-dock/server migrate
npx @gemini-dock/server start

Then visit gemini://localhost to see the server in action.

Installation

npm install -g @gemini-dock/server # or your package manager's equivalent
gemini-dock --help

Upgrade

npm install -g @gemini-dock/server@latest
# or npx @gemini-dock/server@latest
gemini-dock migrate

Concepts

Sites

A 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.

A route key should only be the top-level path, and you should handle subpaths in the route handler with the options.url object.

See the Dock site source for a full-featured example with authentication, posts, comments, messages, profiles, and more.

A site can be very simple, here is the source for gemini://gem.mathis.network:

const fs = require('fs')
const body = fs.readFileSync('sites/gem.mathis.network/index.gmi', 'utf8')

module.exports = {
  '/': async () => ({ code: 20, type: 'text/gemini', body })
}

Sites can also be installed from npm, like plugins:

gemini-dock site install <name> <domain>

To install Dock (gemini://dock.mathis.network), the default development community site, run:

gemini-dock site install @gemini-dock/site-dock localhost
npm i drizzle-orm # your server data directory will need this dependency

To customize the Dock site, you may edit the source directly or use environment variables:

export DOCK_SITE_NAME="My Community"
export DOCK_SITE_DESCRIPTION="A community for my users"
gemini-dock start

To uninstall a site, run:

gemini-dock site uninstall <name>

To generate a minimal site, run:

gemini-dock site generate <name>
export default {
  '/': () => {{ code: 20, type: 'text/gemini', body: 'Hello, world!\r\n=> /login Please login' }},

  '/login': options => {
    const { certificate, db, input, url } = options
    // On non-success codes, "type" is our response content
    if (!certificate?.subject) return { code: 60, type: 'Certificate required for this route' }
    return { code: 20, type: 'text/gemini', body: 'Welcome back!' }
  },

  '/image': options => {
    const fs = require('fs')
    const image = fs.readFileSync('./image.png')
    return { code: 20, type: 'image/png', body: image }
  }
}

For a better development experience, use the @gemini-dock/protocol and @gemini-dock/types packages:

import { CODES, respond } from '@gemini-dock/protocol'
import type { SiteOptions } from '@gemini-dock/types'

export default {
  '/': (options: SiteOptions) => respond(CODES.SUCCESS, 'Hello, world!'),
  '/bad': (options: SiteOptions) => respond(CODES.FAIL_NOT_FOUND, 'Route not found'),
}

Database

There 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.

Sites 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.

Sites can of course use their own database solution for more advanced use cases.

The current database schema can be found in the packages/lib/schema/src/index.ts file.

  • users - A table for storing user accounts
  • sessions - A table for storing sessions
  • posts - A table for storing posts
  • comments - A table for storing comments on posts
  • messages - A table for storing messages between users
  • notifications - A table for storing notifications
  • likes - A table for storing likes on posts
  • data - A table for storing arbitrary data

Modules

Modules are a way to extend the functionality of Gemini Dock at buildtime. Examples can be found in the packages/modules directory.

Plugins

Plugins 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 directory.

To install a plugin, run:

npx @gemini-dock/server plugin install <name>

To uninstall a plugin, run:

npx @gemini-dock/server plugin uninstall <name>

To generate a minimal plugin, run:

npx @gemini-dock/server plugin generate <name>
export default function plugin(options) {
  return {
    on: {
      request: [(event) => {
        console.log(event.data)
        return {
          modifiedRequest: event.data.request
        }
      }],

      response: [(event) => {
        console.log(event.data)
        return {
          modifiedResponse: event.data.response
        }
      }]
    }
  }
}

Setup Certificates

The 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.

Generate a Certificate

gemini-dock certificate generate <domain>

Development

# Clone the repository
git clone https://github.com/mathiscode/gemini-dock.git
cd gemini-dock
# Install dependencies
pnpm install
# Generate a certificate for localhost
pnpm run --filter @gemini-dock/server cert:complete
# Start the server and watch for changes
pnpm dev