Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v1 Setup #31

Merged
merged 28 commits into from
Dec 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
596fdd9
move v0 to its own folder
jackyzha0 Nov 23, 2022
eb8f053
setup typescript and basic linting
jackyzha0 Nov 23, 2022
8eab68c
basic ava setup
jackyzha0 Nov 23, 2022
11b635c
stub out /sites api
jackyzha0 Nov 23, 2022
01a2e89
fix types, update linting+ci
jackyzha0 Nov 23, 2022
db50e84
fix ci
jackyzha0 Nov 23, 2022
3441f9e
move working-directory to with
jackyzha0 Nov 23, 2022
e743b2d
use defaults for ci
jackyzha0 Nov 23, 2022
3429fd9
fix async in fn sig
jackyzha0 Nov 23, 2022
3457826
ci path fix
jackyzha0 Nov 23, 2022
6ca917b
modify tsconfig to qualify included src path
jackyzha0 Nov 23, 2022
cec3ef4
remove lint rule
jackyzha0 Nov 23, 2022
28fd96c
feat: swagger generation
jackyzha0 Nov 29, 2022
2bed4a9
stub out config, protocols, refactor api
jackyzha0 Nov 29, 2022
317750c
linting+fmt pass
jackyzha0 Nov 29, 2022
e954982
Update .github/workflows/tests.yaml
jackyzha0 Nov 30, 2022
295765a
add prometheus, rewrite using esm
jackyzha0 Dec 2, 2022
d7ebcd1
tsc -> ts-node + nodemon
jackyzha0 Dec 2, 2022
0c28db8
Merge branch 'v1-staging' of https://github.com/hyphacoop/api.distrib…
jackyzha0 Dec 2, 2022
fe5a6da
remove build step from ci test
jackyzha0 Dec 2, 2022
192771f
initial leveldb setup
jackyzha0 Dec 4, 2022
cf24dc7
unstub
jackyzha0 Dec 4, 2022
9794abe
leveldb tests and impl
jackyzha0 Dec 5, 2022
e055b09
make config export a class, add support for host option closes #33
jackyzha0 Dec 5, 2022
e56536c
codegen docs
jackyzha0 Dec 5, 2022
f04cdea
move dev deps to proper location
jackyzha0 Dec 6, 2022
07ee182
Merge pull request #32 from hyphacoop/config
jackyzha0 Dec 6, 2022
de409e9
fix dep version
jackyzha0 Dec 6, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Tests

on:
push:
branches: [ main, v1 ]
pull_request:
branches: [ main, v1 ]

jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: v1

strategy:
matrix:
node-version: [18.x]

steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ bower_components

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
v1/build/

# Dependency directories
node_modules/
Expand Down Expand Up @@ -104,4 +105,5 @@ dist
.tern-port

# Distributed Press data files
.data/
.data/
v1/store
364 changes: 13 additions & 351 deletions README.md

Large diffs are not rendered by default.

11 changes: 0 additions & 11 deletions package-lock.json

This file was deleted.

368 changes: 368 additions & 0 deletions v0/README.md

Large diffs are not rendered by default.

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
35 changes: 35 additions & 0 deletions v1/api/admin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Static } from '@sinclair/typebox'
import { FastifyInstance } from 'fastify'
import { StoreI } from '../config/index.js'
import { NewAdmin } from './schemas.js'

export const adminRoutes = (store: StoreI) => async (server: FastifyInstance): Promise<void> => {
server.post<{
Body: Static<typeof NewAdmin>
Reply: string
}>('/admin', {
schema: {
body: NewAdmin,
description: 'Add a new admin.',
tags: ['admin']
}
}, async (request, reply) => {
const id = await store.admin.create(request.body)
return reply.send(id)
})

server.delete<{
Params: {
id: string
}
}>('/admin/:id', {
schema: {
description: 'Delete an admin',
tags: ['admin']
}
}, async (request, reply) => {
const { id } = request.params
await store.admin.delete(id)
return reply.status(200)
})
}
11 changes: 11 additions & 0 deletions v1/api/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import test from 'ava'
import apiBuilder from './index.js'

test('health check /healthz', async t => {
const server = await apiBuilder({})
const response = await server.inject({
method: 'GET',
url: '/healthz'
})
t.is(response.statusCode, 200, 'returns a status code of 200')
})
76 changes: 76 additions & 0 deletions v1/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
import fastify, { FastifyBaseLogger, FastifyInstance, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerDefault } from 'fastify'
import multipart from '@fastify/multipart'
import swagger from '@fastify/swagger'
import swagger_ui from '@fastify/swagger-ui'
import metrics from 'fastify-metrics'
import { siteRoutes } from './sites.js'
import { adminRoutes } from './admin.js'
import { publisherRoutes } from './publisher.js'
import Store, { StoreI } from '../config/index.js'

