Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/sergetymo/kaksik
Middleware library for creating apps for Gemini protocol on top of Deno runtime using TypeScript
https://github.com/sergetymo/kaksik
deno gemini-protocol gemini-server library middleware
Last synced: 3 months ago
JSON representation
Middleware library for creating apps for Gemini protocol on top of Deno runtime using TypeScript
- Host: GitHub
- URL: https://github.com/sergetymo/kaksik
- Owner: sergetymo
- License: mit
- Created: 2021-01-12T15:15:05.000Z (almost 4 years ago)
- Default Branch: master
- Last Pushed: 2022-07-31T08:11:55.000Z (over 2 years ago)
- Last Synced: 2024-02-08T22:30:07.689Z (9 months ago)
- Topics: deno, gemini-protocol, gemini-server, library, middleware
- Language: TypeScript
- Homepage:
- Size: 65.4 KB
- Stars: 10
- Watchers: 1
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-gemini - kaksik - middleware library for building server applications. (Programming / Graphical)
README
# Kaksik
Middleware library for creating applications for [Gemini](https://gemini.circumlunar.space) protocol
on top of [Deno](https://deno.land) runtime, written in TypeScript.Heavily inspired by [oak](https://github.com/oakserver/oak) and [denoscuri](https://github.com/caranatar/denoscuri).
## Feature roadmap
- [x] Serve gemtext (out of the box, see [Gemtext usage](#gemtext-usage))
- [x] Serve static files at configured URLs (via middleware, see [serveStatic](#servestatic))
- [x] Serve programmable resources at configured URLs (via middleware, see [handleRoutes](#handleroutes))
- [x] Serve redirect responses at configured URLs (via middleware, see [handleRedirects](#handleredirects))
- [x] Document `Gemtext` usage
- [ ] Serve gone responses at configured URLs (via middleware)
- [ ] Improve `Response` class
- [ ] -- 'Good enough' point --
- [ ] *Propose yours by [filing an issue](https://github.com/sergetymo/kaksik/issues/new)*## Usage
### Prerequisites
1. [Install](https://deno.land/#installation) Deno executable
2. Obtain SSL certificates. You can generate self-signed ones using `openssl` command:
```bash
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
```### Your first app
Create minimal application in `app.ts`:
```typescript
import { Application } from 'https://deno.land/x/kaksik/mod.ts'const app = new Application({
keyFile: '/path/to/key.pem',
certFile: '/path/to/cert.pem',
})app.use(ctx => {
ctx.response.body = '# Hello World!'
})await app.start()
```Then run it:
```bash
deno run --allow-net --allow-read app.ts
```### Gemtext usage
`Gemtext` class represents a `text/gemini` media type that is native to Gemini protocol
(see chapter 5 of [spec](https://gemini.circumlunar.space/docs/specification.html)).
It's a line-based text format, so essentially `Gemtext` is just an `Array` with helpers.
All six line types are implemented:
- [x] `LineText`
- [x] `LineLink`
- [x] `LinePreformattedToggle`
- [x] `LineHeading`
- [x] `LineQuote`
- [x] `LineListItem``Response.body` setter accepts Gemtext for convenience.
```typescript
const app = new Application({
keyFile: '/path/to/key.pem',
certFile: '/path/to/cert.pem',
})app.use(ctx => {
ctx.response.body = new Gemtext(
new LineHeading('Gemtext demo', 1),
new LineText(),
new LineLink('gemini://s.tymo.name', 'stymo'),
new LineText(),
new LineText('There will be wrapped text. Elit eius magnam quae dolor ipsa eveniet aut? Facilis natus eum reiciendis reprehenderit odio. Sed et consectetur fuga quod illum ex minus. Iste quia dolor minus saepe in! Recusandae eligendi iusto blanditiis nostrum ipsum! Consequuntur tempora eaque dolore reiciendis sit. At exercitationem repudiandae doloremque quasi non. Nesciunt veritatis aliquid magnam unde pariatur'),
new LineText(),
new LineQuote('To be or not to be?'),
new LinePreformattingToggle(),
new LineText('There will be unwrapped text. Put some ASCII-art!'),
new LinePreformattingToggle(),
)
})await app.start()
```Appending new lines and other `Gemtext` instances:
```typescript
const content = new Gemtext(
new LineHeading('Second page', 1),
new LineText(),
)// do some calculation
const prevPageId = 1
const nextPageId = 3// append more lines
content.append(
new LineHeading('Navigation'),
new LineText(),
)// create anoter Gemtext instance
const nav = new Gemtext(
new LineLink(`/pages/${prevPageId}`, 'Previous page'),
new LineLink(`/pages/${nextPageId}`, 'Next page'),
// Gemtext constructor accepts other Gemtext instances
new Gemtext(
new LineText('~~~~~~~~~'),
new LineText('2020 A.D.'),
),
)// appending mixed lines and Gemtext instances works too
content.append(
new LineText('----'),
nav,
new LineText('----'),
)
```### Other examples
See `examples` folder.## Available middleware
### serveStatic
Serves static files from a directory to specified URL
```typescript
import { Application, serveStatic } from 'https://deno.land/x/kaksik/mod.ts'const app = new Application({
keyFile: '/path/to/key.pem',
certFile: '/path/to/cert.pem',
})app.use(serveStatic('./log/', '/gemlog/'))
app.use(serveStatic('./public/'))await app.start()
```
Beware of ordering of `serveStatic` middleware usages: more generic URLs should occur
later that more specific, e.g., `/path/subpath/` must be before `/path/`.### handleRoutes
Runs specified async function when request path matches configured route.```typescript
import {
Application,
handleRoutes,
Route,
} from 'https://deno.land/x/kaksik/mod.ts'const app = new Application({
keyFile: '/path/to/key.pem',
certFile: '/path/to/cert.pem',
})app.use(handleRoutes(
new Route('/test', async (ctx) => {
ctx.response.body = '# Test page'
}),
new Route<{id?: string}>('/param/:id', async (ctx) => {
ctx.response.body = '# Parametrized page\r\n' +
'id = ' + ctx.pathParams.id
}),
new Route('/', async (ctx) => {
ctx.response.body = '# HOME page\r\n' +
'=> /test Test page served by other route\r\n' +
'=> /param/7 Parametrized page, where id=7\r\n' +
'=> /404 No routes matched'
}),
))app.use(async (ctx) => {
ctx.response.body = '# No routes matched\r\n' +
'Running fallback middleware'
})await app.start()
```### handleRedirects
Sends either temporary or permanent redirect response when path matches configuration.
```typescript
import {
Application,
handleRedirects,
handleRoutes,
Redirect,
Route,
} from 'https://deno.land/x/kaksik/mod.ts'const app = new Application({
keyFile: '/path/to/key.pem',
certFile: '/path/to/cert.pem',
})app.use(handleRedirects(
new Redirect('/short', '/long-very-long-url', true),
new Redirect('/home', 'https://tymo.name'),
))app.use(handleRoutes(
new Route('/long-very-long-url', async (ctx) => {
ctx.response.body = '# Redirect target page'
}),
))await app.start()
```## Trivia
"Kaksik" means "twin" in Estonian.