export type FastifyTypebox = FastifyInstance<
RawServerDefault,
RawRequestDefaultExpression<RawServerDefault>,
RawReplyDefaultExpression<RawServerDefault>,
FastifyBaseLogger,
TypeBoxTypeProvider
>

interface APIConfig {
useLogging: boolean
useSwagger: boolean
usePrometheus: boolean
}

async function apiBuilder (cfg: Partial<APIConfig>, store: StoreI = new Store()): Promise<FastifyTypebox> {
const server = fastify({ logger: cfg.useLogging }).withTypeProvider<TypeBoxTypeProvider>()
await server.register(multipart)

server.get('/healthz', () => {
return 'ok\n'
})

await server.register(v1Routes(cfg, store), { prefix: '/v1' })
await server.ready()
return server
}

const v1Routes = (cfg: Partial<APIConfig>, store: StoreI) => async (server: FastifyTypebox): Promise<void> => {
if (cfg.usePrometheus ?? false) {
server.register(metrics, { endpoint: '/metrics' });
}

if (cfg.useSwagger ?? false) {
await server.register(swagger, {
swagger: {
info: {
title: 'Distributed Press API',
description: 'Documentation on how to use the Distributed Press API to publish your website content and the Distributed Press API for your project',
version: '1.0.0'
},
tags: [
{ name: 'site', description: 'Managing site deployments' },
{ name: 'publisher', description: 'Publisher account management. Publishers can manage site deployments' },
{ name: 'admin', description: 'Admin management. Admins can create, modify, and delete publishers' }
]
}
})

await server.register(swagger_ui, {
routePrefix: '/docs'
})
}

// Register Routes
await server.register(siteRoutes(store))
await server.register(publisherRoutes(store))
await server.register(adminRoutes(store))

if (cfg.useSwagger ?? false) {
server.swagger()
server.log.info('Registered Swagger endpoints')
}
}

export default apiBuilder
57 changes: 57 additions & 0 deletions v1/api/publisher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Type, Static } from '@sinclair/typebox'
import { FastifyInstance } from 'fastify'
import { StoreI } from '../config/index.js'
import { NewPublisher, Publisher } from './schemas.js'

export const publisherRoutes = (store: StoreI) => async (server: FastifyInstance): Promise<void> => {
server.post<{
Body: Static<typeof NewPublisher>
Reply: Static<typeof Publisher>
}>('/publisher', {
schema: {
body: Publisher,
response: {
200: Publisher
},
description: 'Add a new publisher.',
tags: ['publisher']
}
}, async (request, _reply) => {
return store.publisher.create(request.body)
})

server.get<{
Params: {
id: string
}
Reply: Static<typeof Publisher>
}>('/publisher/:id', {
schema: {
params: {
id: Type.String()
},
response: {
200: Publisher
},
description: 'Gets information about a specific publisher',
tags: ['publisher']
}
}, async (request, _reply) => {
const { id } = request.params
return store.publisher.get(id)
})

server.delete<{
Params: {
id: string
}
}>('/publisher/:id', {
schema: {
description: 'Delete a publisher',
tags: ['publisher']
}
}, async (request, _reply) => {
const { id } = request.params
return store.publisher.delete(id)
})
}
51 changes: 51 additions & 0 deletions v1/api/schemas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Type } from '@sinclair/typebox'

export const DNS = Type.Object({
server: Type.String(),
domains: Type.Array(Type.String())
})

export const Links = Type.Partial(Type.Object({
http: Type.String(),
hyper: Type.String(),
hyperGateway: Type.String(),
hyperRaw: Type.String(),
ipns: Type.String(),
ipnsRaw: Type.String(),
ipnsGateway: Type.String(),
ipfs: Type.String(),
ipfsGateway: Type.String()
}))

export const Publication = Type.Object({
enabled: Type.Boolean(),
pinningURL: Type.Optional(Type.String())
})

export const Site = Type.Object({
id: Type.String(),
domain: Type.String(),
dns: DNS,
links: Links,
publication: Type.Object({
http: Type.Partial(Publication),
hyper: Type.Partial(Publication),
ipfs: Type.Partial(Publication)
})
})
export const NewSite = Type.Omit(Site, ['publication', 'id'])
export const UpdateSite = Type.Partial(Type.Omit(Site, ['id']))

export const Publisher = Type.Object({
id: Type.String(),
name: Type.String()
// TODO: what other fields do we need here?
})
export const NewPublisher = Type.Omit(Publisher, ['id'])

export const Admin = Type.Object({
id: Type.String(),
name: Type.String()
// TODO: what other fields do we need here?
})
export const NewAdmin = Type.Omit(Admin, ['id'])
Loading